use crate::model::error::ParseError;
use std::convert::TryFrom;
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum FetchHeaderType {
Type0x05 = 0x05,
}
#[derive(Debug, PartialEq, Clone, Copy, Eq)]
pub struct SubgroupHeaderType(u8);
impl SubgroupHeaderType {
pub const EXTENSIONS: u8 = 0x01;
pub const SUBGROUP_ID_MODE_MASK: u8 = 0x06;
pub const END_OF_GROUP: u8 = 0x08;
pub const REQUIRED_BIT: u8 = 0x10;
pub const DEFAULT_PRIORITY: u8 = 0x20;
const INVALID_BITS_MASK: u8 = 0xC0;
const RESERVED_SUBGROUP_MODE: u8 = 0x06;
pub fn try_new(value: u64) -> Result<Self, ParseError> {
if value > u8::MAX as u64 || (value as u8) & Self::INVALID_BITS_MASK != 0 {
return Err(ParseError::InvalidType {
context: "SubgroupHeaderType::try_new",
details: format!("invalid bits set, got {value:#x}"),
});
}
let v = value as u8;
if v & Self::REQUIRED_BIT == 0 {
return Err(ParseError::InvalidType {
context: "SubgroupHeaderType::try_new",
details: format!("bit 4 not set, got {value:#x}"),
});
}
if v & Self::SUBGROUP_ID_MODE_MASK == Self::RESERVED_SUBGROUP_MODE {
return Err(ParseError::InvalidType {
context: "SubgroupHeaderType::try_new",
details: format!("reserved SUBGROUP_ID_MODE 0b11, got {value:#x}"),
});
}
Ok(Self(v))
}
pub fn value(&self) -> u8 {
self.0
}
pub fn has_extensions(&self) -> bool {
self.0 & Self::EXTENSIONS != 0
}
pub fn has_explicit_subgroup_id(&self) -> bool {
self.0 & Self::SUBGROUP_ID_MODE_MASK == 0x04
}
pub fn subgroup_id_is_zero(&self) -> bool {
self.0 & Self::SUBGROUP_ID_MODE_MASK == 0x00
}
pub fn subgroup_id_is_first_object_id(&self) -> bool {
self.0 & Self::SUBGROUP_ID_MODE_MASK == 0x02
}
pub fn contains_end_of_group(&self) -> bool {
self.0 & Self::END_OF_GROUP != 0
}
pub fn has_default_priority(&self) -> bool {
self.0 & Self::DEFAULT_PRIORITY != 0
}
pub fn from_properties(
has_extensions: bool,
subgroup_id_mode: u8,
contains_end_of_group: bool,
has_default_priority: bool,
) -> Self {
let mut v: u8 = Self::REQUIRED_BIT;
if has_extensions {
v |= Self::EXTENSIONS;
}
v |= (subgroup_id_mode & 0x03) << 1; if contains_end_of_group {
v |= Self::END_OF_GROUP;
}
if has_default_priority {
v |= Self::DEFAULT_PRIORITY;
}
Self(v)
}
}
impl TryFrom<u64> for SubgroupHeaderType {
type Error = ParseError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
Self::try_new(value)
}
}
impl From<SubgroupHeaderType> for u64 {
fn from(t: SubgroupHeaderType) -> Self {
t.0 as u64
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ObjectForwardingPreference {
Subgroup,
Datagram,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u64)]
pub enum ObjectStatus {
Normal = 0x0,
EndOfGroup = 0x3,
EndOfTrack = 0x4,
}
impl TryFrom<u64> for ObjectStatus {
type Error = ParseError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
match value {
0x0 => Ok(ObjectStatus::Normal),
0x3 => Ok(ObjectStatus::EndOfGroup),
0x4 => Ok(ObjectStatus::EndOfTrack),
_ => Err(ParseError::InvalidType {
context: "ObjectStatus::try_from(u8)",
details: format!("Invalid status, got {value}"),
}),
}
}
}
impl From<ObjectStatus> for u64 {
fn from(status: ObjectStatus) -> Self {
status as u64
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ObjectDatagramType(u8);
impl ObjectDatagramType {
pub const EXTENSIONS: u8 = 0x01;
pub const END_OF_GROUP: u8 = 0x02;
pub const ZERO_OBJECT_ID: u8 = 0x04;
pub const DEFAULT_PRIORITY: u8 = 0x08;
pub const STATUS: u8 = 0x20;
const INVALID_BITS_MASK: u8 = 0xD0;
pub fn try_new(value: u64) -> Result<Self, ParseError> {
if value > u8::MAX as u64 || (value as u8) & Self::INVALID_BITS_MASK != 0 {
return Err(ParseError::InvalidType {
context: "ObjectDatagramType::try_new",
details: format!("Invalid datagram type {value:#x}, must match form 0b00X0XXXX"),
});
}
let v = value as u8;
if v & Self::STATUS != 0 && v & Self::END_OF_GROUP != 0 {
return Err(ParseError::ProtocolViolation {
context: "ObjectDatagramType::try_new",
details: "STATUS and END_OF_GROUP cannot both be set".to_string(),
});
}
Ok(Self(v))
}
pub fn value(&self) -> u8 {
self.0
}
pub fn has_extensions(&self) -> bool {
self.0 & Self::EXTENSIONS != 0
}
pub fn is_end_of_group(&self) -> bool {
self.0 & Self::END_OF_GROUP != 0
}
pub fn is_zero_object_id(&self) -> bool {
self.0 & Self::ZERO_OBJECT_ID != 0
}
pub fn has_default_priority(&self) -> bool {
self.0 & Self::DEFAULT_PRIORITY != 0
}
pub fn is_status(&self) -> bool {
self.0 & Self::STATUS != 0
}
pub fn from_properties(
has_extensions: bool,
end_of_group: bool,
object_id_is_zero: bool,
default_priority: bool,
is_status: bool,
) -> Result<Self, ParseError> {
let mut v: u8 = 0;
if has_extensions {
v |= Self::EXTENSIONS;
}
if end_of_group {
v |= Self::END_OF_GROUP;
}
if object_id_is_zero {
v |= Self::ZERO_OBJECT_ID;
}
if default_priority {
v |= Self::DEFAULT_PRIORITY;
}
if is_status {
v |= Self::STATUS;
}
Self::try_new(v as u64)
}
}
impl TryFrom<u64> for ObjectDatagramType {
type Error = ParseError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
Self::try_new(value)
}
}
impl From<ObjectDatagramType> for u64 {
fn from(dtype: ObjectDatagramType) -> Self {
dtype.0 as u64
}
}