1use core::fmt;
4
5pub struct Builder(Options);
7
8const DEFAULT: Options = (ByteOrder::Little as Options) << BYTEORDER_BIT;
9
10#[inline]
14pub const fn new() -> Builder {
15 Builder(DEFAULT)
16}
17
18#[inline]
22pub const fn from_raw(value: Options) -> Builder {
23 Builder(value)
24}
25
26pub type Options = u32;
37
38const BYTEORDER_BIT: Options = 0;
39const INTEGER_BIT: Options = 4;
40const FLOAT_BIT: Options = 8;
41const LENGTH_BIT: Options = 12;
42const MAP_KEYS_AS_NUMBERS_BIT: Options = 16;
43
44impl Builder {
45 #[inline]
55 pub const fn integer(self, integer: Integer) -> Self {
56 const MASK: Options = Integer::MASK << INTEGER_BIT;
57 Self((self.0 & !MASK) | ((integer as Options) << INTEGER_BIT))
58 }
59
60 #[inline]
70 pub const fn float(self, float: Float) -> Self {
71 const MASK: Options = Float::MASK << FLOAT_BIT;
72 Self((self.0 & !MASK) | ((float as Options) << FLOAT_BIT))
73 }
74
75 #[inline]
85 pub const fn byte_order(self, byte_order: ByteOrder) -> Self {
86 const MASK: Options = ByteOrder::MASK << BYTEORDER_BIT;
87 Self((self.0 & !MASK) | ((byte_order as Options) << BYTEORDER_BIT))
88 }
89
90 #[inline]
100 pub const fn native_byte_order(self) -> Self {
101 self.byte_order(ByteOrder::NATIVE)
102 }
103
104 #[inline]
115 pub const fn pointer(self, width: Width) -> Self {
116 const MASK: Options = Width::MASK << LENGTH_BIT;
117 Self((self.0 & !MASK) | ((width as Options) << LENGTH_BIT))
118 }
119
120 #[inline]
134 pub const fn map_keys_as_numbers(self) -> Self {
135 const MASK: Options = 0b1 << MAP_KEYS_AS_NUMBERS_BIT;
136 Self((self.0 & !MASK) | (1 << MAP_KEYS_AS_NUMBERS_BIT))
137 }
138
139 #[inline]
161 pub const fn fixed(self) -> Self {
162 self.integer(Integer::Fixed)
163 .float(Float::Fixed)
164 .pointer(Width::NATIVE)
165 }
166
167 #[inline]
189 pub const fn variable(self) -> Self {
190 self.integer(Integer::Variable)
191 .float(Float::Variable)
192 .pointer(Width::Variable)
193 }
194
195 #[inline]
205 pub const fn build(self) -> Options {
206 self.0
207 }
208}
209
210impl fmt::Debug for Builder {
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212 f.debug_struct("Builder")
213 .field("byteorder", &byteorder_value(self.0))
214 .field("integer", &integer_value(self.0))
215 .field("float", &float_value(self.0))
216 .field("length", &length_value(self.0))
217 .field(
218 "is_map_keys_as_numbers",
219 &is_map_keys_as_numbers_value(self.0),
220 )
221 .finish()
222 }
223}
224
225#[cfg(any(
226 feature = "storage",
227 feature = "wire",
228 feature = "descriptive",
229 feature = "json",
230 feature = "value"
231))]
232#[inline]
233pub(crate) const fn integer<const OPT: Options>() -> Integer {
234 integer_value(OPT)
235}
236
237#[inline]
238const fn integer_value(opt: Options) -> Integer {
239 match (opt >> INTEGER_BIT) & 0b1 {
240 0 => Integer::Variable,
241 _ => Integer::Fixed,
242 }
243}
244
245#[cfg(any(
246 feature = "storage",
247 feature = "wire",
248 feature = "descriptive",
249 feature = "json",
250 feature = "value"
251))]
252#[inline]
253pub(crate) const fn float<const OPT: Options>() -> Float {
254 float_value(OPT)
255}
256
257#[inline]
258const fn float_value(opt: Options) -> Float {
259 match (opt >> FLOAT_BIT) & 0b11 {
260 0b00 => Float::Integer,
261 0b01 => Float::Variable,
262 0b10 => Float::Fixed,
263 _ => Float::Pad0,
264 }
265}
266
267#[cfg(any(
268 feature = "storage",
269 feature = "wire",
270 feature = "descriptive",
271 feature = "json",
272 feature = "value"
273))]
274#[inline]
275pub(crate) const fn length<const OPT: Options>() -> Width {
276 length_value(OPT)
277}
278
279#[inline]
280const fn length_value(opt: Options) -> Width {
281 match (opt >> LENGTH_BIT) & 0b111 {
282 0b000 => Width::Variable,
283 0b001 => Width::U8,
284 0b010 => Width::U16,
285 0b011 => Width::U32,
286 0b100 => Width::U64,
287 0b101 => Width::Pad0,
288 0b110 => Width::Pad1,
289 _ => Width::Pad2,
290 }
291}
292
293#[cfg(any(
294 feature = "storage",
295 feature = "wire",
296 feature = "descriptive",
297 feature = "json",
298 feature = "value"
299))]
300#[inline]
301pub(crate) const fn byteorder<const OPT: Options>() -> ByteOrder {
302 byteorder_value(OPT)
303}
304
305#[inline]
306pub(crate) const fn byteorder_value(opt: Options) -> ByteOrder {
307 match (opt >> BYTEORDER_BIT) & 0b1 {
308 0 => ByteOrder::Little,
309 _ => ByteOrder::Big,
310 }
311}
312
313#[cfg(feature = "value")]
314#[inline]
315pub(crate) const fn is_map_keys_as_numbers<const OPT: Options>() -> bool {
316 is_map_keys_as_numbers_value(OPT)
317}
318
319const fn is_map_keys_as_numbers_value(opt: Options) -> bool {
320 ((opt >> MAP_KEYS_AS_NUMBERS_BIT) & 0b1) == 1
321}
322
323#[cfg(any(
324 feature = "storage",
325 feature = "wire",
326 feature = "descriptive",
327 feature = "value"
328))]
329pub(crate) const fn is_native_fixed<const OPT: Options>() -> bool {
330 matches!(
331 (integer::<OPT>(), float::<OPT>(), length::<OPT>(),),
332 (Integer::Fixed, Float::Fixed, Width::NATIVE)
333 )
334}
335
336#[derive(Debug, PartialEq, Eq)]
338#[repr(u8)]
339#[non_exhaustive]
340pub enum Integer {
341 Variable = 0b0,
343 Fixed = 0b1,
345}
346
347impl Integer {
348 const MASK: Options = 0b1;
349}
350
351#[derive(Debug, PartialEq, Eq)]
353#[repr(u8)]
354#[non_exhaustive]
355pub enum Float {
356 Integer = 0b00,
359 Variable = 0b01,
361 Fixed = 0b10,
363 #[doc(hidden)]
365 Pad0 = 0b11,
366}
367
368impl Float {
369 const MASK: Options = 0b11;
370}
371
372#[derive(Debug, PartialEq, Eq)]
377#[repr(u8)]
378#[non_exhaustive]
379pub enum ByteOrder {
380 Little = 0,
382 Big = 1,
384}
385
386impl ByteOrder {
387 const MASK: Options = 0b1;
388
389 pub const NATIVE: Self = if cfg!(target_endian = "little") {
396 Self::Little
397 } else {
398 Self::Big
399 };
400
401 pub const NETWORK: Self = Self::Big;
407}
408
409#[doc(hidden)]
410#[cfg(any(
411 feature = "storage",
412 feature = "wire",
413 feature = "descriptive",
414 feature = "value"
415))]
416macro_rules! width_arm {
417 ($width:expr, $macro:path) => {
418 match $width {
419 $crate::options::Width::U8 => {
420 $macro!(u8)
421 }
422 $crate::options::Width::U16 => {
423 $macro!(u16)
424 }
425 $crate::options::Width::U32 => {
426 $macro!(u32)
427 }
428 _ => {
429 $macro!(u64)
430 }
431 }
432 };
433}
434
435#[cfg(any(
436 feature = "storage",
437 feature = "wire",
438 feature = "descriptive",
439 feature = "value"
440))]
441pub(crate) use width_arm;
442
443#[derive(Clone, Copy, Debug, PartialEq, Eq)]
445#[repr(u8)]
446#[non_exhaustive]
447pub enum Width {
448 Variable = 0b000,
450 U8 = 0b001,
452 U16 = 0b010,
454 U32 = 0b011,
456 U64 = 0b100,
458 #[doc(hidden)]
460 Pad0 = 0b101,
461 #[doc(hidden)]
463 Pad1 = 0b110,
464 #[doc(hidden)]
466 Pad2 = 0b111,
467}
468
469impl Width {
470 const MASK: Options = 0b111;
471
472 pub const NATIVE: Self = const {
476 if cfg!(target_pointer_width = "64") {
477 Self::U64
478 } else if cfg!(target_pointer_width = "32") {
479 Self::U32
480 } else if cfg!(target_pointer_width = "16") {
481 Self::U16
482 } else {
483 panic!("Unsupported target pointer width")
484 }
485 };
486}
487
488#[test]
489fn test_builds() {
490 macro_rules! assert_or_default {
491 ($expr:expr, $test:expr, $default:expr, ()) => {
492 assert_eq!(
493 $test,
494 $default,
495 "{}: Expected default value for {}",
496 stringify!($expr),
497 stringify!($test)
498 );
499 };
500
501 ($expr:expr, $test:expr, $_default:expr, ($expected:expr)) => {
502 assert_eq!(
503 $test,
504 $expected,
505 "{}: Expected custom value for {}",
506 stringify!($expr),
507 stringify!($test)
508 );
509 };
510 }
511
512 macro_rules! test_case {
513 ($expr:expr => {
514 $(byteorder = $byteorder:expr,)?
515 $(integer = $integer:expr,)?
516 $(float = $float:expr,)?
517 $(length = $length:expr,)?
518 $(is_map_keys_as_numbers = $is_map_keys_as_numbers:expr,)?
519 }) => {{
520 const O: Options = $expr.build();
521 assert_or_default!($expr, byteorder::<O>(), ByteOrder::Little, ($($byteorder)?));
522 assert_or_default!($expr, integer::<O>(), Integer::Variable, ($($integer)?));
523 assert_or_default!($expr, float::<O>(), Float::Integer, ($($float)?));
524 assert_or_default!($expr, length::<O>(), Width::Variable, ($($length)?));
525 assert_or_default!($expr, is_map_keys_as_numbers::<O>(), false, ($($is_map_keys_as_numbers)?));
526 }}
527 }
528
529 test_case! {
530 self::new() => {}
531 }
532
533 test_case! {
534 self::new().map_keys_as_numbers() => {
535 is_map_keys_as_numbers = true,
536 }
537 }
538
539 test_case! {
540 self::new().integer(Integer::Fixed) => {
541 integer = Integer::Fixed,
542 }
543 }
544
545 test_case! {
546 self::new().float(Float::Fixed) => {
547 float = Float::Fixed,
548 }
549 }
550
551 test_case! {
552 self::new().float(Float::Variable) => {
553 float = Float::Variable,
554 }
555 }
556
557 test_case! {
558 self::new().float(Float::Variable) => {
559 float = Float::Variable,
560 }
561 }
562
563 test_case! {
564 self::new().byte_order(ByteOrder::Big) => {
565 byteorder = ByteOrder::Big,
566 }
567 }
568
569 test_case! {
570 self::new().byte_order(ByteOrder::Little) => {
571 byteorder = ByteOrder::Little,
572 }
573 }
574
575 test_case! {
576 self::new().pointer(Width::Variable) => {
577 length = Width::Variable,
578 }
579 }
580
581 test_case! {
582 self::new().pointer(Width::U8) => {
583 length = Width::U8,
584 }
585 }
586
587 test_case! {
588 self::new().pointer(Width::U16) => {
589 length = Width::U16,
590 }
591 }
592
593 test_case! {
594 self::new().pointer(Width::U32) => {
595 length = Width::U32,
596 }
597 }
598
599 test_case! {
600 self::new().pointer(Width::U64) => {
601 length = Width::U64,
602 }
603 }
604}