klvm_traits/
klvm_encoder.rs

1use klvmr::{Allocator, Atom, NodePtr};
2use num_bigint::BigInt;
3
4use crate::{klvm_list, klvm_quote, ToKlvm, ToKlvmError};
5
6pub trait KlvmEncoder: Sized {
7    type Node: Clone + ToKlvm<Self>;
8
9    fn encode_atom(&mut self, atom: Atom<'_>) -> Result<Self::Node, ToKlvmError>;
10    fn encode_pair(
11        &mut self,
12        first: Self::Node,
13        rest: Self::Node,
14    ) -> Result<Self::Node, ToKlvmError>;
15
16    fn encode_bigint(&mut self, number: BigInt) -> Result<Self::Node, ToKlvmError> {
17        let bytes = number.to_signed_bytes_be();
18        let mut slice = bytes.as_slice();
19
20        // Remove leading zeros.
21        while !slice.is_empty() && slice[0] == 0 {
22            if slice.len() > 1 && (slice[1] & 0x80 == 0x80) {
23                break;
24            }
25            slice = &slice[1..];
26        }
27
28        self.encode_atom(Atom::Borrowed(slice))
29    }
30
31    fn encode_curried_arg(
32        &mut self,
33        first: Self::Node,
34        rest: Self::Node,
35    ) -> Result<Self::Node, ToKlvmError> {
36        const OP_C: u8 = 4;
37        klvm_list!(OP_C, klvm_quote!(first), rest).to_klvm(self)
38    }
39
40    /// This is a helper function that just calls `clone` on the node.
41    /// It's required only because the compiler can't infer that `N` is `Clone`,
42    /// since there's no `Clone` bound on the `ToKlvm` trait.
43    fn clone_node(&self, node: &Self::Node) -> Self::Node {
44        node.clone()
45    }
46}
47
48impl KlvmEncoder for Allocator {
49    type Node = NodePtr;
50
51    fn encode_atom(&mut self, atom: Atom<'_>) -> Result<Self::Node, ToKlvmError> {
52        match atom {
53            Atom::Borrowed(bytes) => self.new_atom(bytes),
54            Atom::U32(bytes, _len) => self.new_small_number(u32::from_be_bytes(bytes)),
55        }
56        .or(Err(ToKlvmError::OutOfMemory))
57    }
58
59    fn encode_pair(
60        &mut self,
61        first: Self::Node,
62        rest: Self::Node,
63    ) -> Result<Self::Node, ToKlvmError> {
64        self.new_pair(first, rest).or(Err(ToKlvmError::OutOfMemory))
65    }
66
67    fn encode_bigint(&mut self, number: BigInt) -> Result<Self::Node, ToKlvmError> {
68        self.new_number(number).or(Err(ToKlvmError::OutOfMemory))
69    }
70}
71
72impl ToKlvm<Allocator> for NodePtr {
73    fn to_klvm(&self, _encoder: &mut Allocator) -> Result<NodePtr, ToKlvmError> {
74        Ok(*self)
75    }
76}