use crate::error::PfcpError;
use crate::ie::{Ie, IeType};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PacketDelayThresholds {
pub dl_threshold: Option<u32>,
pub ul_threshold: Option<u32>,
pub rp_threshold: Option<u32>,
}
impl PacketDelayThresholds {
pub fn new(dl: Option<u32>, ul: Option<u32>, rp: Option<u32>) -> Self {
Self {
dl_threshold: dl,
ul_threshold: ul,
rp_threshold: rp,
}
}
pub fn marshal(&self) -> Vec<u8> {
let mut flags = 0u8;
if self.dl_threshold.is_some() {
flags |= 0x01;
}
if self.ul_threshold.is_some() {
flags |= 0x02;
}
if self.rp_threshold.is_some() {
flags |= 0x04;
}
let mut data = vec![flags];
if let Some(v) = self.dl_threshold {
data.extend_from_slice(&v.to_be_bytes());
}
if let Some(v) = self.ul_threshold {
data.extend_from_slice(&v.to_be_bytes());
}
if let Some(v) = self.rp_threshold {
data.extend_from_slice(&v.to_be_bytes());
}
data
}
pub fn unmarshal(data: &[u8]) -> Result<Self, PfcpError> {
if data.is_empty() {
return Err(PfcpError::invalid_length(
"Packet Delay Thresholds",
IeType::PacketDelayThresholds,
1,
0,
));
}
let flags = data[0];
let dl_flag = (flags & 0x01) != 0;
let ul_flag = (flags & 0x02) != 0;
let rp_flag = (flags & 0x04) != 0;
let expected = 1 + (dl_flag as usize * 4) + (ul_flag as usize * 4) + (rp_flag as usize * 4);
if data.len() < expected {
return Err(PfcpError::invalid_length(
"Packet Delay Thresholds",
IeType::PacketDelayThresholds,
expected,
data.len(),
));
}
let mut offset = 1;
let dl_threshold = if dl_flag {
let v = u32::from_be_bytes(data[offset..offset + 4].try_into().unwrap());
offset += 4;
Some(v)
} else {
None
};
let ul_threshold = if ul_flag {
let v = u32::from_be_bytes(data[offset..offset + 4].try_into().unwrap());
offset += 4;
Some(v)
} else {
None
};
let rp_threshold = if rp_flag {
Some(u32::from_be_bytes(
data[offset..offset + 4].try_into().unwrap(),
))
} else {
None
};
Ok(Self {
dl_threshold,
ul_threshold,
rp_threshold,
})
}
pub fn to_ie(&self) -> Ie {
Ie::new(IeType::PacketDelayThresholds, self.marshal())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_marshal_unmarshal_all_flags() {
let ie = PacketDelayThresholds::new(Some(100), Some(200), Some(300));
let parsed = PacketDelayThresholds::unmarshal(&ie.marshal()).unwrap();
assert_eq!(parsed, ie);
}
#[test]
fn test_marshal_unmarshal_dl_only() {
let ie = PacketDelayThresholds::new(Some(50), None, None);
let parsed = PacketDelayThresholds::unmarshal(&ie.marshal()).unwrap();
assert_eq!(parsed, ie);
}
#[test]
fn test_marshal_unmarshal_no_flags() {
let ie = PacketDelayThresholds::new(None, None, None);
let parsed = PacketDelayThresholds::unmarshal(&ie.marshal()).unwrap();
assert_eq!(parsed, ie);
}
#[test]
fn test_marshal_byte_layout() {
let ie = PacketDelayThresholds::new(Some(1), None, None);
let data = ie.marshal();
assert_eq!(data[0], 0x01); assert_eq!(data.len(), 5);
}
#[test]
fn test_unmarshal_empty() {
assert!(matches!(
PacketDelayThresholds::unmarshal(&[]),
Err(PfcpError::InvalidLength { .. })
));
}
#[test]
fn test_unmarshal_short_with_flag() {
assert!(matches!(
PacketDelayThresholds::unmarshal(&[0x01]),
Err(PfcpError::InvalidLength { .. })
));
}
#[test]
fn test_to_ie() {
let ie = PacketDelayThresholds::new(Some(10), Some(20), None).to_ie();
assert_eq!(ie.ie_type, IeType::PacketDelayThresholds);
}
}