1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! Remove BAR IE implementation.
//!
//! Per 3GPP TS 29.244 Section 8.2.89, the Remove BAR IE is used to remove
//! a Buffering Action Rule from a PFCP session.
use crate::error::PfcpError;
use crate::ie::bar_id::BarId;
use crate::ie::{Ie, IeType};
/// Remove BAR Information Element.
///
/// Used in PFCP Session Modification Request to remove an existing
/// Buffering Action Rule identified by BAR ID.
///
/// # Structure (per 3GPP TS 29.244)
/// ```text
/// +-----------+
/// | BAR ID | (1 byte)
/// +-----------+
/// ```
///
/// # Example
/// ```
/// use rs_pfcp::ie::remove_bar::RemoveBar;
/// use rs_pfcp::ie::bar_id::BarId;
///
/// let remove_bar = RemoveBar::new(BarId::new(42));
/// let marshaled = remove_bar.marshal();
/// let unmarshaled = RemoveBar::unmarshal(&marshaled).unwrap();
/// assert_eq!(remove_bar, unmarshaled);
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RemoveBar {
/// BAR ID of the Buffering Action Rule to remove
pub bar_id: BarId,
}
impl RemoveBar {
/// Creates a new Remove BAR IE.
///
/// # Arguments
/// * `bar_id` - The BAR ID to remove
///
/// # Example
/// ```
/// use rs_pfcp::ie::remove_bar::RemoveBar;
/// use rs_pfcp::ie::bar_id::BarId;
///
/// let remove_bar = RemoveBar::new(BarId::new(1));
/// ```
pub fn new(bar_id: BarId) -> Self {
RemoveBar { bar_id }
}
/// Marshals the Remove BAR IE to bytes.
///
/// # Returns
/// A vector containing the serialized BAR ID (1 byte).
pub fn marshal(&self) -> Vec<u8> {
self.bar_id.marshal().to_vec()
}
/// Converts to a generic IE.
///
/// # Returns
/// An `Ie` with type `RemoveBar` and the marshaled payload.
pub fn to_ie(self) -> Ie {
Ie::new(IeType::RemoveBar, self.marshal())
}
/// Unmarshals a Remove BAR IE from bytes.
///
/// # Arguments
/// * `data` - The byte slice containing the BAR ID
///
/// # Returns
/// A `RemoveBar` instance or an error if unmarshaling fails.
///
/// # Errors
/// Returns `PfcpError` if:
/// - The buffer is too short (< 1 byte)
/// - The BAR ID cannot be parsed
pub fn unmarshal(data: &[u8]) -> Result<Self, PfcpError> {
Ok(RemoveBar {
bar_id: BarId::unmarshal(data)?,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_remove_bar_new() {
let bar_id = BarId::new(42);
let remove_bar = RemoveBar::new(bar_id.clone());
assert_eq!(remove_bar.bar_id, bar_id);
}
#[test]
fn test_remove_bar_marshal_unmarshal() {
let remove_bar = RemoveBar::new(BarId::new(123));
let marshaled = remove_bar.marshal();
assert_eq!(marshaled, vec![123]);
let unmarshaled = RemoveBar::unmarshal(&marshaled).unwrap();
assert_eq!(remove_bar, unmarshaled);
}
#[test]
fn test_remove_bar_round_trip() {
let original = RemoveBar::new(BarId::new(255));
let marshaled = original.marshal();
let unmarshaled = RemoveBar::unmarshal(&marshaled).unwrap();
assert_eq!(original, unmarshaled);
}
#[test]
fn test_remove_bar_to_ie() {
let ie = RemoveBar::new(BarId::new(100)).to_ie();
assert_eq!(ie.ie_type, IeType::RemoveBar);
assert_eq!(ie.payload.len(), 1);
assert_eq!(ie.payload[0], 100);
}
#[test]
fn test_remove_bar_unmarshal_empty_buffer() {
// Empty payload
assert!(RemoveBar::unmarshal(&[]).is_err());
}
#[test]
fn test_remove_bar_edge_cases() {
// Zero value
let remove_bar = RemoveBar::new(BarId::new(0));
let marshaled = remove_bar.marshal();
let unmarshaled = RemoveBar::unmarshal(&marshaled).unwrap();
assert_eq!(remove_bar, unmarshaled);
// Max value (u8::MAX = 255)
let remove_bar = RemoveBar::new(BarId::new(255));
let marshaled = remove_bar.marshal();
let unmarshaled = RemoveBar::unmarshal(&marshaled).unwrap();
assert_eq!(remove_bar, unmarshaled);
}
}