const_decoder/macros.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
//! `decode!` macro and the associated helper types.
use crate::{
decoder::Decoder,
wrappers::{Pem, SkipWhitespace, Skipper},
};
/// Computes the output length in compile time and decodes the input. This allows to skip specifying
/// output length manually.
///
/// The macro accepts two comma-separate expressions. The first arg must evaluate to [`Decoder`],
/// [`SkipWhitespace`], or [`Pem`]. The second argument must evaluate to `&[u8]`. Both expressions
/// must be assignable to constants. The output of a macro is an array `[u8; N]` with the decoded bytes.
///
/// # Examples
///
/// ## Usage with `Decoder`s
///
/// ```
/// use const_decoder::{decode, Decoder};
///
/// const HEX: &[u8] = &decode!(Decoder::Hex, b"c0ffee");
/// const BASE64: &[u8] = &decode!(Decoder::Base64, b"VGVzdCBzdHJpbmc=");
/// // Can be used with custom decoders as well
/// const BASE32: &[u8] = &decode!(
/// Decoder::custom("qpzry9x8gf2tvdw0s3jn54khce6mua7l"),
/// b"rp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q",
/// );
/// ```
///
/// ## Usage with `SkipWhitespace`
///
/// ```
/// # use const_decoder::{decode, Decoder};
/// const HEX: &[u8] = &decode!(
/// Decoder::Hex.skip_whitespace(),
/// b"c0ff ee00 beef",
/// );
/// ```
///
/// ## Usage with `Pem`
///
/// ```
/// # use const_decoder::{decode, Pem};
/// const PRIVATE_KEY: &[u8] = &decode!(
/// Pem,
/// b"-----BEGIN PRIVATE KEY-----
/// MC4CAQAwBQYDK2VuBCIEINAOV4yAyaoM2wmJPApQs3byDhw7oJRG47V0VHwGnctD
/// -----END PRIVATE KEY-----",
/// );
/// ```
#[macro_export]
macro_rules! decode {
($decoder:expr, $bytes:expr $(,)?) => {{
const __OUTPUT_LEN: usize = $crate::DecoderWrapper($decoder).decode_len($bytes);
$crate::DecoderWrapper($decoder).decode::<__OUTPUT_LEN>($bytes) as [u8; __OUTPUT_LEN]
}};
}
#[derive(Debug)]
#[doc(hidden)] // implementation detail of the `decode!` macro
pub struct DecoderWrapper<T>(pub T);
impl DecoderWrapper<Decoder> {
pub const fn decode_len(&self, input: &[u8]) -> usize {
self.0.do_decode_len(input, None)
}
pub const fn decode<const N: usize>(self, input: &[u8]) -> [u8; N] {
self.0.decode(input)
}
}
impl DecoderWrapper<SkipWhitespace> {
pub const fn decode_len(&self, input: &[u8]) -> usize {
let Self(SkipWhitespace(decoder)) = self;
decoder.do_decode_len(input, Some(Skipper::Whitespace))
}
pub const fn decode<const N: usize>(self, input: &[u8]) -> [u8; N] {
self.0.decode(input)
}
}
impl DecoderWrapper<Pem> {
pub const fn decode_len(&self, input: &[u8]) -> usize {
Decoder::Base64.do_decode_len(input, Some(Skipper::Pem))
}
pub const fn decode<const N: usize>(self, input: &[u8]) -> [u8; N] {
Pem::decode(input)
}
}