use std::fmt::Debug;
use std::fmt::Display;
use dyn_clone::clone_trait_object;
use dyn_clone::DynClone;
use crate::clarity::macros::impl_clarity_primitive;
use crate::clarity::macros::impl_clarity_primitive_cast;
use crate::crypto;
#[path = "impl.rs"]
pub mod impls;
#[path = "macro.rs"]
pub mod macros;
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum Error {
#[error("Bad string length - received {0} bytes, max. {1} bytes")]
BadStringLength(usize, usize),
#[error("Bad string type - expected: {0}")]
BadStringType(String),
#[error("Bad type identifier - expected: {0}, received: {1}")]
BadIdentifier(u8, u8),
#[error("Bad downcast, please check the type identifier and the cast type")]
BadDowncast,
#[error("Unexpected type identifier - received: {0}")]
UnexpectedType(u8),
#[error(transparent)]
C32(#[from] crypto::c32::Error),
#[error(transparent)]
TryFromInt(#[from] std::num::TryFromIntError),
#[error(transparent)]
TryFromUtf8(#[from] std::string::FromUtf8Error),
}
pub(crate) const CLARITY_TYPE_INT: u8 = 0x00;
pub(crate) const CLARITY_TYPE_UINT: u8 = 0x01;
pub(crate) const CLARITY_TYPE_BUFFER: u8 = 0x02;
pub(crate) const CLARITY_TYPE_BOOL_TRUE: u8 = 0x03;
pub(crate) const CLARITY_TYPE_BOOL_FALSE: u8 = 0x04;
pub(crate) const CLARITY_TYPE_STD_PR: u8 = 0x05;
pub(crate) const CLARITY_TYPE_CON_PR: u8 = 0x06;
pub(crate) const CLARITY_TYPE_RESPONSE_OK: u8 = 0x07;
pub(crate) const CLARITY_TYPE_RESPONSE_ERR: u8 = 0x08;
pub(crate) const CLARITY_TYPE_OPTIONAL_NONE: u8 = 0x09;
pub(crate) const CLARITY_TYPE_OPTIONAL_SOME: u8 = 0x0a;
pub(crate) const CLARITY_TYPE_LIST: u8 = 0x0b;
pub(crate) const CLARITY_TYPE_TUPLE: u8 = 0x0c;
pub(crate) const CLARITY_TYPE_STRING_ASCII: u8 = 0x0d;
pub(crate) const CLARITY_TYPE_STRING_UTF8: u8 = 0x0e;
pub(crate) const CLARITY_TYPE_NON_STD: u8 = 0xff;
pub trait Clarity: Codec + Ident + Any + DynClone + Display + Debug {}
clone_trait_object!(Clarity);
pub trait Codec {
fn encode(&self) -> Result<Vec<u8>, Error>;
fn decode(bytes: &[u8]) -> Result<Self, Error>
where
Self: Sized;
fn len(&self) -> Result<usize, Error> {
Ok(self.encode()?.len())
}
fn is_empty(&self) -> Result<bool, Error> {
Ok(self.len()? == 0)
}
fn hex(&self) -> Result<String, Error> {
Ok(crypto::bytes_to_hex(self.encode()?))
}
fn hex_prefixed(&self) -> Result<String, Error> {
Ok(format!("0x{}", self.hex()?))
}
}
pub trait Ident {
fn id() -> u8
where
Self: Sized;
}
pub trait Any: std::any::Any {
fn as_any(&self) -> &dyn std::any::Any;
fn into_any(self: Box<Self>) -> Box<dyn std::any::Any>;
}
pub trait Cast {
fn cast<T: Clarity>(self) -> Result<T, Error>;
fn cast_as<T: Clarity>(&self) -> Result<&T, Error>;
}
impl_clarity_primitive_cast!(Box<dyn Clarity>);
impl_clarity_primitive!(Int, i128, CLARITY_TYPE_INT);
impl_clarity_primitive!(UInt, u128, CLARITY_TYPE_UINT);
impl_clarity_primitive!(Buffer, Vec<u8>, CLARITY_TYPE_BUFFER);
impl_clarity_primitive!(True, true, bool, CLARITY_TYPE_BOOL_TRUE);
impl_clarity_primitive!(False, false, bool, CLARITY_TYPE_BOOL_FALSE);
impl_clarity_primitive!(PrincipalStandard, String, CLARITY_TYPE_STD_PR);
impl_clarity_primitive!(PrincipalContract, (String, String), CLARITY_TYPE_CON_PR);
impl_clarity_primitive_cast!(ResponseOk, Box<dyn Clarity>, CLARITY_TYPE_RESPONSE_OK);
impl_clarity_primitive_cast!(ResponseErr, Box<dyn Clarity>, CLARITY_TYPE_RESPONSE_ERR);
impl_clarity_primitive_cast!(OptionalSome, Box<dyn Clarity>, CLARITY_TYPE_OPTIONAL_SOME);
impl_clarity_primitive!(OptionalNone, None, Option<()>, CLARITY_TYPE_OPTIONAL_NONE);
impl_clarity_primitive!(List, Vec<Box<dyn Clarity>>, CLARITY_TYPE_LIST);
impl_clarity_primitive!(Tuple, Vec<(String, Box<dyn Clarity>)>, CLARITY_TYPE_TUPLE);
impl_clarity_primitive!(StringAscii, String, CLARITY_TYPE_STRING_ASCII);
impl_clarity_primitive!(StringUtf8, String, CLARITY_TYPE_STRING_UTF8);
impl_clarity_primitive!(LengthPrefixedStr, String, CLARITY_TYPE_NON_STD);
impl_clarity_primitive!(FnArguments, Vec<Box<dyn Clarity>>, CLARITY_TYPE_NON_STD);
pub fn decode_clarity_type(bytes: &[u8]) -> Result<Box<dyn Clarity>, Error> {
let tag = bytes[0];
match tag {
CLARITY_TYPE_INT => Ok(Box::new(Int::decode(bytes)?)),
CLARITY_TYPE_UINT => Ok(Box::new(UInt::decode(bytes)?)),
CLARITY_TYPE_BUFFER => Ok(Box::new(Buffer::decode(bytes)?)),
CLARITY_TYPE_BOOL_TRUE => Ok(Box::new(True::decode(bytes)?)),
CLARITY_TYPE_BOOL_FALSE => Ok(Box::new(False::decode(bytes)?)),
CLARITY_TYPE_STD_PR => Ok(Box::new(PrincipalStandard::decode(bytes)?)),
CLARITY_TYPE_CON_PR => Ok(Box::new(PrincipalContract::decode(bytes)?)),
CLARITY_TYPE_RESPONSE_OK => Ok(Box::new(ResponseOk::decode(bytes)?)),
CLARITY_TYPE_RESPONSE_ERR => Ok(Box::new(ResponseErr::decode(bytes)?)),
CLARITY_TYPE_OPTIONAL_NONE => Ok(Box::new(OptionalNone::decode(bytes)?)),
CLARITY_TYPE_OPTIONAL_SOME => Ok(Box::new(OptionalSome::decode(bytes)?)),
CLARITY_TYPE_LIST => Ok(Box::new(List::decode(bytes)?)),
CLARITY_TYPE_TUPLE => Ok(Box::new(Tuple::decode(bytes)?)),
CLARITY_TYPE_STRING_ASCII => Ok(Box::new(StringAscii::decode(bytes)?)),
CLARITY_TYPE_STRING_UTF8 => Ok(Box::new(StringUtf8::decode(bytes)?)),
_ => Err(Error::UnexpectedType(tag)),
}
}