use core::fmt;
use anyhow::{Result, bail};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
bitflags::bitflags! {
#[derive(Default, Debug, PartialEq)]
pub struct DataOutFlags: u8 {
const FINAL = 0b1000_0000;
}
}
impl TryFrom<u8> for DataOutFlags {
type Error = anyhow::Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
DataOutFlags::from_bits(value)
.ok_or_else(|| anyhow::anyhow!("invalid DataOutFlags: {:#08b}", value))
}
}
#[repr(transparent)]
#[derive(Default, Clone, PartialEq, Eq, FromBytes, IntoBytes, KnownLayout, Immutable)]
pub struct RawDataOutFlags(u8);
impl RawDataOutFlags {
pub const FINAL: u8 = 0b1000_0000;
#[inline]
pub const fn raw(&self) -> u8 {
self.0
}
#[inline]
pub const fn new_raw(v: u8) -> Self {
Self(v)
}
#[inline]
pub fn fin(&self) -> bool {
self.0 & Self::FINAL != 0
}
#[inline]
pub fn set_fin(&mut self, on: bool) {
if on {
self.0 |= Self::FINAL;
} else {
self.0 &= !Self::FINAL;
}
}
}
impl From<DataOutFlags> for RawDataOutFlags {
#[inline]
fn from(f: DataOutFlags) -> Self {
Self(f.bits())
}
}
impl TryFrom<RawDataOutFlags> for DataOutFlags {
type Error = anyhow::Error;
#[inline]
fn try_from(r: RawDataOutFlags) -> Result<Self> {
DataOutFlags::from_bits(r.raw())
.ok_or_else(|| anyhow::anyhow!("invalid DataOutFlags: {:#010b}", r.raw()))
}
}
bitflags::bitflags! {
#[derive(Default, Debug, PartialEq)]
pub struct DataInFlags: u8 {
const FINAL = 1 << 7; const A = 1 << 6; const O = 1 << 2; const U = 1 << 1; const S = 1 << 0; }
}
impl TryFrom<u8> for DataInFlags {
type Error = anyhow::Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
let tmp = DataInFlags::from_bits(value)
.ok_or_else(|| anyhow::anyhow!("invalid DataOutFlags: {:#08b}", value))?;
if tmp.contains(DataInFlags::U) && tmp.contains(DataInFlags::O) {
bail!("Protocol error cause U && O both presented")
}
Ok(tmp)
}
}
#[repr(transparent)]
#[derive(Default, PartialEq, Eq, FromBytes, IntoBytes, KnownLayout, Immutable)]
pub struct RawDataInFlags(u8);
impl RawDataInFlags {
pub const A: u8 = 1 << 6;
pub const FINAL: u8 = 1 << 7;
pub const O: u8 = 1 << 2;
const RESERVED_MASK: u8 = 0b0011_1000;
pub const S: u8 = 1 << 0;
pub const U: u8 = 1 << 1;
#[inline]
pub const fn raw(&self) -> u8 {
self.0
}
#[inline]
pub const fn new_raw(v: u8) -> Self {
Self(v)
}
#[inline]
pub fn fin(&self) -> bool {
self.0 & Self::FINAL != 0
}
#[inline]
pub fn ack(&self) -> bool {
self.0 & Self::A != 0
}
#[inline]
pub fn o(&self) -> bool {
self.0 & Self::O != 0
}
#[inline]
pub fn u(&self) -> bool {
self.0 & Self::U != 0
}
#[inline]
pub fn s(&self) -> bool {
self.0 & Self::S != 0
}
#[inline]
pub fn set_fin(&mut self, on: bool) {
Self::set_bit(&mut self.0, Self::FINAL, on)
}
#[inline]
pub fn set_ack(&mut self, on: bool) {
Self::set_bit(&mut self.0, Self::A, on)
}
#[inline]
pub fn set_o(&mut self, on: bool) {
Self::set_pair(&mut self.0, Self::O, Self::U, on)
}
#[inline]
pub fn set_u(&mut self, on: bool) {
Self::set_pair(&mut self.0, Self::U, Self::O, on)
}
#[inline]
pub fn set_s(&mut self, on: bool) {
Self::set_bit(&mut self.0, Self::S, on);
if on {
self.set_fin(true);
} }
#[inline]
fn set_bit(v: &mut u8, bit: u8, on: bool) {
if on {
*v |= bit;
} else {
*v &= !bit;
}
}
#[inline]
fn set_pair(v: &mut u8, set_bit: u8, clear_bit: u8, on: bool) {
if on {
*v |= set_bit;
*v &= !clear_bit;
} else {
*v &= !set_bit;
}
}
#[inline]
pub fn validate(&self) -> Result<()> {
if self.0 & Self::RESERVED_MASK != 0 {
bail!(
"protocol error: reserved bits set in DataInFlags: {:#010b}",
self.0
);
}
if self.u() && self.o() {
bail!("protocol error: both U and O set");
}
if self.s() && !self.fin() {
bail!("protocol error: S=1 requires F=1");
}
Ok(())
}
}
impl From<DataInFlags> for RawDataInFlags {
#[inline]
fn from(f: DataInFlags) -> Self {
Self(f.bits())
}
}
impl TryFrom<RawDataInFlags> for DataInFlags {
type Error = anyhow::Error;
#[inline]
fn try_from(r: RawDataInFlags) -> Result<Self> {
r.validate()?;
DataInFlags::from_bits(r.raw())
.ok_or_else(|| anyhow::anyhow!("invalid DataInFlags: {:#010b}", r.raw()))
}
}
impl fmt::Debug for RawDataOutFlags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "RawDataOutFlags {{ ")?;
if self.fin() {
write!(f, "FIN")?;
}
write!(f, " }}")
}
}
impl fmt::Debug for RawDataInFlags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let raw = self.raw();
let reserved_bits = (raw & Self::RESERVED_MASK) >> 3;
write!(f, "RawDataInFlags {{ ")?;
if self.fin() {
write!(f, "FIN|")?;
}
if self.ack() {
write!(f, "A|")?;
}
if self.o() {
write!(f, "O|")?;
}
if self.u() {
write!(f, "U|")?;
}
if self.s() {
write!(f, "S|")?;
}
if reserved_bits != 0 {
write!(f, "reserved_bits=0b{:03b}|", reserved_bits)?;
}
if self.u() && self.o() {
write!(f, "INVALID:U&O|")?;
}
if self.s() && !self.fin() {
write!(f, "INVALID:S_without_F|")?;
}
write!(f, " }}")
}
}