base64ct/
alphabet.rs
1#![allow(clippy::integer_arithmetic)]
5
6use core::{fmt::Debug, ops::Range};
7
8pub mod bcrypt;
9pub mod crypt;
10pub mod standard;
11pub mod url;
12
13pub trait Alphabet: 'static + Copy + Debug + Eq + Send + Sized + Sync {
15 const BASE: u8;
17
18 const DECODER: &'static [DecodeStep];
20
21 const ENCODER: &'static [EncodeStep];
23
24 const PADDED: bool;
26
27 type Unpadded: Alphabet;
31
32 #[inline(always)]
34 fn decode_3bytes(src: &[u8], dst: &mut [u8]) -> i16 {
35 debug_assert_eq!(src.len(), 4);
36 debug_assert!(dst.len() >= 3, "dst too short: {}", dst.len());
37
38 let c0 = Self::decode_6bits(src[0]);
39 let c1 = Self::decode_6bits(src[1]);
40 let c2 = Self::decode_6bits(src[2]);
41 let c3 = Self::decode_6bits(src[3]);
42
43 dst[0] = ((c0 << 2) | (c1 >> 4)) as u8;
44 dst[1] = ((c1 << 4) | (c2 >> 2)) as u8;
45 dst[2] = ((c2 << 6) | c3) as u8;
46
47 ((c0 | c1 | c2 | c3) >> 8) & 1
48 }
49
50 fn decode_6bits(src: u8) -> i16 {
52 let mut ret: i16 = -1;
53
54 for step in Self::DECODER {
55 ret += match step {
56 DecodeStep::Range(range, offset) => {
57 let start = range.start as i16 - 1;
59 let end = range.end as i16 + 1;
60 (((start - src as i16) & (src as i16 - end)) >> 8) & (src as i16 + *offset)
61 }
62 DecodeStep::Eq(value, offset) => {
63 let start = *value as i16 - 1;
64 let end = *value as i16 + 1;
65 (((start - src as i16) & (src as i16 - end)) >> 8) & *offset
66 }
67 };
68 }
69
70 ret
71 }
72
73 #[inline(always)]
75 fn encode_3bytes(src: &[u8], dst: &mut [u8]) {
76 debug_assert_eq!(src.len(), 3);
77 debug_assert!(dst.len() >= 4, "dst too short: {}", dst.len());
78
79 let b0 = src[0] as i16;
80 let b1 = src[1] as i16;
81 let b2 = src[2] as i16;
82
83 dst[0] = Self::encode_6bits(b0 >> 2);
84 dst[1] = Self::encode_6bits(((b0 << 4) | (b1 >> 4)) & 63);
85 dst[2] = Self::encode_6bits(((b1 << 2) | (b2 >> 6)) & 63);
86 dst[3] = Self::encode_6bits(b2 & 63);
87 }
88
89 #[inline(always)]
91 fn encode_6bits(src: i16) -> u8 {
92 let mut diff = src + Self::BASE as i16;
93
94 for &step in Self::ENCODER {
95 diff += match step {
96 EncodeStep::Apply(threshold, offset) => ((threshold as i16 - diff) >> 8) & offset,
97 EncodeStep::Diff(threshold, offset) => ((threshold as i16 - src) >> 8) & offset,
98 };
99 }
100
101 diff as u8
102 }
103}
104
105#[derive(Debug)]
107pub enum DecodeStep {
108 Range(Range<u8>, i16),
110
111 Eq(u8, i16),
113}
114
115#[derive(Copy, Clone, Debug)]
117pub enum EncodeStep {
118 Apply(u8, i16),
120
121 Diff(u8, i16),
123}