use std::{fmt::Debug, mem::transmute, ops::Range};
use crate::{
core::{
read::unchecked_bit_range_be_read,
view::{
View, ViewConversionError,
macros::{gen_field_read, gen_field_write, gen_unsafe_field_write, gen_view_impl},
},
write::unchecked_bit_range_be_write,
},
path::standard::{
layout::{
HopFieldLayout, InfoFieldLayout, StdPathDataLayout, StdPathLayout, StdPathMetaLayout,
},
mac::{HopMacInput, HopMacInputSource},
types::{HopFieldFlags, HopFieldMac, InfoFieldFlags},
},
};
#[repr(transparent)]
pub struct StandardPathView([u8]);
gen_view_impl!(StandardPathView, StdPathLayout);
impl StandardPathView {
gen_field_read!(curr_info_field, StdPathMetaLayout::CURR_INFO_FIELD_RNG, u8);
gen_field_read!(curr_hop_field, StdPathMetaLayout::CURR_HOP_FIELD_RNG, u8);
gen_field_read!(seg0_len, StdPathMetaLayout::SEG0_LEN_RNG, u8);
gen_field_read!(seg1_len, StdPathMetaLayout::SEG1_LEN_RNG, u8);
gen_field_read!(seg2_len, StdPathMetaLayout::SEG2_LEN_RNG, u8);
#[inline]
pub fn info_field_count(&self) -> u8 {
(self.seg0_len() > 0) as u8 + (self.seg1_len() > 0) as u8 + (self.seg2_len() > 0) as u8
}
#[inline]
pub fn hop_field_count(&self) -> u8 {
self.seg0_len() + self.seg1_len() + self.seg2_len()
}
}
impl StandardPathView {
gen_field_write!(
set_curr_info_field,
StdPathMetaLayout::CURR_INFO_FIELD_RNG,
u8
);
gen_field_write!(
set_curr_hop_field,
StdPathMetaLayout::CURR_HOP_FIELD_RNG,
u8
);
gen_unsafe_field_write!(set_seg0_len, StdPathMetaLayout::SEG0_LEN_RNG, u8);
gen_unsafe_field_write!(set_seg1_len, StdPathMetaLayout::SEG1_LEN_RNG, u8);
gen_unsafe_field_write!(set_seg2_len, StdPathMetaLayout::SEG2_LEN_RNG, u8);
}
impl StandardPathView {
#[inline]
fn checked_info_field_range(&self, index: usize) -> Option<Range<usize>> {
let info_field_count = self.info_field_count() as usize;
if index >= info_field_count {
return None;
}
Some(
StdPathDataLayout::new(self.seg0_len(), self.seg1_len(), self.seg2_len())
.info_field_range(index)
.shift(StdPathMetaLayout::SIZE_BYTES)
.aligned_byte_range(),
)
}
#[inline]
pub fn checked_hop_field_range(&self, index: usize) -> Option<Range<usize>> {
let hop_field_count = self.hop_field_count() as usize;
if index >= hop_field_count {
return None;
}
Some(
StdPathDataLayout::new(self.seg0_len(), self.seg1_len(), self.seg2_len())
.hop_field_range(index)
.shift(StdPathMetaLayout::SIZE_BYTES)
.aligned_byte_range(),
)
}
}
impl StandardPathView {
#[inline]
pub fn info_field(&self, index: usize) -> Option<&InfoFieldView> {
let field_range = self.checked_info_field_range(index)?;
let field =
unsafe { InfoFieldView::from_slice_unchecked(self.0.get_unchecked(field_range)) };
Some(field)
}
#[inline]
pub fn hop_field(&self, index: usize) -> Option<&HopFieldView> {
let field_range = self.checked_hop_field_range(index)?;
let field =
unsafe { HopFieldView::from_slice_unchecked(self.0.get_unchecked(field_range)) };
Some(field)
}
#[inline]
pub fn info_fields(&self) -> &[InfoFieldView] {
let layout = StdPathDataLayout::new(self.seg0_len(), self.seg1_len(), self.seg2_len());
let info_fields_range = layout
.info_fields_range()
.shift(StdPathMetaLayout::SIZE_BYTES)
.aligned_byte_range();
let slice = unsafe { self.0.get_unchecked(info_fields_range) };
debug_assert!(slice.len() == layout.info_field_count() * InfoFieldLayout::SIZE_BYTES);
unsafe {
std::slice::from_raw_parts(
slice.as_ptr() as *const InfoFieldView,
layout.info_field_count(),
)
}
}
#[inline]
pub fn hop_fields(&self) -> &[HopFieldView] {
let layout = StdPathDataLayout::new(self.seg0_len(), self.seg1_len(), self.seg2_len());
let hop_fields_range = layout
.hop_fields_range()
.shift(StdPathMetaLayout::SIZE_BYTES)
.aligned_byte_range();
let slice = unsafe { self.0.get_unchecked(hop_fields_range) };
debug_assert!(slice.len() == layout.hop_field_count() * HopFieldLayout::SIZE_BYTES);
unsafe {
std::slice::from_raw_parts(
slice.as_ptr() as *const HopFieldView,
layout.hop_field_count(),
)
}
}
}
impl StandardPathView {
#[inline]
pub fn info_field_mut(&mut self, index: usize) -> Option<&mut InfoFieldView> {
let field_range = self.checked_info_field_range(index)?;
let field = unsafe {
InfoFieldView::from_mut_slice_unchecked(self.0.get_unchecked_mut(field_range))
};
Some(field)
}
#[inline]
pub fn hop_field_mut(&mut self, index: usize) -> Option<&mut HopFieldView> {
let field_range = self.checked_hop_field_range(index)?;
let field = unsafe {
HopFieldView::from_mut_slice_unchecked(self.0.get_unchecked_mut(field_range))
};
Some(field)
}
#[inline]
pub fn info_fields_mut(&mut self) -> &mut [InfoFieldView] {
let layout = StdPathDataLayout::new(self.seg0_len(), self.seg1_len(), self.seg2_len());
let info_fields_range = layout
.info_fields_range()
.shift(StdPathMetaLayout::SIZE_BYTES)
.aligned_byte_range();
let slice = unsafe { self.0.get_unchecked_mut(info_fields_range) };
debug_assert!(slice.len() == layout.info_field_count() * InfoFieldLayout::SIZE_BYTES);
unsafe {
std::slice::from_raw_parts_mut(
slice.as_mut_ptr() as *mut InfoFieldView,
layout.info_field_count(),
)
}
}
#[inline]
pub fn hop_fields_mut(&mut self) -> &mut [HopFieldView] {
let layout = StdPathDataLayout::new(self.seg0_len(), self.seg1_len(), self.seg2_len());
let hop_fields_range = layout
.hop_fields_range()
.shift(StdPathMetaLayout::SIZE_BYTES)
.aligned_byte_range();
let slice = unsafe { self.0.get_unchecked_mut(hop_fields_range) };
debug_assert!(slice.len() == layout.hop_field_count() * HopFieldLayout::SIZE_BYTES);
unsafe {
std::slice::from_raw_parts_mut(
slice.as_mut_ptr() as *mut HopFieldView,
layout.hop_field_count(),
)
}
}
}
impl Debug for StandardPathView {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let hop_fields = self.hop_fields();
let info_fields = self.info_fields();
f.debug_struct("StandardPathMetaHeaderView")
.field("current_info_field", &self.curr_info_field())
.field("curr_hop_field", &self.curr_hop_field())
.field("seg0_len", &self.seg0_len())
.field("seg1_len", &self.seg1_len())
.field("seg2_len", &self.seg2_len())
.field("info_fields", &info_fields)
.field("hop_fields", &hop_fields)
.finish()
}
}
#[repr(transparent)]
pub struct InfoFieldView([u8; InfoFieldLayout::SIZE_BYTES]);
impl View for InfoFieldView {
#[inline]
fn has_required_size(buf: &[u8]) -> Result<usize, ViewConversionError> {
if buf.len() < InfoFieldLayout::SIZE_BYTES {
return Err(ViewConversionError::BufferTooSmall {
at: "InfoFieldView",
required: InfoFieldLayout::SIZE_BYTES,
actual: buf.len(),
});
}
Ok(InfoFieldLayout::SIZE_BYTES)
}
#[inline]
unsafe fn from_slice_unchecked(buf: &[u8]) -> &Self {
let sized: &[u8; InfoFieldLayout::SIZE_BYTES] =
unsafe { buf.try_into().unwrap_unchecked() };
unsafe { transmute(sized) }
}
#[inline]
unsafe fn from_mut_slice_unchecked(buf: &mut [u8]) -> &mut Self {
let sized: &mut [u8; InfoFieldLayout::SIZE_BYTES] =
unsafe { buf.try_into().unwrap_unchecked() };
unsafe { transmute(sized) }
}
#[inline]
unsafe fn from_boxed_unchecked(buf: Box<[u8]>) -> Box<Self> {
let sized: Box<[u8; InfoFieldLayout::SIZE_BYTES]> =
unsafe { buf.try_into().unwrap_unchecked() };
unsafe { transmute(sized) }
}
#[inline]
unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
&mut self.0
}
#[inline]
fn as_bytes_boxed(self: Box<Self>) -> Box<[u8]> {
let sized: Box<[u8; InfoFieldLayout::SIZE_BYTES]> = unsafe { transmute(self) };
sized
}
#[inline]
fn as_bytes(&self) -> &[u8] {
&self.0
}
}
impl InfoFieldView {
#[inline]
pub fn flags(&self) -> InfoFieldFlags {
let val = unsafe { unchecked_bit_range_be_read::<u8>(&self.0, InfoFieldLayout::FLAGS_RNG) };
InfoFieldFlags::from_bits_retain(val)
}
gen_field_read!(segment_id, InfoFieldLayout::SEGMENT_ID_RNG, u16);
gen_field_read!(timestamp, InfoFieldLayout::TIMESTAMP_RNG, u32);
}
impl InfoFieldView {
#[inline]
pub fn set_flags(&mut self, flags: InfoFieldFlags) {
let val = flags.bits();
unsafe { unchecked_bit_range_be_write::<u8>(&mut self.0, InfoFieldLayout::FLAGS_RNG, val) }
}
gen_field_write!(set_segment_id, InfoFieldLayout::SEGMENT_ID_RNG, u16);
gen_field_write!(set_timestamp, InfoFieldLayout::TIMESTAMP_RNG, u32);
}
impl Debug for InfoFieldView {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("StandardPathInfoFieldView")
.field("flags", &self.flags())
.field("segment_id", &self.segment_id())
.field("timestamp", &self.timestamp())
.finish()
}
}
#[repr(transparent)]
pub struct HopFieldView([u8; HopFieldLayout::SIZE_BYTES]);
impl View for HopFieldView {
#[inline]
fn has_required_size(buf: &[u8]) -> Result<usize, ViewConversionError> {
if buf.len() < HopFieldLayout::SIZE_BYTES {
return Err(ViewConversionError::BufferTooSmall {
at: "HopFieldView",
required: HopFieldLayout::SIZE_BYTES,
actual: buf.len(),
});
}
Ok(HopFieldLayout::SIZE_BYTES)
}
#[inline]
unsafe fn from_slice_unchecked(buf: &[u8]) -> &Self {
let sized: &[u8; HopFieldLayout::SIZE_BYTES] = unsafe { buf.try_into().unwrap_unchecked() };
unsafe { transmute(sized) }
}
#[inline]
unsafe fn from_mut_slice_unchecked(buf: &mut [u8]) -> &mut Self {
let sized: &mut [u8; HopFieldLayout::SIZE_BYTES] =
unsafe { buf.try_into().unwrap_unchecked() };
unsafe { transmute(sized) }
}
#[inline]
unsafe fn from_boxed_unchecked(buf: Box<[u8]>) -> Box<Self> {
let sized: Box<[u8; HopFieldLayout::SIZE_BYTES]> =
unsafe { buf.try_into().unwrap_unchecked() };
unsafe { transmute(sized) }
}
#[inline]
unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
&mut self.0
}
#[inline]
fn as_bytes_boxed(self: Box<Self>) -> Box<[u8]> {
let sized: Box<[u8; HopFieldLayout::SIZE_BYTES]> = unsafe { transmute(self) };
sized
}
#[inline]
fn as_bytes(&self) -> &[u8] {
&self.0
}
}
impl HopFieldView {
#[inline]
pub fn flags(&self) -> HopFieldFlags {
let value =
unsafe { unchecked_bit_range_be_read::<u8>(&self.0, HopFieldLayout::FLAGS_RNG) };
HopFieldFlags::from_bits_retain(value)
}
gen_field_read!(exp_time, HopFieldLayout::EXP_TIME_RNG, u8);
gen_field_read!(cons_ingress, HopFieldLayout::CONS_INGRESS_RNG, u16);
gen_field_read!(cons_egress, HopFieldLayout::CONS_EGRESS_RNG, u16);
#[inline]
pub fn mac(&self) -> HopFieldMac {
let mac: [u8; 6] = unsafe {
self.0
.get_unchecked(HopFieldLayout::MAC_RNG.aligned_byte_range())
.try_into()
.unwrap_unchecked()
};
HopFieldMac(mac)
}
#[inline]
pub fn ingress_interface(&self, info_field: &InfoFieldView) -> u16 {
if info_field.flags().contains(InfoFieldFlags::CONS_DIR) {
self.cons_ingress()
} else {
self.cons_egress()
}
}
#[inline]
pub fn egress_interface(&self, info_field: &InfoFieldView) -> u16 {
if info_field.flags().contains(InfoFieldFlags::CONS_DIR) {
self.cons_egress()
} else {
self.cons_ingress()
}
}
}
impl HopFieldView {
#[inline]
pub fn set_flags(&mut self, flags: HopFieldFlags) {
let value = flags.bits();
unsafe { unchecked_bit_range_be_write::<u8>(&mut self.0, HopFieldLayout::FLAGS_RNG, value) }
}
gen_field_write!(set_exp_time, HopFieldLayout::EXP_TIME_RNG, u8);
gen_field_write!(set_cons_ingress, HopFieldLayout::CONS_INGRESS_RNG, u16);
gen_field_write!(set_cons_egress, HopFieldLayout::CONS_EGRESS_RNG, u16);
#[inline]
pub fn set_mac(&mut self, mac: HopFieldMac) {
unsafe {
self.0
.get_unchecked_mut(HopFieldLayout::MAC_RNG.aligned_byte_range())
.copy_from_slice(&mac.0);
}
}
}
impl Debug for HopFieldView {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("StandardPathHopFieldView")
.field("flags", &self.flags())
.field("exp_time", &self.exp_time())
.field("cons_ingress", &self.cons_ingress())
.field("cons_egress", &self.cons_egress())
.field("mac", &self.mac())
.finish()
}
}
impl HopMacInputSource for HopFieldView {
#[inline]
fn get_mac_input(&self) -> HopMacInput {
HopMacInput {
exp_time: self.exp_time(),
cons_ingress: self.cons_ingress(),
cons_egress: self.cons_egress(),
}
}
}