1#![deny(missing_docs)]
17#![no_std]
18
19extern crate alloc;
20
21use alloc::vec::Vec;
22use core::{
23 fmt::{self, Display},
24 marker::PhantomData,
25};
26use serdapt::{DeserializeWith, SerializeWith};
27use serde::{de::Visitor, Deserializer, Serialize, Serializer};
28
29pub struct Base58<A = Bitcoin> {
50 alphabet: PhantomData<A>,
51}
52
53pub type BitcoinBase58 = Base58<Bitcoin>;
55
56pub type MoneroBase58 = Base58<Monero>;
58
59pub type RippleBase58 = Base58<Ripple>;
61
62pub type FlickrBase58 = Base58<Flickr>;
64
65impl<A> Base58<A> {
66 pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
68 where
69 T: ?Sized,
70 S: Serializer,
71 Self: SerializeWith<T>,
72 {
73 Self::serialize_with(value, serializer)
74 }
75
76 pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
78 where
79 D: Deserializer<'de>,
80 Self: DeserializeWith<'de, T>,
81 {
82 Self::deserialize_with(deserializer)
83 }
84}
85
86impl<A, T> SerializeWith<T> for Base58<A>
87where
88 A: AlphabetTag,
89 T: AsRef<[u8]>,
90{
91 fn serialize_with<S: Serializer>(bytes: &T, serializer: S) -> Result<S::Ok, S::Error> {
92 Serialize::serialize(
93 &bs58::encode(bytes)
94 .with_alphabet(&A::VALUE.inner)
95 .into_string(),
96 serializer,
97 )
98 }
99}
100
101impl<'de, A, T> DeserializeWith<'de, T> for Base58<A>
102where
103 A: AlphabetTag,
104 T: TryFrom<Vec<u8>>,
105 T::Error: Display,
106{
107 fn deserialize_with<D>(deserializer: D) -> Result<T, D::Error>
108 where
109 D: Deserializer<'de>,
110 {
111 let bytes = deserializer.deserialize_str(Base58Visitor::new::<A>())?;
112 bytes.try_into().map_err(serde::de::Error::custom)
113 }
114}
115
116struct Base58Visitor {
117 alphabet: &'static bs58::Alphabet,
118}
119
120impl Base58Visitor {
121 const fn new<A>() -> Self
122 where
123 A: AlphabetTag,
124 {
125 Self {
126 alphabet: &A::VALUE.inner,
127 }
128 }
129}
130
131impl Visitor<'_> for Base58Visitor {
132 type Value = Vec<u8>;
133
134 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 f.write_str("a base58 string")
136 }
137
138 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
139 where
140 E: serde::de::Error,
141 {
142 bs58::decode(v)
143 .with_alphabet(self.alphabet)
144 .into_vec()
145 .map_err(E::custom)
146 }
147}
148
149pub struct Base58Array<A = Bitcoin> {
168 alphabet: PhantomData<A>,
169}
170
171pub type BitcoinBase58Array = Base58Array<Bitcoin>;
173
174pub type MoneroBase58Array = Base58Array<Monero>;
176
177pub type RippleBase58Array = Base58Array<Ripple>;
179
180pub type FlickrBase58Array = Base58Array<Flickr>;
182
183impl<A> Base58Array<A> {
184 pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
186 where
187 T: ?Sized,
188 S: Serializer,
189 Self: SerializeWith<T>,
190 {
191 Self::serialize_with(value, serializer)
192 }
193
194 pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
196 where
197 D: Deserializer<'de>,
198 Self: DeserializeWith<'de, T>,
199 {
200 Self::deserialize_with(deserializer)
201 }
202}
203
204impl<A, T> SerializeWith<T> for Base58Array<A>
205where
206 A: AlphabetTag,
207 T: AsRef<[u8]>,
208{
209 fn serialize_with<S: Serializer>(bytes: &T, serializer: S) -> Result<S::Ok, S::Error> {
210 Serialize::serialize(
211 &bs58::encode(bytes)
212 .with_alphabet(&A::VALUE.inner)
213 .into_string(),
214 serializer,
215 )
216 }
217}
218
219impl<'de, A, const N: usize> DeserializeWith<'de, [u8; N]> for Base58Array<A>
220where
221 A: AlphabetTag,
222{
223 fn deserialize_with<D>(deserializer: D) -> Result<[u8; N], D::Error>
224 where
225 D: Deserializer<'de>,
226 {
227 deserializer.deserialize_str(Base58ArrayVisitor::new::<A>())
228 }
229}
230
231struct Base58ArrayVisitor<const N: usize> {
232 alphabet: &'static bs58::Alphabet,
233}
234
235impl<const N: usize> Base58ArrayVisitor<N> {
236 const fn new<A>() -> Self
237 where
238 A: AlphabetTag,
239 {
240 Self {
241 alphabet: &A::VALUE.inner,
242 }
243 }
244}
245
246impl<const N: usize> Visitor<'_> for Base58ArrayVisitor<N> {
247 type Value = [u8; N];
248
249 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 write!(f, "a base58 string encoding {N} bytes")
251 }
252
253 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
254 where
255 E: serde::de::Error,
256 {
257 let mut out = [0u8; N];
258 let n = bs58::decode(v)
259 .with_alphabet(self.alphabet)
260 .onto(&mut out[..])
261 .map_err(|e| match e {
262 bs58::decode::Error::BufferTooSmall => E::invalid_length(N + 1, &self),
263 _ => E::custom(e),
264 })?;
265 Some(out)
266 .filter(|_| n == N)
267 .ok_or_else(|| serde::de::Error::invalid_length(n, &self))
268 }
269}
270
271pub trait AlphabetTag {
273 const VALUE: Alphabet;
275}
276
277#[derive(Debug)]
279pub struct Alphabet {
280 inner: bs58::Alphabet,
281}
282
283impl Alphabet {
284 pub const fn new(chars: &[u8; 58]) -> Self {
288 Self {
289 inner: bs58::Alphabet::new_unwrap(chars),
290 }
291 }
292}
293
294#[derive(Debug)]
296pub struct Bitcoin;
297
298impl AlphabetTag for Bitcoin {
299 const VALUE: Alphabet = Alphabet {
300 inner: *bs58::Alphabet::BITCOIN,
301 };
302}
303
304#[derive(Debug)]
306pub struct Monero;
307
308impl AlphabetTag for Monero {
309 const VALUE: Alphabet = Alphabet {
310 inner: *bs58::Alphabet::MONERO,
311 };
312}
313
314#[derive(Debug)]
316pub struct Ripple;
317
318impl AlphabetTag for Ripple {
319 const VALUE: Alphabet = Alphabet {
320 inner: *bs58::Alphabet::RIPPLE,
321 };
322}
323
324#[derive(Debug)]
326pub struct Flickr;
327
328impl AlphabetTag for Flickr {
329 const VALUE: Alphabet = Alphabet {
330 inner: *bs58::Alphabet::FLICKR,
331 };
332}