const_decoder/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#[derive(Debug)]
61#[doc(hidden)] // implementation detail of the `decode!` macro
62pub struct DecoderWrapper<T>(pub T);
63
64impl DecoderWrapper<Decoder> {
65 pub const fn decode_len(&self, input: &[u8]) -> usize {
66 self.0.do_decode_len(input, None)
67 }
68
69 pub const fn decode<const N: usize>(self, input: &[u8]) -> [u8; N] {
70 self.0.decode(input)
71 }
72}
73
74impl DecoderWrapper<SkipWhitespace> {
75 pub const fn decode_len(&self, input: &[u8]) -> usize {
76 let Self(SkipWhitespace(decoder)) = self;
77 decoder.do_decode_len(input, Some(Skipper::Whitespace))
78 }
79
80 pub const fn decode<const N: usize>(self, input: &[u8]) -> [u8; N] {
81 self.0.decode(input)
82 }
83}
84
85impl DecoderWrapper<Pem> {
86 pub const fn decode_len(&self, input: &[u8]) -> usize {
87 Decoder::Base64.do_decode_len(input, Some(Skipper::Pem))
88 }
89
90 pub const fn decode<const N: usize>(self, input: &[u8]) -> [u8; N] {
91 Pem::decode(input)
92 }
93}