data_encoding_macro/
lib.rs

1//! Macros for data-encoding
2//!
3//! This library provides macros to define compile-time byte arrays from encoded strings (using
4//! common bases like [base64], [base32], or [hexadecimal], and also custom bases). It also provides
5//! a macro to define compile-time custom encodings to be used with the [data-encoding] crate at
6//! run-time.
7//!
8//! Up to Rust 1.50, you may need to add the following to your `.cargo/config.toml` to use this
9//! library in no-std or no-alloc environments:
10//!
11//! ```toml
12//! [unstable]
13//! features = ["host_dep"]
14//! ```
15//!
16//! From Rust 1.51, you may need to add the following to your `Cargo.toml`:
17//!
18//! ```toml
19//! [package]
20//! resolver = "2"
21//! ```
22//!
23//! # Examples
24//!
25//! You can define a compile-time byte slice from an encoded string literal:
26//!
27//! ```rust
28//! const HELLO_SLICE: &'static [u8] = &data_encoding_macro::hexlower!("68656c6c6f");
29//! const FOOBAR_SLICE: &'static [u8] = &data_encoding_macro::base64!("Zm9vYmFy");
30//! # fn main() {}
31//! ```
32//!
33//! You can also define a compile-time byte array from an encoded string literal:
34//!
35//! ```rust
36//! data_encoding_macro::hexlower_array!("const HELLO" = "68656c6c6f");
37//! data_encoding_macro::base64_array!("const FOOBAR" = "Zm9vYmFy");
38//! # fn main() {}
39//! ```
40//!
41//! You can define a compile-time custom encoding from its specification:
42//!
43//! ```rust
44//! const HEX: data_encoding::Encoding = data_encoding_macro::new_encoding! {
45//!     symbols: "0123456789abcdef",
46//!     translate_from: "ABCDEF",
47//!     translate_to: "abcdef",
48//! };
49//! const BASE64: data_encoding::Encoding = data_encoding_macro::new_encoding! {
50//!     symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
51//!     padding: '=',
52//! };
53//! # fn main() {}
54//! ```
55//!
56//! [base32]: macro.base32.html
57//! [base64]: macro.base64.html
58//! [data-encoding]: https://crates.io/crates/data-encoding
59//! [hexadecimal]: macro.hexlower_permissive.html
60
61#![no_std]
62#![warn(unused_results)]
63
64#[doc(hidden)]
65pub use data_encoding_macro_internal::{
66    internal_decode_array, internal_decode_slice, internal_new_encoding,
67};
68
69/// Defines a compile-time byte array by decoding a string literal
70///
71/// This macro takes a list of `key: value,` pairs (the last comma is required). It takes the
72/// key-value pairs specifying the encoding to use to decode the input (see [new_encoding] for the
73/// possible key-value pairs), the input itself keyed by `input`, and the output keyed by `name`.
74/// The output must be of the form `[pub] {const|static} <name>`.
75///
76/// # Examples
77///
78/// ```rust
79/// data_encoding_macro::decode_array! {
80///     name: "const OCTAL",
81///     symbols: "01234567",
82///     padding: '=',
83///     input: "237610==",
84/// }
85/// # fn main() {}
86/// ```
87///
88/// [new_encoding]: macro.new_encoding.html
89#[macro_export]
90macro_rules! decode_array {
91    ($($arg: tt)*) => {
92        $crate::internal_decode_array!($($arg)*);
93    };
94}
95
96/// Defines a compile-time byte slice by decoding a string literal
97///
98/// This macro takes a list of `key: value,` pairs (the last comma is required). It takes the
99/// key-value pairs specifying the encoding to use to decode the input (see [new_encoding] for the
100/// possible key-value pairs), the input itself keyed by `input`, and the output keyed by `name`.
101///
102/// # Examples
103///
104/// ```rust
105/// const OCTAL: &'static [u8] = &data_encoding_macro::decode_slice! {
106///     symbols: "01234567",
107///     padding: '=',
108///     input: "237610==",
109/// };
110/// # fn main() {}
111/// ```
112///
113/// [new_encoding]: macro.new_encoding.html
114#[macro_export]
115macro_rules! decode_slice {
116    ($($arg: tt)*) => {
117        $crate::internal_decode_slice!($($arg)*)
118    };
119}
120
121/// Defines a compile-time custom encoding
122///
123/// This macro takes a list of `key: value,` pairs (the last comma is required). The possible
124/// key-value pairs are:
125///
126/// ```text
127///             symbols: <string>,       // e.g. "01234567"
128///             padding: [None]|<char>,  // e.g. '='
129///           bit_order: [MostSignificantFirst]|LeastSignificantFirst,
130/// check_trailing_bits: [true]|false,
131///              ignore: [""]|<string>,  // e.g. " \t\n"
132///          wrap_width: [0]|<int>,      // e.g. 76
133///      wrap_separator: [""]|<string>,  // e.g. "\r\n"
134///      translate_from: [""]|<string>,  // e.g. "ABCDEF"
135///        translate_to: [""]|<string>,  // e.g. "abcdef"
136/// ```
137///
138/// Only `symbols` is required. Everything else is optional and defaults to the value between square
139/// brackets.
140///
141/// # Examples
142///
143/// ```rust
144/// const HEX: data_encoding::Encoding = data_encoding_macro::new_encoding! {
145///     symbols: "0123456789abcdef",
146///     ignore: " \r\t\n",
147///     wrap_width: 32,
148///     wrap_separator: "\n",
149///     translate_from: "ABCDEF",
150///     translate_to: "abcdef",
151/// };
152/// # fn main() {}
153/// ```
154#[macro_export]
155macro_rules! new_encoding {
156    ($($arg: tt)*) => {
157        data_encoding::Encoding::internal_new(&$crate::internal_new_encoding!{ $($arg)* })
158    };
159}
160
161macro_rules! make {
162    ($base: ident $base_array: ident = $ref: ident; $($spec: tt)*) => {
163        #[macro_export]
164        macro_rules! $base_array {
165            ($n: tt = $x: tt) => {
166                $crate::decode_array!(name: $n, input: $x, $($spec)*);
167            };
168        }
169        #[macro_export]
170        macro_rules! $base {
171            ($x: tt) => {
172                $crate::decode_slice!(input: $x, $($spec)*)
173            };
174        }
175        #[test]
176        fn $base() {
177            assert_eq!(new_encoding!($($spec)*), data_encoding::$ref);
178        }
179    };
180}
181
182make! {
183    hexlower hexlower_array = HEXLOWER;
184    symbols: "0123456789abcdef",
185}
186make! {
187    hexlower_permissive hexlower_permissive_array = HEXLOWER_PERMISSIVE;
188    symbols: "0123456789abcdef",
189    translate_from: "ABCDEF",
190    translate_to: "abcdef",
191}
192make! {
193    hexupper hexupper_array = HEXUPPER;
194    symbols: "0123456789ABCDEF",
195}
196make! {
197    hexupper_permissive hexupper_permissive_array = HEXUPPER_PERMISSIVE;
198    symbols: "0123456789ABCDEF",
199    translate_from: "abcdef",
200    translate_to: "ABCDEF",
201}
202make! {
203    base32 base32_array = BASE32;
204    symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
205    padding: '=',
206}
207make! {
208    base32_nopad base32_nopad_array = BASE32_NOPAD;
209    symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
210}
211make! {
212    base32hex base32hex_array = BASE32HEX;
213    symbols: "0123456789ABCDEFGHIJKLMNOPQRSTUV",
214    padding: '=',
215}
216make! {
217    base32hex_nopad base32hex_nopad_array = BASE32HEX_NOPAD;
218    symbols: "0123456789ABCDEFGHIJKLMNOPQRSTUV",
219}
220make! {
221    base32_dnssec base32_dnssec_array = BASE32_DNSSEC;
222    symbols: "0123456789abcdefghijklmnopqrstuv",
223    translate_from: "ABCDEFGHIJKLMNOPQRSTUV",
224    translate_to: "abcdefghijklmnopqrstuv",
225}
226make! {
227    base32_dnscurve base32_dnscurve_array = BASE32_DNSCURVE;
228    symbols: "0123456789bcdfghjklmnpqrstuvwxyz",
229    bit_order: LeastSignificantFirst,
230    translate_from: "BCDFGHJKLMNPQRSTUVWXYZ",
231    translate_to: "bcdfghjklmnpqrstuvwxyz",
232}
233make! {
234    base64 base64_array = BASE64;
235    symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
236    padding: '=',
237}
238make! {
239    base64_nopad base64_nopad_array = BASE64_NOPAD;
240    symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
241}
242make! {
243    base64_mime base64_mime_array = BASE64_MIME;
244    symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
245    padding: '=',
246    wrap_width: 76,
247    wrap_separator: "\r\n",
248}
249make! {
250    base64_mime_permissive base64_mime_permissive_array = BASE64_MIME_PERMISSIVE;
251    symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
252    padding: '=',
253    wrap_width: 76,
254    wrap_separator: "\r\n",
255    check_trailing_bits: false,
256}
257make! {
258    base64url base64url_array = BASE64URL;
259    symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
260    padding: '=',
261}
262make! {
263    base64url_nopad base64url_nopad_array = BASE64URL_NOPAD;
264    symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
265}