multibase/
impls.rs

1use crate::encoding;
2use crate::error::Result;
3
4#[cfg(not(feature = "std"))]
5use alloc::{string::String, vec::Vec};
6
7macro_rules! derive_base_encoding {
8    ( $(#[$doc:meta] $type:ident, $encoding:expr;)* ) => {
9        $(
10            #[$doc]
11            #[derive(PartialEq, Eq, Clone, Copy, Debug)]
12            pub(crate) struct $type;
13
14            impl BaseCodec for $type {
15                fn encode<I: AsRef<[u8]>>(input: I) -> String {
16                    $encoding.encode(input.as_ref())
17                }
18
19                fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
20                    Ok($encoding.decode(input.as_ref().as_bytes())?)
21                }
22            }
23        )*
24    };
25}
26
27macro_rules! derive_base_x {
28    ( $(#[$doc:meta] $type:ident, $encoding:expr;)* ) => {
29        $(
30            #[$doc]
31            #[derive(PartialEq, Eq, Clone, Copy, Debug)]
32            pub(crate) struct $type;
33
34            impl BaseCodec for $type {
35                fn encode<I: AsRef<[u8]>>(input: I) -> String {
36                    base_x::encode($encoding, input.as_ref())
37                }
38
39                fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
40                    Ok(base_x::decode($encoding, input.as_ref())?)
41                }
42            }
43        )*
44    };
45}
46
47pub(crate) trait BaseCodec {
48    /// Encode with the given byte slice.
49    fn encode<I: AsRef<[u8]>>(input: I) -> String;
50
51    /// Decode with the given string.
52    fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>>;
53}
54
55/// Identity, 8-bit binary (encoder and decoder keeps data unmodified).
56#[derive(PartialEq, Eq, Clone, Copy, Debug)]
57pub(crate) struct Identity;
58
59impl BaseCodec for Identity {
60    fn encode<I: AsRef<[u8]>>(input: I) -> String {
61        String::from_utf8(input.as_ref().to_vec()).expect("input must be valid UTF-8 bytes")
62    }
63
64    fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
65        Ok(input.as_ref().as_bytes().to_vec())
66    }
67}
68
69derive_base_encoding! {
70    /// Base2 (alphabet: 01).
71    Base2, encoding::BASE2;
72    /// Base8 (alphabet: 01234567).
73    Base8, encoding::BASE8;
74    /// Base16 lower hexadecimal (alphabet: 0123456789abcdef).
75    Base16Lower, encoding::BASE16_LOWER;
76    /// Base16 upper hexadecimal (alphabet: 0123456789ABCDEF).
77    Base16Upper, encoding::BASE16_UPPER;
78    /// Base32, rfc4648 no padding (alphabet: abcdefghijklmnopqrstuvwxyz234567).
79    Base32Lower, encoding::BASE32_NOPAD_LOWER;
80    /// Base32, rfc4648 no padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ234567).
81    Base32Upper, encoding::BASE32_NOPAD_UPPER;
82    /// Base32, rfc4648 with padding (alphabet: abcdefghijklmnopqrstuvwxyz234567).
83    Base32PadLower, encoding::BASE32_PAD_LOWER;
84    /// Base32, rfc4648 with padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ234567).
85    Base32PadUpper, encoding::BASE32_PAD_UPPER;
86    /// Base32hex, rfc4648 no padding (alphabet: 0123456789abcdefghijklmnopqrstuv).
87    Base32HexLower, encoding::BASE32HEX_NOPAD_LOWER;
88    /// Base32hex, rfc4648 no padding (alphabet: 0123456789ABCDEFGHIJKLMNOPQRSTUV).
89    Base32HexUpper, encoding::BASE32HEX_NOPAD_UPPER;
90    /// Base32hex, rfc4648 with padding (alphabet: 0123456789abcdefghijklmnopqrstuv).
91    Base32HexPadLower, encoding::BASE32HEX_PAD_LOWER;
92    /// Base32hex, rfc4648 with padding (alphabet: 0123456789ABCDEFGHIJKLMNOPQRSTUV).
93    Base32HexPadUpper, encoding::BASE32HEX_PAD_UPPER;
94    /// z-base-32 (used by Tahoe-LAFS) (alphabet: ybndrfg8ejkmcpqxot1uwisza345h769).
95    Base32Z, encoding::BASE32Z;
96    /// Base64, rfc4648 no padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/).
97    Base64, encoding::BASE64_NOPAD;
98    /// Base64, rfc4648 with padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/).
99    Base64Pad, encoding::BASE64_PAD;
100    /// Base64 url, rfc4648 no padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_).
101    Base64Url, encoding::BASE64URL_NOPAD;
102    /// Base64 url, rfc4648 with padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_).
103    Base64UrlPad, encoding::BASE64URL_PAD;
104}
105
106derive_base_x! {
107    /// Base10 (alphabet: 0123456789).
108    Base10, encoding::BASE10;
109    /// Base58 flicker (alphabet: 123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ).
110    Base58Flickr, encoding::BASE58_FLICKR;
111    /// Base58 bitcoin (alphabet: 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz).
112    Base58Btc, encoding::BASE58_BITCOIN;
113}
114
115/// Base36, [0-9a-z] no padding (alphabet: abcdefghijklmnopqrstuvwxyz0123456789).
116#[derive(PartialEq, Eq, Clone, Copy, Debug)]
117pub(crate) struct Base36Lower;
118
119impl BaseCodec for Base36Lower {
120    fn encode<I: AsRef<[u8]>>(input: I) -> String {
121        base_x::encode(encoding::BASE36_LOWER, input.as_ref())
122    }
123
124    fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
125        // The input is case insensitive, hence lowercase it
126        let lowercased = input.as_ref().to_ascii_lowercase();
127        Ok(base_x::decode(encoding::BASE36_LOWER, &lowercased)?)
128    }
129}
130
131/// Base36, [0-9A-Z] no padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789).
132#[derive(PartialEq, Eq, Clone, Copy, Debug)]
133pub(crate) struct Base36Upper;
134
135impl BaseCodec for Base36Upper {
136    fn encode<I: AsRef<[u8]>>(input: I) -> String {
137        base_x::encode(encoding::BASE36_UPPER, input.as_ref())
138    }
139
140    fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
141        // The input is case insensitive, hence uppercase it
142        let uppercased = input.as_ref().to_ascii_uppercase();
143        Ok(base_x::decode(encoding::BASE36_UPPER, &uppercased)?)
144    }
145}