use crate::error::PfcpError;
use crate::ie::gate_status::GateStatus;
use crate::ie::gbr::Gbr;
use crate::ie::mbr::Mbr;
use crate::ie::qer_correlation_id::QerCorrelationId;
use crate::ie::qer_id::QerId;
use crate::ie::{marshal_ies, Ie, IeIterator, IeType};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UpdateQer {
pub qer_id: QerId,
pub qer_correlation_id: Option<QerCorrelationId>,
pub gate_status: Option<GateStatus>,
pub mbr: Option<Mbr>,
pub gbr: Option<Gbr>,
}
impl UpdateQer {
pub fn new(
qer_id: QerId,
qer_correlation_id: Option<QerCorrelationId>,
gate_status: Option<GateStatus>,
mbr: Option<Mbr>,
gbr: Option<Gbr>,
) -> Self {
UpdateQer {
qer_id,
qer_correlation_id,
gate_status,
mbr,
gbr,
}
}
pub fn marshal(&self) -> Vec<u8> {
let mut ies = vec![self.qer_id.to_ie()];
if let Some(qer_corr_id) = &self.qer_correlation_id {
ies.push(Ie::new(
IeType::QerCorrelationId,
qer_corr_id.marshal().to_vec(),
));
}
if let Some(gate_status) = &self.gate_status {
ies.push(Ie::new(IeType::GateStatus, gate_status.marshal().to_vec()));
}
if let Some(mbr) = &self.mbr {
ies.push(Ie::new(IeType::Mbr, mbr.marshal().to_vec()));
}
if let Some(gbr) = &self.gbr {
ies.push(Ie::new(IeType::Gbr, gbr.marshal().to_vec()));
}
marshal_ies(&ies)
}
pub fn unmarshal(payload: &[u8]) -> Result<Self, PfcpError> {
let mut qer_id = None;
let mut qer_correlation_id = None;
let mut gate_status = None;
let mut mbr = None;
let mut gbr = None;
for ie_result in IeIterator::new(payload) {
let ie = ie_result?;
match ie.ie_type {
IeType::QerId => qer_id = Some(QerId::unmarshal(&ie.payload)?),
IeType::QerCorrelationId => {
qer_correlation_id = Some(QerCorrelationId::unmarshal(&ie.payload)?)
}
IeType::GateStatus => gate_status = Some(GateStatus::unmarshal(&ie.payload)?),
IeType::Mbr => mbr = Some(Mbr::unmarshal(&ie.payload)?),
IeType::Gbr => gbr = Some(Gbr::unmarshal(&ie.payload)?),
_ => (),
}
}
Ok(UpdateQer {
qer_id: qer_id.ok_or_else(|| {
PfcpError::missing_ie_in_grouped(IeType::QerId, IeType::UpdateQer)
})?,
qer_correlation_id,
gate_status,
mbr,
gbr,
})
}
pub fn to_ie(&self) -> Ie {
Ie::new(IeType::UpdateQer, self.marshal())
}
pub fn builder(qer_id: QerId) -> UpdateQerBuilder {
UpdateQerBuilder::new(qer_id)
}
}
#[derive(Debug, Default)]
pub struct UpdateQerBuilder {
qer_id: Option<QerId>,
qer_correlation_id: Option<QerCorrelationId>,
gate_status: Option<GateStatus>,
mbr: Option<Mbr>,
gbr: Option<Gbr>,
}
impl UpdateQerBuilder {
pub fn new(qer_id: QerId) -> Self {
UpdateQerBuilder {
qer_id: Some(qer_id),
..Default::default()
}
}
pub fn qer_correlation_id(mut self, qer_correlation_id: QerCorrelationId) -> Self {
self.qer_correlation_id = Some(qer_correlation_id);
self
}
pub fn gate_status(mut self, gate_status: GateStatus) -> Self {
self.gate_status = Some(gate_status);
self
}
pub fn mbr(mut self, mbr: Mbr) -> Self {
self.mbr = Some(mbr);
self
}
pub fn gbr(mut self, gbr: Gbr) -> Self {
self.gbr = Some(gbr);
self
}
pub fn rate_limit(mut self, uplink_bps: u64, downlink_bps: u64) -> Self {
self.mbr = Some(Mbr::new(uplink_bps, downlink_bps));
self
}
pub fn guaranteed_rate(mut self, uplink_bps: u64, downlink_bps: u64) -> Self {
self.gbr = Some(Gbr::new(uplink_bps, downlink_bps));
self
}
pub fn open_gate(qer_id: QerId) -> Self {
use crate::ie::gate_status::GateStatusValue;
UpdateQerBuilder::new(qer_id).gate_status(GateStatus::new(
GateStatusValue::Open,
GateStatusValue::Open,
))
}
pub fn closed_gate(qer_id: QerId) -> Self {
use crate::ie::gate_status::GateStatusValue;
UpdateQerBuilder::new(qer_id).gate_status(GateStatus::new(
GateStatusValue::Closed,
GateStatusValue::Closed,
))
}
pub fn uplink_only(qer_id: QerId) -> Self {
use crate::ie::gate_status::GateStatusValue;
UpdateQerBuilder::new(qer_id).gate_status(GateStatus::new(
GateStatusValue::Closed, GateStatusValue::Open, ))
}
pub fn downlink_only(qer_id: QerId) -> Self {
use crate::ie::gate_status::GateStatusValue;
UpdateQerBuilder::new(qer_id).gate_status(GateStatus::new(
GateStatusValue::Open, GateStatusValue::Closed, ))
}
pub fn build(self) -> Result<UpdateQer, PfcpError> {
let qer_id = self.qer_id.ok_or_else(|| {
PfcpError::validation_error("UpdateQerBuilder", "qer_id", "QER ID is required")
})?;
Ok(UpdateQer {
qer_id,
qer_correlation_id: self.qer_correlation_id,
gate_status: self.gate_status,
mbr: self.mbr,
gbr: self.gbr,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ie::gate_status::GateStatusValue;
#[test]
fn test_update_qer_builder_basic() {
let qer = UpdateQerBuilder::new(QerId::new(1))
.gate_status(GateStatus::new(
GateStatusValue::Open,
GateStatusValue::Open,
))
.build()
.unwrap();
assert_eq!(qer.qer_id, QerId::new(1));
assert!(qer.gate_status.is_some());
assert!(qer.mbr.is_none());
assert!(qer.gbr.is_none());
}
#[test]
fn test_update_qer_builder_with_rate_limits() {
let qer = UpdateQerBuilder::new(QerId::new(2))
.rate_limit(1000000, 2000000)
.build()
.unwrap();
assert_eq!(qer.qer_id, QerId::new(2));
assert!(qer.mbr.is_some());
let mbr = qer.mbr.unwrap();
assert_eq!(mbr.uplink, 1000000);
assert_eq!(mbr.downlink, 2000000);
}
#[test]
fn test_update_qer_builder_with_guaranteed_rate() {
let qer = UpdateQerBuilder::new(QerId::new(3))
.guaranteed_rate(500000, 1000000)
.build()
.unwrap();
assert_eq!(qer.qer_id, QerId::new(3));
assert!(qer.gbr.is_some());
let gbr = qer.gbr.unwrap();
assert_eq!(gbr.uplink, 500000);
assert_eq!(gbr.downlink, 1000000);
}
#[test]
fn test_update_qer_builder_comprehensive() {
let qer = UpdateQerBuilder::new(QerId::new(4))
.qer_correlation_id(QerCorrelationId::new(42))
.gate_status(GateStatus::new(
GateStatusValue::Open,
GateStatusValue::Open,
))
.rate_limit(2000000, 4000000)
.guaranteed_rate(1000000, 2000000)
.build()
.unwrap();
assert_eq!(qer.qer_id, QerId::new(4));
assert!(qer.qer_correlation_id.is_some());
assert!(qer.gate_status.is_some());
assert!(qer.mbr.is_some());
assert!(qer.gbr.is_some());
}
#[test]
fn test_update_qer_builder_open_gate() {
let qer = UpdateQerBuilder::open_gate(QerId::new(5))
.build()
.expect("Failed to build open_gate update QER");
assert_eq!(qer.qer_id, QerId::new(5));
assert!(qer.gate_status.is_some());
let gate = qer.gate_status.unwrap();
assert_eq!(gate.uplink_gate, GateStatusValue::Open);
assert_eq!(gate.downlink_gate, GateStatusValue::Open);
}
#[test]
fn test_update_qer_builder_closed_gate() {
let qer = UpdateQerBuilder::closed_gate(QerId::new(6))
.build()
.unwrap();
assert_eq!(qer.qer_id, QerId::new(6));
assert!(qer.gate_status.is_some());
let gate = qer.gate_status.unwrap();
assert_eq!(gate.uplink_gate, GateStatusValue::Closed);
assert_eq!(gate.downlink_gate, GateStatusValue::Closed);
}
#[test]
fn test_update_qer_builder_uplink_only() {
let qer = UpdateQerBuilder::uplink_only(QerId::new(7))
.build()
.unwrap();
assert_eq!(qer.qer_id, QerId::new(7));
assert!(qer.gate_status.is_some());
let gate = qer.gate_status.unwrap();
assert_eq!(gate.uplink_gate, GateStatusValue::Open);
assert_eq!(gate.downlink_gate, GateStatusValue::Closed);
}
#[test]
fn test_update_qer_builder_downlink_only() {
let qer = UpdateQerBuilder::downlink_only(QerId::new(8))
.build()
.unwrap();
assert_eq!(qer.qer_id, QerId::new(8));
assert!(qer.gate_status.is_some());
let gate = qer.gate_status.unwrap();
assert_eq!(gate.uplink_gate, GateStatusValue::Closed);
assert_eq!(gate.downlink_gate, GateStatusValue::Open);
}
#[test]
fn test_update_qer_builder_method() {
let qer = UpdateQer::builder(QerId::new(9))
.gate_status(GateStatus::new(
GateStatusValue::Open,
GateStatusValue::Open,
))
.build()
.unwrap();
assert_eq!(qer.qer_id, QerId::new(9));
assert!(qer.gate_status.is_some());
}
#[test]
fn test_update_qer_builder_round_trip_marshal() {
let qer = UpdateQerBuilder::new(QerId::new(10))
.rate_limit(3000000, 5000000)
.gate_status(GateStatus::new(
GateStatusValue::Open,
GateStatusValue::Open,
))
.build()
.unwrap();
let marshaled = qer.marshal();
let unmarshaled = UpdateQer::unmarshal(&marshaled).unwrap();
assert_eq!(qer, unmarshaled);
}
#[test]
fn test_update_qer_builder_with_mbr_and_gbr() {
let qer = UpdateQerBuilder::new(QerId::new(11))
.mbr(Mbr::new(4000000, 6000000))
.gbr(Gbr::new(2000000, 3000000))
.build()
.unwrap();
assert_eq!(qer.qer_id, QerId::new(11));
assert!(qer.mbr.is_some());
assert!(qer.gbr.is_some());
let marshaled = qer.marshal();
let unmarshaled = UpdateQer::unmarshal(&marshaled).unwrap();
assert_eq!(qer, unmarshaled);
}
#[test]
fn test_update_qer_builder_chain_all_methods() {
let qer = UpdateQerBuilder::new(QerId::new(12))
.qer_correlation_id(QerCorrelationId::new(99))
.gate_status(GateStatus::new(
GateStatusValue::Closed,
GateStatusValue::Closed,
))
.rate_limit(1500000, 2500000)
.guaranteed_rate(750000, 1250000)
.build()
.unwrap();
assert_eq!(qer.qer_id, QerId::new(12));
assert_eq!(qer.qer_correlation_id, Some(QerCorrelationId::new(99)));
assert!(qer.gate_status.is_some());
assert!(qer.mbr.is_some());
assert!(qer.gbr.is_some());
let marshaled = qer.marshal();
let unmarshaled = UpdateQer::unmarshal(&marshaled).unwrap();
assert_eq!(qer, unmarshaled);
}
}