sciparse 0.6.1

Zero-copy SCION packet parsing, serialization and control plane components
Documentation
// Copyright 2026 Anapaya Systems
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! SCION packet payloads (UDP, SCMP) and protocol numbers.

use std::fmt::Display;

pub mod encode;
pub mod scmp;
pub mod udp;

/// SCION protocol numbers for payloads.
///
/// See the [IETF SCION-dataplane RFC draft][rfc] for possible values.
///
///[rfc]: https://www.ietf.org/archive/id/draft-dekater-scion-dataplane-00.html#protnum
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum ProtocolNumber {
    /// SCION/TCP next-header protocol number.
    Tcp  = 6,
    /// SCION/UDP next-header protocol number.
    Udp  = 17,
    /// SCION/Hop-by-hop options.
    Hbh  = 43,
    /// SCION End-to-End Options.
    E2e  = 201,
    /// SCION protocol number for SCMP.
    Scmp = 202,
    /// SCION/BFD next-header protocol number.
    Bfd  = 203,
    /// Other, unrecognized protocol numbers.
    Other(u8),
}
impl ProtocolNumber {
    /// Returns the protocol number as a `u8`.
    #[inline]
    pub fn to_u8(&self) -> u8 {
        (*self).into()
    }

    /// Returns a string representation of the protocol number.
    #[inline]
    pub const fn as_str(&self) -> &'static str {
        match self {
            ProtocolNumber::Tcp => "TCP",
            ProtocolNumber::Udp => "UDP",
            ProtocolNumber::Hbh => "HBH",
            ProtocolNumber::E2e => "E2E",
            ProtocolNumber::Scmp => "SCMP",
            ProtocolNumber::Bfd => "BFD",
            ProtocolNumber::Other(_) => "Other",
        }
    }
}
impl From<u8> for ProtocolNumber {
    #[inline]
    fn from(value: u8) -> Self {
        match value {
            6 => ProtocolNumber::Tcp,
            17 => ProtocolNumber::Udp,
            43 => ProtocolNumber::Hbh,
            201 => ProtocolNumber::E2e,
            202 => ProtocolNumber::Scmp,
            203 => ProtocolNumber::Bfd,
            other => ProtocolNumber::Other(other),
        }
    }
}
impl From<ProtocolNumber> for u8 {
    #[inline]
    fn from(value: ProtocolNumber) -> Self {
        match value {
            ProtocolNumber::Tcp => 6,
            ProtocolNumber::Udp => 17,
            ProtocolNumber::Hbh => 43,
            ProtocolNumber::E2e => 201,
            ProtocolNumber::Scmp => 202,
            ProtocolNumber::Bfd => 203,
            ProtocolNumber::Other(other) => other,
        }
    }
}
impl Display for ProtocolNumber {
    #[inline]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

/// Support for [`proptest::arbitrary`].
#[cfg(feature = "proptest")]
pub mod ptest {
    use ::proptest::prelude::*;

    use super::*;

    /// Configuration for generating arbitrary [`ProtocolNumber`] values.
    ///
    /// Controls the relative probability of each protocol number variant being generated.
    ///
    /// Default weights: all variants = 1.
    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub struct ArbitraryProtocolNumberParams {
        /// Weight for TCP protocol.
        pub tcp: u32,
        /// Weight for UDP protocol.
        pub udp: u32,
        /// Weight for Hop-by-hop options.
        pub hbh: u32,
        /// Weight for End-to-End options.
        pub e2e: u32,
        /// Weight for SCMP protocol.
        pub scmp: u32,
        /// Weight for BFD protocol.
        pub bfd: u32,
        /// Weight for other (unknown) protocol numbers.
        pub other: u32,
    }
    impl Default for ArbitraryProtocolNumberParams {
        fn default() -> Self {
            Self {
                tcp: 1,
                udp: 1,
                hbh: 1,
                e2e: 1,
                scmp: 1,
                bfd: 1,
                other: 1,
            }
        }
    }

    impl Arbitrary for ProtocolNumber {
        type Parameters = ArbitraryProtocolNumberParams;
        type Strategy = BoxedStrategy<Self>;

        fn arbitrary_with(params: Self::Parameters) -> Self::Strategy {
            prop_oneof![
                params.tcp => Just(ProtocolNumber::Tcp),
                params.udp => Just(ProtocolNumber::Udp),
                params.hbh => Just(ProtocolNumber::Hbh),
                params.e2e => Just(ProtocolNumber::E2e),
                params.scmp => Just(ProtocolNumber::Scmp),
                params.bfd => Just(ProtocolNumber::Bfd),
                params.other => any::<u8>().prop_map(|v| {
                    let mut v = v;
                    while !matches!(ProtocolNumber::from(v), ProtocolNumber::Other(_)) {
                        v = v.wrapping_add(1);
                    }
                    ProtocolNumber::Other(v)
                }),
            ]
            .boxed()
        }
    }
}