bitfield_layout/
layouts.rs

1//! This module contains useful structures that can be used as meaning of bitflag
2//!
3//!
4
5use core::fmt;
6
7/// Simple structure for basic and alternate string view
8/// 
9/// This struct may be used in most cases of crate using. 
10/// We can rewrite [6502 status register example](super#example-status-register-of-mos-technology-6502)
11/// using this struct
12/// ```
13/// # use std::{array, fmt, slice, ops::Deref};
14/// # use bitfield_layout::{Layout, BitFieldLayout, DualView};
15/// 
16/// struct StatusRegister(u8);
17/// impl StatusRegister {
18///     const LAYOUT: [DualView<'static>; 8] = [
19///         DualView(
20///             "Carry flag",
21///             "Enables numbers larger than a single word to be added/subtracted by
22///             carrying a binary digit from a less significant word to the least
23///             significant bit of a more significant word as needed."
24///         ),
25///         DualView(
26///             "Zero flag",
27///             "Indicates that the result of an arithmetic or logical operation
28///             (or, sometimes, a load) was zero."
29///         ),
30///         DualView(
31///             "Interrupt flag",
32///             "Indicates whether interrupts are enabled or masked."
33///         ),
34///         DualView(
35///             "Decimal flag",
36///             "Indicates that a bit carry was produced between the nibbles as a
37///             result of the last arithmetic operation."
38///         ),
39///         DualView(
40///             "Break flag",
41///             "It can be examined as a value stored on the stack."
42///         ),
43///         DualView("Unused", "Unused"),
44///         DualView(
45///             "Overflow flag",
46///             "Indicates that the signed result of an operation is too large to
47///             fit in the register width using two's complement representation."
48///         ),
49///         DualView(
50///             "Negative flag",
51///             "Indicates that the result of a mathematical operation is negative."
52///         ),
53///     ];
54/// }
55/// impl Layout for StatusRegister {
56///     type Layout = slice::Iter<'static, DualView<'static>>;
57///     fn layout() -> Self::Layout { StatusRegister::LAYOUT.iter() }
58/// }
59/// impl BitFieldLayout for StatusRegister {
60///     type Value = u8;
61///     fn get(&self) -> Self::Value { self.0 }
62///     fn set(&mut self, new: Self::Value) { self.0 = new; }
63/// }
64/// ```
65#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
66pub struct DualView<'a>(pub &'a str, pub &'a str);
67impl<'a> fmt::Display for DualView<'a> {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        let s = if f.alternate() { self.1 } else { self.0 };
70        write!(f, "{}", s)
71    }
72}
73
74/// Complex enumeration for several types of bit (flag)
75///
76/// This enum variants may be used to show difference beetween meaningful and reserved flags.
77/// ```
78/// # use core::{slice,array};
79/// # use pretty_assertions::assert_eq;
80/// # use bitfield_layout::{Layout, BitFieldLayout, FlagType, layout};
81///
82/// // Bitfield type definition
83/// struct Light(u8);
84/// impl Light {
85///     const LAYOUT: [FlagType<'static>; 8] = [
86///         FlagType::Significant("Red", "Red is the color at the long wavelength end"),
87///         FlagType::Significant("Blue", "Blue is one of the three primary colours of pigments"),
88///         FlagType::Significant("Green", "Green is the color between blue and yellow"),
89///         FlagType::Reserved("Invisible"),
90///         FlagType::ShouldBe0,
91///         FlagType::ShouldBe1,
92///         FlagType::Unknown,
93///         FlagType::Undefined,
94///     ];
95/// }
96/// // Implementation
97/// impl Layout for Light {
98///     type Layout = slice::Iter<'static, FlagType<'static>>;
99///     fn layout() -> Self::Layout { Light::LAYOUT.iter() }
100/// }
101/// impl BitFieldLayout for Light {
102///     type Value = u8;
103///     fn get(&self) -> Self::Value { self.0 }
104///     fn set(&mut self, new: Self::Value) { self.0 = new; }
105/// }
106///
107/// // Value assignment
108/// let white = Light(0b00100111);
109///
110/// let result = white.flags()
111///     .enumerate()
112///     .find(|(n, f)| n == &5 && f.is_set == true)
113///     .map(|(_, f)| *f.value);
114/// let sample = Some(FlagType::ShouldBe1);
115///
116/// assert_eq!(sample, result);
117/// ```
118#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
119pub enum FlagType<'a> {
120    /// Has two strings - one for meaning, other for long description
121    Significant(&'a str, &'a str),
122    /// Reserved bit (flag) may has different types of reservation. Ex: OEM and Future using 
123    Reserved(&'a str),
124    /// Should always be set
125    ShouldBe0,
126    /// Should always be unset
127    ShouldBe1,
128    /// Unknown for current specification
129    Unknown,
130    /// Undefined in current specification
131    Undefined,
132}
133impl<'a> fmt::Display for FlagType<'a> {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        match (self, f.alternate()) {
136            (Self::Significant(s, _), false) => write!(f, "{}", s),
137            (Self::Significant(_, s), true) => write!(f, "{}", s),
138            (Self::Reserved(s), _) => write!(f, "{}", s),
139            (Self::ShouldBe0, _) => write!(f, "Should be 0"),
140            (Self::ShouldBe1, _) => write!(f, "Should be 1"),
141            (Self::Unknown, _) => write!(f, "Unknown"),
142            (Self::Undefined, _) => write!(f, "Undefined"),
143        }
144    }
145}
146
147
148
149
150/// Fast defining of useful types
151///
152/// This macro helps to implement [crate::BitFieldLayout] trait and create associated const layout.
153/// Macro may be used for following data types:
154/// - [DualView](#dualview)
155/// - [FlagType](#flagtype)
156///
157/// ## DualView
158/// 
159/// ```
160/// # use core::{slice,array};
161/// # use bitfield_layout::{Layout, BitFieldLayout, DualView, layout};
162/// # fn main() {
163///
164/// // Data created by macro
165/// let macro_data = {
166///     layout!(
167///         DualView;
168///         struct Letters(u8);
169///         "a",
170///         "b" "B",
171///         "c",
172///         "d",
173///         "e",
174///         "f" "F",
175///         "g" "G",
176///         "h" "H",
177///     );
178///
179///     Letters(42).flags()
180/// };
181/// // Expands to:
182/// let manual_data = {
183///     struct Letters(u8);
184///     impl Letters {
185///         const LAYOUT: [DualView<'static>; 8] = [
186///             DualView("a", "a"),
187///             DualView("b", "B"),
188///             DualView("c", "c"),
189///             DualView("d", "d"),
190///             DualView("e", "e"),
191///             DualView("f", "F"),
192///             DualView("g", "G"),
193///             DualView("h", "H"),
194///         ];
195///     }
196///     
197///     impl Layout for Letters {
198///         type Layout = slice::Iter<'static, DualView<'static>>;
199///         fn layout() -> Self::Layout { Letters::LAYOUT.iter() }
200///     }
201///     impl BitFieldLayout for Letters {
202///         type Value = u8;
203///         fn get(&self) -> Self::Value { self.0 }
204///         fn set(&mut self, new: Self::Value) { self.0 = new; }
205///     }
206///
207///     Letters(42).flags()
208/// };
209///
210/// assert_eq!(macro_data.collect::<Vec<_>>(), manual_data.collect::<Vec<_>>());
211/// # }
212/// ```
213///
214/// ## FlagType
215/// ```
216/// # use core::{slice,array};
217/// # use pretty_assertions::assert_eq;
218/// # use bitfield_layout::{Layout, BitFieldLayout, FlagType, layout};
219/// # fn main() {
220/// let macro_data = {
221///     layout!(
222///         FlagType;
223///         struct EightFlags(u8);
224///         "Significant: meaning",
225///         "Significant: meaning" "Significant: description",
226///         "Reserved: 2 bits": 2,
227///         "Reserved: shouldn't exists": 0,
228///         ShouldBe0,
229///         ShouldBe1,
230///         Unknown,
231///         Undefined,
232///     );
233///
234///     EightFlags(73).flags()
235/// };
236/// // Expands to:
237/// let manual_data = {
238///     struct EightFlags(u8);
239///     impl EightFlags {
240///         const LAYOUT: [FlagType<'static>; 8] = [
241///             FlagType::Significant("Significant: meaning", "Significant: meaning"),
242///             FlagType::Significant("Significant: meaning", "Significant: description"),
243///             FlagType::Reserved("Reserved: 2 bits"),
244///             FlagType::Reserved("Reserved: 2 bits"),
245///             FlagType::ShouldBe0,
246///             FlagType::ShouldBe1,
247///             FlagType::Unknown,
248///             FlagType::Undefined,
249///         ];
250///     }
251///     
252///     impl Layout for EightFlags {
253///         type Layout = slice::Iter<'static, FlagType<'static>>;
254///         fn layout() -> Self::Layout { EightFlags::LAYOUT.iter() }
255///     }
256///     impl BitFieldLayout for EightFlags {
257///         type Value = u8;
258///         fn get(&self) -> Self::Value { self.0 }
259///         fn set(&mut self, new: Self::Value) { self.0 = new; }
260///     }
261///
262///     EightFlags(73).flags()
263/// };
264///
265/// assert_eq!(macro_data.collect::<Vec<_>>(), manual_data.collect::<Vec<_>>());
266/// # }
267/// ```
268#[macro_export]
269macro_rules! layout  {
270    // DualView
271    (item = DualView; [] -> [$($output:tt)*]) => {
272        [$($output)*]
273    };
274    (item = DualView; [$m:literal $d:literal, $($input:tt)*] -> [$($output:tt)*]) => {
275        layout!(item = DualView; [$($input)*] -> [$($output)* DualView($m, $d),])
276    };
277    (item = DualView; [$m:literal, $($input:tt)*] -> [$($output:tt)*]) => {{
278        layout!(item = DualView; [$($input)*] -> [$($output)* DualView($m, $m),])
279    }};
280    (DualView; $(#[$meta:meta])* $vis:vis $ident:ident $name:ident($value:tt); $($input:tt)*) => {
281        $(#[$meta])*
282        $vis $ident $name($value);
283        impl $name {
284            const LAYOUT: &'static [DualView<'static>] =
285                &layout!(item = DualView; [$($input)*] -> []);
286        }
287        impl Layout for $name {
288            type Layout = slice::Iter<'static, DualView<'static>>;
289            fn layout() -> Self::Layout { $name::LAYOUT.iter() }
290        }
291        impl BitFieldLayout for $name {
292            type Value = $value;
293            fn get(&self) -> Self::Value { self.0 }
294            fn set(&mut self, new: Self::Value) { self.0 = new; }
295        }
296    };
297
298    // FlagType
299    (item = FlagType; array = $a:expr; index = $i:expr;) => {{ $a }};
300    (item = FlagType; array = $a:expr; index = $i:expr; Undefined, $($input:tt)*) => {{
301        let mut result = layout!(item = FlagType; array = $a; index = $i + 1; $($input)*);
302        result[$i] = FlagType::Undefined;
303        result
304    }};
305    (item = FlagType; array = $a:expr; index = $i:expr; Unknown, $($input:tt)*) => {{
306        let mut result = layout!(item = FlagType; array = $a; index = $i + 1; $($input)*);
307        result[$i] = FlagType::Unknown;
308        result
309    }};
310    (item = FlagType; array = $a:expr; index = $i:expr; ShouldBe1, $($input:tt)*) => {{
311        let mut result = layout!(item = FlagType; array = $a; index = $i + 1; $($input)*);
312        result[$i] = FlagType::ShouldBe1;
313        result
314    }};
315    (item = FlagType; array = $a:expr; index = $i:expr; ShouldBe0, $($input:tt)*) => {{
316        let mut result = layout!(item = FlagType; array = $a; index = $i + 1; $($input)*);
317        result[$i] = FlagType::ShouldBe0;
318        result
319    }};
320    (item = FlagType; array = $a:expr; index = $i:expr; $m:literal: $n:expr, $($input:tt)*) => {{
321        let mut result = layout!(item = FlagType; array = $a; index = $i + $n; $($input)*);
322        let mut i = $i;
323        while i < $i + $n {
324            result[i] = FlagType::Reserved($m);
325            i += 1;
326        }
327        result
328    }};
329    (item = FlagType; array = $a:expr; index = $i:expr; $m:literal $d:literal, $($input:tt)*) => {{
330        let mut result = layout!(item = FlagType; array = $a; index = $i + 1; $($input)*);
331        result[$i] = FlagType::Significant($m, $d);
332        result
333    }};
334    (item = FlagType; array = $a:expr; index = $i:expr; $m:literal, $($input:tt)*) => {{
335        let mut result = layout!(item = FlagType; array = $a; index = $i + 1; $($input)*);
336        result[$i] = FlagType::Significant($m, $m);
337        result
338    }};
339    (FlagType; $(#[$meta:meta])* $vis:vis $ident:ident $name:ident($value:tt); $($input:tt)*) => {
340        $(#[$meta])*
341        $vis $ident $name($value);
342        impl $name {
343            const LAYOUT: [FlagType<'static>; { layout!(@count_bytes $value) * 8 }] =
344                layout!(
345                    item = FlagType;
346                    array = [FlagType::Unknown; { layout!(@count_bytes $value) * 8 }];
347                    index = 0;
348                    $($input)*
349                );
350        }
351        impl Layout for $name {
352            type Layout = core::slice::Iter<'static, FlagType<'static>>;
353            fn layout() -> Self::Layout { $name::LAYOUT.iter() }
354        }
355        impl BitFieldLayout for $name {
356            type Value = $value;
357            fn get(&self) -> Self::Value { self.0 }
358            fn set(&mut self, new: Self::Value) { self.0 = new; }
359        }
360    };
361
362    // Utils
363    (@as_expr $expr:expr) => { $expr };
364    (@as_ty $ty:ty) => { $ty };
365    (@count_bytes u8) => { 1 };
366    (@count_bytes u16) => { 2 };
367    (@count_bytes u32) => { 4 };
368    (@count_bytes u64) => { 8 };
369    (@count_bytes u128) => { 16 };
370    (@count_bytes [u8; $n:expr]) => { $n };
371}
372
373
374
375#[cfg(test)]
376mod tests {
377    use std::prelude::v1::*;
378    use std::{slice,};
379
380    use pretty_assertions::assert_eq;
381    use crate::*;
382
383
384    #[test]
385    fn dual_view() {
386        let result = DualView("a", "A");
387        assert_eq!("a", format!("{}", result));
388        assert_eq!("A", format!("{:#}", result));
389    }
390
391    #[test]
392    fn flag_type() {
393        let significant = FlagType::Significant("s", "S");
394        let reserved = FlagType::Reserved("r");
395        assert_eq!("s", format!("{}", significant));
396        assert_eq!("S", format!("{:#}", significant));
397        assert_eq!("r", format!("{:#}", reserved));
398    }
399
400    #[test]
401    fn layout_macro_dual_view() {
402        layout!(
403            DualView;
404            struct Letters(u8);
405            "a",
406            "b" "B",
407            "c",
408            "d",
409            "e",
410            "f" "F",
411            "g" "G",
412            "h" "H",
413        );
414        let l0 = Letters(0b00000000);
415        let l1 = Letters(0b00100000);
416        let result = l0.diff(l1).next().unwrap();
417        let sample = either::Either::Right((5, &DualView("f", "F")));
418        assert_eq!(sample, result);
419        layout!(
420            DualView;
421            pub struct Triple([u8; 3]);
422            "a",
423            "b" "B",
424            "c",
425            "d",
426            "e",
427            "f" "F",
428            "g" "G",
429            "h" "H",
430        );
431    }
432
433    #[test]
434    fn layout_macro_flag_type() {
435        layout!(
436            FlagType;
437            struct EightFlags(u8);
438            "Significant: meaning",
439            "Significant: meaning" "Significant: description",
440            "Reserved: 2 bits": 2,
441            "Reserved: shouldn't exists": 0,
442            ShouldBe0,
443            ShouldBe1,
444            Unknown,
445            Undefined,
446        );
447        let ef0 = EightFlags(0b00000000);
448        let ef1 = EightFlags(0b00100000);
449        let result = ef0.diff(ef1).next().unwrap();
450        let sample = either::Either::Right((5, &FlagType::ShouldBe1));
451        assert_eq!(sample, result);
452    }
453}