Skip to main content

rs_pfcp/
types.rs

1//! Type-safe newtype wrappers for PFCP protocol identifiers.
2//!
3//! This module provides newtype wrappers that prevent accidental argument swapping
4//! at compile time. For example, mixing up `seid` and `sequence_number` parameters
5//! is a common source of bugs that these types eliminate.
6//!
7//! # Types
8//!
9//! - [`Seid`] - Session Endpoint Identifier (64-bit)
10//! - [`SequenceNumber`] - Message sequence number (24-bit, stored as u32)
11//! - [`Teid`] - Tunnel Endpoint Identifier (32-bit)
12//!
13//! # Examples
14//!
15//! ```rust
16//! use rs_pfcp::types::{Seid, SequenceNumber, Teid};
17//!
18//! // Create from primitives
19//! let seid = Seid(0x123456789ABCDEF0);
20//! let seq = SequenceNumber::new(42);
21//! let teid = Teid(0x12345678);
22//!
23//! // Convert back to primitives
24//! let seid_val: u64 = seid.into();
25//! let seq_val: u32 = seq.into();
26//! let teid_val: u32 = teid.into();
27//!
28//! // Use From trait
29//! let seid2: Seid = 100u64.into();
30//! let seq2: SequenceNumber = 50u32.into();
31//! let teid2: Teid = 200u32.into();
32//!
33//! // Access inner value via Deref
34//! assert_eq!(*seid, 0x123456789ABCDEF0u64);
35//! ```
36
37use std::fmt;
38use std::ops::Deref;
39
40// ============================================================================
41// Seid - Session Endpoint Identifier
42// ============================================================================
43
44/// Session Endpoint Identifier (SEID) - 64-bit identifier.
45///
46/// The SEID uniquely identifies a PFCP session on a given node.
47/// Per 3GPP TS 29.244, the SEID is present in session-related messages
48/// to identify the PFCP session context.
49///
50/// # Examples
51///
52/// ```rust
53/// use rs_pfcp::types::Seid;
54///
55/// let seid = Seid(0x123456789ABCDEF0);
56/// assert_eq!(*seid, 0x123456789ABCDEF0);
57///
58/// // From/Into conversions
59/// let seid: Seid = 42u64.into();
60/// let value: u64 = seid.into();
61/// assert_eq!(value, 42);
62/// ```
63#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
64pub struct Seid(pub u64);
65
66impl Seid {
67    /// Creates a new SEID with the given value.
68    #[inline]
69    pub const fn new(value: u64) -> Self {
70        Self(value)
71    }
72
73    /// Returns the inner u64 value.
74    #[inline]
75    pub const fn value(&self) -> u64 {
76        self.0
77    }
78}
79
80impl From<u64> for Seid {
81    #[inline]
82    fn from(value: u64) -> Self {
83        Self(value)
84    }
85}
86
87impl From<Seid> for u64 {
88    #[inline]
89    fn from(seid: Seid) -> Self {
90        seid.0
91    }
92}
93
94impl Deref for Seid {
95    type Target = u64;
96
97    #[inline]
98    fn deref(&self) -> &Self::Target {
99        &self.0
100    }
101}
102
103impl fmt::Display for Seid {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        write!(f, "0x{:016X}", self.0)
106    }
107}
108
109impl fmt::LowerHex for Seid {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        fmt::LowerHex::fmt(&self.0, f)
112    }
113}
114
115impl fmt::UpperHex for Seid {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        fmt::UpperHex::fmt(&self.0, f)
118    }
119}
120
121// ============================================================================
122// SequenceNumber - 24-bit Message Sequence Number
123// ============================================================================
124
125/// Sequence Number - 24-bit message sequence number (stored as u32).
126///
127/// Per 3GPP TS 29.244 Section 5.1, the sequence number is a 24-bit field
128/// used to match request and response messages. Valid range: 0 to 0x00FFFFFF.
129///
130/// # Examples
131///
132/// ```rust
133/// use rs_pfcp::types::SequenceNumber;
134///
135/// // Create with masking to 24 bits
136/// let seq = SequenceNumber::new(0x123456);
137/// assert_eq!(*seq, 0x123456);
138///
139/// // Values larger than 24 bits are masked
140/// let seq = SequenceNumber::new(0xFF123456);
141/// assert_eq!(*seq, 0x123456);
142///
143/// // Increment with wrap-around
144/// let seq = SequenceNumber::new(SequenceNumber::MAX);
145/// let next = seq.next();
146/// assert_eq!(*next, 0);
147/// ```
148#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
149pub struct SequenceNumber(pub u32);
150
151impl SequenceNumber {
152    /// Maximum value for a 24-bit sequence number.
153    pub const MAX: u32 = 0x00FFFFFF;
154
155    /// Creates a new sequence number, masking to 24 bits.
156    #[inline]
157    pub const fn new(value: u32) -> Self {
158        Self(value & Self::MAX)
159    }
160
161    /// Returns the inner u32 value.
162    #[inline]
163    pub const fn value(&self) -> u32 {
164        self.0
165    }
166
167    /// Returns the next sequence number with wrap-around at MAX.
168    ///
169    /// # Examples
170    ///
171    /// ```rust
172    /// use rs_pfcp::types::SequenceNumber;
173    ///
174    /// let seq = SequenceNumber::new(100);
175    /// assert_eq!(*seq.next(), 101);
176    ///
177    /// let max_seq = SequenceNumber::new(SequenceNumber::MAX);
178    /// assert_eq!(*max_seq.next(), 0);
179    /// ```
180    #[inline]
181    pub const fn next(&self) -> Self {
182        Self((self.0 + 1) & Self::MAX)
183    }
184
185    /// Checks if this sequence number is within a valid 24-bit range.
186    ///
187    /// Always returns true since the constructor masks to 24 bits.
188    #[inline]
189    pub const fn is_valid(&self) -> bool {
190        self.0 <= Self::MAX
191    }
192}
193
194impl From<u32> for SequenceNumber {
195    #[inline]
196    fn from(value: u32) -> Self {
197        Self::new(value)
198    }
199}
200
201impl From<SequenceNumber> for u32 {
202    #[inline]
203    fn from(seq: SequenceNumber) -> Self {
204        seq.0
205    }
206}
207
208impl Deref for SequenceNumber {
209    type Target = u32;
210
211    #[inline]
212    fn deref(&self) -> &Self::Target {
213        &self.0
214    }
215}
216
217impl fmt::Display for SequenceNumber {
218    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219        write!(f, "{}", self.0)
220    }
221}
222
223// ============================================================================
224// Teid - Tunnel Endpoint Identifier
225// ============================================================================
226
227/// Tunnel Endpoint Identifier (TEID) - 32-bit identifier.
228///
229/// The TEID identifies a GTP-U tunnel endpoint. It is used in F-TEID IEs
230/// to specify tunnel endpoints for user plane data forwarding.
231///
232/// # Examples
233///
234/// ```rust
235/// use rs_pfcp::types::Teid;
236///
237/// let teid = Teid(0x12345678);
238/// assert_eq!(*teid, 0x12345678);
239///
240/// // From/Into conversions
241/// let teid: Teid = 42u32.into();
242/// let value: u32 = teid.into();
243/// assert_eq!(value, 42);
244/// ```
245#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
246pub struct Teid(pub u32);
247
248impl Teid {
249    /// Creates a new TEID with the given value.
250    #[inline]
251    pub const fn new(value: u32) -> Self {
252        Self(value)
253    }
254
255    /// Returns the inner u32 value.
256    #[inline]
257    pub const fn value(&self) -> u32 {
258        self.0
259    }
260}
261
262impl From<u32> for Teid {
263    #[inline]
264    fn from(value: u32) -> Self {
265        Self(value)
266    }
267}
268
269impl From<Teid> for u32 {
270    #[inline]
271    fn from(teid: Teid) -> Self {
272        teid.0
273    }
274}
275
276impl Deref for Teid {
277    type Target = u32;
278
279    #[inline]
280    fn deref(&self) -> &Self::Target {
281        &self.0
282    }
283}
284
285impl fmt::Display for Teid {
286    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287        write!(f, "0x{:08X}", self.0)
288    }
289}
290
291impl fmt::LowerHex for Teid {
292    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293        fmt::LowerHex::fmt(&self.0, f)
294    }
295}
296
297impl fmt::UpperHex for Teid {
298    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299        fmt::UpperHex::fmt(&self.0, f)
300    }
301}
302
303// ============================================================================
304// Tests
305// ============================================================================
306
307#[cfg(test)]
308mod tests {
309    use super::*;
310
311    // Seid tests
312    mod seid_tests {
313        use super::*;
314
315        #[test]
316        fn test_seid_new() {
317            let seid = Seid::new(0x123456789ABCDEF0);
318            assert_eq!(seid.value(), 0x123456789ABCDEF0);
319        }
320
321        #[test]
322        fn test_seid_default() {
323            let seid = Seid::default();
324            assert_eq!(*seid, 0);
325        }
326
327        #[test]
328        fn test_seid_from_u64() {
329            let seid: Seid = 42u64.into();
330            assert_eq!(*seid, 42);
331        }
332
333        #[test]
334        fn test_seid_into_u64() {
335            let seid = Seid(100);
336            let value: u64 = seid.into();
337            assert_eq!(value, 100);
338        }
339
340        #[test]
341        fn test_seid_deref() {
342            let seid = Seid(0xDEADBEEF);
343            assert_eq!(*seid, 0xDEADBEEF);
344        }
345
346        #[test]
347        fn test_seid_display() {
348            let seid = Seid(0x123456789ABCDEF0);
349            assert_eq!(format!("{}", seid), "0x123456789ABCDEF0");
350        }
351
352        #[test]
353        fn test_seid_equality() {
354            let seid1 = Seid(100);
355            let seid2 = Seid(100);
356            let seid3 = Seid(200);
357            assert_eq!(seid1, seid2);
358            assert_ne!(seid1, seid3);
359        }
360
361        #[test]
362        fn test_seid_clone() {
363            let seid = Seid(42);
364            let cloned = seid;
365            assert_eq!(seid, cloned);
366        }
367
368        #[test]
369        fn test_seid_hash() {
370            use std::collections::HashSet;
371            let mut set = HashSet::new();
372            set.insert(Seid(1));
373            set.insert(Seid(2));
374            set.insert(Seid(1));
375            assert_eq!(set.len(), 2);
376        }
377    }
378
379    // SequenceNumber tests
380    mod sequence_number_tests {
381        use super::*;
382
383        #[test]
384        fn test_sequence_number_new() {
385            let seq = SequenceNumber::new(42);
386            assert_eq!(seq.value(), 42);
387        }
388
389        #[test]
390        fn test_sequence_number_max() {
391            assert_eq!(SequenceNumber::MAX, 0x00FFFFFF);
392        }
393
394        #[test]
395        fn test_sequence_number_masking() {
396            let seq = SequenceNumber::new(0xFF123456);
397            assert_eq!(*seq, 0x123456);
398        }
399
400        #[test]
401        fn test_sequence_number_default() {
402            let seq = SequenceNumber::default();
403            assert_eq!(*seq, 0);
404        }
405
406        #[test]
407        fn test_sequence_number_next() {
408            let seq = SequenceNumber::new(100);
409            assert_eq!(*seq.next(), 101);
410        }
411
412        #[test]
413        fn test_sequence_number_next_wrap() {
414            let seq = SequenceNumber::new(SequenceNumber::MAX);
415            assert_eq!(*seq.next(), 0);
416        }
417
418        #[test]
419        fn test_sequence_number_from_u32() {
420            let seq: SequenceNumber = 50u32.into();
421            assert_eq!(*seq, 50);
422        }
423
424        #[test]
425        fn test_sequence_number_into_u32() {
426            let seq = SequenceNumber::new(75);
427            let value: u32 = seq.into();
428            assert_eq!(value, 75);
429        }
430
431        #[test]
432        fn test_sequence_number_deref() {
433            let seq = SequenceNumber::new(999);
434            assert_eq!(*seq, 999);
435        }
436
437        #[test]
438        fn test_sequence_number_display() {
439            let seq = SequenceNumber::new(12345);
440            assert_eq!(format!("{}", seq), "12345");
441        }
442
443        #[test]
444        fn test_sequence_number_ordering() {
445            let seq1 = SequenceNumber::new(10);
446            let seq2 = SequenceNumber::new(20);
447            assert!(seq1 < seq2);
448            assert!(seq2 > seq1);
449        }
450
451        #[test]
452        fn test_sequence_number_is_valid() {
453            let seq = SequenceNumber::new(100);
454            assert!(seq.is_valid());
455
456            let seq_max = SequenceNumber::new(SequenceNumber::MAX);
457            assert!(seq_max.is_valid());
458        }
459    }
460
461    // Teid tests
462    mod teid_tests {
463        use super::*;
464
465        #[test]
466        fn test_teid_new() {
467            let teid = Teid::new(0x12345678);
468            assert_eq!(teid.value(), 0x12345678);
469        }
470
471        #[test]
472        fn test_teid_default() {
473            let teid = Teid::default();
474            assert_eq!(*teid, 0);
475        }
476
477        #[test]
478        fn test_teid_from_u32() {
479            let teid: Teid = 42u32.into();
480            assert_eq!(*teid, 42);
481        }
482
483        #[test]
484        fn test_teid_into_u32() {
485            let teid = Teid(100);
486            let value: u32 = teid.into();
487            assert_eq!(value, 100);
488        }
489
490        #[test]
491        fn test_teid_deref() {
492            let teid = Teid(0xDEADBEEF);
493            assert_eq!(*teid, 0xDEADBEEF);
494        }
495
496        #[test]
497        fn test_teid_display() {
498            let teid = Teid(0x12345678);
499            assert_eq!(format!("{}", teid), "0x12345678");
500        }
501
502        #[test]
503        fn test_teid_equality() {
504            let teid1 = Teid(100);
505            let teid2 = Teid(100);
506            let teid3 = Teid(200);
507            assert_eq!(teid1, teid2);
508            assert_ne!(teid1, teid3);
509        }
510
511        #[test]
512        fn test_teid_clone() {
513            let teid = Teid(42);
514            let cloned = teid;
515            assert_eq!(teid, cloned);
516        }
517
518        #[test]
519        fn test_teid_hash() {
520            use std::collections::HashSet;
521            let mut set = HashSet::new();
522            set.insert(Teid(1));
523            set.insert(Teid(2));
524            set.insert(Teid(1));
525            assert_eq!(set.len(), 2);
526        }
527    }
528}