use core::convert::TryFrom;
use core::fmt;
use core::iter::FromIterator;
use core::ops::{Deref, RangeInclusive};
#[derive(Copy, Clone, Eq, Hash, PartialEq)]
pub struct Flag<'a> {
pub position: Position,
pub is_set: bool,
pub type_: FlagType<'a>,
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Default)]
pub enum FlagType<'a> {
#[default]
Unknown,
Significant(&'a str, &'a str),
Reserved(&'a str),
}
pub type Layout<'a> = &'a [FlagType<'a>];
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Default)]
pub struct Iter<'a, T> {
pub value: T,
pub index: usize,
pub layout: Layout<'a>,
}
#[derive(Copy, Clone, Eq, Hash, PartialEq, Debug)]
pub struct Position(pub usize);
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Default)]
pub struct Significants<'a, T>(Iter<'a, T>);
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Default)]
pub struct Reserved<'a, T> {
iter: Iter<'a, T>,
desc: Option<&'a str>,
start: usize,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct ReservedRange<'a> {
pub description: &'a str,
pub range: RangeInclusive<usize>,
}
pub trait BitField<'a> {
type Size: Default + Into<u128> + TryFrom<u128> + Copy + fmt::Debug;
const LAYOUT: Layout<'a> = &[];
fn value(&self) -> Self::Size;
fn iter(&self) -> Iter<'a, Self::Size> {
Iter::new(self.value(), Self::LAYOUT)
}
fn significants(&self) -> Significants<'a, Self::Size> {
Significants::new(self.iter())
}
fn reserved(&self) -> Reserved<'a, Self::Size> {
Reserved::new(self.iter())
}
}
macro_rules! layout {
(length = $len:expr; $($tail:tt)*) => {
const LAYOUT: Layout<'static> = &layout!(array = [FlagType::Unknown; $len], index = 0; $($tail)*);
};
(array = $arr:expr, index = $_idx:expr; ) => { { $arr } };
(array = $arr:expr, index = $idx:expr; $desc:literal: $count:expr, $($tail:tt)*) => {
{
let mut arr = layout!(array = $arr, index = $idx + $count; $($tail)*);
let mut i = $idx;
while i < $idx + $count {
arr[i] = FlagType::Reserved($desc);
i += 1;
}
arr
}
};
(array = $arr:expr, index = $idx:expr; $short:literal $long:literal, $($tail:tt)*) => {
{
let mut arr = layout!(array = $arr, index = $idx + 1; $($tail)*);
arr[$idx] = FlagType::Significant($short, $long);
arr
}
};
(array = $arr:expr, index = $idx:expr; $short:literal, $($tail:tt)*) => {
{
let mut arr = layout!(array = $arr, index = $idx + 1; $($tail)*);
arr[$idx] = FlagType::Significant($short, $short);
arr
}
};
}
impl fmt::Display for Flag<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.type_ {
FlagType::Significant(meaning, description) => {
if f.alternate() {
write!(f, "{description}")
} else {
write!(f, "{meaning}")
}
}
FlagType::Reserved(note) => {
write!(f, "{note}")
}
FlagType::Unknown => {
write!(f, "Unknown")
}
}
}
}
impl fmt::Debug for Flag<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Flag")
.field("position", &self.position)
.field("is_set", &self.is_set)
.finish()
}
}
impl<'a, T> Iter<'a, T> {
fn new(value: T, layout: Layout<'a>) -> Self {
Self {
value,
layout,
index: 0,
}
}
}
impl<'a, T: Into<u128> + Copy> Iterator for Iter<'a, T> {
type Item = Flag<'a>;
fn next(&mut self) -> Option<Self::Item> {
let len = core::mem::size_of::<T>() * 8;
if self.index == len {
None
} else {
let is_set = (self.value.into() & (1 << self.index)) != 0;
let p = self.index;
self.index += 1;
Some(Flag {
position: Position(p),
is_set,
type_: self.layout[p],
})
}
}
}
impl Deref for Position {
type Target = usize;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl FromIterator<Position> for u8 {
fn from_iter<I: IntoIterator<Item = Position>>(iter: I) -> Self {
iter.into_iter().fold(0, |acc, p| acc | (1 << p.deref()))
}
}
impl FromIterator<Position> for u16 {
fn from_iter<I: IntoIterator<Item = Position>>(iter: I) -> Self {
iter.into_iter().fold(0, |acc, p| acc | (1 << p.deref()))
}
}
impl FromIterator<Position> for u32 {
fn from_iter<I: IntoIterator<Item = Position>>(iter: I) -> Self {
iter.into_iter().fold(0, |acc, p| acc | (1 << p.deref()))
}
}
impl FromIterator<Position> for u64 {
fn from_iter<I: IntoIterator<Item = Position>>(iter: I) -> Self {
iter.into_iter().fold(0, |acc, p| acc | (1 << p.deref()))
}
}
impl FromIterator<Position> for u128 {
fn from_iter<I: IntoIterator<Item = Position>>(iter: I) -> Self {
iter.into_iter().fold(0, |acc, p| acc | (1 << p.deref()))
}
}
impl FromIterator<Position> for usize {
fn from_iter<I: IntoIterator<Item = Position>>(iter: I) -> Self {
iter.into_iter().fold(0, |acc, p| acc | (1 << p.deref()))
}
}
impl<'a> FromIterator<&'a Position> for u8 {
fn from_iter<I: IntoIterator<Item = &'a Position>>(iter: I) -> Self {
iter.into_iter().fold(0, |acc, p| acc | (1 << p.deref()))
}
}
impl<'a> FromIterator<&'a Position> for u16 {
fn from_iter<I: IntoIterator<Item = &'a Position>>(iter: I) -> Self {
iter.into_iter().fold(0, |acc, p| acc | (1 << p.deref()))
}
}
impl<'a> FromIterator<&'a Position> for u32 {
fn from_iter<I: IntoIterator<Item = &'a Position>>(iter: I) -> Self {
iter.into_iter().fold(0, |acc, p| acc | (1 << p.deref()))
}
}
impl<'a> FromIterator<&'a Position> for u64 {
fn from_iter<I: IntoIterator<Item = &'a Position>>(iter: I) -> Self {
iter.into_iter().fold(0, |acc, p| acc | (1 << p.deref()))
}
}
impl<'a> FromIterator<&'a Position> for u128 {
fn from_iter<I: IntoIterator<Item = &'a Position>>(iter: I) -> Self {
iter.into_iter().fold(0, |acc, p| acc | (1 << p.deref()))
}
}
impl<'a> FromIterator<&'a Position> for usize {
fn from_iter<I: IntoIterator<Item = &'a Position>>(iter: I) -> Self {
iter.into_iter().fold(0, |acc, p| acc | (1 << p.deref()))
}
}
impl<'a, T> Significants<'a, T> {
fn new(iter: Iter<'a, T>) -> Self {
Self(iter)
}
}
impl<'a, T: Into<u128> + Copy> Iterator for Significants<'a, T> {
type Item = Flag<'a>;
fn next(&mut self) -> Option<Self::Item> {
for f in self.0.by_ref() {
if matches!(f.type_, FlagType::Reserved(_)) || !f.is_set {
continue;
}
return Some(f);
}
None
}
}
impl<'a, T> Reserved<'a, T> {
fn new(iter: Iter<'a, T>) -> Self {
Self {
iter,
desc: None,
start: 0,
}
}
}
impl<'a, T: Into<u128> + Copy + fmt::Debug> Iterator for Reserved<'a, T> {
type Item = ReservedRange<'a>;
fn next(&mut self) -> Option<Self::Item> {
let mut end = 0;
for Flag {
position: Position(p),
type_,
..
} in self.iter.by_ref()
{
match (type_, self.desc) {
(FlagType::Reserved(s), Some(desc)) => {
self.desc = Some(s);
if s != desc {
let start = self.start;
self.start = p;
return Some(ReservedRange {
description: desc,
range: start..=end,
});
}
}
(FlagType::Reserved(s), None) => {
self.desc = Some(s);
self.start = p;
}
(_, Some(desc)) => {
self.desc = None;
return Some(ReservedRange {
description: desc,
range: self.start..=end,
});
}
(_, None) => {
self.desc = None;
}
}
end = p;
}
self.desc.take().map(|description| ReservedRange {
description,
range: self.start..=end,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::prelude::v1::*;
const INDEX_SAMPLE: &[usize] = &[
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107,
109, 113, 127,
];
layout!(
length = 8;
"A" "A Long",
"B" "B Long",
"Reserved 1": 1,
"C" "C Long",
"D" "D Long",
"E" "E Long",
"Reserved 2": 2,
);
#[test]
fn layout_macro() {
let sample = [
FlagType::Significant("A", "A Long"),
FlagType::Significant("B", "B Long"),
FlagType::Reserved("Reserved 1"),
FlagType::Significant("C", "C Long"),
FlagType::Significant("D", "D Long"),
FlagType::Significant("E", "E Long"),
FlagType::Reserved("Reserved 2"),
FlagType::Reserved("Reserved 2"),
];
assert_eq!(sample, LAYOUT);
}
#[test]
fn iter() {
let iter = Iter::new(0b1010_1001u8, LAYOUT);
let sample = vec![
(0, true, LAYOUT[0]),
(1, false, LAYOUT[1]),
(2, false, LAYOUT[2]),
(3, true, LAYOUT[3]),
(4, false, LAYOUT[4]),
(5, true, LAYOUT[5]),
(6, false, LAYOUT[6]),
(7, true, LAYOUT[7]),
];
for i in iter {
println!("{i:?}");
}
assert_eq!(8, iter.count(), "BYTE setted flags count");
assert_eq!(
sample,
iter.map(|v| (*v.position, v.is_set, v.type_)).collect::<Vec<_>>(),
"As triple vec"
);
}
#[test]
fn significants() {
let iter = Significants::new(Iter::new(0b1010_1001u8, LAYOUT));
let meanings = vec!["A", "C", "E"];
let descriptions = vec!["A Long", "C Long", "E Long"];
assert_eq!(meanings, iter.map(|v| format!("{v}")).collect::<Vec<_>>(), "Meanings");
assert_eq!(
descriptions,
iter.map(|v| format!("{v:#}")).collect::<Vec<_>>(),
"Descriptions"
);
}
#[test]
fn reserved() {
let layout = &layout!(
array = [FlagType::Unknown; 8], index = 0;
"S A" "A Long",
"S B" "B Long",
"S C" "C Long",
"S D" "D Long",
"S E" "E Long",
"S F" "F Long",
"S G" "G Long",
"S H" "H Long",
);
let iter = Reserved::new(Iter::new(u8::MAX, layout));
assert_eq!(0, iter.count(), "Empty");
let layout = &layout!(
array = [FlagType::Unknown; 8], index = 0;
"R 1": 8,
);
let sample = vec![0..=7];
let iter = Reserved::new(Iter::new(u8::MAX, layout));
assert_eq!(sample, iter.map(|v| v.range).collect::<Vec<_>>(), "Full");
let layout = &layout!(
array = [FlagType::Unknown; 8], index = 0;
"S A" "A Long",
"S B" "B Long",
"S C" "C Long",
"S D" "D Long",
"S E" "E Long",
"S F" "F Long",
"R 1": 2,
);
let sample = vec![6..=7];
let iter = Reserved::new(Iter::new(u8::MAX, layout));
assert_eq!(sample, iter.map(|v| v.range).collect::<Vec<_>>(), "Simple");
let layout = &layout!(
array = [FlagType::Unknown; 16], index = 0;
"S A" "A Long",
"S B" "B Long",
"R 1": 1,
"S C" "C Long",
"S C" "C Long",
"S D" "D Long",
"S E" "E Long",
"R 2": 2,
"S C" "C Long",
"R 2": 2,
"R 3": 4,
);
let sample = vec![2..=2, 7..=8, 10..=11, 12..=15];
let iter = Reserved::new(Iter::new(u16::MAX, layout));
assert_eq!(sample, iter.map(|v| v.range).collect::<Vec<_>>(), "Complex");
}
#[test]
#[should_panic(expected = "attempt to shift left with overflow")]
fn from_iterator_shift_overflow() {
let _ = INDEX_SAMPLE.iter().map(|&p| Position(p)).collect::<u8>();
}
#[test]
fn from_iterator_values() {
let a = 0b1010_1100u8;
let b = INDEX_SAMPLE
.iter()
.take_while(|&&p| p < 8)
.map(|&p| Position(p))
.collect();
assert_eq!(a, b, "u8:\n{a:08b}\n{b:08b}");
let a = 0b0010_1000_1010_1100u16;
let b = INDEX_SAMPLE
.iter()
.take_while(|&&p| p < 16)
.map(|&p| Position(p))
.collect();
assert_eq!(a, b, "u16:\n{a:016b}\n{b:016b}");
let a = 2693408940u32;
let b = INDEX_SAMPLE
.iter()
.take_while(|&&p| p < 32)
.map(|&p| Position(p))
.collect();
assert_eq!(a, b, "u32:\n{a:032b}\n{b:032b}");
let a = 2891462833508853932u64;
let b = INDEX_SAMPLE
.iter()
.take_while(|&&p| p < 64)
.map(|&p| Position(p))
.collect();
assert_eq!(a, b, "u64:\n{a:064b}\n{b:064b}");
let a = 170152392186162032610075049835446806700u128;
let b = INDEX_SAMPLE
.iter()
.take_while(|&&p| p < 128)
.map(|&p| Position(p))
.collect();
assert_eq!(a, b, "u128:\n{a:0128b}\n{b:0128b}");
}
}