1pub struct Builder(Options);
5
6const DEFAULT: Options = (ByteOrder::NATIVE as Options) << BYTEORDER_BIT;
7
8pub const fn new() -> Builder {
12 Builder(DEFAULT)
13}
14
15pub type Options = u128;
26
27const BYTEORDER_BIT: Options = 0;
28const INTEGER_BIT: Options = 1;
29const LENGTH_BIT: Options = 2;
30const MAP_KEYS_AS_NUMBERS_BIT: Options = 3;
31const FLOAT_BIT: Options = 8;
32const LENGTH_WIDTH_BIT: Options = 16;
33
34impl Builder {
35 #[inline(always)]
37 pub const fn with_integer(self, integer: Integer) -> Self {
38 const MASK: Options = 0b11 << INTEGER_BIT;
39 Self((self.0 & !MASK) | ((integer as Options) << INTEGER_BIT))
40 }
41
42 #[inline(always)]
44 pub const fn with_float(self, float: Float) -> Self {
45 const MASK: Options = 0b11 << FLOAT_BIT;
46 Self((self.0 & !MASK) | ((float as Options) << FLOAT_BIT))
47 }
48
49 #[inline(always)]
51 pub const fn with_byte_order(self, byte_order: ByteOrder) -> Self {
52 const MASK: Options = 0b1 << BYTEORDER_BIT;
53 Self((self.0 & !MASK) | ((byte_order as Options) << BYTEORDER_BIT))
54 }
55
56 #[inline(always)]
58 pub const fn with_length(self, length: Integer) -> Self {
59 const MASK: Options = 0b1 << LENGTH_BIT;
60 Self((self.0 & !MASK) | ((length as Options) << LENGTH_BIT))
61 }
62
63 #[inline(always)]
65 pub const fn with_map_keys_as_numbers(self, value: bool) -> Self {
66 const MASK: Options = 0b1 << MAP_KEYS_AS_NUMBERS_BIT;
67 let value = if value { 1 } else { 0 };
68 Self((self.0 & !MASK) | (value << MAP_KEYS_AS_NUMBERS_BIT))
69 }
70
71 #[inline(always)]
73 pub const fn with_length_width(self, width: Width) -> Self {
74 const MASK: Options = 0b11 << LENGTH_WIDTH_BIT;
75 let this = self.with_length(Integer::Fixed);
76 Self((this.0 & !MASK) | ((width as Options) << LENGTH_WIDTH_BIT))
77 }
78
79 #[inline(always)]
81 pub const fn build(self) -> Options {
82 self.0
83 }
84}
85
86#[cfg(any(
87 feature = "storage",
88 feature = "wire",
89 feature = "descriptive",
90 feature = "json",
91 feature = "value"
92))]
93#[inline(always)]
94pub(crate) const fn integer<const OPT: Options>() -> Integer {
95 match (OPT >> INTEGER_BIT) & 0b1 {
96 0 => Integer::Variable,
97 _ => Integer::Fixed,
98 }
99}
100
101#[cfg(test)]
102#[inline(always)]
103pub(crate) const fn float<const OPT: Options>() -> Float {
104 match (OPT >> FLOAT_BIT) & 0b11 {
105 0 => Float::Integer,
106 1 => Float::Variable,
107 _ => Float::Fixed,
108 }
109}
110
111#[cfg(any(
112 feature = "storage",
113 feature = "wire",
114 feature = "descriptive",
115 feature = "json",
116 feature = "value"
117))]
118#[inline(always)]
119pub(crate) const fn length<const OPT: Options>() -> Integer {
120 match (OPT >> LENGTH_BIT) & 0b1 {
121 0 => Integer::Variable,
122 _ => Integer::Fixed,
123 }
124}
125
126#[cfg(any(
127 feature = "storage",
128 feature = "wire",
129 feature = "descriptive",
130 feature = "json",
131 feature = "value"
132))]
133#[inline(always)]
134pub(crate) const fn length_width<const OPT: Options>() -> Width {
135 match (OPT >> LENGTH_WIDTH_BIT) & 0b11 {
136 0 => Width::U8,
137 1 => Width::U16,
138 2 => Width::U32,
139 _ => Width::U64,
140 }
141}
142
143#[cfg(any(
144 feature = "storage",
145 feature = "wire",
146 feature = "descriptive",
147 feature = "json",
148 feature = "value"
149))]
150#[inline(always)]
151pub(crate) const fn byteorder<const OPT: Options>() -> ByteOrder {
152 match (OPT >> BYTEORDER_BIT) & 0b1 {
153 0 => ByteOrder::Little,
154 _ => ByteOrder::Big,
155 }
156}
157
158#[cfg(all(feature = "alloc", feature = "value"))]
159#[inline(always)]
160pub(crate) const fn is_map_keys_as_numbers<const OPT: Options>() -> bool {
161 ((OPT >> MAP_KEYS_AS_NUMBERS_BIT) & 0b1) == 1
162}
163
164#[cfg_attr(test, derive(Debug, PartialEq))]
166#[repr(u8)]
167#[non_exhaustive]
168pub enum Integer {
169 Variable = 0,
171 Fixed = 1,
173}
174
175#[cfg_attr(test, derive(Debug, PartialEq))]
177#[repr(u8)]
178#[non_exhaustive]
179pub enum Float {
180 Integer = 0,
183 Variable = 1,
185 Fixed = 2,
187}
188
189#[derive(PartialEq, Eq)]
194#[cfg_attr(test, derive(Debug))]
195#[repr(u8)]
196#[non_exhaustive]
197pub enum ByteOrder {
198 Little = 0,
200 Big = 1,
202}
203
204impl ByteOrder {
205 pub const NATIVE: Self = if cfg!(target_endian = "little") {
212 Self::Little
213 } else {
214 Self::Big
215 };
216
217 pub const NETWORK: Self = Self::Big;
223}
224
225#[doc(hidden)]
226#[cfg(any(
227 feature = "storage",
228 feature = "wire",
229 feature = "descriptive",
230 feature = "value"
231))]
232macro_rules! width_arm {
233 ($width:expr, $macro:path) => {
234 match $width {
235 $crate::options::Width::U8 => {
236 $macro!(u8)
237 }
238 $crate::options::Width::U16 => {
239 $macro!(u16)
240 }
241 $crate::options::Width::U32 => {
242 $macro!(u32)
243 }
244 $crate::options::Width::U64 => {
245 $macro!(u64)
246 }
247 }
248 };
249}
250
251#[cfg(any(
252 feature = "storage",
253 feature = "wire",
254 feature = "descriptive",
255 feature = "value"
256))]
257pub(crate) use width_arm;
258
259#[derive(Clone, Copy)]
261#[cfg_attr(test, derive(Debug, PartialEq))]
262#[repr(u8)]
263#[non_exhaustive]
264pub enum Width {
265 U8 = 0,
267 U16 = 1,
269 U32 = 2,
271 U64 = 3,
273}
274
275#[test]
276fn test_builds() {
277 macro_rules! assert_or_default {
278 ($expr:expr, $test:expr, $default:expr, ()) => {
279 assert_eq!(
280 $test,
281 $default,
282 "{}: Expected default value for {}",
283 stringify!($expr),
284 stringify!($test)
285 );
286 };
287
288 ($expr:expr, $test:expr, $_default:expr, ($expected:expr)) => {
289 assert_eq!(
290 $test,
291 $expected,
292 "{}: Expected custom value for {}",
293 stringify!($expr),
294 stringify!($test)
295 );
296 };
297 }
298
299 macro_rules! test_case {
300 ($expr:expr => {
301 $(byteorder = $byteorder:expr,)?
302 $(integer = $integer:expr,)?
303 $(float = $float:expr,)?
304 $(length = $length:expr,)?
305 $(length_width = $length_width:expr,)?
306 $(is_map_keys_as_numbers = $is_map_keys_as_numbers:expr,)?
307 }) => {{
308 const O: Options = $expr.build();
309 assert_or_default!($expr, byteorder::<O>(), ByteOrder::NATIVE, ($($byteorder)?));
310 assert_or_default!($expr, integer::<O>(), Integer::Variable, ($($integer)?));
311 assert_or_default!($expr, float::<O>(), Float::Integer, ($($float)?));
312 assert_or_default!($expr, length::<O>(), Integer::Variable, ($($length)?));
313 assert_or_default!($expr, is_map_keys_as_numbers::<O>(), false, ($($is_map_keys_as_numbers)?));
314 }}
315 }
316
317 test_case! {
318 self::new() => {}
319 }
320
321 test_case! {
322 self::new().with_map_keys_as_numbers(true) => {
323 is_map_keys_as_numbers = true,
324 }
325 }
326
327 test_case! {
328 self::new().with_integer(Integer::Fixed) => {
329 integer = Integer::Fixed,
330 }
331 }
332
333 test_case! {
334 self::new().with_float(Float::Fixed) => {
335 float = Float::Fixed,
336 }
337 }
338
339 test_case! {
340 self::new().with_float(Float::Variable) => {
341 float = Float::Variable,
342 }
343 }
344
345 test_case! {
346 self::new().with_float(Float::Variable) => {
347 float = Float::Variable,
348 }
349 }
350
351 test_case! {
352 self::new().with_byte_order(ByteOrder::Big) => {
353 byteorder = ByteOrder::Big,
354 }
355 }
356
357 test_case! {
358 self::new().with_byte_order(ByteOrder::Little) => {
359 byteorder = ByteOrder::Little,
360 }
361 }
362
363 test_case! {
364 self::new().with_length_width(Width::U16) => {
365 length = Integer::Fixed,
366 length_width = Width::U16,
367 }
368 }
369
370 test_case! {
371 self::new().with_length_width(Width::U32) => {
372 length = Integer::Fixed,
373 length_width = Width::U32,
374 }
375 }
376
377 test_case! {
378 self::new().with_length_width(Width::U64) => {
379 length = Integer::Fixed,
380 length_width = Width::U64,
381 }
382 }
383}