Skip to content

Commit 10bdbe3

Browse files
authored
refactor: build Codecs with macros (#27)
Use macros instead of duplicating a lot of code. Base36 still needs its own implementation due to its case-insensitivity.
1 parent c6e8093 commit 10bdbe3

File tree

1 file changed

+84
-278
lines changed

1 file changed

+84
-278
lines changed

src/impls.rs

Lines changed: 84 additions & 278 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,46 @@
11
use crate::encoding;
22
use crate::error::Result;
33

4+
macro_rules! derive_base_encoding {
5+
( $(#[$doc:meta] $type:ident, $encoding:expr;)* ) => {
6+
$(
7+
#[$doc]
8+
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
9+
pub(crate) struct $type;
10+
11+
impl BaseCodec for $type {
12+
fn encode<I: AsRef<[u8]>>(input: I) -> String {
13+
$encoding.encode(input.as_ref())
14+
}
15+
16+
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
17+
Ok($encoding.decode(input.as_ref().as_bytes())?)
18+
}
19+
}
20+
)*
21+
};
22+
}
23+
24+
macro_rules! derive_base_x {
25+
( $(#[$doc:meta] $type:ident, $encoding:expr;)* ) => {
26+
$(
27+
#[$doc]
28+
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
29+
pub(crate) struct $type;
30+
31+
impl BaseCodec for $type {
32+
fn encode<I: AsRef<[u8]>>(input: I) -> String {
33+
base_x::encode($encoding, input.as_ref())
34+
}
35+
36+
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
37+
Ok(base_x::decode($encoding, input.as_ref())?)
38+
}
39+
}
40+
)*
41+
};
42+
}
43+
444
pub(crate) trait BaseCodec {
545
/// Encode with the given byte slice.
646
fn encode<I: AsRef<[u8]>>(input: I) -> String;
@@ -23,200 +63,50 @@ impl BaseCodec for Identity {
2363
}
2464
}
2565

26-
/// Base2 (alphabet: 01).
27-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
28-
pub(crate) struct Base2;
29-
30-
impl BaseCodec for Base2 {
31-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
32-
encoding::BASE2.encode(input.as_ref())
33-
}
34-
35-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
36-
Ok(encoding::BASE2.decode(input.as_ref().as_bytes())?)
37-
}
38-
}
39-
40-
/// Base8 (alphabet: 01234567).
41-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
42-
pub(crate) struct Base8;
43-
44-
impl BaseCodec for Base8 {
45-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
46-
encoding::BASE8.encode(input.as_ref())
47-
}
48-
49-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
50-
Ok(encoding::BASE8.decode(input.as_ref().as_bytes())?)
51-
}
52-
}
53-
54-
/// Base10 (alphabet: 0123456789).
55-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
56-
pub(crate) struct Base10;
57-
58-
impl BaseCodec for Base10 {
59-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
60-
base_x::encode(encoding::BASE10, input.as_ref())
61-
}
62-
63-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
64-
Ok(base_x::decode(encoding::BASE10, input.as_ref())?)
65-
}
66-
}
67-
68-
/// Base16 lower hexadecimal (alphabet: 0123456789abcdef).
69-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
70-
pub(crate) struct Base16Lower;
71-
72-
impl BaseCodec for Base16Lower {
73-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
74-
encoding::BASE16_LOWER.encode(input.as_ref())
75-
}
76-
77-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
78-
Ok(encoding::BASE16_LOWER.decode(input.as_ref().as_bytes())?)
79-
}
80-
}
81-
82-
/// Base16 upper hexadecimal (alphabet: 0123456789ABCDEF).
83-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
84-
pub(crate) struct Base16Upper;
85-
86-
impl BaseCodec for Base16Upper {
87-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
88-
encoding::BASE16_UPPER.encode(input.as_ref())
89-
}
90-
91-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
92-
Ok(encoding::BASE16_UPPER.decode(input.as_ref().as_bytes())?)
93-
}
94-
}
95-
96-
/// Base32, rfc4648 no padding (alphabet: abcdefghijklmnopqrstuvwxyz234567).
97-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
98-
pub(crate) struct Base32Lower;
99-
100-
impl BaseCodec for Base32Lower {
101-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
102-
encoding::BASE32_NOPAD_LOWER.encode(input.as_ref())
103-
}
104-
105-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
106-
Ok(encoding::BASE32_NOPAD_LOWER.decode(input.as_ref().as_bytes())?)
107-
}
108-
}
109-
110-
/// Base32, rfc4648 no padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ234567).
111-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
112-
pub(crate) struct Base32Upper;
113-
114-
impl BaseCodec for Base32Upper {
115-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
116-
encoding::BASE32_NOPAD_UPPER.encode(input.as_ref())
117-
}
118-
119-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
120-
Ok(encoding::BASE32_NOPAD_UPPER.decode(input.as_ref().as_bytes())?)
121-
}
122-
}
123-
124-
/// Base32, rfc4648 with padding (alphabet: abcdefghijklmnopqrstuvwxyz234567).
125-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
126-
pub(crate) struct Base32PadLower;
127-
128-
impl BaseCodec for Base32PadLower {
129-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
130-
encoding::BASE32_PAD_LOWER.encode(input.as_ref())
131-
}
132-
133-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
134-
Ok(encoding::BASE32_PAD_LOWER.decode(input.as_ref().as_bytes())?)
135-
}
136-
}
137-
138-
/// Base32, rfc4648 with padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ234567).
139-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
140-
pub(crate) struct Base32PadUpper;
141-
142-
impl BaseCodec for Base32PadUpper {
143-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
144-
encoding::BASE32_PAD_UPPER.encode(input.as_ref())
145-
}
146-
147-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
148-
Ok(encoding::BASE32_PAD_UPPER.decode(input.as_ref().as_bytes())?)
149-
}
150-
}
151-
152-
/// Base32hex, rfc4648 no padding (alphabet: 0123456789abcdefghijklmnopqrstuv).
153-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
154-
pub(crate) struct Base32HexLower;
155-
156-
impl BaseCodec for Base32HexLower {
157-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
158-
encoding::BASE32HEX_NOPAD_LOWER.encode(input.as_ref())
159-
}
160-
161-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
162-
Ok(encoding::BASE32HEX_NOPAD_LOWER.decode(input.as_ref().as_bytes())?)
163-
}
164-
}
165-
166-
/// Base32hex, rfc4648 no padding (alphabet: 0123456789ABCDEFGHIJKLMNOPQRSTUV).
167-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
168-
pub(crate) struct Base32HexUpper;
169-
170-
impl BaseCodec for Base32HexUpper {
171-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
172-
encoding::BASE32HEX_NOPAD_UPPER.encode(input.as_ref())
173-
}
174-
175-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
176-
Ok(encoding::BASE32HEX_NOPAD_UPPER.decode(input.as_ref().as_bytes())?)
177-
}
178-
}
179-
180-
/// Base32hex, rfc4648 with padding (alphabet: 0123456789abcdefghijklmnopqrstuv).
181-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
182-
pub(crate) struct Base32HexPadLower;
183-
184-
impl BaseCodec for Base32HexPadLower {
185-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
186-
encoding::BASE32HEX_PAD_LOWER.encode(input.as_ref())
187-
}
188-
189-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
190-
Ok(encoding::BASE32HEX_PAD_LOWER.decode(input.as_ref().as_bytes())?)
191-
}
192-
}
193-
194-
/// Base32hex, rfc4648 with padding (alphabet: 0123456789ABCDEFGHIJKLMNOPQRSTUV).
195-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
196-
pub(crate) struct Base32HexPadUpper;
197-
198-
impl BaseCodec for Base32HexPadUpper {
199-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
200-
encoding::BASE32HEX_PAD_UPPER.encode(input.as_ref())
201-
}
202-
203-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
204-
Ok(encoding::BASE32HEX_PAD_UPPER.decode(input.as_ref().as_bytes())?)
205-
}
206-
}
207-
208-
/// z-base-32 (used by Tahoe-LAFS) (alphabet: ybndrfg8ejkmcpqxot1uwisza345h769).
209-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
210-
pub(crate) struct Base32Z;
211-
212-
impl BaseCodec for Base32Z {
213-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
214-
encoding::BASE32Z.encode(input.as_ref())
215-
}
216-
217-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
218-
Ok(encoding::BASE32Z.decode(input.as_ref().as_bytes())?)
219-
}
66+
derive_base_encoding! {
67+
/// Base2 (alphabet: 01).
68+
Base2, encoding::BASE2;
69+
/// Base8 (alphabet: 01234567).
70+
Base8, encoding::BASE8;
71+
/// Base16 lower hexadecimal (alphabet: 0123456789abcdef).
72+
Base16Lower, encoding::BASE16_LOWER;
73+
/// Base16 upper hexadecimal (alphabet: 0123456789ABCDEF).
74+
Base16Upper, encoding::BASE16_UPPER;
75+
/// Base32, rfc4648 no padding (alphabet: abcdefghijklmnopqrstuvwxyz234567).
76+
Base32Lower, encoding::BASE32_NOPAD_LOWER;
77+
/// Base32, rfc4648 no padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ234567).
78+
Base32Upper, encoding::BASE32_NOPAD_UPPER;
79+
/// Base32, rfc4648 with padding (alphabet: abcdefghijklmnopqrstuvwxyz234567).
80+
Base32PadLower, encoding::BASE32_PAD_LOWER;
81+
/// Base32, rfc4648 with padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ234567).
82+
Base32PadUpper, encoding::BASE32_PAD_UPPER;
83+
/// Base32hex, rfc4648 no padding (alphabet: 0123456789abcdefghijklmnopqrstuv).
84+
Base32HexLower, encoding::BASE32HEX_NOPAD_LOWER;
85+
/// Base32hex, rfc4648 no padding (alphabet: 0123456789ABCDEFGHIJKLMNOPQRSTUV).
86+
Base32HexUpper, encoding::BASE32HEX_NOPAD_UPPER;
87+
/// Base32hex, rfc4648 with padding (alphabet: 0123456789abcdefghijklmnopqrstuv).
88+
Base32HexPadLower, encoding::BASE32HEX_PAD_LOWER;
89+
/// Base32hex, rfc4648 with padding (alphabet: 0123456789ABCDEFGHIJKLMNOPQRSTUV).
90+
Base32HexPadUpper, encoding::BASE32HEX_PAD_UPPER;
91+
/// z-base-32 (used by Tahoe-LAFS) (alphabet: ybndrfg8ejkmcpqxot1uwisza345h769).
92+
Base32Z, encoding::BASE32Z;
93+
/// Base64, rfc4648 no padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/).
94+
Base64, encoding::BASE64_NOPAD;
95+
/// Base64, rfc4648 with padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/).
96+
Base64Pad, encoding::BASE64_PAD;
97+
/// Base64 url, rfc4648 no padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_).
98+
Base64Url, encoding::BASE64URL_NOPAD;
99+
/// Base64 url, rfc4648 with padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_).
100+
Base64UrlPad, encoding::BASE64URL_PAD;
101+
}
102+
103+
derive_base_x! {
104+
/// Base10 (alphabet: 0123456789).
105+
Base10, encoding::BASE10;
106+
/// Base58 flicker (alphabet: 123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ).
107+
Base58Flickr, encoding::BASE58_FLICKR;
108+
/// Base58 bitcoin (alphabet: 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz).
109+
Base58Btc, encoding::BASE58_BITCOIN;
220110
}
221111

