const_decoder2/
macros.rs

1//! `decode!` macro and the associated helper types.
2
3use crate::{
4    decoder::Decoder,
5    wrappers::{Pem, SkipWhitespace, Skipper},
6};
7
8/// Computes the output length in compile time and decodes the input. This allows to skip specifying
9/// output length manually.
10///
11/// The macro accepts two comma-separate expressions. The first arg must evaluate to [`Decoder`],
12/// [`SkipWhitespace`], or [`Pem`]. The second argument must evaluate to `&[u8]`. Both expressions
13/// must be assignable to constants. The output of a macro is an array `[u8; N]` with the decoded bytes.
14///
15/// # Examples
16///
17/// ## Usage with `Decoder`s
18///
19/// ```
20/// use const_decoder::{decode, Decoder};
21///
22/// const HEX: &[u8] = &decode!(Decoder::Hex, b"c0ffee");
23/// const BASE64: &[u8] = &decode!(Decoder::Base64, b"VGVzdCBzdHJpbmc=");
24/// // Can be used with custom decoders as well
25/// const BASE32: &[u8] = &decode!(
26///     Decoder::custom("qpzry9x8gf2tvdw0s3jn54khce6mua7l"),
27///     b"rp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q",
28/// );
29/// ```
30///
31/// ## Usage with `SkipWhitespace`
32///
33/// ```
34/// # use const_decoder::{decode, Decoder};
35/// const HEX: &[u8] = &decode!(
36///     Decoder::Hex.skip_whitespace(),
37///     b"c0ff ee00 beef",
38/// );
39/// ```
40///
41/// ## Usage with `Pem`
42///
43/// ```
44/// # use const_decoder::{decode, Pem};
45/// const PRIVATE_KEY: &[u8] = &decode!(
46///     Pem,
47///     b"-----BEGIN PRIVATE KEY-----
48///       MC4CAQAwBQYDK2VuBCIEINAOV4yAyaoM2wmJPApQs3byDhw7oJRG47V0VHwGnctD
49///       -----END PRIVATE KEY-----",
50/// );
51/// ```
52#[macro_export]
53macro_rules! decode {
54    ($decoder:expr, $bytes:expr $(,)?) => {{
55        const __OUTPUT_LEN: usize = $crate::DecoderWrapper($decoder).decode_len($bytes);
56        $crate::DecoderWrapper($decoder).decode::<__OUTPUT_LEN>($bytes) as [u8; __OUTPUT_LEN]
57    }};
58}
59
60/// decode base64 encoded data.
61#[macro_export]
62macro_rules! decode_base64 {
63    ($bytes:expr $(,)?) => {
64        $crate::decode!($crate::Decoder::Base64, $bytes)
65    };
66}
67
68/// decode base64url encoded data.
69#[macro_export]
70macro_rules! decode_base64_url {
71    ($bytes:expr $(,)?) => {
72        $crate::decode!($crate::Decoder::Base64Url, $bytes)
73    };
74}
75
76/// It conforms to [RFC4648](https://tools.ietf.org/html/rfc4648).
77///
78/// from: <https://docs.rs/data-encoding/2.6.0/data_encoding/constant.BASE32.html>
79#[macro_export]
80macro_rules! decode_base32 {
81    ($bytes:expr $(,)?) => {
82        $crate::decode!($crate::Decoder::custom("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), $bytes)
83    };
84}
85
86/// It conforms to [RFC4648](https://tools.ietf.org/html/rfc4648).
87///
88/// from: <https://docs.rs/data-encoding/2.6.0/data_encoding/constant.BASE32HEX.html>
89#[macro_export]
90macro_rules! decode_base32_hex {
91    ($bytes:expr $(,)?) => {
92        $crate::decode!($crate::Decoder::custom("0123456789ABCDEFGHIJKLMNOPQRSTUV"), $bytes)
93    };
94}
95
96/// It conforms to [RFC5155](https://tools.ietf.org/html/rfc5155):
97///     It uses a base32 extended hex alphabet.
98///     It is case-insensitive when decoding and uses lowercase when encoding.
99///     It does not use padding.
100///
101/// from: <https://docs.rs/data-encoding/2.6.0/data_encoding/constant.BASE32_DNSSEC.html>
102#[macro_export]
103macro_rules! decode_base32_dnssec {
104    ($bytes:expr $(,)?) => {
105        $crate::decode!($crate::Decoder::custom("0123456789abcdefghijklmnopqrstuv"), $bytes)
106    };
107}
108
109/// It conforms to [DNSCurve](https://dnscurve.org/in-implement.html).
110///
111/// from: <https://docs.rs/data-encoding/2.6.0/data_encoding/constant.BASE32_DNSCURVE.html>
112#[macro_export]
113macro_rules! decode_base32_dnscurve {
114    ($bytes:expr $(,)?) => {
115        $crate::decode!($crate::Decoder::custom("0123456789bcdfghjklmnpqrstuvwxyz"), $bytes)
116    };
117}
118
119#[derive(Debug)]
120#[doc(hidden)] // implementation detail of the `decode!` macro
121pub struct DecoderWrapper<T>(pub T);
122
123impl DecoderWrapper<Decoder> {
124    pub const fn decode_len(&self, input: &[u8]) -> usize {
125        self.0.do_decode_len(input, None)
126    }
127
128    pub const fn decode<const N: usize>(self, input: &[u8]) -> [u8; N] {
129        self.0.decode(input)
130    }
131}
132
133impl DecoderWrapper<SkipWhitespace> {
134    pub const fn decode_len(&self, input: &[u8]) -> usize {
135        let Self(SkipWhitespace(decoder)) = self;
136        decoder.do_decode_len(input, Some(Skipper::Whitespace))
137    }
138
139    pub const fn decode<const N: usize>(self, input: &[u8]) -> [u8; N] {
140        self.0.decode(input)
141    }
142}
143
144impl DecoderWrapper<Pem> {
145    pub const fn decode_len(&self, input: &[u8]) -> usize {
146        Decoder::Base64.do_decode_len(input, Some(Skipper::Pem))
147    }
148
149    pub const fn decode<const N: usize>(self, input: &[u8]) -> [u8; N] {
150        Pem::decode(input)
151    }
152}