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}