snarkvm_console_network/helpers/
id.rs1use crate::prelude::*;
17
18use anyhow::Result;
19use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
20use std::borrow::Borrow;
21
22pub trait Bech32ID<F: FieldTrait>:
23 From<F>
24 + Deref<Target = F>
25 + Into<Vec<F>>
26 + Uniform
27 + Copy
28 + Clone
29 + Default
30 + Debug
31 + Display
32 + FromStr
33 + ToBytes
34 + FromBytes
35 + Serialize
36 + DeserializeOwned
37 + PartialEq
38 + Eq
39 + core::hash::Hash
40 + Sync
41 + Send
42{
43 fn prefix() -> String;
44 fn size_in_bytes() -> usize;
45 fn number_of_data_characters() -> usize;
46}
47
48#[rustfmt::skip]
49#[macro_export]
50macro_rules! const_assert {
51 ($x:expr $(,)*) => {
52 pub const ASSERT: [(); 1] = [()];
53 pub const fn bool_assert(x: bool) -> bool { x }
54 let _ = ASSERT[!bool_assert($x) as usize];
55 };
56}
57
58#[macro_export]
60macro_rules! hrp2 {
61 ( $persona: expr ) => {{
62 const_assert!($persona.len() == 2);
63 let p = $persona.as_bytes();
64 u16::from_le_bytes([p[0], p[1]])
65 }};
66}
67
68#[derive(Copy, Clone, PartialEq, Eq, Hash)]
69pub struct AleoID<F: FieldTrait, const PREFIX: u16>(F);
70
71impl<F: FieldTrait, const PREFIX: u16> Bech32ID<F> for AleoID<F, PREFIX> {
72 #[inline]
73 fn prefix() -> String {
74 String::from_utf8(PREFIX.to_le_bytes().to_vec()).expect("Failed to convert prefix to string")
75 }
76
77 #[inline]
78 fn size_in_bytes() -> usize {
79 F::size_in_bits().div_ceil(8)
80 }
81
82 #[inline]
83 fn number_of_data_characters() -> usize {
84 (Self::size_in_bytes() * 8).div_ceil(5)
85 }
86}
87
88impl<F: FieldTrait, const PREFIX: u16> From<F> for AleoID<F, PREFIX> {
89 #[inline]
90 fn from(data: F) -> Self {
91 Self(data)
92 }
93}
94
95impl<F: FieldTrait, const PREFIX: u16> Default for AleoID<F, PREFIX> {
96 #[inline]
97 fn default() -> Self {
98 Self(F::zero())
99 }
100}
101
102impl<F: FieldTrait, const PREFIX: u16> FromBytes for AleoID<F, PREFIX> {
103 #[inline]
105 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
106 Ok(Self(F::read_le(&mut reader)?))
107 }
108}
109
110impl<F: FieldTrait, const PREFIX: u16> ToBytes for AleoID<F, PREFIX> {
111 #[inline]
113 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
114 self.0.write_le(&mut writer)
115 }
116}
117
118impl<F: FieldTrait, const PREFIX: u16> FromStr for AleoID<F, PREFIX> {
119 type Err = Error;
120
121 #[inline]
123 fn from_str(string: &str) -> Result<Self, Self::Err> {
124 const CHECKSUM_STRING_LENGTH: usize = 6;
125 if string.len() != 3 + Self::number_of_data_characters() + CHECKSUM_STRING_LENGTH {
126 bail!("Invalid byte size for a bech32m hash: {} bytes", string.len())
127 }
128
129 let checked = bech32::primitives::decode::CheckedHrpstring::new::<LongBech32m>(string)?;
130 let hrp = checked.hrp();
131 let data: Vec<u8> = checked.byte_iter().collect();
132 if hrp.as_bytes() != PREFIX.to_le_bytes() {
133 bail!("Invalid prefix for a bech32m hash: {hrp}")
134 };
135 if data.is_empty() {
136 bail!("Bech32m hash data is empty")
137 }
138 Ok(Self::read_le(&*data)?)
139 }
140}
141
142impl<F: FieldTrait, const PREFIX: u16> Display for AleoID<F, PREFIX> {
143 #[inline]
144 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
145 bech32::encode_to_fmt::<LongBech32m, _>(
146 f,
147 bech32::Hrp::parse_unchecked(&Self::prefix()),
148 &self.0.to_bytes_le().expect("Failed to write data as bytes"),
149 )
150 .map_err(|_| fmt::Error)
151 }
152}
153
154impl<F: FieldTrait, const PREFIX: u16> Debug for AleoID<F, PREFIX> {
155 #[inline]
156 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
157 write!(f, "AleoLocator {{ hrp: {:?}, data: {:?} }}", &Self::prefix(), self.0)
158 }
159}
160
161impl<F: FieldTrait, const PREFIX: u16> Serialize for AleoID<F, PREFIX> {
162 #[inline]
163 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
164 match serializer.is_human_readable() {
165 true => serializer.collect_str(self),
166 false => ToBytesSerializer::serialize(self, serializer),
167 }
168 }
169}
170
171impl<'de, F: FieldTrait, const PREFIX: u16> Deserialize<'de> for AleoID<F, PREFIX> {
172 #[inline]
173 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
174 match deserializer.is_human_readable() {
175 true => FromStr::from_str(&String::deserialize(deserializer)?).map_err(de::Error::custom),
176 false => FromBytesDeserializer::<Self>::deserialize(deserializer, &Self::prefix(), Self::size_in_bytes()),
177 }
178 }
179}
180
181impl<F: FieldTrait, const PREFIX: u16> Deref for AleoID<F, PREFIX> {
182 type Target = F;
183
184 #[inline]
185 fn deref(&self) -> &Self::Target {
186 &self.0
187 }
188}
189
190impl<F: FieldTrait, const PREFIX: u16> Borrow<F> for AleoID<F, PREFIX> {
191 #[inline]
192 fn borrow(&self) -> &F {
193 &self.0
194 }
195}
196
197#[allow(clippy::from_over_into)]
198impl<F: FieldTrait, const PREFIX: u16> Into<Vec<F>> for AleoID<F, PREFIX> {
199 #[inline]
200 fn into(self) -> Vec<F> {
201 vec![self.0]
202 }
203}
204
205impl<F: FieldTrait, const PREFIX: u16> Distribution<AleoID<F, PREFIX>> for StandardUniform {
206 #[inline]
207 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> AleoID<F, PREFIX> {
208 AleoID::<F, PREFIX>(Uniform::rand(rng))
209 }
210}