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 fn encode<I: AsRef<[u8]>>(input: I) -> String;
50
51 fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>>;
53}
54
55#[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, encoding::BASE2;
72 Base8, encoding::BASE8;
74 Base16Lower, encoding::BASE16_LOWER;
76 Base16Upper, encoding::BASE16_UPPER;
78 Base32Lower, encoding::BASE32_NOPAD_LOWER;
80 Base32Upper, encoding::BASE32_NOPAD_UPPER;
82 Base32PadLower, encoding::BASE32_PAD_LOWER;
84 Base32PadUpper, encoding::BASE32_PAD_UPPER;
86 Base32HexLower, encoding::BASE32HEX_NOPAD_LOWER;
88 Base32HexUpper, encoding::BASE32HEX_NOPAD_UPPER;
90 Base32HexPadLower, encoding::BASE32HEX_PAD_LOWER;
92 Base32HexPadUpper, encoding::BASE32HEX_PAD_UPPER;
94 Base32Z, encoding::BASE32Z;
96 Base64, encoding::BASE64_NOPAD;
98 Base64Pad, encoding::BASE64_PAD;
100 Base64Url, encoding::BASE64URL_NOPAD;
102 Base64UrlPad, encoding::BASE64URL_PAD;
104}
105
106derive_base_x! {
107 Base10, encoding::BASE10;
109 Base58Flickr, encoding::BASE58_FLICKR;
111 Base58Btc, encoding::BASE58_BITCOIN;
113}
114
115#[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 let lowercased = input.as_ref().to_ascii_lowercase();
127 Ok(base_x::decode(encoding::BASE36_LOWER, &lowercased)?)
128 }
129}
130
131#[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 let uppercased = input.as_ref().to_ascii_uppercase();
143 Ok(base_x::decode(encoding::BASE36_UPPER, &uppercased)?)
144 }
145}