1#![no_std]
54#![warn(
55 absolute_paths_not_starting_with_crate,
56 meta_variable_misuse,
57 missing_debug_implementations,
58 missing_docs,
59 noop_method_call,
60 pointer_structural_match,
61 unreachable_pub,
62 unused_crate_dependencies,
63 unused_lifetimes,
64 clippy::cast_lossless,
65 clippy::cast_possible_truncation,
66 clippy::cast_possible_wrap,
67 clippy::cast_precision_loss,
68 clippy::cast_sign_loss,
69 clippy::checked_conversions,
70 clippy::cognitive_complexity,
71 clippy::exhaustive_enums,
72 clippy::exhaustive_structs,
73 clippy::future_not_send,
74 clippy::inconsistent_struct_constructor,
75 clippy::inefficient_to_string,
76 clippy::use_debug,
77 clippy::use_self
78)]
79
80use typewit::{HasTypeWitness, MakeTypeWitness, TypeEq, TypeWitnessTypeArg};
81
82#[derive(Debug)]
83#[non_exhaustive]
84#[doc(hidden)]
85pub enum Endianness {
86 Native,
87 Big,
88 Little,
89}
90
91#[macro_export]
93macro_rules! bytify_be {
94 ($visibility:vis const $name:ident: $($items:expr),* $(,)?) => {
95 $visibility const $name: [::core::primitive::u8; $crate::bytify!(priv len: $($items),*)] = $crate::bytify!(priv endianness: Big => $($items),*);
96 };
97 ($visibility:vis static $name:ident: $($items:expr),* $(,)?) => {
98 $visibility static $name: [::core::primitive::u8; $crate::bytify!(priv len: $($items),*)] = $crate::bytify!(priv endianness: Big => $($items),*);
99 };
100 ($($items:expr),* $(,)?) => {
101 $crate::bytify!(priv endianness: Big => $($items),*)
102 };
103}
104
105#[macro_export]
107macro_rules! bytify_le {
108 ($visibility:vis const $name:ident: $($items:expr),* $(,)?) => {
109 $visibility const $name: [::core::primitive::u8; $crate::bytify!(priv len: $($items),*)] = $crate::bytify!(priv endianness: Little => $($items),*);
110 };
111 ($visibility:vis static $name:ident: $($items:expr),* $(,)?) => {
112 $visibility static $name: [::core::primitive::u8; $crate::bytify!(priv len: $($items),*)] = $crate::bytify!(priv endianness: Little => $($items),*);
113 };
114 ($($items:expr),* $(,)?) => {
115 $crate::bytify!(priv endianness: Little => $($items),*)
116 };
117}
118
119#[macro_export]
170macro_rules! bytify {
171 ($visibility:vis const $name:ident: $($items:expr),* $(,)?) => {
172 $visibility const $name: [::core::primitive::u8; $crate::bytify!(priv len: $($items),*)] = $crate::bytify!(priv endianness: Native => $($items),*);
173 };
174 ($visibility:vis static $name:ident: $($items:expr),* $(,)?) => {
175 $visibility static $name: [::core::primitive::u8; $crate::bytify!(priv len: $($items),*)] = $crate::bytify!(priv endianness: Native => $($items),*);
176 };
177 ($($items:expr),* $(,)?) => {
178 $crate::bytify!(priv endianness: Native => $($items),*)
179 };
180 (priv endianness: $endianness:ident => $($items:expr),*) => {
181 $crate::bytify!(priv concat: $(($crate::bytify_len($items), $crate::bytify_one($crate::Endianness::$endianness, $items))),*)
182 };
183 (priv len: $($items:expr),*) => {
184 0 $(+ $crate::bytify_len($items))*
185 };
186 (priv concat: $(($len:expr, $bytes:expr)),*) => {
187 {
188 const LEN: ::core::primitive::usize = 0 $(+ $len)*;
189 const SUM: [::core::primitive::u8; LEN] = {
190 let mut sum: [::core::primitive::u8; LEN] = [0; LEN];
191 let mut offset: ::core::primitive::usize = 0;
192 $(
193 {
194 const LEN: ::core::primitive::usize = $len;
195 const BYTES: [::core::primitive::u8; $len] = $bytes;
196 let mut i = 0;
197 while i < LEN {
198 sum[offset + i] = BYTES[i];
199 i += 1;
200 }
201 offset += LEN;
202 }
203 )*
204 sum
205 };
206 SUM
207 }
208 };
209 (priv $($unhandled:tt)*) => {
210 ::core::compile_error!(::core::stringify!(unhandled input: $($unhandled)*))
211 };
212}
213
214#[doc(hidden)]
215pub const fn bytify_len<const X: usize, T>(value: T) -> usize
216where
217 T: HasTypeWitness<BytifyWitness<X, T>>,
218{
219 match T::WITNESS {
220 BytifyWitness::bool(witness) => bool::len(witness.to_right(value)),
221 BytifyWitness::char(witness) => char::len(witness.to_right(value)),
222 BytifyWitness::u8(witness) => u8::len(witness.to_right(value)),
223 BytifyWitness::i8(witness) => i8::len(witness.to_right(value)),
224 BytifyWitness::u16(witness) => u16::len(witness.to_right(value)),
225 BytifyWitness::i16(witness) => i16::len(witness.to_right(value)),
226 BytifyWitness::u32(witness) => u32::len(witness.to_right(value)),
227 BytifyWitness::i32(witness) => i32::len(witness.to_right(value)),
228 BytifyWitness::u64(witness) => u64::len(witness.to_right(value)),
229 BytifyWitness::i64(witness) => i64::len(witness.to_right(value)),
230 BytifyWitness::u128(witness) => u128::len(witness.to_right(value)),
231 BytifyWitness::i128(witness) => i128::len(witness.to_right(value)),
232 BytifyWitness::usize(witness) => usize::len(witness.to_right(value)),
233 BytifyWitness::isize(witness) => isize::len(witness.to_right(value)),
234 BytifyWitness::f32(witness) => f32::len(witness.to_right(value)),
235 BytifyWitness::f64(witness) => f64::len(witness.to_right(value)),
236 BytifyWitness::str(witness) => str::len(witness.to_right(value)),
237 BytifyWitness::SliceArray(witness) => slice_array::len(witness.to_right(value)),
238 BytifyWitness::Array(witness) => array::len(witness.to_right(value)),
239 }
240}
241
242#[doc(hidden)]
243pub const fn bytify_one<const X: usize, const N: usize, T>(
244 endianness: Endianness,
245 value: T,
246) -> [u8; N]
247where
248 T: HasTypeWitness<BytifyWitness<X, T>>,
249{
250 match T::WITNESS {
251 BytifyWitness::bool(witness) => bool::copy(endianness, witness.to_right(value)),
252 BytifyWitness::char(witness) => char::copy(endianness, witness.to_right(value)),
253 BytifyWitness::u8(witness) => u8::copy(endianness, witness.to_right(value)),
254 BytifyWitness::i8(witness) => i8::copy(endianness, witness.to_right(value)),
255 BytifyWitness::u16(witness) => u16::copy(endianness, witness.to_right(value)),
256 BytifyWitness::i16(witness) => i16::copy(endianness, witness.to_right(value)),
257 BytifyWitness::u32(witness) => u32::copy(endianness, witness.to_right(value)),
258 BytifyWitness::i32(witness) => i32::copy(endianness, witness.to_right(value)),
259 BytifyWitness::u64(witness) => u64::copy(endianness, witness.to_right(value)),
260 BytifyWitness::i64(witness) => i64::copy(endianness, witness.to_right(value)),
261 BytifyWitness::u128(witness) => u128::copy(endianness, witness.to_right(value)),
262 BytifyWitness::i128(witness) => i128::copy(endianness, witness.to_right(value)),
263 BytifyWitness::usize(witness) => usize::copy(endianness, witness.to_right(value)),
264 BytifyWitness::isize(witness) => isize::copy(endianness, witness.to_right(value)),
265 BytifyWitness::f32(witness) => f32::copy(endianness, witness.to_right(value)),
266 BytifyWitness::f64(witness) => f64::copy(endianness, witness.to_right(value)),
267 BytifyWitness::str(witness) => str::copy(endianness, witness.to_right(value)),
268 BytifyWitness::SliceArray(witness) => {
269 slice_array::copy(endianness, witness.to_right(value))
270 },
271 BytifyWitness::Array(witness) => array::copy(endianness, witness.to_right(value)),
272 }
273}
274
275#[derive(Debug)]
276#[non_exhaustive]
277#[doc(hidden)]
278#[allow(non_camel_case_types)]
279pub enum BytifyWitness<const X: usize, Witness: ?Sized> {
280 bool(TypeEq<Witness, bool>),
281 char(TypeEq<Witness, char>),
282 u8(TypeEq<Witness, u8>),
283 i8(TypeEq<Witness, i8>),
284 u16(TypeEq<Witness, u16>),
285 i16(TypeEq<Witness, i16>),
286 u32(TypeEq<Witness, u32>),
287 i32(TypeEq<Witness, i32>),
288 u64(TypeEq<Witness, u64>),
289 i64(TypeEq<Witness, i64>),
290 u128(TypeEq<Witness, u128>),
291 i128(TypeEq<Witness, i128>),
292 usize(TypeEq<Witness, usize>),
293 isize(TypeEq<Witness, isize>),
294 f32(TypeEq<Witness, f32>),
295 f64(TypeEq<Witness, f64>),
296 str(TypeEq<Witness, &'static str>),
297 SliceArray(TypeEq<Witness, &'static [u8]>),
298 Array(TypeEq<Witness, [u8; X]>),
299}
300
301impl<const X: usize, Witness> TypeWitnessTypeArg for BytifyWitness<X, Witness> {
302 type Arg = Witness;
303}
304
305mod bool {
306 use super::*;
307
308 pub(crate) const fn len(value: bool) -> usize {
309 u8::len(value as u8)
310 }
311
312 pub(crate) const fn copy<const N: usize>(endianness: Endianness, value: bool) -> [u8; N] {
313 u8::copy(endianness, value as u8)
314 }
315
316 impl MakeTypeWitness for BytifyWitness<0, bool> {
317 const MAKE: Self = Self::bool(TypeEq::NEW);
318 }
319}
320
321mod char {
322 use super::*;
323
324 pub(crate) const fn len(value: char) -> usize {
325 value.len_utf8()
326 }
327
328 pub(crate) const fn copy<const N: usize>(endianness: Endianness, value: char) -> [u8; N] {
329 array::copy(endianness, bytes::<N>(value))
330 }
331
332 const fn bytes<const N: usize>(char: char) -> [u8; N] {
333 const TAG_CONT: u8 = 0b1000_0000;
334 const TAG_TWO_B: u8 = 0b1100_0000;
335 const TAG_THREE_B: u8 = 0b1110_0000;
336 const TAG_FOUR_B: u8 = 0b1111_0000;
337 let mut array = [0; N];
338 let code = char as u32;
339 match code {
340 ..= 0x0000007F => {
341 array[0] = (code & 0xFF) as u8;
342 },
343 0x00000080 ..= 0x000007FF => {
344 array[0] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
345 array[1] = (code & 0x3F) as u8 | TAG_CONT;
346 },
347 0x00000800 ..= 0x0000FFFF => {
348 array[0] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
349 array[1] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
350 array[2] = (code & 0x3F) as u8 | TAG_CONT;
351 },
352 0x00010000 .. => {
353 array[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
354 array[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
355 array[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
356 array[3] = (code & 0x3F) as u8 | TAG_CONT;
357 },
358 }
359 array
360 }
361
362 impl MakeTypeWitness for BytifyWitness<0, char> {
363 const MAKE: Self = Self::char(TypeEq::NEW);
364 }
365}
366
367macro_rules! bytify_integer {
368 ($name:ident) => {
369 mod $name {
370 use super::*;
371
372 pub(crate) const fn len(value: $name) -> usize {
373 value.to_ne_bytes().len()
374 }
375
376 pub(crate) const fn copy<const N: usize>(
377 endianness: Endianness,
378 value: $name,
379 ) -> [u8; N] {
380 let bytes = match endianness {
381 Endianness::Native => value.to_ne_bytes(),
382 Endianness::Big => value.to_be_bytes(),
383 Endianness::Little => value.to_le_bytes(),
384 };
385 let mut array = [0; N];
386 let mut i = 0;
387 while i < bytes.len() {
388 array[i] = bytes[i];
389 i += 1;
390 }
391 array
392 }
393
394 impl MakeTypeWitness for BytifyWitness<0, $name> {
395 const MAKE: Self = Self::$name(TypeEq::NEW);
396 }
397 }
398 };
399}
400
401bytify_integer!(u8);
402bytify_integer!(i8);
403bytify_integer!(u16);
404bytify_integer!(i16);
405bytify_integer!(u32);
406bytify_integer!(i32);
407bytify_integer!(u64);
408bytify_integer!(i64);
409bytify_integer!(u128);
410bytify_integer!(i128);
411bytify_integer!(usize);
412bytify_integer!(isize);
413
414macro_rules! bytify_float {
415 ($name:ident, $bits:ident) => {
416 mod $name {
417 use super::*;
418 use core::mem::transmute;
419
420 pub(crate) const fn len(value: $name) -> usize {
421 $bits::len(bits(value))
422 }
423
424 pub(crate) const fn copy<const N: usize>(
425 endianness: Endianness,
426 value: $name,
427 ) -> [u8; N] {
428 $bits::copy(endianness, bits(value))
429 }
430
431 const fn bits(value: $name) -> $bits {
432 unsafe { transmute::<$name, $bits>(value) }
433 }
434
435 impl MakeTypeWitness for BytifyWitness<0, $name> {
436 const MAKE: Self = Self::$name(TypeEq::NEW);
437 }
438 }
439 };
440}
441
442bytify_float!(f32, u32);
443bytify_float!(f64, u64);
444
445mod str {
446 use super::*;
447
448 pub(crate) const fn len(value: &str) -> usize {
449 slice_array::len(value.as_bytes())
450 }
451
452 pub(crate) const fn copy<const N: usize>(endianness: Endianness, value: &str) -> [u8; N] {
453 slice_array::copy(endianness, value.as_bytes())
454 }
455
456 impl MakeTypeWitness for BytifyWitness<0, &'static str> {
457 const MAKE: Self = Self::str(TypeEq::NEW);
458 }
459}
460
461mod slice_array {
462 use super::*;
463
464 pub(crate) const fn len(value: &[u8]) -> usize {
465 value.len()
466 }
467
468 pub(crate) const fn copy<const N: usize>(_: Endianness, value: &[u8]) -> [u8; N] {
469 let mut array = [0; N];
470 let mut i = 0;
471 while i < value.len() {
472 array[i] = value[i];
473 i += 1;
474 }
475 array
476 }
477
478 impl MakeTypeWitness for BytifyWitness<0, &'static [u8]> {
479 const MAKE: Self = Self::SliceArray(TypeEq::NEW);
480 }
481}
482
483mod array {
484 use super::*;
485
486 pub(crate) const fn len<const X: usize>(value: [u8; X]) -> usize {
487 slice_array::len(&value)
488 }
489
490 pub(crate) const fn copy<const X: usize, const N: usize>(
491 endianness: Endianness,
492 value: [u8; X],
493 ) -> [u8; N] {
494 slice_array::copy(endianness, &value)
495 }
496
497 impl<const X: usize> MakeTypeWitness for BytifyWitness<X, [u8; X]> {
498 const MAKE: Self = Self::Array(TypeEq::NEW);
499 }
500}