1#![no_std]
2
3#[cfg(feature = "alloc")]
4extern crate alloc;
5
6use core::{
7 fmt::{self, Debug},
8 str
9};
10
11pub mod base85;
12pub mod hex;
13
14pub trait Encoder<const LEN: usize>: Decoder<LEN> {
15 fn alphabet(&self) -> Alphabet<'_, LEN>;
16 fn encoded_len(&self, len: usize) -> Option<usize>;
17 fn encode_into<'a>(&self, dst: &'a mut [u8], src: &[u8]) -> &'a str;
18
19 #[cfg(feature = "alloc")]
20 #[track_caller]
21 fn encode(&self, src: &[u8]) -> alloc::string::String {
22 let mut dst = alloc::vec![0; self.encoded_len(src.len()).unwrap()];
23 let s = self.encode_into(&mut dst, src);
24 debug_assert!(s.len() == dst.len());
25 unsafe { alloc::string::String::from_utf8_unchecked(dst) }
26 }
27}
28
29pub trait Decoder<const LEN: usize> {
30 type Error: From<InvalidLength>;
31
32 fn decoded_len(&self, len: usize) -> Result<usize, InvalidLength>;
33 fn decode_into<'a>(&self, dst: &'a mut [u8], src: &[u8]) -> Result<&'a [u8], Self::Error>;
34
35 #[cfg(feature = "alloc")]
36 #[track_caller]
37 fn decode(&self, src: &[u8]) -> Result<alloc::vec::Vec<u8>, Self::Error> {
38 let mut dst = alloc::vec![0; self.decoded_len(src.len())?];
39 let s = self.decode_into(&mut dst, src)?;
40 debug_assert!(s.len() == dst.len());
41 Ok(dst)
42 }
43}
44
45#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
46#[repr(transparent)]
47pub struct Alphabet<'a, const LEN: usize>(&'a [u8; LEN]);
48
49impl<'a, const LEN: usize> Alphabet<'a, LEN> {
50 #[track_caller]
51 pub const fn new(alphabet: &'a [u8; LEN]) -> Result<Self, AlphabetError> {
52 let mut i = 0;
53 while i < alphabet.len() {
54 if !alphabet[i].is_ascii() {
55 return Err(AlphabetError::NonAscii(alphabet[i]));
56 }
57
58 let mut j = 0;
59 while j < i {
60 if alphabet[i] == alphabet[j] {
61 return Err(AlphabetError::Duplicate {
62 character: alphabet[i],
63 first: j,
64 second: i
65 });
66 }
67
68 j += 1;
69 }
70
71 i += 1;
72 }
73
74 Ok(Self(alphabet))
75 }
76
77 #[allow(clippy::missing_safety_doc)]
78 #[track_caller]
79 pub const unsafe fn new_unchecked(alphabet: &'a [u8; LEN]) -> Self {
80 debug_assert!(Self::new(alphabet).is_ok());
81 Self(alphabet)
82 }
83
84 pub const fn as_bytes(&self) -> &'a [u8; LEN] {
85 self.0
86 }
87
88 pub const fn as_str(&self) -> &'a str {
89 unsafe { str::from_utf8_unchecked(self.0) }
90 }
91}
92
93impl<const LEN: usize> Debug for Alphabet<'_, LEN> {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 write!(f, "Alphabet<{LEN}>({})", self.as_str().escape_debug())
96 }
97}
98
99#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
100pub struct InvalidLength;
101
102#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
103pub enum AlphabetError {
104 NonAscii(u8),
105 Duplicate { character: u8, first: usize, second: usize }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn test() {
114 assert_eq!(Alphabet::new(b"").unwrap().as_str(), "");
115 assert_eq!(Alphabet::new(b"123").unwrap().as_str(), "123");
116 assert_eq!(Alphabet::new(b"\0\n\t\x7f").unwrap().as_str(), "\0\n\t\x7f");
117 assert_eq!(Alphabet::new(b"\x80"), Err(AlphabetError::NonAscii(0x80)));
118
119 assert_eq!(
120 Alphabet::new(b"aa"),
121 Err(AlphabetError::Duplicate { character: b'a', first: 0, second: 1 })
122 );
123 }
124}