1use std::{borrow::Cow, fmt};
2
3use clvmr::Allocator;
4use derive_more::Display;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display)]
7pub enum AtomSemantic {
8 #[display("Atom")]
9 Any,
10
11 #[display("Bytes")]
12 Bytes,
13
14 #[display("Int")]
15 Int,
16
17 #[display("PublicKey")]
18 PublicKey,
19
20 #[display("Bool")]
21 Bool,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub enum AtomRestriction {
26 Value(Cow<'static, [u8]>),
27 Length(usize),
28}
29
30#[derive(Debug, Clone)]
31pub struct Atom {
32 pub semantic: AtomSemantic,
33 pub restriction: Option<AtomRestriction>,
34}
35
36impl Atom {
37 pub const ANY: Self = Self::new(AtomSemantic::Any, None);
38 pub const NIL: Self = Self::new(
39 AtomSemantic::Bytes,
40 Some(AtomRestriction::Value(Cow::Borrowed(&[]))),
41 );
42 pub const FALSE: Self = Self::new(
43 AtomSemantic::Bool,
44 Some(AtomRestriction::Value(Cow::Borrowed(&[]))),
45 );
46 pub const TRUE: Self = Self::new(
47 AtomSemantic::Bool,
48 Some(AtomRestriction::Value(Cow::Borrowed(&[1]))),
49 );
50 pub const BYTES: Self = Self::new(AtomSemantic::Bytes, None);
51 pub const BYTES_32: Self = Self::new(AtomSemantic::Bytes, Some(AtomRestriction::Length(32)));
52 pub const PUBLIC_KEY: Self =
53 Self::new(AtomSemantic::PublicKey, Some(AtomRestriction::Length(48)));
54 pub const INT: Self = Self::new(AtomSemantic::Int, None);
55
56 pub const fn new(semantic: AtomSemantic, restriction: Option<AtomRestriction>) -> Self {
57 Self {
58 semantic,
59 restriction,
60 }
61 }
62}
63
64impl fmt::Display for Atom {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 let name = format!("{}", self.semantic);
67
68 let qualifier = match &self.restriction {
69 None => None,
70 Some(AtomRestriction::Length(length)) => {
71 if self.semantic == AtomSemantic::PublicKey && *length == 48 {
72 None
73 } else {
74 Some(format!("{length}"))
75 }
76 }
77 Some(AtomRestriction::Value(value)) => match self.semantic {
78 AtomSemantic::Any | AtomSemantic::Bytes | AtomSemantic::PublicKey => {
79 if value.is_empty() {
80 return write!(f, "nil");
81 }
82
83 return write!(f, "0x{}", hex::encode(value));
84 }
85 AtomSemantic::Int => {
86 let mut allocator = Allocator::new();
87 let ptr = allocator.new_atom(value).unwrap();
88 return write!(f, "{}", allocator.number(ptr));
89 }
90 AtomSemantic::Bool => {
91 if value.is_empty() {
92 return write!(f, "false");
93 } else if value.as_ref() == [1] {
94 return write!(f, "true");
95 }
96
97 return write!(f, "0x{}", hex::encode(value));
98 }
99 },
100 };
101
102 if let Some(qualifier) = qualifier {
103 write!(f, "{name}{qualifier}")
104 } else {
105 write!(f, "{name}")
106 }
107 }
108}