diff --git a/crates/clvm-utils/src/lib.rs b/crates/clvm-utils/src/lib.rs index 5d642a3e1..ebeca6c7c 100644 --- a/crates/clvm-utils/src/lib.rs +++ b/crates/clvm-utils/src/lib.rs @@ -26,8 +26,12 @@ mod curried_program; mod curry_tree_hash; +mod owned_atom; +mod sized_atom; mod tree_hash; pub use curried_program::*; pub use curry_tree_hash::*; +pub use owned_atom::*; +pub use sized_atom::*; pub use tree_hash::*; diff --git a/crates/clvm-utils/src/owned_atom.rs b/crates/clvm-utils/src/owned_atom.rs new file mode 100644 index 000000000..624770fbe --- /dev/null +++ b/crates/clvm-utils/src/owned_atom.rs @@ -0,0 +1,92 @@ +use std::ops::Deref; + +use clvm_traits::{ClvmDecoder, ClvmEncoder, FromClvm, FromClvmError, ToClvm, ToClvmError}; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct OwnedAtom(Vec); + +impl OwnedAtom { + pub fn new(data: Vec) -> Self { + Self(data) + } + + pub fn into_inner(self) -> Vec { + self.0 + } +} + +impl AsRef<[u8]> for OwnedAtom { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl From> for OwnedAtom { + fn from(data: Vec) -> Self { + Self(data) + } +} + +impl From for Vec { + fn from(atom: OwnedAtom) -> Self { + atom.0 + } +} + +impl Deref for OwnedAtom { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl ToClvm for OwnedAtom { + fn to_clvm(&self, encoder: &mut impl ClvmEncoder) -> Result { + encoder.encode_atom(self) + } +} + +impl FromClvm for OwnedAtom { + fn from_clvm(decoder: &impl ClvmDecoder, node: N) -> Result { + decoder + .decode_atom(&node) + .map(|atom| Self::new(atom.as_ref().to_vec())) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use clvmr::{ + serde::{node_from_bytes, node_to_bytes}, + Allocator, + }; + + #[test] + fn test_to_clvm() { + let a = &mut Allocator::new(); + + let ptr = OwnedAtom::new(Vec::new()).to_clvm(a).unwrap(); + let bytes = node_to_bytes(a, ptr).unwrap(); + assert_eq!(hex::encode(bytes), "80".to_owned()); + + let ptr = OwnedAtom::new(b"hello".to_vec()).to_clvm(a).unwrap(); + let bytes = node_to_bytes(a, ptr).unwrap(); + assert_eq!(hex::encode(bytes), "8568656c6c6f".to_owned()); + } + + #[test] + fn test_from_clvm() { + let a = &mut Allocator::new(); + + let ptr = node_from_bytes(a, &hex::decode("80").unwrap()).unwrap(); + let value = OwnedAtom::from_clvm(a, ptr).unwrap(); + assert_eq!(value, OwnedAtom::new(Vec::new())); + + let ptr = node_from_bytes(a, &hex::decode("8568656c6c6f").unwrap()).unwrap(); + let value = OwnedAtom::from_clvm(a, ptr).unwrap(); + assert_eq!(value, OwnedAtom::new(b"hello".to_vec())); + } +} diff --git a/crates/clvm-utils/src/sized_atom.rs b/crates/clvm-utils/src/sized_atom.rs new file mode 100644 index 000000000..5cc29c56a --- /dev/null +++ b/crates/clvm-utils/src/sized_atom.rs @@ -0,0 +1,98 @@ +use std::ops::Deref; + +use clvm_traits::{ClvmDecoder, ClvmEncoder, FromClvm, FromClvmError, ToClvm, ToClvmError}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct SizedAtom([u8; LEN]); + +impl SizedAtom { + pub fn new(data: [u8; LEN]) -> Self { + Self(data) + } + + pub fn as_bytes(self) -> [u8; LEN] { + self.0 + } +} + +impl AsRef<[u8]> for SizedAtom { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl Deref for SizedAtom { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From<[u8; LEN]> for SizedAtom { + fn from(data: [u8; LEN]) -> Self { + Self(data) + } +} + +impl From> for [u8; LEN] { + fn from(atom: SizedAtom) -> Self { + atom.0 + } +} + +impl ToClvm for SizedAtom { + fn to_clvm(&self, encoder: &mut impl ClvmEncoder) -> Result { + encoder.encode_atom(self) + } +} + +impl FromClvm for SizedAtom { + fn from_clvm(decoder: &impl ClvmDecoder, node: N) -> Result { + let atom = decoder.decode_atom(&node)?; + let bytes = atom.as_ref(); + + Ok(Self::new(bytes.try_into().map_err(|_| { + FromClvmError::WrongAtomLength { + expected: LEN, + found: bytes.len(), + } + })?)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use clvmr::{ + serde::{node_from_bytes, node_to_bytes}, + Allocator, + }; + + #[test] + fn test_to_clvm() { + let a = &mut Allocator::new(); + + let ptr = SizedAtom::new([]).to_clvm(a).unwrap(); + let bytes = node_to_bytes(a, ptr).unwrap(); + assert_eq!(hex::encode(bytes), "80".to_owned()); + + let ptr = SizedAtom::new(*b"hello").to_clvm(a).unwrap(); + let bytes = node_to_bytes(a, ptr).unwrap(); + assert_eq!(hex::encode(bytes), "8568656c6c6f".to_owned()); + } + + #[test] + fn test_from_clvm() { + let a = &mut Allocator::new(); + + let ptr = node_from_bytes(a, &hex::decode("80").unwrap()).unwrap(); + let value = SizedAtom::from_clvm(a, ptr).unwrap(); + assert_eq!(value, SizedAtom::new([])); + + let ptr = node_from_bytes(a, &hex::decode("8568656c6c6f").unwrap()).unwrap(); + let value = SizedAtom::from_clvm(a, ptr).unwrap(); + assert_eq!(value, SizedAtom::new(*b"hello")); + } +}