use std::{fmt::Debug, mem::transmute};
use crate::{
core::view::{View, ViewConversionError},
path::{
onehop::layout::OneHopPathLayout,
standard::{
mac::{ForwardingKey, HopMacCalculate, algo::mac_beta_step},
view::{HopFieldView, InfoFieldView},
},
},
};
#[repr(transparent)]
pub struct OneHopPathView([u8; OneHopPathLayout::SIZE_BYTES]);
impl OneHopPathView {
#[inline]
pub fn info_field(&self) -> &InfoFieldView {
unsafe {
InfoFieldView::from_slice_unchecked(
&self.0[OneHopPathLayout::INFO_FIELD.aligned_byte_range()],
)
}
}
#[inline]
pub fn info_field_mut(&mut self) -> &mut InfoFieldView {
unsafe {
InfoFieldView::from_mut_slice_unchecked(
&mut self.0[OneHopPathLayout::INFO_FIELD.aligned_byte_range()],
)
}
}
#[inline]
pub fn hop_fields(&self) -> [&HopFieldView; 2] {
unsafe {
[
HopFieldView::from_slice_unchecked(
&self.0[OneHopPathLayout::HOP_FIELD_1.aligned_byte_range()],
),
HopFieldView::from_slice_unchecked(
&self.0[OneHopPathLayout::HOP_FIELD_2.aligned_byte_range()],
),
]
}
}
#[inline]
pub fn mut_hop_fields(&mut self) -> [&mut HopFieldView; 2] {
unsafe {
let [hop1, hop2] = self.0.get_disjoint_unchecked_mut([
OneHopPathLayout::HOP_FIELD_1.aligned_byte_range(),
OneHopPathLayout::HOP_FIELD_2.aligned_byte_range(),
]);
[
HopFieldView::from_mut_slice_unchecked(hop1),
HopFieldView::from_mut_slice_unchecked(hop2),
]
}
}
}
impl OneHopPathView {
pub fn set_second_hop(
&mut self,
ingress_interface: u16,
forwarding_key: ForwardingKey,
segment_id_was_advanced: bool,
) {
let (beta, timestamp) = {
let info = self.info_field();
let beta = if segment_id_was_advanced {
info.segment_id()
} else {
mac_beta_step(info.segment_id(), self.hop_fields()[0].mac().into())
};
(beta, info.timestamp())
};
let [hop1, hop2] = self.mut_hop_fields();
hop2.set_cons_ingress(ingress_interface);
hop2.set_cons_ingress(ingress_interface);
hop2.set_cons_egress(0);
hop2.set_cons_ingress(ingress_interface);
hop2.set_exp_time(hop1.exp_time());
let mac = hop2.calculate_mac(beta, timestamp, &forwarding_key);
hop2.set_mac(mac);
}
}
impl Debug for OneHopPathView {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OneHopPathView")
.field("info_field", &self.info_field())
.field("hop_fields", &self.hop_fields())
.finish()
}
}
impl View for OneHopPathView {
fn has_required_size(buf: &[u8]) -> Result<usize, ViewConversionError> {
use crate::core::layout::Layout;
let layout = OneHopPathLayout::try_from(buf)?;
Ok(layout.size_bytes())
}
fn as_bytes(&self) -> &[u8] {
&self.0
}
unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
&mut self.0
}
fn as_bytes_boxed(self: Box<Self>) -> Box<[u8]> {
let sized: Box<[u8; OneHopPathLayout::SIZE_BYTES]> = unsafe { transmute(self) };
sized
}
unsafe fn from_slice_unchecked(buf: &[u8]) -> &Self {
let sized: &[u8; OneHopPathLayout::SIZE_BYTES] =
unsafe { buf.try_into().unwrap_unchecked() };
unsafe { transmute(sized) }
}
unsafe fn from_mut_slice_unchecked(buf: &mut [u8]) -> &mut Self {
let sized: &mut [u8; OneHopPathLayout::SIZE_BYTES] =
unsafe { buf.try_into().unwrap_unchecked() };
unsafe { transmute(sized) }
}
unsafe fn from_boxed_unchecked(buf: Box<[u8]>) -> Box<Self> {
let sized: Box<[u8; OneHopPathLayout::SIZE_BYTES]> =
unsafe { buf.try_into().unwrap_unchecked() };
unsafe { transmute(sized) }
}
}