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
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
/*!
BaseNC
======

Encoding and decoding of Base-N encodings, `#[no_std]` compatible.

Encoding trait
--------------

The hero of the show is [`Encoding`](trait.Encoding.html), defining the entry point for encoding and decoding for an encoding.

The trait is implemented by unit structs, eg. `Base64Std`, allowing type inference to help out.

The hero has two sidekicks: [`Encoder`](trait.Encoder.html) and [`Decoder`](trait.Decoder.html) providing access to the encoding's iterator adapters.

Buffer to buffer
----------------

When you have an input buffer, `&[u8]` or `&str`, and want to encode or decode respectively to a new buffer
can be done conveniently using the [`encode`](fn.encode.html) and [`decode`](fn.decode.html) free functions.

They are ensured to be implemented efficiently and avoid code bloat.

### Buffers

A side note about buffers, they are types implementing the [`EncodeBuf`](trait.EncodeBuf.html) and [`DecodeBuf`](trait.DecodeBuf.html) traits.

Under `#[no_std]` they are only implemented by `&mut [u8]` acting as a fixed size buffer.

Otherwise `EncodeBuf` is implemented by `String` for convenience and `&mut String` and `&mut Vec<u8>` for efficient buffer reuse.
`DecodeBuf` is implemented by `Vec<u8>` for convenience and `&mut Vec<u8>` for efficient buffer reuse.

Iterator adapters
-----------------

For maximum flexibility the encoding and decoding can be pipelined as an iterator adapter.

The trait [`Encode`](trait.Encode.html) adapts an iterator over bytes given an encoding into an iterator over chars of the encoded input.

The trait [`Decode`](trait.Decode.html) adapts an iterator over chars given an encoding into an iterator over the resulting bytes of the decoded input.

*/

#![no_std]

#[cfg(any(test, feature = "std"))]
#[macro_use]
extern crate std;

#[cfg(feature = "unstable")]
pub mod details;
#[cfg(not(feature = "unstable"))]
mod details;

mod buf;
pub use buf::{EncodeBuf, DecodeBuf};

//----------------------------------------------------------------

/// Decoding error.
///
/// Note that encoding can never fail.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Error {
	/// Not a valid character in the alphabet.
	InvalidChar(char),
	/// Input has incorrect length or is not padded to the required length.
	BadLength,
	/// Input is not canonical.
	///
	/// Unused padding MUST consist of zero bits.
	Denormal,
}

use ::core::fmt;
impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			Error::InvalidChar(chr) => write!(f, "invalid char: {}", chr),
			Error::BadLength => write!(f, "bad length"),
			Error::Denormal => write!(f, "denormal"),
		}
	}
}
#[cfg(any(test, feature = "std"))]
impl ::std::error::Error for Error {
	fn description(&self) -> &str {
		match *self {
			Error::InvalidChar(_) => "invalid char",
			Error::BadLength => "bad length",
			Error::Denormal => "denormal",
		}
	}
}

//----------------------------------------------------------------

/// Data encoding.
///
/// Use the free-standing functions to avoid having to drag in this trait.
pub trait Encoding {
	/// Returns the encoding's alphabet.
	///
	/// # Examples
	///
	/// ```
	/// use basenc::{Encoding};
	///
	/// assert_eq!(
	/// 	basenc::LowerHex.alphabet(),
	/// 	"0123456789abcdef"
	/// );
	/// ```
	fn alphabet(self) -> &'static str;

	/// Directly encode into an encode buffer.
	///
	/// Use [`encode`](fn.encode.html) for convenience.
	fn encode<B: EncodeBuf>(self, bytes: &[u8], buffer: B) -> B::Output;

	/// Directly decode into a decode buffer.
	///
	/// Use [`decode`](fn.decode.html) for convenience.
	fn decode<B: DecodeBuf>(self, string: &str, buffer: B) -> Result<B::Output, Error>;
}

