psibase 0.23.0

Library and command-line tool for interacting with psibase networks
Documentation
use crate::serialize_as_str;
use custom_error::custom_error;
use fracpack::{FracInputStream, Pack, ToSchema, Unpack};
use std::fmt;
use std::str::FromStr;

custom_error! { pub MemoError
    MemoTooLarge = "Memo must be 80 bytes or less"
}

#[derive(Debug, Clone, ToSchema, Default, Pack)]
#[fracpack(fracpack_mod = "fracpack")]
pub struct Memo(String);

impl Memo {
    pub fn new(value: String) -> Result<Self, MemoError> {
        if value.len() <= 80 {
            Ok(Self(value))
        } else {
            Err(MemoError::MemoTooLarge)
        }
    }
}

impl fmt::Display for Memo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl TryFrom<String> for Memo {
    type Error = MemoError;

    fn try_from(value: String) -> Result<Self, Self::Error> {
        Self::new(value)
    }
}

impl FromStr for Memo {
    type Err = MemoError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::new(s.to_string())
    }
}

impl From<&str> for Memo {
    fn from(s: &str) -> Self {
        Memo::from_str(s).unwrap()
    }
}

impl<'a> Unpack<'a> for Memo {
    const FIXED_SIZE: u32 = 4;
    const VARIABLE_SIZE: bool = true;

    fn unpack(src: &mut FracInputStream) -> fracpack::Result<Self> {
        Ok(Self::new(String::unpack(src)?).map_err(|_| fracpack::Error::ExtraData)?)
    }

    fn verify(src: &mut FracInputStream) -> fracpack::Result<()> {
        let len = <&str>::unpack(src)?.len();

        if len <= 80 {
            Ok(())
        } else {
            Err(fracpack::Error::ExtraData)
        }
    }

    fn new_empty_container() -> fracpack::Result<Self> {
        Ok(Default::default())
    }
}

serialize_as_str!(Memo, "memo");