use core::fmt;
use super::{Error, Script, ScriptBuf};
use crate::opcodes::all::{
OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY, OP_CHECKSIG, OP_CHECKSIGVERIFY, OP_EQUAL,
OP_EQUALVERIFY, OP_NUMEQUAL, OP_NUMEQUALVERIFY, OP_VERIFY,
};
use crate::opcodes::Opcode;
use crate::prelude::Vec;
#[derive(PartialEq, Eq, Clone)]
pub struct Builder<T>(ScriptBuf<T>, Option<Opcode>);
impl<T> Builder<T> {
pub const fn new() -> Self {
Self(ScriptBuf::new(), None)
}
pub fn with_capacity(capacity: usize) -> Self {
Self(ScriptBuf::with_capacity(capacity), None)
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn push_int(mut self, n: i32) -> Result<Self, Error> {
self.0.push_int(n)?;
self.1 = None;
Ok(self)
}
#[must_use]
pub fn push_int_unchecked(mut self, n: i64) -> Self {
self.0.push_int_unchecked(n);
self.1 = None;
self
}
#[must_use]
pub fn push_int_non_minimal(mut self, data: i64) -> Self {
self.0.push_int_non_minimal(data);
self.1 = None;
self
}
#[must_use]
pub fn push_slice<D: AsRef<[u8]>>(mut self, data: D) -> Self {
self.0.push_slice(data);
self.1 = None;
self
}
#[must_use]
pub fn push_slice_non_minimal<D: AsRef<[u8]>>(mut self, data: D) -> Self {
self.0.push_slice_non_minimal(data);
self.1 = None;
self
}
#[must_use]
pub fn push_opcode(mut self, opcode: Opcode) -> Self {
self.0.push_opcode(opcode);
self.1 = Some(opcode);
self
}
#[must_use]
pub fn push_verify(mut self) -> Self {
match opcode_to_verify(self.1) {
Some(opcode) => {
self.0.as_byte_vec().pop();
self.push_opcode(opcode)
}
None => self.push_opcode(OP_VERIFY),
}
}
pub fn into_script(self) -> ScriptBuf<T> {
self.0
}
pub fn into_bytes(self) -> Vec<u8> {
self.0.into_bytes()
}
pub fn as_script(&self) -> &Script<T> {
self.0.as_script()
}
pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}
}
impl<T> Default for Builder<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> From<Vec<u8>> for Builder<T> {
fn from(v: Vec<u8>) -> Self {
let script = ScriptBuf::from_bytes(v);
let last_op = script.last_opcode();
Self(script, last_op)
}
}
impl<T> fmt::Display for Builder<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl<T> fmt::Debug for Builder<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
fn opcode_to_verify(opcode: Option<Opcode>) -> Option<Opcode> {
opcode.and_then(|opcode| match opcode {
OP_EQUAL => Some(OP_EQUALVERIFY),
OP_NUMEQUAL => Some(OP_NUMEQUALVERIFY),
OP_CHECKSIG => Some(OP_CHECKSIGVERIFY),
OP_CHECKMULTISIG => Some(OP_CHECKMULTISIGVERIFY),
_ => None,
})
}