/// Directly encode into an encode buffer.
///
/// Convenient as it doesn't require the [`Encoding`](trait.Encoding.html) trait to be imported.
///
/// Note that encoding can never fail.
///
/// # Examples
///
/// ```
/// assert_eq!(
/// 	basenc::encode(b"hello world", basenc::Base64Std, String::new()),
/// 	"aGVsbG8gd29ybGQ="
/// );
/// ```
///
/// Convenience, appends to a by-value buffer and returns that buffer.
///
/// ```
/// let mut str_buf = String::from("output: ");
/// assert_eq!(
/// 	basenc::encode(b"BuFfEr ReUsE!", basenc::Base64Url, &mut str_buf),
/// 	"QnVGZkVyIFJlVXNFIQ"
/// );
/// assert_eq!(str_buf, "output: QnVGZkVyIFJlVXNFIQ");
/// ```
///
/// Appends to an existing buffer, returns a reference to the encoded input.
///
/// ```
/// let mut stack_buf = [0u8; 16];
/// assert_eq!(
/// 	basenc::encode(b"\x00\x80\xFF\xDC", basenc::LowerHex, &mut stack_buf[..]),
/// 	"0080ffdc"
/// );
/// ```
///
/// Uses fixed-size arrays on the stack as a buffer, available with `#[no_std]`.
///
/// Panics if the buffer is too small to fit the output.
pub fn encode<C: Encoding, B: EncodeBuf>(bytes: &[u8], encoding: C, buffer: B) -> B::Output {
	encoding.encode(bytes, buffer)
}
/// Directly decode into a decode buffer.
///
/// Convenient as it doesn't require the [`Encoding`](trait.Encoding.html) trait to be imported.
///
/// Decoding may fail and produce an [`Error`](enum.Error.html) instead.
///
/// # Examples
///
/// ```
/// assert_eq!(
/// 	basenc::decode("aGVsbG8gd29ybGQ=", basenc::Base64Std, Vec::new()),
/// 	Ok(b"hello world"[..].to_vec())
/// );
/// // Note that the buffer is swallowed on error
/// assert_eq!(
/// 	basenc::decode("&'nv@l!d", basenc::Base64Std, Vec::new()),
/// 	Err(basenc::Error::InvalidChar('&'))
/// );
/// ```
///
/// Convenience, appends to a by-value buffer and returns that buffer.
///
/// ```
/// let mut byte_buf = vec![0x11, 0x22, 0x33];
/// assert_eq!(
/// 	basenc::decode("QnVGZkVyIFJlVXNFIQ", basenc::Base64Url, &mut byte_buf),
/// 	Ok(&b"BuFfEr ReUsE!"[..])
/// );
/// assert_eq!(byte_buf, b"\x11\x22\x33BuFfEr ReUsE!");
/// ```
///
/// Appends to an existing buffer, returns a reference to the decoded input.
///
/// ```
/// let mut stack_buf = [0u8; 16];
/// assert_eq!(
/// 	basenc::decode("0080FFDC", basenc::UpperHex, &mut stack_buf[..]),
/// 	Ok(&b"\x00\x80\xFF\xDC"[..])
/// );
/// ```
///
/// Uses fixed-size arrays on the stack as a buffer, available with `#[no_std]`.
///
/// Panics if the buffer is too small to fit the output.
pub fn decode<C: Encoding, B: DecodeBuf>(string: &str, encoding: C, buffer: B) -> Result<B::Output, Error> {
	encoding.decode(string, buffer)
}

//----------------------------------------------------------------

/// Create an encoder adapter for an encoding given an `Iterator<Item = u8>`.
///
/// Helper for [`Encode`](trait.Encode.html), should be merged into [`Encoding`](trait.Encoding.html) but can't be due to HKT reasons.
pub trait Encoder<I: Iterator<Item = u8>>: Encoding {
	type Encoder: Iterator<Item = char>;
	fn encoder(self, iter: I) -> Self::Encoder;
}
/// Byte iterator adapter to an encoder.
///
/// Adapts any `Iterator<Item = u8>` into an iterator over the encoded chars.
///
/// Beware of code bloat! The entire decode logic may get inlined at the invocation site.
///
/// # Examples
///
/// ```
/// use basenc::Encode;
///
/// assert!(
/// 	"hello".bytes()
/// 	.encode(basenc::UpperHex)
/// 	.eq("68656C6C6F".chars())
/// );
///
/// assert!(
/// 	b"\xadapters\xff"[..].iter().cloned()
/// 	.encode(basenc::Base64Url)
/// 	.eq("rWFwdGVyc_8".chars())
/// );
///
/// assert!(
/// 	"STRingS".bytes()
/// 	.encode(basenc::LowerHex)
/// 	.eq("535452696e6753".chars())
/// );
/// ```
pub trait Encode<I: Iterator<Item = u8>, R: Encoder<I>> {
	fn encode(self, encoding: R) -> R::Encoder;
}
impl<I: Iterator<Item = u8>, R: Encoder<I>> Encode<I, R> for I {
	fn encode(self, encoding: R) -> R::Encoder {
		encoding.encoder(self)
	}
}

/// Create a decoder adapter for an encoding given an `Iterator<Item = char>`.
///
/// Helper for [`Decode`](trait.Decode.html), should be merged into [`Encoding`](trait.Encoding.html) but can't be due to HKT reasons.
pub trait Decoder<I: Iterator<Item = char>>: Encoding {
	type Decoder: Iterator<Item = Result<u8, Error>>;
	fn decoder(self, iter: I) -> Self::Decoder;
}
/// Char iterator adapter to a decoder.
///
/// Adapts any `Iterator<Item = char>` into an iterator over a result of the decoded bytes.
///
/// Beware of code bloat! The entire decode logic may get inlined at the invocation site.
///
/// # Examples
///
/// ```
/// use basenc::Decode;
///
/// assert!(
/// 	"68656c6c6F".chars()
/// 	.decode(basenc::AnyHex)
/// 	.eq("hello".bytes().map(Ok))
/// );
/// ```
pub trait Decode<I: Iterator<Item = char>, R: Decoder<I>> {
	fn decode(self, encoding: R) -> R::Decoder;
}
impl<I: Iterator<Item = char>, R: Decoder<I>> Decode<I, R> for I {
	fn decode(self, encoding: R) -> R::Decoder {
		encoding.decoder(self)
	}
}

//----------------------------------------------------------------

pub use details::base64::{Base64Std, Base64Url};
pub use details::hex::{LowerHex, UpperHex, AnyHex};