1use crate::Error;
2use derive_more::{AsMut, AsRef, Deref, Display, From, FromStr, Into};
3use serde::de::{Deserializer, Visitor};
4use serde::ser::Serializer;
5use serde::{Deserialize, Serialize};
6#[cfg(feature = "speedy")]
7use speedy::{Readable, Writable};
8use std::fmt;
9
10#[derive(
12 AsMut, AsRef, Clone, Copy, Debug, Deref, Eq, From, Hash, Into, Ord, PartialEq, PartialOrd,
13)]
14#[cfg_attr(feature = "speedy", derive(Readable, Writable))]
15pub struct Id(pub [u8; 32]);
16
17impl Id {
18 pub fn as_hex_string(&self) -> String {
22 hex::encode(self.0)
23 }
24
25 pub fn try_from_hex_string(v: &str) -> Result<Id, Error> {
27 let vec: Vec<u8> = hex::decode(v)?;
28 Ok(Id(vec
29 .try_into()
30 .map_err(|_| Error::WrongLengthHexString)?))
31 }
32
33 pub fn as_bech32_string(&self) -> String {
35 bech32::encode::<bech32::Bech32>(*crate::HRP_NOTE, &self.0).unwrap()
36 }
37
38 pub fn try_from_bech32_string(s: &str) -> Result<Id, Error> {
40 let data = bech32::decode(s)?;
41 if data.0 != *crate::HRP_NOTE {
42 Err(Error::WrongBech32(
43 crate::HRP_NOTE.to_lowercase(),
44 data.0.to_lowercase(),
45 ))
46 } else if data.1.len() != 32 {
47 Err(Error::InvalidId)
48 } else {
49 match <[u8; 32]>::try_from(data.1) {
50 Ok(array) => Ok(Id(array)),
51 _ => Err(Error::InvalidId),
52 }
53 }
54 }
55
56 #[allow(dead_code)]
58 pub(crate) fn mock() -> Id {
59 Id::try_from_hex_string("5df64b33303d62afc799bdc36d178c07b2e1f0d824f31b7dc812219440affab6")
60 .unwrap()
61 }
62}
63
64impl Serialize for Id {
65 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
66 where
67 S: Serializer,
68 {
69 serializer.serialize_str(&hex::encode(self.0))
70 }
71}
72
73impl<'de> Deserialize<'de> for Id {
74 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
75 where
76 D: Deserializer<'de>,
77 {
78 deserializer.deserialize_str(IdVisitor)
79 }
80}
81
82struct IdVisitor;
83
84impl Visitor<'_> for IdVisitor {
85 type Value = Id;
86
87 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
88 write!(f, "a lowercase hexadecimal string representing 32 bytes")
89 }
90
91 fn visit_str<E>(self, v: &str) -> Result<Id, E>
92 where
93 E: serde::de::Error,
94 {
95 let vec: Vec<u8> = hex::decode(v).map_err(|e| serde::de::Error::custom(format!("{e}")))?;
96
97 Ok(Id(vec.try_into().map_err(|e: Vec<u8>| {
98 E::custom(format!(
99 "Id is not 32 bytes long. Was {} bytes long",
100 e.len()
101 ))
102 })?))
103 }
104}
105
106#[derive(
110 AsMut,
111 AsRef,
112 Clone,
113 Debug,
114 Deref,
115 Display,
116 Eq,
117 From,
118 FromStr,
119 Hash,
120 Into,
121 Ord,
122 PartialEq,
123 PartialOrd,
124)]
125#[cfg_attr(feature = "speedy", derive(Readable, Writable))]
126pub struct IdHex(String);
127
128impl IdHex {
129 #[allow(dead_code)]
131 pub(crate) fn mock() -> IdHex {
132 From::from(Id::mock())
133 }
134
135 pub fn try_from_str(s: &str) -> Result<IdHex, Error> {
137 Self::try_from_string(s.to_owned())
138 }
139
140 pub fn try_from_string(s: String) -> Result<IdHex, Error> {
142 if s.len() != 64 {
143 return Err(Error::InvalidId);
144 }
145 let vec: Vec<u8> = hex::decode(&s)?;
146 if vec.len() != 32 {
147 return Err(Error::InvalidId);
148 }
149 Ok(IdHex(s))
150 }
151
152 pub fn as_str(&self) -> &str {
154 &self.0
155 }
156
157 pub fn into_string(self) -> String {
159 self.0
160 }
161}
162
163impl TryFrom<&str> for IdHex {
164 type Error = Error;
165
166 fn try_from(s: &str) -> Result<IdHex, Error> {
167 IdHex::try_from_str(s)
168 }
169}
170
171impl From<Id> for IdHex {
172 fn from(i: Id) -> IdHex {
173 IdHex(i.as_hex_string())
174 }
175}
176
177impl From<IdHex> for Id {
178 fn from(h: IdHex) -> Id {
179 Id::try_from_hex_string(&h.0).unwrap()
181 }
182}
183
184impl Serialize for IdHex {
185 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
186 where
187 S: Serializer,
188 {
189 serializer.serialize_str(&self.0)
190 }
191}
192
193impl<'de> Deserialize<'de> for IdHex {
194 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
195 where
196 D: Deserializer<'de>,
197 {
198 deserializer.deserialize_str(IdHexVisitor)
199 }
200}
201
202struct IdHexVisitor;
203
204impl Visitor<'_> for IdHexVisitor {
205 type Value = IdHex;
206
207 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
208 write!(f, "a lowercase hexadecimal string representing 32 bytes")
209 }
210
211 fn visit_str<E>(self, v: &str) -> Result<IdHex, E>
212 where
213 E: serde::de::Error,
214 {
215 if v.len() != 64 {
216 return Err(serde::de::Error::custom("IdHex is not 64 characters long"));
217 }
218
219 let vec: Vec<u8> = hex::decode(v).map_err(|e| serde::de::Error::custom(format!("{e}")))?;
220 if vec.len() != 32 {
221 return Err(serde::de::Error::custom("Invalid IdHex"));
222 }
223
224 Ok(IdHex(v.to_owned()))
225 }
226}
227
228#[cfg(test)]
229mod test {
230 use super::*;
231
232 test_serde! {Id, test_id_serde}
233 test_serde! {IdHex, test_id_hex_serde}
234
235 #[test]
236 fn test_id_bech32() {
237 let bech32 = Id::mock().as_bech32_string();
238 println!("{bech32}");
239 assert_eq!(Id::mock(), Id::try_from_bech32_string(&bech32).unwrap());
240 }
241}