Skip to main content

iris_ztd/
fixed.rs

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/// Converts a string to 64-bit value, in little-endian. Max 8 characters.
91#[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/// FixedU64 of the bytes of a string
106#[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}