1use crate::Error;
2use bech32::{FromBase32, ToBase32};
3use derive_more::{AsMut, AsRef, Deref, Display, From, FromStr, Into};
4use serde::de::{Deserializer, Visitor};
5use serde::ser::Serializer;
6use serde::{Deserialize, Serialize};
7use std::fmt;
8
9#[derive(
11 AsMut, AsRef, Clone, Copy, Debug, Deref, Eq, From, Hash, Into, Ord, PartialEq, PartialOrd,
12)]
13pub struct Id(pub [u8; 32]);
14
15impl Id {
16 pub fn as_hex_string(&self) -> String {
20 hex::encode(self.0)
21 }
22
23 pub fn try_from_hex_string(v: &str) -> Result<Id, Error> {
25 let vec: Vec<u8> = hex::decode(v)?;
26 Ok(Id(vec
27 .try_into()
28 .map_err(|_| Error::WrongLengthHexString)?))
29 }
30
31 pub fn try_as_bech32_string(&self) -> Result<String, Error> {
33 Ok(bech32::encode(
34 "note",
35 self.0.to_vec().to_base32(),
36 bech32::Variant::Bech32,
37 )?)
38 }
39
40 pub fn try_from_bech32_string(s: &str) -> Result<Id, Error> {
42 let data = bech32::decode(s)?;
43 if data.0 != "note" {
44 Err(Error::WrongBech32("note".to_string(), data.0))
45 } else {
46 let decoded = Vec::<u8>::from_base32(&data.1)?;
47 if decoded.len() != 32 {
48 Err(Error::InvalidId)
49 } else {
50 match <[u8; 32]>::try_from(decoded) {
51 Ok(array) => Ok(Id(array)),
52 _ => Err(Error::InvalidId),
53 }
54 }
55 }
56 }
57
58 #[allow(dead_code)]
60 pub(crate) fn mock() -> Id {
61 Id::try_from_hex_string("5df64b33303d62afc799bdc36d178c07b2e1f0d824f31b7dc812219440affab6")
62 .unwrap()
63 }
64}
65
66impl Serialize for Id {
67 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
68 where
69 S: Serializer,
70 {
71 serializer.serialize_str(&hex::encode(self.0))
72 }
73}
74
75impl<'de> Deserialize<'de> for Id {
76 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
77 where
78 D: Deserializer<'de>,
79 {
80 deserializer.deserialize_str(IdVisitor)
81 }
82}
83
84struct IdVisitor;
85
86impl Visitor<'_> for IdVisitor {
87 type Value = Id;
88
89 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
90 write!(f, "a hexadecimal string representing 32 bytes")
91 }
92
93 fn visit_str<E>(self, v: &str) -> Result<Id, E>
94 where
95 E: serde::de::Error,
96 {
97 let vec: Vec<u8> =
98 hex::decode(v).map_err(|e| serde::de::Error::custom(format!("{}", e)))?;
99
100 Ok(Id(vec.try_into().map_err(|e: Vec<u8>| {
101 E::custom(format!(
102 "Id is not 32 bytes long. Was {} bytes long",
103 e.len()
104 ))
105 })?))
106 }
107}
108
109#[derive(
113 AsMut,
114 AsRef,
115 Clone,
116 Debug,
117 Deref,
118 Deserialize,
119 Display,
120 Eq,
121 From,
122 FromStr,
123 Hash,
124 Into,
125 PartialEq,
126 Serialize,
127)]
128pub struct IdHex(String);
129
130impl IdHex {
131 #[allow(dead_code)]
133 pub(crate) fn mock() -> IdHex {
134 From::from(Id::mock())
135 }
136
137 pub fn try_from_str(s: &str) -> Result<IdHex, Error> {
139 Self::try_from_string(s.to_owned())
140 }
141
142 pub fn try_from_string(s: String) -> Result<IdHex, Error> {
144 if s.len() != 64 {
145 return Err(Error::InvalidId);
146 }
147 let vec: Vec<u8> = hex::decode(&s)?;
148 if vec.len() != 32 {
149 return Err(Error::InvalidId);
150 }
151 Ok(IdHex(s))
152 }
153
154 pub fn as_str(&self) -> &str {
156 &self.0
157 }
158
159 pub fn into_string(self) -> String {
161 self.0
162 }
163
164 pub fn prefix(&self, mut chars: usize) -> IdHexPrefix {
166 if chars > 64 {
167 chars = 64;
168 }
169 IdHexPrefix(self.0[0..chars].to_owned())
170 }
171}
172
173impl TryFrom<&str> for IdHex {
174 type Error = Error;
175
176 fn try_from(s: &str) -> Result<IdHex, Error> {
177 IdHex::try_from_str(s)
178 }
179}
180
181impl From<Id> for IdHex {
182 fn from(i: Id) -> IdHex {
183 IdHex(i.as_hex_string())
184 }
185}
186
187impl From<IdHex> for Id {
188 fn from(h: IdHex) -> Id {
189 Id::try_from_hex_string(&h.0).unwrap()
191 }
192}
193
194#[derive(
196 AsMut,
197 AsRef,
198 Clone,
199 Debug,
200 Deref,
201 Deserialize,
202 Display,
203 Eq,
204 From,
205 FromStr,
206 Hash,
207 Into,
208 PartialEq,
209 Serialize,
210)]
211pub struct IdHexPrefix(String);
212
213impl IdHexPrefix {
214 #[allow(dead_code)]
216 pub(crate) fn mock() -> IdHexPrefix {
217 IdHexPrefix("a872bee017".to_owned())
218 }
219
220 pub fn try_from_str(s: &str) -> Result<IdHexPrefix, Error> {
222 Self::try_from_string(s.to_owned())
223 }
224
225 pub fn try_from_string(s: String) -> Result<IdHexPrefix, Error> {
227 if s.len() > 64 {
228 return Err(Error::InvalidIdPrefix);
229 }
230 if s.chars().any(|c| !c.is_ascii_hexdigit()) {
231 return Err(Error::InvalidPublicKeyPrefix);
232 }
233 Ok(IdHexPrefix(s))
238 }
239
240 pub fn as_str(&self) -> &str {
242 &self.0
243 }
244
245 pub fn into_string(self) -> String {
247 self.0
248 }
249
250 pub fn matches(&self, id: &IdHex) -> bool {
252 id.0.starts_with(&self.0)
253 }
254}
255
256impl From<IdHex> for IdHexPrefix {
257 fn from(id: IdHex) -> IdHexPrefix {
258 IdHexPrefix(id.0)
259 }
260}
261
262impl TryFrom<&str> for IdHexPrefix {
263 type Error = Error;
264
265 fn try_from(s: &str) -> Result<IdHexPrefix, Error> {
266 IdHexPrefix::try_from_str(s)
267 }
268}
269
270#[cfg(test)]
271mod test {
272 use super::*;
273
274 test_serde! {Id, test_id_serde}
275 test_serde! {IdHex, test_id_hex_serde}
276 test_serde! {IdHexPrefix, test_id_hex_prefix_serde}
277
278 #[test]
279 fn test_id_bech32() {
280 let bech32 = Id::mock().try_as_bech32_string().unwrap();
281 println!("{}", bech32);
282 assert_eq!(Id::mock(), Id::try_from_bech32_string(&bech32).unwrap());
283 }
284}