bitcoin-cash 1.0.0-beta.0

A library for creating and parsing Bitcoin Cash trasactions
Documentation
use crate::{
    encoding_utils::{encode_var_int, read_var_int},
    error::Result,
    ByteArray, FixedByteArray,
};

pub trait BitcoinCode: Sized {
    fn ser(&self) -> ByteArray;
    fn deser(data: ByteArray) -> Result<(Self, ByteArray)>;
}

fn read_size(data: ByteArray) -> Result<(usize, ByteArray)> {
    let mut cursor = std::io::Cursor::new(data.as_slice());
    let len = read_var_int(&mut cursor)? as usize;
    let position = cursor.position() as usize;
    let (_, rest) = data.split(position)?;
    Ok((len, rest))
}

impl BitcoinCode for ByteArray {
    fn ser(&self) -> ByteArray {
        ByteArray::new("size", encode_var_int(self.len() as u64)).concat(self.clone())
    }

    fn deser(data: ByteArray) -> Result<(Self, ByteArray)> {
        let (len, rest) = read_size(data)?;
        let (byte_array, rest) = rest.split(len)?;
        Ok((byte_array, rest))
    }
}

impl<T> BitcoinCode for FixedByteArray<T>
where
    T: Default + AsRef<[u8]>,
{
    fn ser(&self) -> ByteArray {
        self.as_byte_array().clone()
    }

    fn deser(data: ByteArray) -> Result<(Self, ByteArray)> {
        let array = T::default();
        let split_idx = array.as_ref().len();
        let (left, right) = data.split(split_idx)?;
        let fixed_byte_array = Self::from_byte_array(left)?;
        Ok((fixed_byte_array, right))
    }
}

impl<T: BitcoinCode> BitcoinCode for Vec<T> {
    fn ser(&self) -> ByteArray {
        let parts = self.iter().map(|item| item.ser());
        let data = ByteArray::from_parts(parts);
        ByteArray::new("size", encode_var_int(self.len() as u64)).concat(data)
    }

    fn deser(data: ByteArray) -> Result<(Self, ByteArray)> {
        let (len, mut byte_array) = read_size(data)?;
        let mut vec = Vec::with_capacity(len);
        for _ in 0..len {
            let (item, rest) = T::deser(byte_array)?;
            vec.push(item);
            byte_array = rest;
        }
        Ok((vec, byte_array))
    }
}

impl BitcoinCode for bool {
    fn ser(&self) -> ByteArray {
        [*self as u8].into()
    }

    fn deser(data: ByteArray) -> Result<(Self, ByteArray)> {
        let (left, right) = data.split(1)?;
        Ok((left[0] != 0, right))
    }
}

macro_rules! array_impls {
    ($($T:ident)+) => {
        $(
            impl BitcoinCode for $T {
                fn ser(&self) -> ByteArray {
                    self.to_le_bytes().into()
                }

                fn deser(data: ByteArray) -> Result<(Self, ByteArray)> {
                    let split_idx = std::mem::size_of::<$T>();
                    let (left, right) = data.split(split_idx)?;
                    let mut array = [0; std::mem::size_of::<$T>()];
                    array.copy_from_slice(&left);
                    let value = $T::from_le_bytes(array);
                    Ok((value, right))
                }
            }
        )+
    }
}

array_impls! {
    u8 i8 u16 i16 u32 i32 u64 i64 u128 i128
}