222112
/// Base36, [0-9a-z] no padding (alphabet: abcdefghijklmnopqrstuvwxyz0123456789).
@@ -250,87 +140,3 @@ impl BaseCodec for Base36Upper {
250140
Ok(base_x::decode(encoding::BASE36_UPPER, &uppercased)?)
251141
}
252142
}
253-
254-
/// Base58 flicker (alphabet: 123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ).
255-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
256-
pub(crate) struct Base58Flickr;
257-
258-
impl BaseCodec for Base58Flickr {
259-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
260-
base_x::encode(encoding::BASE58_FLICKR, input.as_ref())
261-
}
262-
263-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
264-
Ok(base_x::decode(encoding::BASE58_FLICKR, input.as_ref())?)
265-
}
266-
}
267-
268-
/// Base58 bitcoin (alphabet: 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz).
269-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
270-
pub(crate) struct Base58Btc;
271-
272-
impl BaseCodec for Base58Btc {
273-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
274-
base_x::encode(encoding::BASE58_BITCOIN, input.as_ref())
275-
}
276-
277-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
278-
Ok(base_x::decode(encoding::BASE58_BITCOIN, input.as_ref())?)
279-
}
280-
}
281-
282-
/// Base64, rfc4648 no padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/).
283-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
284-
pub(crate) struct Base64;
285-
286-
impl BaseCodec for Base64 {
287-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
288-
encoding::BASE64_NOPAD.encode(input.as_ref())
289-
}
290-
291-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
292-
Ok(encoding::BASE64_NOPAD.decode(input.as_ref().as_bytes())?)
293-
}
294-
}
295-
296-
/// Base64, rfc4648 with padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/).
297-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
298-
pub(crate) struct Base64Pad;
299-
300-
impl BaseCodec for Base64Pad {
301-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
302-
encoding::BASE64_PAD.encode(input.as_ref())
303-
}
304-
305-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
306-
Ok(encoding::BASE64_PAD.decode(input.as_ref().as_bytes())?)
307-
}
308-
}
309-
310-
/// Base64 url, rfc4648 no padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_).
311-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
312-
pub(crate) struct Base64Url;
313-
314-
impl BaseCodec for Base64Url {
315-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
316-
encoding::BASE64URL_NOPAD.encode(input.as_ref())
317-
}
318-
319-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
320-
Ok(encoding::BASE64URL_NOPAD.decode(input.as_ref().as_bytes())?)
321-
}
322-
}
323-
324-
/// Base64 url, rfc4648 with padding (alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_).
325-
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
326-
pub(crate) struct Base64UrlPad;
327-
328-
impl BaseCodec for Base64UrlPad {
329-
fn encode<I: AsRef<[u8]>>(input: I) -> String {
330-
encoding::BASE64URL_PAD.encode(input.as_ref())
331-
}
332-
333-
fn decode<I: AsRef<str>>(input: I) -> Result<Vec<u8>> {
334-
Ok(encoding::BASE64URL_PAD.decode(input.as_ref().as_bytes())?)
335-
}
336-
}

0 commit comments

Comments
 (0)