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("String")]
15 String,
16
17 #[display("Int")]
18 Int,
19
20 #[display("PublicKey")]
21 PublicKey,
22
23 #[display("Signature")]
24 Signature,
25
26 #[display("K1PublicKey")]
27 K1PublicKey,
28
29 #[display("K1Signature")]
30 K1Signature,
31
32 #[display("R1PublicKey")]
33 R1PublicKey,
34
35 #[display("R1Signature")]
36 R1Signature,
37
38 #[display("Bool")]
39 Bool,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Hash)]
43pub enum AtomRestriction {
44 Value(Cow<'static, [u8]>),
45 Length(usize),
46}
47
48#[derive(Debug, Clone)]
49pub struct Atom {
50 pub semantic: AtomSemantic,
51 pub restriction: Option<AtomRestriction>,
52}
53
54impl Atom {
55 pub const ANY: Self = Self::new(AtomSemantic::Any, None);
56 pub const NIL: Self = Self::new(
57 AtomSemantic::Bytes,
58 Some(AtomRestriction::Value(Cow::Borrowed(&[]))),
59 );
60 pub const FALSE: Self = Self::new(
61 AtomSemantic::Bool,
62 Some(AtomRestriction::Value(Cow::Borrowed(&[]))),
63 );
64 pub const TRUE: Self = Self::new(
65 AtomSemantic::Bool,
66 Some(AtomRestriction::Value(Cow::Borrowed(&[1]))),
67 );
68 pub const BYTES: Self = Self::new(AtomSemantic::Bytes, None);
69 pub const BYTES_32: Self = Self::new(AtomSemantic::Bytes, Some(AtomRestriction::Length(32)));
70 pub const STRING: Self = Self::new(AtomSemantic::String, None);
71 pub const PUBLIC_KEY: Self =
72 Self::new(AtomSemantic::PublicKey, Some(AtomRestriction::Length(48)));
73 pub const SIGNATURE: Self =
74 Self::new(AtomSemantic::Signature, Some(AtomRestriction::Length(96)));
75 pub const K1_PUBLIC_KEY: Self =
76 Self::new(AtomSemantic::K1PublicKey, Some(AtomRestriction::Length(33)));
77 pub const K1_SIGNATURE: Self =
78 Self::new(AtomSemantic::K1Signature, Some(AtomRestriction::Length(64)));
79 pub const R1_PUBLIC_KEY: Self =
80 Self::new(AtomSemantic::R1PublicKey, Some(AtomRestriction::Length(33)));
81 pub const R1_SIGNATURE: Self =
82 Self::new(AtomSemantic::Signature, Some(AtomRestriction::Length(64)));
83 pub const INT: Self = Self::new(AtomSemantic::Int, None);
84
85 pub const fn new(semantic: AtomSemantic, restriction: Option<AtomRestriction>) -> Self {
86 Self {
87 semantic,
88 restriction,
89 }
90 }
91}
92
93impl fmt::Display for Atom {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 match self.semantic {
96 AtomSemantic::Any => write!(f, "Atom"),
97 AtomSemantic::Bytes => match &self.restriction {
98 None => write!(f, "Bytes"),
99 Some(AtomRestriction::Length(length)) => {
100 if *length == 32 {
101 write!(f, "Bytes32")
102 } else {
103 write!(f, "Bytes")
104 }
105 }
106 Some(AtomRestriction::Value(value)) => {
107 if value.is_empty() {
108 write!(f, "nil")
109 } else {
110 write!(f, "0x{}", hex::encode(value))
111 }
112 }
113 },
114 AtomSemantic::String => match &self.restriction {
115 None | Some(AtomRestriction::Length(_)) => {
116 write!(f, "String")
117 }
118 Some(AtomRestriction::Value(value)) => {
119 write!(f, "\"{}\"", String::from_utf8_lossy(value))
120 }
121 },
122 AtomSemantic::Int => match &self.restriction {
123 None | Some(AtomRestriction::Length(_)) => write!(f, "Int"),
124 Some(AtomRestriction::Value(value)) => {
125 let mut allocator = Allocator::new();
126 let ptr = allocator.new_atom(value).unwrap();
127 let bigint = allocator.number(ptr);
128 write!(f, "{bigint}")
129 }
130 },
131 AtomSemantic::PublicKey => write!(f, "PublicKey"),
132 AtomSemantic::Signature => write!(f, "Signature"),
133 AtomSemantic::K1PublicKey => write!(f, "K1PublicKey"),
134 AtomSemantic::K1Signature => write!(f, "K1Signature"),
135 AtomSemantic::R1PublicKey => write!(f, "R1PublicKey"),
136 AtomSemantic::R1Signature => write!(f, "R1Signature"),
137 AtomSemantic::Bool => match &self.restriction {
138 None | Some(AtomRestriction::Length(_)) => write!(f, "Bool"),
139 Some(AtomRestriction::Value(value)) => {
140 if value.is_empty() {
141 write!(f, "false")
142 } else if value.as_ref() == [1] {
143 write!(f, "true")
144 } else {
145 write!(f, "Bool")
146 }
147 }
148 },
149 }
150 }
151}