1use crate::{Digest, Hashable, Noun, NounDecode, NounEncode};
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3
4macro_rules! fixed_noun {
5 ($n:ident, $t:ty, $d:ty) => {
6 #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
7 pub struct $n<const V: $t>;
8
9 impl<const V: $t> $n<V> {
10 pub const VALUE: $t = V;
11
12 pub fn value(self) -> $t {
13 V
14 }
15 }
16
17 impl<const V: $t> core::ops::Deref for $n<V> {
18 type Target = $t;
19
20 fn deref(&self) -> &$t {
21 &V
22 }
23 }
24
25 impl<const V: $t> Serialize for $n<V> {
26 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
27 where
28 S: Serializer,
29 {
30 V.serialize(serializer)
31 }
32 }
33
34 impl<'de, const V: $t> Deserialize<'de> for $n<V> {
35 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
36 where
37 D: Deserializer<'de>,
38 {
39 let v = <$d>::deserialize(deserializer)?;
40 if v != V {
41 return Err(serde::de::Error::custom("Invalid value"));
42 }
43 Ok($n)
44 }
45 }
46
47 impl<const V: $t> NounEncode for $n<V> {
48 fn to_noun(&self) -> Noun {
49 V.to_noun()
50 }
51 }
52
53 impl<const V: $t> NounDecode for $n<V> {
54 fn from_noun(noun: &Noun) -> Option<Self> {
55 let v: $d = NounDecode::from_noun(noun)?;
56
57 if v != V {
58 return None;
59 }
60
61 Some($n)
62 }
63 }
64
65 impl<const V: $t> Hashable for $n<V> {
66 fn hash(&self) -> Digest {
67 V.hash()
68 }
69
70 fn leaf_count(&self) -> usize {
71 1
72 }
73
74 fn hashable_pair(&self) -> Option<(impl Hashable + '_, impl Hashable + '_)> {
75 Option::<((), ())>::None
76 }
77 }
78 };
79 ($n: ident, $t:ty, $d:ty; $($tt:tt)*) => {
80 fixed_noun!($n, $t, $d);
81 fixed_noun!($($tt)*);
82 };
83}
84
85fixed_noun! {
86 FixedU32, u32, u32;
87 FixedU64, u64, u64
88}
89
90#[macro_export]
92macro_rules! tas {
93 ($b: expr) => {{
94 let b = $b.as_bytes();
95 let mut o = 0u64;
96 let mut i = 0;
97 while i < b.len() {
98 o |= (b[i] as u64) << (i * 8);
99 i += 1;
100 }
101 o
102 }};
103}
104
105#[macro_export]
107macro_rules! ftas {
108 ($b: expr) => {
109 $crate::FixedTas<{ $crate::tas!($b) }>
110 };
111}
112
113#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
114pub struct FixedTas<const N: u64>;
115
116impl<const V: u64> FixedTas<V> {
117 pub const VALUE_U64: u64 = V;
118 pub const VALUE_LE_BYTES: [u8; 8] = const {
119 let mut b = [0u8; 8];
120 b.copy_from_slice(&V.to_le_bytes());
121 b
122 };
123 pub const VALUE_STR: &str = const {
124 let mut cnt = 0;
125 while cnt < 8 && Self::VALUE_LE_BYTES[cnt] != 0 {
126 cnt += 1;
127 }
128 unsafe { core::str::from_utf8_unchecked(Self::VALUE_LE_BYTES.split_at(cnt).0) }
129 };
130
131 pub fn value_u64(self) -> u64 {
132 V
133 }
134}
135
136impl<const V: u64> core::ops::Deref for FixedTas<V> {
137 type Target = str;
138
139 fn deref(&self) -> &str {
140 Self::VALUE_STR
141 }
142}
143
144impl<const V: u64> Serialize for FixedTas<V> {
145 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
146 where
147 S: Serializer,
148 {
149 Self::VALUE_STR.serialize(serializer)
150 }
151}
152
153#[cfg(feature = "alloc")]
154impl<'de, const V: u64> Deserialize<'de> for FixedTas<V> {
155 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
156 where
157 D: Deserializer<'de>,
158 {
159 let v = alloc::string::String::deserialize(deserializer)?;
160 if v != Self::VALUE_STR {
161 return Err(serde::de::Error::custom("Invalid value"));
162 }
163 Ok(FixedTas)
164 }
165}
166
167impl<const V: u64> NounEncode for FixedTas<V> {
168 fn to_noun(&self) -> Noun {
169 V.to_noun()
170 }
171}
172
173impl<const V: u64> NounDecode for FixedTas<V> {
174 fn from_noun(noun: &Noun) -> Option<Self> {
175 let v: u64 = NounDecode::from_noun(noun)?;
176
177 if v != V {
178 return None;
179 }
180
181 Some(FixedTas)
182 }
183}
184
185impl<const V: u64> Hashable for FixedTas<V> {
186 fn hash(&self) -> Digest {
187 V.hash()
188 }
189
190 fn leaf_count(&self) -> usize {
191 1
192 }
193
194 fn hashable_pair(&self) -> Option<(impl Hashable + '_, impl Hashable + '_)> {
195 Option::<((), ())>::None
196 }
197}
198
199#[cfg(all(test, feature = "alloc"))]
200mod tests {
201 use super::*;
202
203 #[test]
204 fn test_tas() {
205 let a = <ftas!("testing")>::VALUE_STR;
206 assert_eq!("testing", a);
207 let b = a.to_noun();
208 let c: alloc::string::String = NounDecode::from_noun(&b).unwrap();
209 assert_eq!("testing", c);
210 }
211}