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}