]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | //! # Configs |
2 | //! | |
3 | //! There isn't just one type of Base64; that would be too simple. You need to choose a character | |
4 | //! set (standard, URL-safe, etc) and padding suffix (yes/no). | |
5 | //! The `Config` struct encapsulates this info. There are some common configs included: `STANDARD`, | |
6 | //! `URL_SAFE`, etc. You can also make your own `Config` if needed. | |
7 | //! | |
8 | //! The functions that don't have `config` in the name (e.g. `encode()` and `decode()`) use the | |
9 | //! `STANDARD` config . | |
10 | //! | |
11 | //! The functions that write to a slice (the ones that end in `_slice`) are generally the fastest | |
12 | //! because they don't need to resize anything. If it fits in your workflow and you care about | |
13 | //! performance, keep using the same buffer (growing as need be) and use the `_slice` methods for | |
14 | //! the best performance. | |
15 | //! | |
16 | //! # Encoding | |
17 | //! | |
18 | //! Several different encoding functions are available to you depending on your desire for | |
19 | //! convenience vs performance. | |
20 | //! | |
21 | //! | Function | Output | Allocates | | |
22 | //! | ----------------------- | ---------------------------- | ------------------------------ | | |
23 | //! | `encode` | Returns a new `String` | Always | | |
24 | //! | `encode_config` | Returns a new `String` | Always | | |
25 | //! | `encode_config_buf` | Appends to provided `String` | Only if `String` needs to grow | | |
26 | //! | `encode_config_slice` | Writes to provided `&[u8]` | Never | | |
27 | //! | |
28 | //! All of the encoding functions that take a `Config` will pad as per the config. | |
29 | //! | |
30 | //! # Decoding | |
31 | //! | |
32 | //! Just as for encoding, there are different decoding functions available. | |
33 | //! | |
34 | //! | Function | Output | Allocates | | |
35 | //! | ----------------------- | ----------------------------- | ------------------------------ | | |
36 | //! | `decode` | Returns a new `Vec<u8>` | Always | | |
37 | //! | `decode_config` | Returns a new `Vec<u8>` | Always | | |
38 | //! | `decode_config_buf` | Appends to provided `Vec<u8>` | Only if `Vec` needs to grow | | |
39 | //! | `decode_config_slice` | Writes to provided `&[u8]` | Never | | |
40 | //! | |
41 | //! Unlike encoding, where all possible input is valid, decoding can fail (see `DecodeError`). | |
42 | //! | |
43 | //! Input can be invalid because it has invalid characters or invalid padding. (No padding at all is | |
44 | //! valid, but excess padding is not.) Whitespace in the input is invalid. | |
45 | //! | |
46 | //! # Panics | |
47 | //! | |
48 | //! If length calculations result in overflowing `usize`, a panic will result. | |
49 | //! | |
50 | //! The `_slice` flavors of encode or decode will panic if the provided output slice is too small, | |
51 | ||
52 | #![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))] | |
53 | #![deny( | |
54 | missing_docs, | |
55 | trivial_casts, | |
56 | trivial_numeric_casts, | |
57 | unused_extern_crates, | |
58 | unused_import_braces, | |
59 | unused_results, | |
60 | variant_size_differences, | |
61 | warnings | |
62 | )] | |
63 | #![forbid(unsafe_code)] | |
64 | #![cfg_attr(not(any(feature = "std", test)), no_std)] | |
65 | ||
66 | #[cfg(all(feature = "alloc", not(any(feature = "std", test))))] | |
67 | extern crate alloc; | |
68 | #[cfg(any(feature = "std", test))] | |
69 | extern crate std as alloc; | |
70 | ||
71 | #[cfg(test)] | |
72 | #[macro_use] | |
73 | extern crate doc_comment; | |
74 | ||
75 | #[cfg(test)] | |
76 | doctest!("../README.md"); | |
77 | ||
78 | mod chunked_encoder; | |
79 | pub mod display; | |
80 | mod tables; | |
81 | #[cfg(any(feature = "std", test))] | |
82 | pub mod write; | |
83 | ||
84 | mod encode; | |
85 | pub use crate::encode::encode_config_slice; | |
86 | #[cfg(any(feature = "alloc", feature = "std", test))] | |
87 | pub use crate::encode::{encode, encode_config, encode_config_buf}; | |
88 | ||
89 | mod decode; | |
90 | #[cfg(any(feature = "alloc", feature = "std", test))] | |
91 | pub use crate::decode::{decode, decode_config, decode_config_buf}; | |
92 | pub use crate::decode::{decode_config_slice, DecodeError}; | |
93 | ||
94 | #[cfg(test)] | |
95 | mod tests; | |
96 | ||
97 | /// Available encoding character sets | |
98 | #[derive(Clone, Copy, Debug)] | |
99 | pub enum CharacterSet { | |
100 | /// The standard character set (uses `+` and `/`). | |
101 | /// | |
102 | /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3). | |
103 | Standard, | |
104 | /// The URL safe character set (uses `-` and `_`). | |
105 | /// | |
106 | /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-4). | |
107 | UrlSafe, | |
108 | /// The `crypt(3)` character set (uses `./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`). | |
109 | /// | |
110 | /// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses. | |
111 | Crypt, | |
112 | } | |
113 | ||
114 | impl CharacterSet { | |
115 | fn encode_table(self) -> &'static [u8; 64] { | |
116 | match self { | |
117 | CharacterSet::Standard => tables::STANDARD_ENCODE, | |
118 | CharacterSet::UrlSafe => tables::URL_SAFE_ENCODE, | |
119 | CharacterSet::Crypt => tables::CRYPT_ENCODE, | |
120 | } | |
121 | } | |
122 | ||
123 | fn decode_table(self) -> &'static [u8; 256] { | |
124 | match self { | |
125 | CharacterSet::Standard => tables::STANDARD_DECODE, | |
126 | CharacterSet::UrlSafe => tables::URL_SAFE_DECODE, | |
127 | CharacterSet::Crypt => tables::CRYPT_DECODE, | |
128 | } | |
129 | } | |
130 | } | |
131 | ||
132 | /// Contains configuration parameters for base64 encoding | |
133 | #[derive(Clone, Copy, Debug)] | |
134 | pub struct Config { | |
135 | /// Character set to use | |
136 | char_set: CharacterSet, | |
137 | /// True to pad output with `=` characters | |
138 | pad: bool, | |
139 | /// True to ignore excess nonzero bits in the last few symbols, otherwise an error is returned. | |
140 | decode_allow_trailing_bits: bool, | |
141 | } | |
142 | ||
143 | impl Config { | |
144 | /// Create a new `Config`. | |
145 | pub fn new(char_set: CharacterSet, pad: bool) -> Config { | |
146 | Config { | |
147 | char_set, | |
148 | pad, | |
149 | decode_allow_trailing_bits: false, | |
150 | } | |
151 | } | |
152 | ||
153 | /// Sets whether to pad output with `=` characters. | |
154 | pub fn pad(self, pad: bool) -> Config { | |
155 | Config { pad, ..self } | |
156 | } | |
157 | ||
158 | /// Sets whether to emit errors for nonzero trailing bits. | |
159 | /// | |
160 | /// This is useful when implementing | |
161 | /// [forgiving-base64 decode](https://infra.spec.whatwg.org/#forgiving-base64-decode). | |
162 | pub fn decode_allow_trailing_bits(self, allow: bool) -> Config { | |
163 | Config { | |
164 | decode_allow_trailing_bits: allow, | |
165 | ..self | |
166 | } | |
167 | } | |
168 | } | |
169 | ||
170 | /// Standard character set with padding. | |
171 | pub const STANDARD: Config = Config { | |
172 | char_set: CharacterSet::Standard, | |
173 | pad: true, | |
174 | decode_allow_trailing_bits: false, | |
175 | }; | |
176 | ||
177 | /// Standard character set without padding. | |
178 | pub const STANDARD_NO_PAD: Config = Config { | |
179 | char_set: CharacterSet::Standard, | |
180 | pad: false, | |
181 | decode_allow_trailing_bits: false, | |
182 | }; | |
183 | ||
184 | /// URL-safe character set with padding | |
185 | pub const URL_SAFE: Config = Config { | |
186 | char_set: CharacterSet::UrlSafe, | |
187 | pad: true, | |
188 | decode_allow_trailing_bits: false, | |
189 | }; | |
190 | ||
191 | /// URL-safe character set without padding | |
192 | pub const URL_SAFE_NO_PAD: Config = Config { | |
193 | char_set: CharacterSet::UrlSafe, | |
194 | pad: false, | |
195 | decode_allow_trailing_bits: false, | |
196 | }; | |
197 | ||
198 | /// As per `crypt(3)` requirements | |
199 | pub const CRYPT: Config = Config { | |
200 | char_set: CharacterSet::Crypt, | |
201 | pad: false, | |
202 | decode_allow_trailing_bits: false, | |
203 | }; |