inetnum/
asn.rs

1//! Types for Autonomous Systems Numbers (ASN) and ASN collections
2
3use std::cmp::Ordering;
4use std::convert::TryInto;
5use std::iter::Peekable;
6use std::str::FromStr;
7use std::{error, fmt, iter, ops, slice};
8
9//------------ Asn -----------------------------------------------------------
10
11/// An AS number (ASN).
12#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
13#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
14#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
15#[repr(transparent)]
16pub struct Asn(u32);
17
18impl Asn {
19    pub const MIN: Asn = Asn(u32::MIN);
20    pub const MAX: Asn = Asn(u32::MAX);
21
22    /// Creates an AS number from a `u32`.
23    pub fn from_u32(value: u32) -> Self {
24        Asn(value)
25    }
26
27    /// Converts an AS number into a `u32`.
28    pub fn into_u32(self) -> u32 {
29        self.0
30    }
31
32    /// Try to convert a 4-octet AS number into a `u16`.
33    pub fn try_into_u16(self) -> Result<u16, LargeAsnError> {
34        self.0.try_into().map_err(|_| LargeAsnError)
35    }
36
37    /// Try to convert a 4-octet AS number into a 2-octet `Asn16`.
38    pub fn try_into_asn16(self) -> Result<Asn16, LargeAsnError> {
39        Ok(Asn16(self.try_into_u16()?))
40    }
41
42    /// Converts an AS number into a network-order byte array.
43    pub fn to_raw(self) -> [u8; 4] {
44        self.0.to_be_bytes()
45    }
46
47    #[cfg(feature = "octseq")]
48    pub fn compose<Target: octseq::OctetsBuilder>(
49        self,
50        target: &mut Target,
51    ) -> Result<(), Target::AppendError> {
52        target.append_slice(&self.to_raw())
53    }
54
55    // XXX or do we want this?
56    // possibly returning LargeAsnError in addition to AppendError?
57    //pub fn compose_16<Target: OctetsBuilder>(
58    //    self, target: &mut Target
59    //) -> Result<(), Target::AppendError> {
60    //    todo!()
61    //}
62}
63
64//--- From
65
66impl From<u32> for Asn {
67    fn from(id: u32) -> Self {
68        Asn(id)
69    }
70}
71
72impl From<Asn> for u32 {
73    fn from(id: Asn) -> Self {
74        id.0
75    }
76}
77
78//--- FromStr
79
80impl FromStr for Asn {
81    type Err = ParseAsnError;
82
83    fn from_str(s: &str) -> Result<Self, Self::Err> {
84        let s = if s.len() > 2 && s[..2].eq_ignore_ascii_case("as") {
85            &s[2..]
86        } else {
87            s
88        };
89
90        u32::from_str(s).map(Asn).map_err(|_| ParseAsnError)
91    }
92}
93
94//--- Serialize and Deserialize
95
96/// # Serialization
97///
98/// With the `"serde"` feature enabled, `Asn` implements the `Serialize` and
99/// `Deserialize` traits via _serde-derive_ as a newtype wrapping a `u32`.
100///
101/// However, ASNs are often serialized as a string prefix with `AS`. In order
102/// to allow this, a number of methods are provided that can be used with
103/// Serde’s field attributes to choose how to serialize an ASN as part of a
104/// struct.
105#[cfg(feature = "serde")]
106impl Asn {
107    /// Serializes an AS number as a simple `u32`.
108    ///
109    /// Normally, you wouldn’t need to use this method, as the default
110    /// implementation serializes the ASN as a newtype struct with a `u32`
111    /// inside which most serialization formats will turn into a sole `u32`.
112    /// However, in case your format doesn’t, you can use this method.
113    pub fn serialize_as_u32<S: serde::Serializer>(
114        &self,
115        serializer: S,
116    ) -> Result<S::Ok, S::Error> {
117        serializer.serialize_u32(self.0)
118    }
119
120    /// Serializes an AS number as a string without prefix.
121    pub fn serialize_as_bare_str<S: serde::Serializer>(
122        &self,
123        serializer: S,
124    ) -> Result<S::Ok, S::Error> {
125        serializer.collect_str(&format_args!("{}", self.0))
126    }
127
128    /// Seriaizes an AS number as a string with a `AS` prefix.
129    pub fn serialize_as_str<S: serde::Serializer>(
130        &self,
131        serializer: S,
132    ) -> Result<S::Ok, S::Error> {
133        serializer.collect_str(&format_args!("AS{}", self.0))
134    }
135
136    /// Deserializes an AS number from a simple `u32`.
137    ///
138    /// Normally, you wouldn’t need to use this method, as the default
139    /// implementation deserializes the ASN from a newtype struct with a
140    /// `u32` inside for which most serialization formats will use a sole
141    /// `u32`. However, in case your format doesn’t, you can use this method.
142    pub fn deserialize_from_u32<'de, D: serde::Deserializer<'de>>(
143        deserializer: D,
144    ) -> Result<Self, D::Error> {
145        <u32 as serde::Deserialize>::deserialize(deserializer).map(Into::into)
146    }
147
148    /// Deserializes an AS number from a string.
149    ///
150    /// The string may or may not have a case-insensitive `"AS"` prefix.
151    pub fn deserialize_from_str<'de, D: serde::de::Deserializer<'de>>(
152        deserializer: D,
153    ) -> Result<Self, D::Error> {
154        struct Visitor;
155
156        impl<'de> serde::de::Visitor<'de> for Visitor {
157            type Value = Asn;
158
159            fn expecting(
160                &self,
161                formatter: &mut fmt::Formatter,
162            ) -> fmt::Result {
163                write!(formatter, "an AS number")
164            }
165
166            fn visit_str<E: serde::de::Error>(
167                self,
168                v: &str,
169            ) -> Result<Self::Value, E> {
170                Asn::from_str(v).map_err(E::custom)
171            }
172        }
173        deserializer.deserialize_str(Visitor)
174    }
175
176    /// Deserializes an AS number as either a string or `u32`.
177    ///
178    /// This function can only be used with self-describing serialization
179    /// formats as it uses `Deserializer::deserialize_any`. It accepts an
180    /// AS number as any kind of integer as well as a string with or without
181    /// a case-insensitive `"AS"` prefix.
182    pub fn deserialize_from_any<'de, D: serde::de::Deserializer<'de>>(
183        deserializer: D,
184    ) -> Result<Self, D::Error> {
185        struct Visitor;
186
187        impl<'de> serde::de::Visitor<'de> for Visitor {
188            type Value = Asn;
189
190            fn expecting(
191                &self,
192                formatter: &mut fmt::Formatter,
193            ) -> fmt::Result {
194                write!(formatter, "an AS number")
195            }
196
197            fn visit_u8<E: serde::de::Error>(
198                self,
199                v: u8,
200            ) -> Result<Self::Value, E> {
201                Ok(Asn(v.into()))
202            }
203
204            fn visit_u16<E: serde::de::Error>(
205                self,
206                v: u16,
207            ) -> Result<Self::Value, E> {
208                Ok(Asn(v.into()))
209            }
210
211            fn visit_u32<E: serde::de::Error>(
212                self,
213                v: u32,
214            ) -> Result<Self::Value, E> {
215                Ok(Asn(v))
216            }
217
218            fn visit_u64<E: serde::de::Error>(
219                self,
220                v: u64,
221            ) -> Result<Self::Value, E> {
222                Ok(Asn(v.try_into().map_err(E::custom)?))
223            }
224
225            fn visit_i8<E: serde::de::Error>(
226                self,
227                v: i8,
228            ) -> Result<Self::Value, E> {
229                Ok(Asn(v.try_into().map_err(E::custom)?))
230            }
231
232            fn visit_i16<E: serde::de::Error>(
233                self,
234                v: i16,
235            ) -> Result<Self::Value, E> {
236                Ok(Asn(v.try_into().map_err(E::custom)?))
237            }
238
239            fn visit_i32<E: serde::de::Error>(
240                self,
241                v: i32,
242            ) -> Result<Self::Value, E> {
243                Ok(Asn(v.try_into().map_err(E::custom)?))
244            }
245
246            fn visit_i64<E: serde::de::Error>(
247                self,
248                v: i64,
249            ) -> Result<Self::Value, E> {
250                Ok(Asn(v.try_into().map_err(E::custom)?))
251            }
252
253            fn visit_str<E: serde::de::Error>(
254                self,
255                v: &str,
256            ) -> Result<Self::Value, E> {
257                Asn::from_str(v).map_err(E::custom)
258            }
259        }
260        deserializer.deserialize_any(Visitor)
261    }
262}
263
264//--- Add
265
266impl ops::Add<u32> for Asn {
267    type Output = Self;
268
269    fn add(self, rhs: u32) -> Self {
270        Asn(self.0.checked_add(rhs).unwrap())
271    }
272}
273
274//--- Display
275
276impl fmt::Display for Asn {
277    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
278        write!(f, "AS{}", self.0)
279    }
280}
281
282//------------ Asn16 ---------------------------------------------------------
283
284/// A 2-octet ASN.
285///
286/// This is only here to facilitate 'legacy' BGP, i.e., BGP messages in a BGP
287/// session for which the FourOctet Capability has not been exchanged.
288#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
289#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
290pub struct Asn16(u16);
291
292impl Asn16 {
293    pub fn from_u16(u: u16) -> Self {
294        Self(u)
295    }
296    pub fn to_u16(self) -> u16 {
297        self.0
298    }
299    pub fn into_asn32(self) -> Asn {
300        Asn::from_u32(self.0 as u32)
301    }
302    pub fn to_raw(self) -> [u8; 2] {
303        self.0.to_be_bytes()
304    }
305}
306
307//--- Display
308
309impl fmt::Display for Asn16 {
310    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
311        write!(f, "AS{}", self.0)
312    }
313}
314
315//--- From / FromStr
316
317impl From<u16> for Asn16 {
318    fn from(n: u16) -> Self {
319        Self(n)
320    }
321}
322
323fn strip_as(s: &str) -> &str {
324    s.strip_prefix("AS")
325        .or_else(|| s.strip_prefix("as"))
326        .or_else(|| s.strip_prefix("As"))
327        .or_else(|| s.strip_prefix("aS"))
328        .unwrap_or(s)
329}
330
331impl FromStr for Asn16 {
332    type Err = ParseAsnError;
333
334    fn from_str(s: &str) -> Result<Self, Self::Err> {
335        u16::from_str(strip_as(s))
336            .map_err(|_| ParseAsnError)
337            .map(Asn16::from_u16)
338
339        // more strict version:
340        /*
341            s.strip_prefix("AS").ok_or_else(|| "missing AS".into())
342                .and_then(|e| u16::from_str(e)
343                          .map_err(|_e| "u16 parsing failed".into())
344                         )
345                .map(Asn16::from_u16)
346        */
347    }
348}
349
350//------------ SmallAsnSet --------------------------------------------------
351
352/// A relatively small set of ASNs.
353///
354/// This type is only efficient if the amount of ASNs in it is relatively
355/// small as it is represented internally by an ordered vec of ASNs to avoid
356/// memory overhead.
357#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
358#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
359pub struct SmallAsnSet(Vec<Asn>);
360
361impl SmallAsnSet {
362    pub fn iter(&self) -> SmallSetIter {
363        self.0.iter().cloned()
364    }
365
366    pub fn len(&self) -> usize {
367        self.0.len()
368    }
369
370    pub fn is_empty(&self) -> bool {
371        self.0.is_empty()
372    }
373
374    pub fn difference<'a>(
375        &'a self,
376        other: &'a Self,
377    ) -> SmallSetDifference<'a> {
378        SmallSetDifference {
379            left: self.iter().peekable(),
380            right: other.iter().peekable(),
381        }
382    }
383
384    pub fn symmetric_difference<'a>(
385        &'a self,
386        other: &'a Self,
387    ) -> SmallSetSymmetricDifference<'a> {
388        SmallSetSymmetricDifference {
389            left: self.iter().peekable(),
390            right: other.iter().peekable(),
391        }
392    }
393
394    pub fn intersection<'a>(
395        &'a self,
396        other: &'a Self,
397    ) -> SmallSetIntersection<'a> {
398        SmallSetIntersection {
399            left: self.iter().peekable(),
400            right: other.iter().peekable(),
401        }
402    }
403
404    pub fn union<'a>(&'a self, other: &'a Self) -> SmallSetUnion<'a> {
405        SmallSetUnion {
406            left: self.iter().peekable(),
407            right: other.iter().peekable(),
408        }
409    }
410
411    pub fn contains(&self, asn: Asn) -> bool {
412        self.0.binary_search(&asn).is_ok()
413    }
414
415    // Missing: is_disjoint, is_subset, is_superset, insert, remove,
416}
417
418impl iter::FromIterator<Asn> for SmallAsnSet {
419    fn from_iter<T: IntoIterator<Item = Asn>>(iter: T) -> Self {
420        let mut res = Self(iter.into_iter().collect());
421        res.0.sort();
422        res
423    }
424}
425
426impl<'a> IntoIterator for &'a SmallAsnSet {
427    type Item = Asn;
428    type IntoIter = SmallSetIter<'a>;
429
430    fn into_iter(self) -> Self::IntoIter {
431        self.0.iter().cloned()
432    }
433}
434
435//------------ SmallSetIter --------------------------------------------------
436
437pub type SmallSetIter<'a> = iter::Cloned<slice::Iter<'a, Asn>>;
438
439//------------ SmallSetDifference --------------------------------------------
440
441pub struct SmallSetDifference<'a> {
442    left: Peekable<SmallSetIter<'a>>,
443    right: Peekable<SmallSetIter<'a>>,
444}
445
446impl<'a> Iterator for SmallSetDifference<'a> {
447    type Item = Asn;
448
449    fn next(&mut self) -> Option<Self::Item> {
450        loop {
451            match (self.left.peek(), self.right.peek()) {
452                (None, _) => return None,
453                (Some(_), None) => return self.left.next(),
454                (Some(left), Some(right)) => match left.cmp(right) {
455                    Ordering::Less => return self.left.next(),
456                    Ordering::Equal => {
457                        let _ = self.left.next();
458                        let _ = self.right.next();
459                    }
460                    Ordering::Greater => {
461                        let _ = self.right.next();
462                    }
463                },
464            }
465        }
466    }
467}
468
469//------------ SmallSetSymmetricDifference -----------------------------------
470
471pub struct SmallSetSymmetricDifference<'a> {
472    left: Peekable<SmallSetIter<'a>>,
473    right: Peekable<SmallSetIter<'a>>,
474}
475
476impl<'a> Iterator for SmallSetSymmetricDifference<'a> {
477    type Item = Asn;
478
479    fn next(&mut self) -> Option<Self::Item> {
480        loop {
481            match (self.left.peek(), self.right.peek()) {
482                (None, None) => return None,
483                (Some(_), None) => return self.left.next(),
484                (None, Some(_)) => return self.right.next(),
485                (Some(left), Some(right)) => match left.cmp(right) {
486                    Ordering::Equal => {
487                        let _ = self.left.next();
488                        let _ = self.right.next();
489                    }
490                    Ordering::Less => return self.left.next(),
491                    Ordering::Greater => return self.right.next(),
492                },
493            }
494        }
495    }
496}
497
498//------------ SmallSetIntersection ------------------------------------------
499
500pub struct SmallSetIntersection<'a> {
501    left: Peekable<SmallSetIter<'a>>,
502    right: Peekable<SmallSetIter<'a>>,
503}
504
505impl<'a> Iterator for SmallSetIntersection<'a> {
506    type Item = Asn;
507
508    fn next(&mut self) -> Option<Self::Item> {
509        loop {
510            match (self.left.peek(), self.right.peek()) {
511                (None, _) | (_, None) => return None,
512                (Some(left), Some(right)) => match left.cmp(right) {
513                    Ordering::Equal => {
514                        let _ = self.left.next();
515                        return self.right.next();
516                    }
517                    Ordering::Less => {
518                        let _ = self.left.next();
519                    }
520                    Ordering::Greater => {
521                        let _ = self.right.next();
522                    }
523                },
524            }
525        }
526    }
527}
528
529//------------ SmallSetUnion -------------------------------------------------
530
531pub struct SmallSetUnion<'a> {
532    left: Peekable<SmallSetIter<'a>>,
533    right: Peekable<SmallSetIter<'a>>,
534}
535
536impl<'a> Iterator for SmallSetUnion<'a> {
537    type Item = Asn;
538
539    fn next(&mut self) -> Option<Self::Item> {
540        match (self.left.peek(), self.right.peek()) {
541            (None, None) => None,
542            (Some(_), None) => self.left.next(),
543            (None, Some(_)) => self.right.next(),
544            (Some(left), Some(right)) => match left.cmp(right) {
545                Ordering::Less => self.left.next(),
546                Ordering::Equal => {
547                    let _ = self.left.next();
548                    self.right.next()
549                }
550                Ordering::Greater => self.right.next(),
551            },
552        }
553    }
554}
555
556//============ Error Types ===================================================
557
558//------------ ParseAsnError ------------------------------------------------
559
560#[derive(Clone, Copy, Debug, Eq, PartialEq)]
561pub struct ParseAsnError;
562
563impl fmt::Display for ParseAsnError {
564    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
565        f.write_str("invalid AS number")
566    }
567}
568
569impl error::Error for ParseAsnError {}
570
571//------------ LargeAsnError ------------------------------------------------
572
573#[derive(Clone, Copy, Debug, Eq, PartialEq)]
574pub struct LargeAsnError;
575
576impl fmt::Display for LargeAsnError {
577    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
578        f.write_str("ASN too large")
579    }
580}
581
582impl error::Error for LargeAsnError {}
583
584//------------ LongSegmentError ----------------------------------------------
585
586#[derive(Clone, Copy, Debug)]
587pub struct LongSegmentError;
588
589impl fmt::Display for LongSegmentError {
590    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
591        f.write_str("path segment too long")
592    }
593}
594
595impl error::Error for LongSegmentError {}
596
597//------------ InvalidSegmentTypeError ---------------------------------------
598
599#[derive(Clone, Copy, Debug)]
600pub struct InvalidSegmentTypeError;
601
602impl fmt::Display for InvalidSegmentTypeError {
603    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
604        f.write_str("invalid segment type")
605    }
606}
607
608impl error::Error for InvalidSegmentTypeError {}
609
610//============ Tests =========================================================
611
612#[cfg(all(test, feature = "serde"))]
613mod test_serde {
614    use super::*;
615    use serde_test::{assert_de_tokens, assert_tokens, Token};
616
617    #[test]
618    fn asn() {
619        #[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
620        struct AsnTest(
621            Asn,
622            #[serde(
623                deserialize_with = "Asn::deserialize_from_u32",
624                serialize_with = "Asn::serialize_as_u32"
625            )]
626            Asn,
627            #[serde(
628                deserialize_with = "Asn::deserialize_from_str",
629                serialize_with = "Asn::serialize_as_str"
630            )]
631            Asn,
632        );
633
634        assert_tokens(
635            &AsnTest(Asn(0), Asn(0), Asn(0)),
636            &[
637                Token::TupleStruct {
638                    name: "AsnTest",
639                    len: 3,
640                },
641                Token::NewtypeStruct { name: "Asn" },
642                Token::U32(0),
643                Token::U32(0),
644                Token::Str("AS0"),
645                Token::TupleStructEnd,
646            ],
647        );
648    }
649
650    #[test]
651    fn asn_any() {
652        #[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
653        struct AsnTest(
654            #[serde(deserialize_with = "Asn::deserialize_from_any")] Asn,
655            #[serde(deserialize_with = "Asn::deserialize_from_any")] Asn,
656            #[serde(deserialize_with = "Asn::deserialize_from_any")] Asn,
657            #[serde(deserialize_with = "Asn::deserialize_from_any")] Asn,
658            #[serde(deserialize_with = "Asn::deserialize_from_any")] Asn,
659            #[serde(deserialize_with = "Asn::deserialize_from_any")] Asn,
660        );
661
662        assert_de_tokens(
663            &AsnTest(Asn(0), Asn(0), Asn(0), Asn(0), Asn(0), Asn(0)),
664            &[
665                Token::TupleStruct {
666                    name: "AsnTest",
667                    len: 5,
668                },
669                Token::U32(0),
670                Token::U64(0),
671                Token::I64(0),
672                Token::Str("0"),
673                Token::Str("AS0"),
674                Token::Str("As0"),
675                Token::TupleStructEnd,
676            ],
677        );
678    }
679}
680
681#[cfg(test)]
682mod tests {
683    use super::*;
684    use std::collections::HashSet;
685
686    #[test]
687    fn asn() {
688        assert_eq!(Asn::from_u32(1234), Asn(1234));
689        assert_eq!(Asn(1234).into_u32(), 1234);
690
691        assert_eq!(Asn::from(1234_u32), Asn(1234));
692        assert_eq!(u32::from(Asn(1234)), 1234_u32);
693
694        assert_eq!(format!("{}", Asn(1234)).as_str(), "AS1234");
695
696        assert_eq!("0".parse::<Asn>(), Ok(Asn(0)));
697        assert_eq!("AS1234".parse::<Asn>(), Ok(Asn(1234)));
698        assert_eq!("as1234".parse::<Asn>(), Ok(Asn(1234)));
699        assert_eq!("As1234".parse::<Asn>(), Ok(Asn(1234)));
700        assert_eq!("aS1234".parse::<Asn>(), Ok(Asn(1234)));
701        assert_eq!("1234".parse::<Asn>(), Ok(Asn(1234)));
702
703        assert_eq!("".parse::<Asn>(), Err(ParseAsnError));
704        assert_eq!("-1234".parse::<Asn>(), Err(ParseAsnError));
705        assert_eq!("4294967296".parse::<Asn>(), Err(ParseAsnError));
706    }
707
708    //--- SmallAsnSet
709
710    // Checks that our set operation does the same as the same on
711    // HashSet<Asn>.
712    macro_rules! check_set_fn {
713        ( $fn:ident, $left:expr, $right:expr $(,)? ) => {{
714            let left = Vec::from_iter($left.into_iter().map(Asn::from_u32));
715            let right = Vec::from_iter($right.into_iter().map(Asn::from_u32));
716
717            let set_fn = {
718                let left = SmallAsnSet::from_iter(left.clone().into_iter());
719                let right = SmallAsnSet::from_iter(right.clone().into_iter());
720                left.$fn(&right).collect::<HashSet<Asn>>()
721            };
722            let hash_fn: HashSet<Asn> = {
723                let left: HashSet<Asn> =
724                    HashSet::from_iter(left.clone().into_iter());
725                let right: HashSet<Asn> =
726                    HashSet::from_iter(right.clone().into_iter());
727                left.$fn(&right).cloned().collect()
728            };
729            assert_eq!(set_fn, hash_fn);
730        }};
731    }
732
733    macro_rules! check_all_set_fns {
734        ( $left:expr, $right:expr $(,)? ) => {{
735            check_set_fn!(difference, $left, $right);
736            check_set_fn!(symmetric_difference, $left, $right);
737            check_set_fn!(intersection, $left, $right);
738            check_set_fn!(union, $left, $right);
739        }};
740    }
741
742    #[test]
743    fn small_set_operations() {
744        check_all_set_fns!([0, 1, 2, 3], [0, 1, 2, 3]);
745        check_all_set_fns!([0, 1, 2], [0, 1, 2, 3]);
746        check_all_set_fns!([0, 1, 2, 3], [0, 1, 2]);
747        check_all_set_fns!([0, 1, 2, 3], [0, 1, 2]);
748        check_all_set_fns!([], []);
749        check_all_set_fns!([1, 2, 3], []);
750        check_all_set_fns!([], [1, 2, 3]);
751    }
752}