1pub struct OptionsBuilder(Options);
5
6const DEFAULT: Options = (ByteOrder::NATIVE as Options) << BYTEORDER_BIT;
7
8pub const fn new() -> OptionsBuilder {
12 OptionsBuilder(DEFAULT)
13}
14
15pub type Options = u128;
23
24const BYTEORDER_BIT: Options = 0;
25const INTEGER_BIT: Options = 1;
26const LENGTH_BIT: Options = 2;
27const MAP_KEYS_AS_NUMBERS_BIT: Options = 3;
28const FLOAT_BIT: Options = 8;
29const LENGTH_WIDTH_BIT: Options = 16;
30
31impl OptionsBuilder {
32 #[inline(always)]
34 pub const fn with_integer(self, integer: Integer) -> Self {
35 const MASK: Options = 0b11 << INTEGER_BIT;
36 Self((self.0 & !MASK) | ((integer as Options) << INTEGER_BIT))
37 }
38
39 #[inline(always)]
41 pub const fn with_float(self, float: Float) -> Self {
42 const MASK: Options = 0b11 << FLOAT_BIT;
43 Self((self.0 & !MASK) | ((float as Options) << FLOAT_BIT))
44 }
45
46 #[inline(always)]
48 pub const fn with_byte_order(self, byte_order: ByteOrder) -> Self {
49 const MASK: Options = 0b1 << BYTEORDER_BIT;
50 Self((self.0 & !MASK) | ((byte_order as Options) << BYTEORDER_BIT))
51 }
52
53 #[inline(always)]
55 pub const fn with_length(self, length: Integer) -> Self {
56 const MASK: Options = 0b1 << LENGTH_BIT;
57 Self((self.0 & !MASK) | ((length as Options) << LENGTH_BIT))
58 }
59
60 #[inline(always)]
62 pub const fn with_map_keys_as_numbers(self, value: bool) -> Self {
63 const MASK: Options = 0b1 << MAP_KEYS_AS_NUMBERS_BIT;
64 let value = if value { 1 } else { 0 };
65 Self((self.0 & !MASK) | (value << MAP_KEYS_AS_NUMBERS_BIT))
66 }
67
68 #[inline(always)]
70 pub const fn with_length_width(self, width: Width) -> Self {
71 const MASK: Options = 0b11 << LENGTH_WIDTH_BIT;
72 let this = self.with_length(Integer::Fixed);
73 Self((this.0 & !MASK) | ((width as Options) << LENGTH_WIDTH_BIT))
74 }
75
76 #[inline(always)]
78 pub const fn build(self) -> Options {
79 self.0
80 }
81}
82
83#[doc(hidden)]
84pub const fn integer<const OPT: Options>() -> Integer {
85 match (OPT >> INTEGER_BIT) & 0b1 {
86 0 => Integer::Variable,
87 _ => Integer::Fixed,
88 }
89}
90
91#[doc(hidden)]
92pub const fn float<const OPT: Options>() -> Float {
93 match (OPT >> FLOAT_BIT) & 0b11 {
94 0 => Float::Integer,
95 1 => Float::Variable,
96 _ => Float::Fixed,
97 }
98}
99
100#[doc(hidden)]
101pub const fn length<const OPT: Options>() -> Integer {
102 match (OPT >> LENGTH_BIT) & 0b1 {
103 0 => Integer::Variable,
104 _ => Integer::Fixed,
105 }
106}
107
108#[doc(hidden)]
109pub const fn length_width<const OPT: Options>() -> Width {
110 match (OPT >> LENGTH_WIDTH_BIT) & 0b11 {
111 0 => Width::U8,
112 1 => Width::U16,
113 2 => Width::U32,
114 _ => Width::U64,
115 }
116}
117
118#[doc(hidden)]
119pub const fn byteorder<const OPT: Options>() -> ByteOrder {
120 match (OPT >> BYTEORDER_BIT) & 0b1 {
121 0 => ByteOrder::LittleEndian,
122 _ => ByteOrder::BigEndian,
123 }
124}
125
126#[doc(hidden)]
127pub const fn is_map_keys_as_numbers<const OPT: Options>() -> bool {
128 ((OPT >> MAP_KEYS_AS_NUMBERS_BIT) & 0b1) == 1
129}
130
131#[cfg_attr(test, derive(Debug, PartialEq))]
133#[repr(u8)]
134#[non_exhaustive]
135pub enum Integer {
136 Variable = 0,
138 Fixed = 1,
140}
141
142#[cfg_attr(test, derive(Debug, PartialEq))]
144#[repr(u8)]
145#[non_exhaustive]
146pub enum Float {
147 Integer = 0,
150 Variable = 1,
152 Fixed = 2,
154}
155
156#[derive(PartialEq, Eq)]
158#[cfg_attr(test, derive(Debug))]
159#[repr(u8)]
160#[non_exhaustive]
161pub enum ByteOrder {
162 LittleEndian = 0,
164 BigEndian = 1,
166}
167
168impl ByteOrder {
169 pub const NATIVE: Self = if cfg!(target_endian = "little") {
171 Self::LittleEndian
172 } else {
173 Self::BigEndian
174 };
175
176 pub const NETWORK: Self = Self::BigEndian;
178}
179
180#[doc(hidden)]
181#[macro_export]
182macro_rules! width_arm {
183 ($width:expr, $macro:path) => {
184 match $width {
185 $crate::options::Width::U8 => {
186 $macro!(u8)
187 }
188 $crate::options::Width::U16 => {
189 $macro!(u16)
190 }
191 $crate::options::Width::U32 => {
192 $macro!(u32)
193 }
194 _ => {
195 $macro!(u64)
196 }
197 }
198 };
199}
200
201#[derive(Clone, Copy)]
203#[cfg_attr(test, derive(Debug, PartialEq))]
204#[repr(u8)]
205#[non_exhaustive]
206pub enum Width {
207 U8 = 0,
209 U16 = 1,
211 U32 = 2,
213 U64 = 3,
215}
216
217#[test]
218fn test_builds() {
219 macro_rules! assert_or_default {
220 ($expr:expr, $test:expr, $default:expr, ()) => {
221 assert_eq!(
222 $test,
223 $default,
224 "{}: Expected default value for {}",
225 stringify!($expr),
226 stringify!($test)
227 );
228 };
229
230 ($expr:expr, $test:expr, $_default:expr, ($expected:expr)) => {
231 assert_eq!(
232 $test,
233 $expected,
234 "{}: Expected custom value for {}",
235 stringify!($expr),
236 stringify!($test)
237 );
238 };
239 }
240
241 macro_rules! test_case {
242 ($expr:expr => {
243 $(byteorder = $byteorder:expr,)?
244 $(integer = $integer:expr,)?
245 $(float = $float:expr,)?
246 $(length = $length:expr,)?
247 $(length_width = $length_width:expr,)?
248 $(is_map_keys_as_numbers = $is_map_keys_as_numbers:expr,)?
249 }) => {{
250 const O: Options = $expr.build();
251 assert_or_default!($expr, byteorder::<O>(), ByteOrder::NATIVE, ($($byteorder)?));
252 assert_or_default!($expr, integer::<O>(), Integer::Variable, ($($integer)?));
253 assert_or_default!($expr, float::<O>(), Float::Integer, ($($float)?));
254 assert_or_default!($expr, length::<O>(), Integer::Variable, ($($length)?));
255 assert_or_default!($expr, is_map_keys_as_numbers::<O>(), false, ($($is_map_keys_as_numbers)?));
256 }}
257 }
258
259 test_case! {
260 self::new() => {}
261 }
262
263 test_case! {
264 self::new().with_map_keys_as_numbers(true) => {
265 is_map_keys_as_numbers = true,
266 }
267 }
268
269 test_case! {
270 self::new().with_integer(Integer::Fixed) => {
271 integer = Integer::Fixed,
272 }
273 }
274
275 test_case! {
276 self::new().with_float(Float::Fixed) => {
277 float = Float::Fixed,
278 }
279 }
280
281 test_case! {
282 self::new().with_float(Float::Variable) => {
283 float = Float::Variable,
284 }
285 }
286
287 test_case! {
288 self::new().with_float(Float::Variable) => {
289 float = Float::Variable,
290 }
291 }
292
293 test_case! {
294 self::new().with_byte_order(ByteOrder::BigEndian) => {
295 byteorder = ByteOrder::BigEndian,
296 }
297 }
298
299 test_case! {
300 self::new().with_byte_order(ByteOrder::LittleEndian) => {
301 byteorder = ByteOrder::LittleEndian,
302 }
303 }
304
305 test_case! {
306 self::new().with_length_width(Width::U16) => {
307 length = Integer::Fixed,
308 length_width = Width::U16,
309 }
310 }
311
312 test_case! {
313 self::new().with_length_width(Width::U32) => {
314 length = Integer::Fixed,
315 length_width = Width::U32,
316 }
317 }
318
319 test_case! {
320 self::new().with_length_width(Width::U64) => {
321 length = Integer::Fixed,
322 length_width = Width::U64,
323 }
324 }
325}