qubit_codec_misc/
base64_quantum_codec.rs1use crate::{
11 Codec,
12 MiscCodecError,
13 MiscCodecResult,
14};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct Base64QuantumCodec {
23 url_safe: bool,
24}
25
26impl Base64QuantumCodec {
27 #[inline]
32 pub fn standard() -> Self {
33 Self { url_safe: false }
34 }
35
36 #[inline]
41 pub fn url_safe() -> Self {
42 Self { url_safe: true }
43 }
44
45 #[inline(always)]
50 fn alphabet(&self) -> &'static [u8; 64] {
51 if self.url_safe {
52 b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
53 } else {
54 b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
55 }
56 }
57
58 #[inline]
71 fn decode_unit(&self, unit: u8, index: usize) -> MiscCodecResult<u8> {
72 match unit {
73 b'A'..=b'Z' => Ok(unit - b'A'),
74 b'a'..=b'z' => Ok(unit - b'a' + 26),
75 b'0'..=b'9' => Ok(unit - b'0' + 52),
76 b'+' if !self.url_safe => Ok(62),
77 b'/' if !self.url_safe => Ok(63),
78 b'-' if self.url_safe => Ok(62),
79 b'_' if self.url_safe => Ok(63),
80 _ => Err(MiscCodecError::InvalidInput {
81 codec: "base64-quantum",
82 reason: format!(
83 "invalid Base64 unit '{}' at index {}",
84 char::from(unit),
85 index
86 ),
87 }),
88 }
89 }
90}
91
92impl Default for Base64QuantumCodec {
93 #[inline]
95 fn default() -> Self {
96 Self::standard()
97 }
98}
99
100unsafe impl Codec for Base64QuantumCodec {
101 type Value = [u8; 3];
102 type Unit = u8;
103 type DecodeError = MiscCodecError;
104 type EncodeError = MiscCodecError;
105
106 #[inline(always)]
108 fn min_units_per_value(&self) -> core::num::NonZeroUsize {
109 unsafe { core::num::NonZeroUsize::new_unchecked(4) }
111 }
112
113 #[inline(always)]
115 fn max_units_per_value(&self) -> core::num::NonZeroUsize {
116 unsafe { core::num::NonZeroUsize::new_unchecked(4) }
118 }
119
120 #[inline]
122 unsafe fn decode_unchecked(
123 &self,
124 input: &[u8],
125 index: usize,
126 ) -> Result<([u8; 3], core::num::NonZeroUsize), Self::DecodeError> {
127 debug_assert!(index + 4 <= input.len());
128
129 let first = self.decode_unit(input[index], index)?;
130 let second = self.decode_unit(input[index + 1], index + 1)?;
131 let third = self.decode_unit(input[index + 2], index + 2)?;
132 let fourth = self.decode_unit(input[index + 3], index + 3)?;
133 Ok((
134 [
135 (first << 2) | (second >> 4),
136 (second << 4) | (third >> 2),
137 (third << 6) | fourth,
138 ],
139 unsafe { core::num::NonZeroUsize::new_unchecked(4) },
141 ))
142 }
143
144 #[inline]
146 unsafe fn encode_unchecked(
147 &self,
148 value: &[u8; 3],
149 output: &mut [u8],
150 index: usize,
151 ) -> Result<usize, Self::EncodeError> {
152 debug_assert!(index + 4 <= output.len());
153
154 let alphabet = self.alphabet();
155 output[index] = alphabet[(value[0] >> 2) as usize];
156 output[index + 1] =
157 alphabet[(((value[0] & 0x03) << 4) | (value[1] >> 4)) as usize];
158 output[index + 2] =
159 alphabet[(((value[1] & 0x0f) << 2) | (value[2] >> 6)) as usize];
160 output[index + 3] = alphabet[(value[2] & 0x3f) as usize];
161 Ok(4)
162 }
163}