Add private ScriptBufAsVec type
Add a private type that allows us to mutate the inner vector of a `ScriptBuf` only using public functions and never touching the inner field. Done in preparation for moving the `ScriptBuf` to `primitives`. Mad hackery by Kix!
This commit is contained in:
parent
c81fb93359
commit
4ff5d6886b
|
@ -105,7 +105,7 @@ impl ScriptBuf {
|
|||
}
|
||||
|
||||
/// Adds a single opcode to the script.
|
||||
pub fn push_opcode(&mut self, data: Opcode) { self.0.push(data.to_u8()); }
|
||||
pub fn push_opcode(&mut self, data: Opcode) { self.as_byte_vec().push(data.to_u8()); }
|
||||
|
||||
/// Adds instructions to push some arbitrary data onto the stack.
|
||||
pub fn push_slice<T: AsRef<PushBytes>>(&mut self, data: T) {
|
||||
|
@ -153,33 +153,42 @@ impl ScriptBuf {
|
|||
}
|
||||
|
||||
impl ScriptBuf {
|
||||
/// Pretends to convert `&mut ScriptBuf` to `&mut Vec<u8>` so that it can be modified.
|
||||
///
|
||||
/// Note: if the returned value leaks the original `ScriptBuf` will become empty.
|
||||
pub(crate) fn as_byte_vec(&mut self) -> ScriptBufAsVec<'_> {
|
||||
let vec = core::mem::take(self).into_bytes();
|
||||
ScriptBufAsVec(self, vec)
|
||||
}
|
||||
|
||||
/// Pushes the slice without reserving
|
||||
pub(crate) fn push_slice_no_opt(&mut self, data: &PushBytes) {
|
||||
let mut this = self.as_byte_vec();
|
||||
// Start with a PUSH opcode
|
||||
match data.len().to_u64() {
|
||||
n if n < opcodes::Ordinary::OP_PUSHDATA1 as u64 => {
|
||||
self.0.push(n as u8);
|
||||
this.push(n as u8);
|
||||
}
|
||||
n if n < 0x100 => {
|
||||
self.0.push(opcodes::Ordinary::OP_PUSHDATA1.to_u8());
|
||||
self.0.push(n as u8);
|
||||
this.push(opcodes::Ordinary::OP_PUSHDATA1.to_u8());
|
||||
this.push(n as u8);
|
||||
}
|
||||
n if n < 0x10000 => {
|
||||
self.0.push(opcodes::Ordinary::OP_PUSHDATA2.to_u8());
|
||||
self.0.push((n % 0x100) as u8);
|
||||
self.0.push((n / 0x100) as u8);
|
||||
this.push(opcodes::Ordinary::OP_PUSHDATA2.to_u8());
|
||||
this.push((n % 0x100) as u8);
|
||||
this.push((n / 0x100) as u8);
|
||||
}
|
||||
// `PushBytes` enforces len < 0x100000000
|
||||
n => {
|
||||
self.0.push(opcodes::Ordinary::OP_PUSHDATA4.to_u8());
|
||||
self.0.push((n % 0x100) as u8);
|
||||
self.0.push(((n / 0x100) % 0x100) as u8);
|
||||
self.0.push(((n / 0x10000) % 0x100) as u8);
|
||||
self.0.push((n / 0x1000000) as u8);
|
||||
this.push(opcodes::Ordinary::OP_PUSHDATA4.to_u8());
|
||||
this.push((n % 0x100) as u8);
|
||||
this.push(((n / 0x100) % 0x100) as u8);
|
||||
this.push(((n / 0x10000) % 0x100) as u8);
|
||||
this.push((n / 0x1000000) as u8);
|
||||
}
|
||||
}
|
||||
// Then push the raw bytes
|
||||
self.0.extend_from_slice(data.as_bytes());
|
||||
this.extend_from_slice(data.as_bytes());
|
||||
}
|
||||
|
||||
/// Computes the sum of `len` and the length of an appropriate push opcode.
|
||||
|
@ -200,7 +209,7 @@ impl ScriptBuf {
|
|||
pub(crate) fn push_verify(&mut self, last_opcode: Option<Opcode>) {
|
||||
match opcode_to_verify(last_opcode) {
|
||||
Some(opcode) => {
|
||||
self.0.pop();
|
||||
self.as_byte_vec().pop();
|
||||
self.push_opcode(opcode);
|
||||
}
|
||||
None => self.push_opcode(OP_VERIFY),
|
||||
|
@ -254,3 +263,31 @@ impl<'a> Extend<Instruction<'a>> for ScriptBuf {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pretends that this is a mutable reference to [`ScriptBuf`]'s internal buffer.
|
||||
///
|
||||
/// In reality the backing `Vec<u8>` is swapped with an empty one and this is holding both the
|
||||
/// reference and the vec. The vec is put back when this drops so it also covers paics. (But not
|
||||
/// leaks, which is OK since we never leak.)
|
||||
pub(crate) struct ScriptBufAsVec<'a>(&'a mut ScriptBuf, Vec<u8>);
|
||||
|
||||
impl<'a> core::ops::Deref for ScriptBufAsVec<'a> {
|
||||
type Target = Vec<u8>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.1
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> core::ops::DerefMut for ScriptBufAsVec<'a> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.1
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for ScriptBufAsVec<'a> {
|
||||
fn drop(&mut self) {
|
||||
let vec = core::mem::take(&mut self.1);
|
||||
*(self.0) = ScriptBuf::from_bytes(vec);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue