1pub struct OptionsBuilder(Options);
3
4const DEFAULT: Options = (ByteOrder::NATIVE as Options) << BYTEORDER_BIT;
5
6pub const fn new() -> OptionsBuilder {
10 OptionsBuilder(DEFAULT)
11}
12
13pub type Options = u128;
21
22const BYTEORDER_BIT: Options = 0;
23const INTEGER_BIT: Options = 1;
24const LENGTH_BIT: Options = 2;
25const FLOAT_BIT: Options = 8;
26const LENGTH_WIDTH_BIT: Options = 16;
27
28impl OptionsBuilder {
29 pub const fn with_integer(self, integer: Integer) -> Self {
31 Self(self.0 | ((integer as Options) << INTEGER_BIT))
32 }
33
34 pub const fn with_float(self, float: Float) -> Self {
36 Self(self.0 | ((float as Options) << FLOAT_BIT))
37 }
38
39 pub const fn with_byte_order(self, byte_order: ByteOrder) -> Self {
41 Self(self.0 | ((byte_order as Options) << BYTEORDER_BIT))
42 }
43
44 pub const fn with_length(self, length: Integer) -> Self {
46 Self(self.0 | ((length as Options) << LENGTH_BIT))
47 }
48
49 pub const fn with_length_width(self, width: Width) -> Self {
51 let this = self.with_length(Integer::Fixed);
52 Self(this.0 | ((width as Options) << LENGTH_WIDTH_BIT))
53 }
54
55 pub const fn build(self) -> Options {
57 self.0
58 }
59}
60
61#[doc(hidden)]
62pub const fn integer<const OPT: Options>() -> Integer {
63 match (OPT >> INTEGER_BIT) & 0b1 {
64 0 => Integer::Variable,
65 _ => Integer::Fixed,
66 }
67}
68
69#[doc(hidden)]
70pub const fn float<const OPT: Options>() -> Float {
71 match (OPT >> FLOAT_BIT) & 0b11 {
72 0 => Float::Integer,
73 1 => Float::Variable,
74 _ => Float::Fixed,
75 }
76}
77
78#[doc(hidden)]
79pub const fn length<const OPT: Options>() -> Integer {
80 match (OPT >> LENGTH_BIT) & 0b1 {
81 0 => Integer::Variable,
82 _ => Integer::Fixed,
83 }
84}
85
86#[doc(hidden)]
87pub const fn length_width<const OPT: Options>() -> Width {
88 match (OPT >> LENGTH_WIDTH_BIT) & 0b11 {
89 0 => Width::U8,
90 1 => Width::U16,
91 2 => Width::U32,
92 _ => Width::U64,
93 }
94}
95
96#[doc(hidden)]
97pub const fn byteorder<const OPT: Options>() -> ByteOrder {
98 match (OPT >> BYTEORDER_BIT) & 0b1 {
99 0 => ByteOrder::LittleEndian,
100 _ => ByteOrder::BigEndian,
101 }
102}
103
104#[cfg_attr(test, derive(Debug, PartialEq))]
106#[repr(u8)]
107#[non_exhaustive]
108pub enum Integer {
109 Variable = 0,
111 Fixed = 1,
113}
114
115#[cfg_attr(test, derive(Debug, PartialEq))]
117#[repr(u8)]
118#[non_exhaustive]
119pub enum Float {
120 Integer = 0,
123 Variable = 1,
125 Fixed = 2,
127}
128
129#[derive(PartialEq, Eq)]
131#[cfg_attr(test, derive(Debug))]
132#[repr(u8)]
133#[non_exhaustive]
134pub enum ByteOrder {
135 LittleEndian = 0,
137 BigEndian = 1,
139}
140
141impl ByteOrder {
142 pub const NATIVE: Self = if cfg!(target_endian = "little") {
144 Self::LittleEndian
145 } else {
146 Self::BigEndian
147 };
148
149 pub const NETWORK: Self = Self::BigEndian;
151}
152
153#[doc(hidden)]
154#[macro_export]
155macro_rules! width_arm {
156 ($width:expr, $macro:path) => {
157 match $width {
158 $crate::exports::options::Width::U8 => {
159 $macro!(u8)
160 }
161 $crate::exports::options::Width::U16 => {
162 $macro!(u16)
163 }
164 $crate::exports::options::Width::U32 => {
165 $macro!(u32)
166 }
167 _ => {
168 $macro!(u64)
169 }
170 }
171 };
172}
173
174#[derive(Clone, Copy)]
176#[cfg_attr(test, derive(Debug, PartialEq))]
177#[repr(u8)]
178#[non_exhaustive]
179pub enum Width {
180 U8 = 0,
182 U16 = 1,
184 U32 = 2,
186 U64 = 3,
188}
189
190#[test]
191fn test_builds() {
192 macro_rules! assert_or_default {
193 ($expr:expr, $test:expr, $default:expr, ()) => {
194 assert_eq!(
195 $test,
196 $default,
197 "{}: Expected default value for {}",
198 stringify!($expr),
199 stringify!($test)
200 );
201 };
202
203 ($expr:expr, $test:expr, $_default:expr, ($expected:expr)) => {
204 assert_eq!(
205 $test,
206 $expected,
207 "{}: Expected custom value for {}",
208 stringify!($expr),
209 stringify!($test)
210 );
211 };
212 }
213
214 macro_rules! test_case {
215 ($expr:expr => {
216 $(byteorder = $byteorder:expr,)?
217 $(integer = $integer:expr,)?
218 $(float = $float:expr,)?
219 $(length = $length:expr,)?
220 $(length_width = $length_width:expr,)?
221 }) => {{
222 const O: Options = $expr.build();
223 assert_or_default!($expr, byteorder::<O>(), ByteOrder::NATIVE, ($($byteorder)?));
224 assert_or_default!($expr, integer::<O>(), Integer::Variable, ($($integer)?));
225 assert_or_default!($expr, float::<O>(), Float::Integer, ($($float)?));
226 assert_or_default!($expr, length::<O>(), Integer::Variable, ($($length)?));
227 assert_or_default!($expr, length_width::<O>(), Width::U8, ($($length_width)?));
228 }}
229 }
230
231 test_case! {
232 self::new() => {}
233 }
234
235 test_case! {
236 self::new().with_integer(Integer::Fixed) => {
237 integer = Integer::Fixed,
238 }
239 }
240
241 test_case! {
242 self::new().with_float(Float::Fixed) => {
243 float = Float::Fixed,
244 }
245 }
246
247 test_case! {
248 self::new().with_float(Float::Variable) => {
249 float = Float::Variable,
250 }
251 }
252
253 test_case! {
254 self::new().with_float(Float::Variable) => {
255 float = Float::Variable,
256 }
257 }
258
259 test_case! {
260 self::new().with_byte_order(ByteOrder::BigEndian) => {
261 byteorder = ByteOrder::BigEndian,
262 }
263 }
264
265 test_case! {
266 self::new().with_byte_order(ByteOrder::LittleEndian) => {
267 byteorder = ByteOrder::LittleEndian,
268 }
269 }
270
271 test_case! {
272 self::new().with_length_width(Width::U16) => {
273 length = Integer::Fixed,
274 length_width = Width::U16,
275 }
276 }
277
278 test_case! {
279 self::new().with_length_width(Width::U32) => {
280 length = Integer::Fixed,
281 length_width = Width::U32,
282 }
283 }
284
285 test_case! {
286 self::new().with_length_width(Width::U64) => {
287 length = Integer::Fixed,
288 length_width = Width::U64,
289 }
290 }
291}