1use core::marker::PhantomData;
4
5use crate::runtime::{Backend, OperationKind};
6use crate::{Alphabet, DecodeError, EncodeError, Standard, UrlSafe};
7
8#[derive(Debug)]
23pub struct StaticBackendToken {
24 backend: Backend,
25 generation: usize,
26 _thread_bound: PhantomData<*mut ()>,
27}
28
29impl StaticBackendToken {
30 #[must_use]
35 pub fn for_compiled_target() -> Option<Self> {
36 let backend = compiled_backend()?;
37 Self::admit(backend, false)
38 }
39
40 #[must_use]
51 pub unsafe fn assume_supported(backend: Backend) -> Option<Self> {
52 if backend_matches_target(backend) {
53 Self::admit(backend, true)
54 } else {
55 None
56 }
57 }
58
59 #[must_use]
61 pub const fn backend(&self) -> Backend {
62 self.backend
63 }
64
65 #[must_use]
67 pub const fn health_generation(&self) -> usize {
68 self.generation
69 }
70
71 #[must_use]
77 pub fn is_valid(&self) -> bool {
78 let encode = crate::v2::backend_health::snapshot(OperationKind::Encode, self.backend);
79 let decode = crate::v2::backend_health::snapshot(OperationKind::StrictDecode, self.backend);
80 encode.state == crate::BackendHealthState::Healthy
81 && decode.state == crate::BackendHealthState::Healthy
82 && encode.generation == self.generation
83 && decode.generation == self.generation
84 }
85
86 pub fn encode_standard<const PAD: bool>(
94 &self,
95 input: &[u8],
96 output: &mut [u8],
97 ) -> Result<usize, EncodeError> {
98 self.encode::<Standard, PAD>(input, output)
99 }
100
101 pub fn encode_url_safe<const PAD: bool>(
109 &self,
110 input: &[u8],
111 output: &mut [u8],
112 ) -> Result<usize, EncodeError> {
113 self.encode::<UrlSafe, PAD>(input, output)
114 }
115
116 pub fn decode_standard<const PAD: bool>(
124 &self,
125 input: &[u8],
126 output: &mut [u8],
127 ) -> Result<usize, DecodeError> {
128 self.decode::<Standard, PAD>(input, output)
129 }
130
131 pub fn decode_url_safe<const PAD: bool>(
139 &self,
140 input: &[u8],
141 output: &mut [u8],
142 ) -> Result<usize, DecodeError> {
143 self.decode::<UrlSafe, PAD>(input, output)
144 }
145
146 fn encode<A: Alphabet, const PAD: bool>(
147 &self,
148 input: &[u8],
149 output: &mut [u8],
150 ) -> Result<usize, EncodeError> {
151 if !self.is_valid() {
152 return crate::scalar::encode_slice::<A, PAD>(input, output);
153 }
154 #[cfg(all(
155 feature = "checked-backend",
156 any(
157 target_arch = "x86",
158 target_arch = "x86_64",
159 all(target_arch = "aarch64", target_endian = "little")
160 )
161 ))]
162 match self.backend {
163 Backend::Avx512Vbmi | Backend::Avx2 | Backend::Ssse3Sse41 => {
164 return crate::encode_backend::encode_checked::<A, PAD>(
165 self.backend,
166 input,
167 output,
168 );
169 }
170 #[cfg(all(target_arch = "aarch64", target_endian = "little"))]
171 Backend::Neon => {
172 return crate::encode_backend::encode_checked::<A, PAD>(
173 self.backend,
174 input,
175 output,
176 );
177 }
178 _ => {}
179 }
180 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
181 match self.backend {
182 Backend::Avx512Vbmi => {
183 return crate::simd::encode_slice_avx512::<A, PAD>(input, output);
184 }
185 Backend::Avx2 => return crate::simd::encode_slice_avx2::<A, PAD>(input, output),
186 Backend::Ssse3Sse41 => {
187 return crate::simd::encode_slice_ssse3_sse41::<A, PAD>(input, output);
188 }
189 _ => {}
190 }
191 #[cfg(all(target_arch = "aarch64", target_endian = "little"))]
192 if self.backend == Backend::Neon {
193 return crate::simd::encode_slice_neon::<A, PAD>(input, output);
194 }
195 crate::scalar::encode_slice::<A, PAD>(input, output)
196 }
197
198 fn decode<A: Alphabet, const PAD: bool>(
199 &self,
200 input: &[u8],
201 output: &mut [u8],
202 ) -> Result<usize, DecodeError> {
203 if !self.is_valid() {
204 return crate::scalar::decode_slice::<A, PAD>(input, output);
205 }
206 #[cfg(all(
207 feature = "checked-backend",
208 any(
209 target_arch = "x86",
210 target_arch = "x86_64",
211 all(target_arch = "aarch64", target_endian = "little")
212 )
213 ))]
214 match self.backend {
215 Backend::Avx512Vbmi | Backend::Avx2 | Backend::Ssse3Sse41 => {
216 return crate::decode_backend::decode_checked::<A, PAD>(
217 self.backend,
218 input,
219 output,
220 );
221 }
222 #[cfg(all(target_arch = "aarch64", target_endian = "little"))]
223 Backend::Neon => {
224 return crate::decode_backend::decode_checked::<A, PAD>(
225 self.backend,
226 input,
227 output,
228 );
229 }
230 _ => {}
231 }
232 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
233 match self.backend {
234 Backend::Avx512Vbmi => {
235 return crate::simd::decode_slice_avx512::<A, PAD>(input, output);
236 }
237 Backend::Avx2 => return crate::simd::decode_slice_avx2::<A, PAD>(input, output),
238 Backend::Ssse3Sse41 => {
239 return crate::simd::decode_slice_ssse3_sse41::<A, PAD>(input, output);
240 }
241 _ => {}
242 }
243 #[cfg(all(target_arch = "aarch64", target_endian = "little"))]
244 if self.backend == Backend::Neon {
245 return crate::simd::decode_slice_neon::<A, PAD>(input, output);
246 }
247 crate::scalar::decode_slice::<A, PAD>(input, output)
248 }
249
250 fn admit(backend: Backend, deployment_attested: bool) -> Option<Self> {
251 let admit_operation = |operation| {
252 if deployment_attested {
253 crate::v2::backend_health::admit_deployment_attested(operation, backend)
254 } else {
255 crate::v2::backend_health::admit(operation, backend)
256 }
257 };
258 if !cfg!(target_has_atomic = "ptr")
259 || !admit_operation(OperationKind::Encode)
260 || !admit_operation(OperationKind::StrictDecode)
261 {
262 return None;
263 }
264 let encode = crate::v2::backend_health::snapshot(OperationKind::Encode, backend);
265 let decode = crate::v2::backend_health::snapshot(OperationKind::StrictDecode, backend);
266 if encode.generation != decode.generation {
267 return None;
268 }
269 Some(Self {
270 backend,
271 generation: encode.generation,
272 _thread_bound: PhantomData,
273 })
274 }
275}
276
277fn compiled_backend() -> Option<Backend> {
278 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
279 {
280 if cfg!(all(
281 target_feature = "avx512f",
282 target_feature = "avx512bw",
283 target_feature = "avx512vl",
284 target_feature = "avx512vbmi"
285 )) {
286 return Some(Backend::Avx512Vbmi);
287 }
288 if cfg!(target_feature = "avx2") {
289 return Some(Backend::Avx2);
290 }
291 if cfg!(all(target_feature = "ssse3", target_feature = "sse4.1")) {
292 return Some(Backend::Ssse3Sse41);
293 }
294 }
295 #[cfg(all(target_arch = "aarch64", target_endian = "little"))]
296 if cfg!(target_feature = "neon") {
297 return Some(Backend::Neon);
298 }
299 #[cfg(target_arch = "wasm32")]
300 if cfg!(target_feature = "simd128") {
301 return Some(Backend::WasmSimd128);
302 }
303 None
304}
305
306const fn backend_matches_target(backend: Backend) -> bool {
307 match backend {
308 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
309 Backend::Avx512Vbmi | Backend::Avx2 | Backend::Ssse3Sse41 => true,
310 #[cfg(all(target_arch = "aarch64", target_endian = "little"))]
311 Backend::Neon => true,
312 #[cfg(target_arch = "wasm32")]
313 Backend::WasmSimd128 => true,
314 _ => false,
315 }
316}