#![deny(unsafe_code)]
#![cfg_attr(not(any(test)), no_std)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(doc_cfg_hide))]
#![cfg_attr(docsrs, doc(cfg_hide(docsrs)))]
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Asn(u32);
impl Asn {
pub const ZERO: Self = Self::new(0);
pub const LAST: Self = Self::new(65535);
pub const LAST4: Self = Self::new(4294967295);
pub const RESERVED_DOCUMENTATION: core::ops::RangeInclusive<Self> =
(Self::new(64496)..=Self::new(64511));
pub const RESERVED_DOCUMENTATION4: core::ops::RangeInclusive<Self> =
(Self::new(65536)..=Self::new(65551));
pub const RESERVED_PRIVATE: core::ops::RangeInclusive<Self> =
(Self::new(64512)..=Self::new(65534));
pub const RESERVED_PRIVATE4: core::ops::RangeInclusive<Self> =
(Self::new(4200000000)..=Self::new(4294967294));
pub const TRANS: Self = Self::new(23456);
pub const RESERVED_IANA4: core::ops::RangeInclusive<Self> =
(Self::new(65552)..=Self::new(131071));
#[inline]
pub const fn new(asn: u32) -> Self {
Self(asn)
}
pub const fn from_str(src: &str) -> Result<Self, ParseAsnError> {
if src.is_empty() {
return Err(ParseAsnError());
}
let src = src.as_bytes();
let mut digits = src;
let mut result = 0;
macro_rules! unwrap_or_PAE {
($option:expr) => {
match $option {
Some(value) => value,
None => return Err(ParseAsnError()),
}
};
}
#[inline(always)]
pub const fn can_not_overflow<T>(digits: &[u8]) -> bool {
digits.len() <= core::mem::size_of::<T>() * 2
}
if can_not_overflow::<u32>(digits) {
while let [c, rest @ ..] = digits {
result *= 10_u32;
let x = unwrap_or_PAE!((*c as char).to_digit(10));
result += x;
digits = rest;
}
} else {
while let [c, rest @ ..] = digits {
let mul = result.checked_mul(10_u32);
let x = unwrap_or_PAE!((*c as char).to_digit(10));
result = unwrap_or_PAE!(mul);
result = unwrap_or_PAE!(u32::checked_add(result, x));
digits = rest;
}
}
Ok(Self(result))
}
}
impl core::convert::From<Asn> for u32 {
#[inline]
fn from(asn: Asn) -> u32 {
asn.0
}
}
impl core::convert::From<u32> for Asn {
#[inline]
fn from(asn: u32) -> Asn {
Asn::new(asn)
}
}
impl core::convert::From<u16> for Asn {
#[inline]
fn from(asn: u16) -> Asn {
Asn::new(u32::from(asn))
}
}
impl core::str::FromStr for Asn {
type Err = ParseAsnError;
fn from_str(src: &str) -> Result<Self, Self::Err> {
Self::from_str(src)
}
}
impl core::fmt::Display for Asn {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseAsnError();
impl core::fmt::Display for ParseAsnError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "can not parse ASN")
}
}
impl core::error::Error for ParseAsnError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<Asn>();
}
#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Asn>();
}
#[test]
fn test_new() {
let _ = Asn::new(0);
}
#[test]
fn test_u32_from_asn() {
let _: u32 = Asn::new(0).into();
}
#[test]
fn test_asn_from_u32() {
let _: Asn = 0_u32.into();
}
#[test]
fn test_asn_from_u16() {
let _: Asn = 0_u16.into();
}
#[test]
fn test_debug() {
assert_eq!(format!("{:?}", Asn::new(0)), "Asn(0)");
}
#[test]
fn test_asn0_eq() {
assert_eq!(Asn::ZERO, Asn::new(0));
}
#[test]
fn test_display() {
assert_eq!(format!("{}", Asn::new(65526)), "65526");
assert_eq!(format!("{}", Asn::new(65546)), "65546");
}
#[test]
fn test_last_eq() {
assert_eq!(Asn::LAST, Asn::new(65535));
assert_eq!(Asn::LAST4, Asn::new(4294967295));
}
#[test]
fn test_reserved_documentation_contains() {
assert!(Asn::RESERVED_DOCUMENTATION.contains(&Asn::new(64500)));
assert!(Asn::RESERVED_DOCUMENTATION4.contains(&Asn::new(65540)));
}
#[test]
fn test_reserved_private_contains() {
assert!(Asn::RESERVED_PRIVATE.contains(&Asn::new(64520)));
assert!(Asn::RESERVED_PRIVATE4.contains(&Asn::new(4242424242)));
}
#[test]
fn test_trans_eq() {
assert_eq!(Asn::TRANS, Asn::new(23456));
}
#[test]
fn test_reserved_iana_contains() {
assert!(Asn::RESERVED_IANA4.contains(&Asn::new(100000)));
}
#[test]
fn test_from_str() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(Asn::from_str("65526")?, Asn::new(65526));
assert_eq!(Asn::from_str("65546")?, Asn::new(65546));
assert_eq!(Asn::from_str("hurz").unwrap_err(), ParseAsnError());
Ok(())
}
#[test]
fn test_parseasnerror_display() {
assert_eq!(
format!("{}", Asn::from_str("hurz").unwrap_err()),
"can not parse ASN"
);
}
#[test]
fn test_fromstr() {
assert_eq!("65526".parse(), Ok(Asn::new(65526)));
}
}
#[cfg(doctest)]
#[doc=include_str!("../README-crate.md")]
mod readme {}