btt/
lib.rs

1#![no_std]
2
3#[cfg(feature = "alloc")]
4extern crate alloc;
5
6use core::{
7	error::Error,
8	fmt::{self, Debug, Display},
9	iter, str
10};
11
12#[macro_use]
13mod macros;
14
15pub mod alphabet;
16pub mod base32;
17pub mod base64;
18pub mod base85;
19pub mod generic;
20pub mod hex;
21pub mod padding;
22
23mod chunked;
24
25use self::alphabet::{DynAlphabet, DynDecodingTable};
26pub use self::{
27	base32::{
28		Base32HexLower, Base32HexLowerUnpadded, Base32HexUpper, Base32HexUpperUnpadded,
29		Base32Lower, Base32LowerUnpadded, Base32Upper, Base32UpperUnpadded
30	},
31	base64::{Base64, Base64Unpadded, Base64UrlPadded, Base64UrlUnpadded},
32	base85::Z85,
33	hex::{HexLower, HexUpper}
34};
35
36pub trait Encoder: Decoder {
37	fn alphabet(&self) -> &DynAlphabet;
38	fn encoded_len(&self, len: usize) -> Option<usize>;
39
40	fn encode_into_exact<'a>(
41		&self,
42		src: &[u8],
43		dst: &'a mut [u8]
44	) -> Result<&'a str, EncodeIntoExactError>;
45
46	#[inline]
47	fn encode_into<'a>(&self, src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, EncodeIntoError> {
48		let dst = dst
49			.get_mut(..self.encoded_len(src.len()).ok_or(EncodeIntoError::LengthOverflow)?)
50			.ok_or(EncodeIntoError::TooSmall)?;
51
52		Ok(self.encode_into_exact(src, dst).unwrap())
53	}
54
55	#[cfg(feature = "alloc")]
56	#[inline]
57	fn encode_string(&self, src: &[u8]) -> Option<alloc::string::String> {
58		let mut vec = alloc::vec::Vec::new();
59		let _ = self.encode_into_vec(src, &mut vec)?;
60		Some(unsafe { alloc::string::String::from_utf8_unchecked(vec) })
61	}
62
63	#[cfg(feature = "alloc")]
64	#[inline]
65	fn encode_into_vec<'a>(&self, src: &[u8], dst: &'a mut alloc::vec::Vec<u8>) -> Option<&'a str> {
66		let start = dst.len();
67		dst.extend(iter::repeat_n(0, self.encoded_len(src.len())?));
68		Some(self.encode_into_exact(src, &mut dst[start..]).unwrap())
69	}
70
71	#[cfg(feature = "alloc")]
72	#[inline]
73	fn encode_into_string<'a>(
74		&self,
75		src: &[u8],
76		dst: &'a mut alloc::string::String
77	) -> Option<&'a str> {
78		self.encode_into_vec(src, unsafe { dst.as_mut_vec() })
79	}
80}
81
82pub trait Decoder {
83	fn decoding_table(&self) -> &DynDecodingTable;
84	fn decoded_len(&self, src: &[u8]) -> Option<usize>;
85
86	fn decode_into_exact<'a>(
87		&self,
88		src: &[u8],
89		dst: &'a mut [u8]
90	) -> Result<&'a [u8], DecodeIntoExactError>;
91
92	#[inline]
93	fn decode_into<'a>(&self, src: &[u8], dst: &'a mut [u8]) -> Result<&'a [u8], DecodeIntoError> {
94		let dst = dst
95			.get_mut(..self.decoded_len(src).ok_or(DecodeIntoError::InvalidLength)?)
96			.ok_or(DecodeIntoError::TooSmall)?;
97
98		match self.decode_into_exact(src, dst) {
99			Ok(s) => Ok(s),
100			Err(DecodeIntoExactError::InvalidCharacter(i)) => {
101				Err(DecodeIntoError::InvalidCharacter(i))
102			}
103			Err(DecodeIntoExactError::InvalidChunk { index, len }) => {
104				Err(DecodeIntoError::InvalidChunk { index, len })
105			}
106			Err(DecodeIntoExactError::NonCanonical) => Err(DecodeIntoError::NonCanonical),
107			Err(DecodeIntoExactError::InvalidLength | DecodeIntoExactError::LengthMismatch) => {
108				unreachable!()
109			}
110		}
111	}
112
113	#[cfg(feature = "alloc")]
114	#[inline]
115	fn decode_vec(&self, src: &[u8]) -> Result<alloc::vec::Vec<u8>, DecodeVecError> {
116		let mut vec = alloc::vec::Vec::new();
117		let _ = self.decode_into_vec(src, &mut vec)?;
118		Ok(vec)
119	}
120
121	#[cfg(feature = "alloc")]
122	#[inline]
123	fn decode_into_vec<'a>(
124		&self,
125		src: &[u8],
126		dst: &'a mut alloc::vec::Vec<u8>
127	) -> Result<&'a [u8], DecodeVecError> {
128		let start = dst.len();
129		dst.extend(iter::repeat_n(0, self.decoded_len(src).ok_or(DecodeVecError::InvalidLength)?));
130
131		match self.decode_into_exact(src, &mut dst[start..]) {
132			Ok(dst) => Ok(dst),
133			Err(DecodeIntoExactError::InvalidCharacter(i)) => {
134				Err(DecodeVecError::InvalidCharacter(i))
135			}
136			Err(DecodeIntoExactError::InvalidChunk { index, len }) => {
137				Err(DecodeVecError::InvalidChunk { index, len })
138			}
139			Err(DecodeIntoExactError::NonCanonical) => Err(DecodeVecError::NonCanonical),
140			Err(DecodeIntoExactError::InvalidLength | DecodeIntoExactError::LengthMismatch) => {
141				unreachable!()
142			}
143		}
144	}
145}
146
147#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
148pub enum EncodeIntoError {
149	LengthOverflow,
150	TooSmall
151}
152
153#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
154pub enum EncodeIntoExactError {
155	LengthOverflow,
156	LengthMismatch
157}
158
159#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
160pub enum DecodeIntoError {
161	InvalidLength,
162	TooSmall,
163	InvalidCharacter(usize),
164	NonCanonical,
165	InvalidChunk { index: usize, len: usize }
166}
167
168#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
169pub enum DecodeIntoExactError {
170	InvalidLength,
171	LengthMismatch,
172	InvalidCharacter(usize),
173	NonCanonical,
174	InvalidChunk { index: usize, len: usize }
175}
176
177#[cfg(feature = "alloc")]
178#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
179pub enum DecodeVecError {
180	InvalidLength,
181	InvalidCharacter(usize),
182	NonCanonical,
183	InvalidChunk { index: usize, len: usize }
184}
185
186#[cfg(test)]
187mod tests {
188	use super::*;
189
190	#[allow(dead_code)]
191	fn assert_dyn_safe(_: &dyn Encoder) {}
192}