use core::fmt;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct DualView<'a>(pub &'a str, pub &'a str);
impl<'a> fmt::Display for DualView<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = if f.alternate() { self.1 } else { self.0 };
write!(f, "{}", s)
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub enum FlagType<'a> {
Significant(&'a str, &'a str),
Reserved(&'a str),
ShouldBe0,
ShouldBe1,
Unknown,
Undefined,
}
impl<'a> fmt::Display for FlagType<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match (self, f.alternate()) {
(Self::Significant(s, _), false) => write!(f, "{}", s),
(Self::Significant(_, s), true) => write!(f, "{}", s),
(Self::Reserved(s), _) => write!(f, "{}", s),
(Self::ShouldBe0, _) => write!(f, "Should be 0"),
(Self::ShouldBe1, _) => write!(f, "Should be 1"),
(Self::Unknown, _) => write!(f, "Unknown"),
(Self::Undefined, _) => write!(f, "Undefined"),
}
}
}
#[macro_export]
macro_rules! layout {
(item = DualView; [] -> [$($output:tt)*]) => {
[$($output)*]
};
(item = DualView; [$m:literal $d:literal, $($input:tt)*] -> [$($output:tt)*]) => {
layout!(item = DualView; [$($input)*] -> [$($output)* DualView($m, $d),])
};
(item = DualView; [$m:literal, $($input:tt)*] -> [$($output:tt)*]) => {{
layout!(item = DualView; [$($input)*] -> [$($output)* DualView($m, $m),])
}};
(DualView; $(#[$meta:meta])* $vis:vis $ident:ident $name:ident($value:tt); $($input:tt)*) => {
$(#[$meta])*
$vis $ident $name($value);
impl $name {
const LAYOUT: &'static [DualView<'static>] =
&layout!(item = DualView; [$($input)*] -> []);
}
impl Layout for $name {
type Layout = slice::Iter<'static, DualView<'static>>;
fn layout() -> Self::Layout { $name::LAYOUT.iter() }
}
impl BitFieldLayout for $name {
type Value = $value;
fn get(&self) -> Self::Value { self.0 }
fn set(&mut self, new: Self::Value) { self.0 = new; }
}
};
(item = FlagType; array = $a:expr; index = $i:expr;) => {{ $a }};
(item = FlagType; array = $a:expr; index = $i:expr; Undefined, $($input:tt)*) => {{
let mut result = layout!(item = FlagType; array = $a; index = $i + 1; $($input)*);
result[$i] = FlagType::Undefined;
result
}};
(item = FlagType; array = $a:expr; index = $i:expr; Unknown, $($input:tt)*) => {{
let mut result = layout!(item = FlagType; array = $a; index = $i + 1; $($input)*);
result[$i] = FlagType::Unknown;
result
}};
(item = FlagType; array = $a:expr; index = $i:expr; ShouldBe1, $($input:tt)*) => {{
let mut result = layout!(item = FlagType; array = $a; index = $i + 1; $($input)*);
result[$i] = FlagType::ShouldBe1;
result
}};
(item = FlagType; array = $a:expr; index = $i:expr; ShouldBe0, $($input:tt)*) => {{
let mut result = layout!(item = FlagType; array = $a; index = $i + 1; $($input)*);
result[$i] = FlagType::ShouldBe0;
result
}};
(item = FlagType; array = $a:expr; index = $i:expr; $m:literal: $n:expr, $($input:tt)*) => {{
let mut result = layout!(item = FlagType; array = $a; index = $i + $n; $($input)*);
let mut i = $i;
while i < $i + $n {
result[i] = FlagType::Reserved($m);
i += 1;
}
result
}};
(item = FlagType; array = $a:expr; index = $i:expr; $m:literal $d:literal, $($input:tt)*) => {{
let mut result = layout!(item = FlagType; array = $a; index = $i + 1; $($input)*);
result[$i] = FlagType::Significant($m, $d);
result
}};
(item = FlagType; array = $a:expr; index = $i:expr; $m:literal, $($input:tt)*) => {{
let mut result = layout!(item = FlagType; array = $a; index = $i + 1; $($input)*);
result[$i] = FlagType::Significant($m, $m);
result
}};
(FlagType; $(#[$meta:meta])* $vis:vis $ident:ident $name:ident($value:tt); $($input:tt)*) => {
$(#[$meta])*
$vis $ident $name($value);
impl $name {
const LAYOUT: [FlagType<'static>; { layout!(@count_bytes $value) * 8 }] =
layout!(
item = FlagType;
array = [FlagType::Unknown; { layout!(@count_bytes $value) * 8 }];
index = 0;
$($input)*
);
}
impl Layout for $name {
type Layout = core::slice::Iter<'static, FlagType<'static>>;
fn layout() -> Self::Layout { $name::LAYOUT.iter() }
}
impl BitFieldLayout for $name {
type Value = $value;
fn get(&self) -> Self::Value { self.0 }
fn set(&mut self, new: Self::Value) { self.0 = new; }
}
};
(@as_expr $expr:expr) => { $expr };
(@as_ty $ty:ty) => { $ty };
(@count_bytes u8) => { 1 };
(@count_bytes u16) => { 2 };
(@count_bytes u32) => { 4 };
(@count_bytes u64) => { 8 };
(@count_bytes u128) => { 16 };
(@count_bytes [u8; $n:expr]) => { $n };
}
#[cfg(test)]
mod tests {
use std::prelude::v1::*;
use std::{slice,};
use pretty_assertions::assert_eq;
use crate::*;
#[test]
fn dual_view() {
let result = DualView("a", "A");
assert_eq!("a", format!("{}", result));
assert_eq!("A", format!("{:#}", result));
}
#[test]
fn flag_type() {
let significant = FlagType::Significant("s", "S");
let reserved = FlagType::Reserved("r");
assert_eq!("s", format!("{}", significant));
assert_eq!("S", format!("{:#}", significant));
assert_eq!("r", format!("{:#}", reserved));
}
#[test]
fn layout_macro_dual_view() {
layout!(
DualView;
struct Letters(u8);
"a",
"b" "B",
"c",
"d",
"e",
"f" "F",
"g" "G",
"h" "H",
);
let l0 = Letters(0b00000000);
let l1 = Letters(0b00100000);
let result = l0.diff(l1).next().unwrap();
let sample = either::Either::Right((5, &DualView("f", "F")));
assert_eq!(sample, result);
layout!(
DualView;
pub struct Triple([u8; 3]);
"a",
"b" "B",
"c",
"d",
"e",
"f" "F",
"g" "G",
"h" "H",
);
}
#[test]
fn layout_macro_flag_type() {
layout!(
FlagType;
struct EightFlags(u8);
"Significant: meaning",
"Significant: meaning" "Significant: description",
"Reserved: 2 bits": 2,
"Reserved: shouldn't exists": 0,
ShouldBe0,
ShouldBe1,
Unknown,
Undefined,
);
let ef0 = EightFlags(0b00000000);
let ef1 = EightFlags(0b00100000);
let result = ef0.diff(ef1).next().unwrap();
let sample = either::Either::Right((5, &FlagType::ShouldBe1));
assert_eq!(sample, result);
}
}