qubit_codec_misc/
base64_quantum_codec.rs1use core::num::NonZeroUsize;
11
12use qubit_codec::Codec;
13use qubit_codec::DecodeFailure;
14use qubit_utils::nonzero;
15
16use crate::MiscCodecError;
17use crate::MiscCodecResult;
18use crate::misc_codec_error::map_misc_decode_failure_with_consumed;
19
20#[must_use]
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub struct Base64QuantumCodec {
28 url_safe: bool,
29}
30
31impl Base64QuantumCodec {
32 #[inline]
37 pub fn standard() -> Self {
38 Self { url_safe: false }
39 }
40
41 #[inline]
46 pub fn url_safe() -> Self {
47 Self { url_safe: true }
48 }
49
50 #[inline(always)]
55 fn alphabet(&self) -> &'static [u8; 64] {
56 if self.url_safe {
57 b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
58 } else {
59 b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
60 }
61 }
62
63 fn decode_unit(&self, unit: u8, index: usize) -> MiscCodecResult<u8> {
76 match unit {
77 b'A'..=b'Z' => Ok(unit - b'A'),
78 b'a'..=b'z' => Ok(unit - b'a' + 26),
79 b'0'..=b'9' => Ok(unit - b'0' + 52),
80 b'+' if !self.url_safe => Ok(62),
81 b'/' if !self.url_safe => Ok(63),
82 b'-' if self.url_safe => Ok(62),
83 b'_' if self.url_safe => Ok(63),
84 _ => Err(MiscCodecError::InvalidInput {
85 codec: "base64-quantum",
86 reason: format!(
87 "invalid Base64 unit '{}' at index {}",
88 char::from(unit),
89 index
90 ),
91 }),
92 }
93 }
94}
95
96impl Default for Base64QuantumCodec {
97 #[inline]
99 fn default() -> Self {
100 Self::standard()
101 }
102}
103
104impl Codec for Base64QuantumCodec {
105 type Value = [u8; 3];
106 type Unit = u8;
107 type DecodeError = MiscCodecError;
108 type EncodeError = MiscCodecError;
109
110 const MIN_UNITS_PER_VALUE: usize = 4;
111 const MAX_ENCODE_UNITS_PER_VALUE: usize = 4;
112
113 const MAX_DECODE_UNITS_PER_VALUE: usize = 4;
114
115 unsafe fn decode(
120 &mut self,
121 input: &[u8],
122 input_index: usize,
123 ) -> Result<([u8; 3], NonZeroUsize), DecodeFailure<Self::DecodeError>> {
124 debug_assert!(input_index + 4 <= input.len());
125
126 let first = self
127 .decode_unit(input[input_index], input_index)
128 .map_err(|error| map_misc_decode_failure_with_consumed(error, nonzero(4)))?;
129 let second = self
130 .decode_unit(input[input_index + 1], input_index + 1)
131 .map_err(|error| map_misc_decode_failure_with_consumed(error, nonzero(4)))?;
132 let third = self
133 .decode_unit(input[input_index + 2], input_index + 2)
134 .map_err(|error| map_misc_decode_failure_with_consumed(error, nonzero(4)))?;
135 let fourth = self
136 .decode_unit(input[input_index + 3], input_index + 3)
137 .map_err(|error| map_misc_decode_failure_with_consumed(error, nonzero(4)))?;
138 Ok((
139 [
140 (first << 2) | (second >> 4),
141 (second << 4) | (third >> 2),
142 (third << 6) | fourth,
143 ],
144 nonzero(4),
145 ))
146 }
147
148 unsafe fn encode(
153 &mut self,
154 value: &[u8; 3],
155 output: &mut [u8],
156 output_index: usize,
157 ) -> Result<usize, Self::EncodeError> {
158 debug_assert!(output_index + 4 <= output.len());
159
160 let alphabet = self.alphabet();
161 output[output_index] = alphabet[(value[0] >> 2) as usize];
162 output[output_index + 1] = alphabet[(((value[0] & 0x03) << 4) | (value[1] >> 4)) as usize];
163 output[output_index + 2] = alphabet[(((value[1] & 0x0f) << 2) | (value[2] >> 6)) as usize];
164 output[output_index + 3] = alphabet[(value[2] & 0x3f) as usize];
165 Ok(4)
166 }
167}