#![doc = include_str!("../README.md")]
#![no_std]
#![allow(non_camel_case_types)]
mod bcd;
mod data;
mod display;
mod error;
mod isoiec646;
mod parse;
mod utils;
use crate::display::{fmt_naddr, fmt_naddr_type};
use crate::parse::parse_nsap;
use crate::utils::{u8_to_decimal_bytes, u16_to_decimal_bytes};
pub use bcd::*;
use core::convert::TryFrom;
use core::fmt::Display;
use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4};
use core::str::FromStr;
pub use data::*;
pub use error::*;
pub use isoiec646::*;
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::string::String;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
pub type AFI = u8;
pub type Rfc1277NetworkId = u8;
pub type Rfc1277TransportSet = u16;
pub const DEFAULT_ITOT_TRANSPORT_SET: Rfc1277TransportSet = 1;
pub type Rfc1277SocketInfo = (Rfc1277NetworkId, SocketAddrV4, Rfc1277TransportSet);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DSPSyntax {
Decimal,
Binary,
IsoIec646Chars,
NationalChars,
}
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
pub enum X213NetworkAddressType {
X121,
ISO_DCC,
F69,
E163,
E164,
ISO_6523_ICD,
IANA_ICP,
ITU_T_IND,
LOCAL,
URL,
}
impl Display for X213NetworkAddressType {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
fmt_naddr_type(self, f)
}
}
impl TryFrom<AFI> for X213NetworkAddressType {
type Error = ();
#[inline]
fn try_from(value: AFI) -> Result<Self, Self::Error> {
afi_to_network_type(value).ok_or(())
}
}
#[derive(Debug)]
pub enum X213NetworkAddress<'a> {
#[cfg(feature = "alloc")]
Heap(Vec<u8>),
Inline((u8, [u8; 22])),
Borrowed(&'a [u8]),
}
impl<'a> X213NetworkAddress<'a> {
#[inline]
pub fn get_octets(&'a self) -> &'a [u8] {
match &self {
#[cfg(feature = "alloc")]
X213NetworkAddress::Heap(o) => o.as_ref(),
X213NetworkAddress::Inline((sz, buf)) => &buf[0..(*sz).clamp(0u8, 20u8) as usize],
X213NetworkAddress::Borrowed(o) => *o,
}
}
#[inline]
pub fn afi(&self) -> u8 {
if self.get_octets().len() > 0 {
self.get_octets()[0]
} else {
panic!("Zero-length IDP in an X.213 network address")
}
}
#[cfg(feature = "alloc")]
pub fn from_vec_unchecked(octets: Vec<u8>) -> X213NetworkAddress<'static> {
X213NetworkAddress::Heap(octets)
}
#[cfg(feature = "alloc")]
pub fn from_vec(octets: Vec<u8>) -> Result<X213NetworkAddress<'static>, NAddressParseError> {
validate_raw_nsap(octets.as_ref())?;
Ok(X213NetworkAddress::Heap(octets))
}
pub fn from_slice_unchecked(octets: &'a [u8]) -> X213NetworkAddress<'a> {
X213NetworkAddress::Borrowed(octets)
}
pub fn from_slice(octets: &'a [u8]) -> Result<X213NetworkAddress<'a>, NAddressParseError> {
validate_raw_nsap(octets.as_ref())?;
Ok(X213NetworkAddress::Borrowed(octets))
}
#[inline]
pub fn get_network_type_info(&self) -> Option<X213NetworkAddressInfo> {
get_nsap_address_schema(self.afi())
}
#[inline]
pub fn get_network_type(&self) -> Option<X213NetworkAddressType> {
afi_to_network_type(self.afi())
}
pub fn idi_digits(&'a self) -> Option<BCDDigitsIter<'a>> {
let addr_type_info = get_nsap_address_schema(self.afi())?;
let leading_0_sig = addr_type_info.leading_zeroes_in_idi;
let is_dsp_decimal = matches!(addr_type_info.dsp_syntax, DSPSyntax::Decimal);
let idi_len = addr_type_info.max_idi_len_digits as usize;
let idi_len_in_bytes = (idi_len >> 1) + (idi_len % 2);
let odd_len_idi: bool = (idi_len % 2) > 0;
let octets = self.get_octets();
let idi = &octets[1..1 + idi_len_in_bytes];
Some(BCDDigitsIter::new(
idi,
leading_0_sig,
is_dsp_decimal && odd_len_idi,
false,
true,
))
}
pub fn dsp_digits(&'a self) -> Option<BCDDigitsIter<'a>> {
let addr_type_info = get_nsap_address_schema(self.afi())?;
let is_dsp_decimal = matches!(addr_type_info.dsp_syntax, DSPSyntax::Decimal);
if !is_dsp_decimal {
return None;
}
let idi_len = addr_type_info.max_idi_len_digits as usize;
let idi_len_in_bytes = (idi_len >> 1) + (idi_len % 2);
let odd_len_idi: bool = (idi_len % 2) > 0;
let octets = self.get_octets();
let (dsp, start_on_lsn) = if is_dsp_decimal && odd_len_idi {
(&octets[idi_len_in_bytes..], true)
} else {
(&octets[1 + idi_len_in_bytes..], false)
};
Some(BCDDigitsIter::new(
dsp,
false, false, start_on_lsn,
false,
))
}
pub fn get_url(&'a self) -> Option<&'a str> {
let octets = self.get_octets();
if octets.len() <= 5 || octets[0] != AFI_URL {
return None;
}
str::from_utf8(&octets[3..]).ok()
}
pub fn get_ip(&self) -> Option<IpAddr> {
let octets = self.get_octets();
if octets.len() < 7 || octets[0] != AFI_IANA_ICP_BIN {
return None;
}
match (octets[1], octets[2]) {
(0, 0) => {
if octets.len() < 19 {
return None;
}
let ip = Ipv6Addr::from([
octets[3], octets[4], octets[5], octets[6], octets[7], octets[8], octets[9],
octets[10], octets[11], octets[12], octets[13], octets[14], octets[15],
octets[16], octets[17], octets[18],
]);
Some(IpAddr::V6(ip))
}
(0, 1) => {
let ip = Ipv4Addr::from([octets[3], octets[4], octets[5], octets[6]]);
Some(IpAddr::V4(ip))
}
_ => None,
}
}
pub fn get_rfc1277_socket(&self) -> Option<Rfc1277SocketInfo> {
let octets = self.get_octets();
if !octets.starts_with(RFC_1277_PREFIX.as_slice()) {
return None;
}
let dsp = &octets[RFC_1277_PREFIX.len() + 1..];
if dsp.len() < 6 {
return None;
}
let mut bcd = BCDDigitsIter::new(dsp, false, false, false, false);
let oct1digs = [bcd.next()? + 0x30, bcd.next()? + 0x30, bcd.next()? + 0x30];
let oct2digs = [bcd.next()? + 0x30, bcd.next()? + 0x30, bcd.next()? + 0x30];
let oct3digs = [bcd.next()? + 0x30, bcd.next()? + 0x30, bcd.next()? + 0x30];
let oct4digs = [bcd.next()? + 0x30, bcd.next()? + 0x30, bcd.next()? + 0x30];
let oct1str = unsafe { str::from_utf8_unchecked(oct1digs.as_slice()) };
let oct2str = unsafe { str::from_utf8_unchecked(oct2digs.as_slice()) };
let oct3str = unsafe { str::from_utf8_unchecked(oct3digs.as_slice()) };
let oct4str = unsafe { str::from_utf8_unchecked(oct4digs.as_slice()) };
let oct1: u8 = oct1str.parse().ok()?;
let oct2: u8 = oct2str.parse().ok()?;
let oct3: u8 = oct3str.parse().ok()?;
let oct4: u8 = oct4str.parse().ok()?;
let ip = Ipv4Addr::new(oct1, oct2, oct3, oct4);
if dsp.len() < 9 {
return Some((
octets[5],
SocketAddrV4::new(ip, ITOT_OVER_IPV4_DEFAULT_PORT),
DEFAULT_ITOT_TRANSPORT_SET,
));
}
let portstr = [
bcd.next()? + 0x30,
bcd.next()? + 0x30,
bcd.next()? + 0x30,
bcd.next()? + 0x30,
bcd.next()? + 0x30,
];
let portstr = unsafe { str::from_utf8_unchecked(portstr.as_slice()) };
let port: u16 = portstr.parse().ok()?;
if dsp.len() < 11 {
return Some((
octets[5],
SocketAddrV4::new(ip, ITOT_OVER_IPV4_DEFAULT_PORT),
DEFAULT_ITOT_TRANSPORT_SET,
));
}
let tsetstr = [
bcd.next()? + 0x30,
bcd.next()? + 0x30,
bcd.next()? + 0x30,
bcd.next()? + 0x30,
bcd.next()? + 0x30,
];
let tsetstr = unsafe { str::from_utf8_unchecked(tsetstr.as_slice()) };
let tset: Rfc1277TransportSet = tsetstr.parse().ok()?;
Some((octets[5], SocketAddrV4::new(ip, port), tset))
}
pub fn from_ip(ip: &IpAddr) -> Self {
match ip {
IpAddr::V4(v4) => X213NetworkAddress::from_ipv4(v4),
IpAddr::V6(v6) => X213NetworkAddress::from_ipv6(v6),
}
}
pub fn from_ipv4(ip: &Ipv4Addr) -> Self {
let mut out: [u8; 22] = [0; 22];
out[0..3].copy_from_slice(&[AFI_IANA_ICP_BIN, 0, 1]);
out[3..7].copy_from_slice(ip.octets().as_slice());
return X213NetworkAddress::Inline((20, out));
}
pub fn from_ipv6(ip: &Ipv6Addr) -> Self {
let mut out: [u8; 22] = [0; 22];
out[0..3].copy_from_slice(&[AFI_IANA_ICP_BIN, 0, 0]);
out[3..19].copy_from_slice(ip.octets().as_slice());
return X213NetworkAddress::Inline((20, out));
}
#[cfg(feature = "alloc")]
pub fn from_itot_url(url: &str) -> Self {
let mut out: Vec<u8> = Vec::with_capacity(3 + url.len());
out.extend(&[AFI_URL, 0, 0]);
out.extend(url.as_bytes());
return X213NetworkAddress::Heap(out);
}
#[cfg(feature = "alloc")]
pub fn from_non_osi_url(url: &str) -> Self {
let mut out: Vec<u8> = Vec::with_capacity(3 + url.len());
out.extend(&[AFI_URL, 0, 1]);
out.extend(url.as_bytes());
return X213NetworkAddress::Heap(out);
}
pub fn from_socket_addr_v4(network: u8, addr: &SocketAddrV4, tset: Option<u16>) -> Self {
let mut out: [u8; 22] = [0; 22];
out[0..5].copy_from_slice(RFC_1277_PREFIX.as_slice());
out[5] = network;
let mut bcd_buf = BCDBuffer::new();
addr.ip()
.octets()
.map(|o| u8_to_decimal_bytes(o))
.iter()
.for_each(|dec_oct| bcd_buf.push_ascii_bytes(dec_oct.as_slice()));
let port = addr.port();
if port != ITOT_OVER_IPV4_DEFAULT_PORT
|| tset.is_some_and(|t| t != DEFAULT_ITOT_TRANSPORT_SET)
{
let port_str = u16_to_decimal_bytes(port);
bcd_buf.push_ascii_bytes(port_str.as_slice());
if let Some(tset) = tset {
let tset_str = u16_to_decimal_bytes(tset);
bcd_buf.push_ascii_bytes(tset_str.as_slice());
} else {
bcd_buf.push_nybble(0xF);
}
}
let bcd_len = bcd_buf.len_in_bytes();
debug_assert_eq!(bcd_len, bcd_buf.as_ref().len());
debug_assert!(bcd_len < 19);
out[6..6 + bcd_len].copy_from_slice(bcd_buf.as_ref());
X213NetworkAddress::Inline((6 + bcd_len as u8, out))
}
#[cfg(feature = "alloc")]
pub fn to_ns_string(&self) -> String {
let octets = self.get_octets();
let len = 3 + (octets.len() << 1);
let mut out: Vec<u8> = Vec::with_capacity(len);
out.extend(b"NS+");
unsafe {
out.set_len(len);
}
faster_hex::hex_encode(octets, &mut out[3..]).expect("hex output buffer mis-sized");
unsafe { String::from_utf8_unchecked(out) }
}
pub fn fmt_as_ns_string(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("NS+")?;
for byte in self.get_octets() {
f.write_fmt(format_args!("{:02X}", *byte))?;
}
Ok(())
}
}
fn validate_decimal(bytes: &[u8]) -> bool {
for byte in bytes {
if (byte & 0b0000_1111) > 9 {
return false;
}
if (byte & 0b1111_0000) > 0b1001_0000 {
return false;
}
}
true
}
fn validate_raw_nsap<'a>(octets: &'a [u8]) -> Result<(), NAddressParseError> {
let len = octets.len();
if len < 2 {
return Err(NAddressParseError::TooShort);
}
if octets[0] != AFI_URL && len > 20 {
return Err(NAddressParseError::TooLong);
}
match octets[0] {
crate::AFI_URL => {
if len > 248 {
return Err(NAddressParseError::TooLong);
}
if len <= 5 {
return Err(NAddressParseError::TooShort);
}
if !validate_decimal(&octets[1..3]) {
return Err(NAddressParseError::NonDigitsInIDI);
}
}
crate::AFI_IANA_ICP_BIN => {
if len > 20 {
return Err(NAddressParseError::TooLong);
}
if len < 20 {
return Err(NAddressParseError::TooShort);
}
if !validate_decimal(&octets[1..3]) {
return Err(NAddressParseError::NonDigitsInIDI);
}
}
_ => (),
};
if len >= RFC_1277_PREFIX.len() + 7 && octets.starts_with(RFC_1277_PREFIX.as_slice()) {
match octets[RFC_1277_PREFIX.len()] {
crate::data::RFC_1277_WELL_KNOWN_NETWORK_DARPA_NSF_INTERNET
| crate::data::ITU_X519_DSP_PREFIX_LDAP
| crate::data::ITU_X519_DSP_PREFIX_IDM_OVER_IPV4
=> {
let end_of_digits = match len {
12 => 12,
15 => 14,
17 => 17,
_ => return Err(NAddressParseError::MalformedDSP),
};
if !validate_decimal(&octets[6..end_of_digits]) {
return Err(NAddressParseError::MalformedDSP);
}
},
_ => (),
};
}
Ok(())
}
impl<'a> TryFrom<&'a [u8]> for X213NetworkAddress<'a> {
type Error = NAddressParseError;
fn try_from(octets: &'a [u8]) -> Result<Self, Self::Error> {
validate_raw_nsap(octets)?;
Ok(X213NetworkAddress::Borrowed(octets))
}
}
#[cfg(feature = "alloc")]
impl<'a> TryFrom<Vec<u8>> for X213NetworkAddress<'a> {
type Error = NAddressParseError;
fn try_from(octets: Vec<u8>) -> Result<Self, Self::Error> {
validate_raw_nsap(octets.as_ref())?;
Ok(X213NetworkAddress::Heap(octets))
}
}
impl<'a> From<&IpAddr> for X213NetworkAddress<'a> {
#[inline]
fn from(value: &IpAddr) -> Self {
X213NetworkAddress::from_ip(value)
}
}
impl<'a> From<&Ipv4Addr> for X213NetworkAddress<'a> {
#[inline]
fn from(value: &Ipv4Addr) -> Self {
X213NetworkAddress::from_ipv4(value)
}
}
impl<'a> From<&Ipv6Addr> for X213NetworkAddress<'a> {
#[inline]
fn from(value: &Ipv6Addr) -> Self {
X213NetworkAddress::from_ipv6(value)
}
}
impl<'a> Display for X213NetworkAddress<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
fmt_naddr(self, f)
}
}
impl<'a> FromStr for X213NetworkAddress<'a> {
type Err = RFC1278ParseError;
#[inline]
fn from_str(s: &str) -> Result<Self, RFC1278ParseError> {
parse_nsap(s)
}
}
#[cfg(test)]
mod tests {
extern crate alloc;
use crate::data::{
AFI_IANA_ICP_BIN, AFI_ISO_DCC_DEC, AFI_X121_DEC_LEADING_ZERO,
RFC_1277_WELL_KNOWN_NETWORK_DARPA_NSF_INTERNET,
};
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use alloc::format;
use core::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4};
use core::str::FromStr;
use super::X213NetworkAddress;
use super::data::AFI_F69_DEC_LEADING_ZERO;
#[test]
fn test_display_01() {
let input = [
0x36u8, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x12, 0x34, 0x56, 0x78, 0x90,
];
let addr = X213NetworkAddress::try_from(input.as_slice()).unwrap();
let addr_str = addr.to_string();
assert_eq!(addr_str, "X121+102030405+d1234567890");
}
#[cfg(feature = "nonstddisplay")]
#[test]
fn test_display_02_url() {
let input = b"\xFF\x00\x01https://wildboarsoftware.com/x500directory";
let addr = X213NetworkAddress::try_from(input.as_slice()).unwrap();
let addr_str = addr.to_string();
assert_eq!(
addr_str,
"URL+0001+https://wildboarsoftware.com/x500directory"
);
}
#[test]
fn test_display_02_itot() {
let input = &[
0x54, 0, 0x72, 0x87, 0x22, 3, 1, 0, 0, 0, 0, 6, 0, 0, 0x90, 0, 2,
];
let addr = X213NetworkAddress::try_from(input.as_slice()).unwrap();
let addr_str = addr.to_string();
assert_eq!(addr_str, "TELEX+00728722+RFC-1006+03+10.0.0.6+9+2");
}
#[cfg(feature = "nonstddisplay")]
#[test]
fn test_display_03_ip() {
let input = &[
AFI_IANA_ICP_BIN,
0,
1,
192,
168,
1,
100,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
];
let addr = X213NetworkAddress::try_from(input.as_slice()).unwrap();
let addr_str = addr.to_string();
assert_eq!(addr_str, "IP4+192.168.1.100");
}
#[test]
fn test_get_url() {
let input = b"\xFF\x00\x01https://wildboarsoftware.com/x500directory";
let addr = X213NetworkAddress::try_from(input.as_slice()).unwrap();
assert_eq!(
addr.get_url().unwrap(),
"https://wildboarsoftware.com/x500directory"
);
}
#[test]
fn test_from_itot_socket_addr() {
let sock = SocketAddrV4::from_str("192.168.1.100:8000").unwrap();
let addr = X213NetworkAddress::from_socket_addr_v4(
RFC_1277_WELL_KNOWN_NETWORK_DARPA_NSF_INTERNET,
&sock,
None,
);
assert_eq!(
addr.get_octets(),
&[
AFI_F69_DEC_LEADING_ZERO, 0x00,
0x72,
0x87,
0x22, 0x03, 0x19,
0x21,
0x68,
0x00,
0x11,
0x00,
0x08,
0x00,
0x0F,
]
);
}
#[cfg(feature = "nonstd")]
#[test]
fn test_ip_overflow_1() {
let input = "IP4+999.999.2.100";
let maybe_addr = X213NetworkAddress::from_str(input);
assert!(maybe_addr.is_err());
}
#[test]
fn test_ip_overflow_2() {
let input = "TELEX+00728722+RFC-1006+03+256.0.0.2+9+2";
let maybe_addr = X213NetworkAddress::from_str(input);
assert!(maybe_addr.is_err());
}
#[test]
fn test_ip_overflow_3() {
let input = "TELEX+00728722+RFC-1006+03+0.255.255.255+99999+88888";
let maybe_addr = X213NetworkAddress::from_str(input);
assert!(maybe_addr.is_err());
}
#[test]
#[ignore]
fn test_ip_overflow_4() {
let input: &[u8] = &[
0x54, 0x00, 0x72, 0x87, 0x22, 0x03, 0x99, 0x90, 0x00, 0x00, 0x00,
0x06, ];
let maybe_addr = X213NetworkAddress::try_from(input);
assert!(maybe_addr.is_err());
}
#[test]
fn test_get_itot_socket_adder() {
let input = "TELEX+00728722+RFC-1006+03+255.0.0.2+65535+2";
let addr = X213NetworkAddress::from_str(input).unwrap();
let (_, sock, _) = addr.get_rfc1277_socket().unwrap();
assert_eq!(sock.ip(), &Ipv4Addr::new(255, 0, 0, 2));
assert_eq!(sock.port(), 65535);
}
#[test]
fn test_idi_digits_x121() {
let input = "X121+00123456789+x0824";
let addr = X213NetworkAddress::from_str(input).unwrap();
let digits: Vec<u8> = addr.idi_digits().unwrap().collect();
assert_eq!(digits.as_slice(), &[0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
}
#[test]
fn test_idi_digits_dcc() {
let input = "X121+023+x0824";
let addr = X213NetworkAddress::from_str(input).unwrap();
let digits: Vec<u8> = addr.idi_digits().unwrap().collect();
assert_eq!(digits.as_slice(), &[0, 2, 3]);
}
#[test]
fn test_idi_digits_telex() {
let input = "TELEX+01234+x0824";
let addr = X213NetworkAddress::from_str(input).unwrap();
let digits: Vec<u8> = addr.idi_digits().unwrap().collect();
assert_eq!(digits.as_slice(), &[0, 1, 2, 3, 4]);
}
#[test]
fn test_idi_digits_pstn() {
let input = "PSTN+8883334022+x0824";
let addr = X213NetworkAddress::from_str(input).unwrap();
let digits: Vec<u8> = addr.idi_digits().unwrap().collect();
assert_eq!(digits.as_slice(), &[8, 8, 8, 3, 3, 3, 4, 0, 2, 2]);
}
#[test]
fn test_idi_digits_idsn() {
let input = "ISDN+0018883334022+x0824";
let addr = X213NetworkAddress::from_str(input).unwrap();
let digits: Vec<u8> = addr.idi_digits().unwrap().collect();
assert_eq!(digits.as_slice(), &[0, 0, 1, 8, 8, 8, 3, 3, 3, 4, 0, 2, 2]);
}
#[test]
fn test_idi_digits_icd() {
let input = "ICD+0023+x0824";
let addr = X213NetworkAddress::from_str(input).unwrap();
let digits: Vec<u8> = addr.idi_digits().unwrap().collect();
assert_eq!(digits.as_slice(), &[2, 3]);
}
#[cfg(feature = "nonstd")]
#[test]
fn test_idi_digits_icp() {
let input = "ICP+0001+x0824";
let addr = X213NetworkAddress::from_str(input).unwrap();
let digits: Vec<u8> = addr.idi_digits().unwrap().collect();
assert_eq!(digits.as_slice(), &[1]);
}
#[cfg(feature = "nonstd")]
#[test]
fn test_idi_digits_ind() {
let input = "IND+0123+x0824";
let addr = X213NetworkAddress::from_str(input).unwrap();
let digits: Vec<u8> = addr.idi_digits().unwrap().collect();
assert_eq!(digits.as_slice(), &[1, 2, 3]);
}
#[test]
fn test_idi_digits_local() {
let input = "LOCAL++x0824";
let addr = X213NetworkAddress::from_str(input).unwrap();
let digits: Vec<u8> = addr.idi_digits().unwrap().collect();
assert_eq!(digits.as_slice(), &[]);
}
#[cfg(feature = "nonstd")]
#[test]
fn test_idi_digits_url() {
let input = "URL+0001+x0824";
let addr = X213NetworkAddress::from_str(input).unwrap();
let digits: Vec<u8> = addr.idi_digits().unwrap().collect();
assert_eq!(digits.as_slice(), &[1]);
}
#[test]
fn test_dsp_digits_x121() {
let input = "X121+00123456789+d2929";
let addr = X213NetworkAddress::from_str(input).unwrap();
let digits: Vec<u8> = addr.dsp_digits().unwrap().collect();
assert_eq!(digits.as_slice(), &[2, 9, 2, 9]);
assert_eq!(
addr.get_octets(),
&[
AFI_X121_DEC_LEADING_ZERO,
0x11,
0x10,
0x01,
0x23,
0x45,
0x67,
0x89,
0x29,
0x29,
]
);
}
#[test]
fn test_dsp_digits_dcc() {
let input = "DCC+840+d1298";
let addr = X213NetworkAddress::from_str(input).unwrap();
let digits: Vec<u8> = addr.dsp_digits().unwrap().collect();
assert_eq!(digits.as_slice(), &[1, 2, 9, 8]);
assert_eq!(
addr.get_octets(),
&[AFI_ISO_DCC_DEC, 0x84, 0x01, 0x29, 0x8F,]
);
}
#[test]
fn test_from_ipv4() {
let input = Ipv4Addr::new(192, 168, 1, 255);
let addr = X213NetworkAddress::from_ipv4(&input);
assert_eq!(
addr.get_octets(),
&[
AFI_IANA_ICP_BIN,
0,
1, 192,
168,
1,
255, 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0, ]
);
}
#[test]
fn test_from_ipv6() {
let input = Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8);
let addr = X213NetworkAddress::from_ipv6(&input);
assert_eq!(
addr.get_octets(),
&[
AFI_IANA_ICP_BIN,
0,
0, 0,
1,
0,
2,
0,
3,
0,
4,
0,
5,
0,
6,
0,
7,
0,
8, 0, ]
);
}
#[test]
fn test_from_itot_url() {
let addr = X213NetworkAddress::from_itot_url("https://himom.org");
assert_eq!(addr.get_octets(), b"\xFF\x00\x00https://himom.org");
}
#[test]
fn test_to_ns_string() {
let input = "DCC+840+d1298";
let addr = X213NetworkAddress::from_str(input).unwrap();
assert_eq!(addr.to_ns_string().as_str(), "NS+388401298f");
}
#[test]
fn test_fuzz_failure_01() {
let input: (&[u8], &str, u64, u8) = (
[
0,
0,
].as_slice(),
"+\0\0+",
82,
0,
);
let (input_b, input_s, input_u64, input_u8) = input;
let _ = X213NetworkAddress::try_from(input_b);
let _ = X213NetworkAddress::from_str(input_s);
let ss1 = [ "X121+", input_s ].join("");
let ss2 = [ "DCC+", input_s ].join("");
let ss3 = [ "TELEX+", input_s ].join("");
let ss4 = [ "PSTN+", input_s ].join("");
let ss5 = [ "ISDN+", input_s ].join("");
let ss6 = [ "ICD+", input_s ].join("");
let ss7 = [ "ICP+", input_s ].join("");
let ss8 = [ "IND+", input_s ].join("");
let ss9 = [ "LOCAL+", input_s ].join("");
let ss10 = [ "URL+", input_s ].join("");
let ss11 = [ "IP4+", input_s ].join("");
let ss12 = [ "IP6+", input_s ].join("");
let mut hexstr: Vec<u8> = Vec::with_capacity(input_b.len() << 1);
unsafe { hexstr.set_len(input_b.len() << 1) };
faster_hex::hex_encode(input_b, hexstr.as_mut_slice()).unwrap();
let hexstr = unsafe { String::from_utf8_unchecked(hexstr) };
let sb1 = [ "X121+", hexstr.as_str() ].join("");
let sb2 = [ "DCC+", hexstr.as_str() ].join("");
let sb3 = [ "TELEX+", hexstr.as_str() ].join("");
let sb4 = [ "PSTN+", hexstr.as_str() ].join("");
let sb5 = [ "ISDN+", hexstr.as_str() ].join("");
let sb6 = [ "ICD+", hexstr.as_str() ].join("");
let sb7 = [ "ICP+", hexstr.as_str() ].join("");
let sb8 = [ "IND+", hexstr.as_str() ].join("");
let sb9 = [ "LOCAL+", hexstr.as_str() ].join("");
let sb10 = [ "URL+", hexstr.as_str() ].join("");
let sb11 = [ "IP4+", hexstr.as_str() ].join("");
let sb12 = [ "IP6+", hexstr.as_str() ].join("");
let url = format!("URL+{}+{}", input_u8, input_s);
let x25_1 = format!("TELEX+00728722+X.25(80)+02+{}", input_u64);
let x25_2 = format!("TELEX+00728722+X.25(80)+02+{}+CUDF+{}", input_u64, input_u8);
let x25_3 = format!("TELEX+00728722+X.25(80)+{}+{}+CUDF+{}", input_u8, input_u8, input_u8);
let itot1 = format!("TELEX+00728722+RFC-1006+{}+{}.{}.{}.{}", input_u8, input_u8, input_u8, input_u8, input_u8);
let itot2 = format!("TELEX+00728722+RFC-1006+03+2.3.4.5+{}", input_u8);
let itot3 = format!("TELEX+00728722+RFC-1006+03+2.3.4.5+{}+{}", input_u8, input_u8);
let x121 = format!("X121+{}", input_u64);
let _ = X213NetworkAddress::from_str(ss1.as_str());
let _ = X213NetworkAddress::from_str(ss2.as_str());
let _ = X213NetworkAddress::from_str(ss3.as_str());
let _ = X213NetworkAddress::from_str(ss4.as_str());
let _ = X213NetworkAddress::from_str(ss5.as_str());
let _ = X213NetworkAddress::from_str(ss6.as_str());
let _ = X213NetworkAddress::from_str(ss7.as_str());
let _ = X213NetworkAddress::from_str(ss8.as_str());
let _ = X213NetworkAddress::from_str(ss9.as_str());
let _ = X213NetworkAddress::from_str(ss10.as_str());
let _ = X213NetworkAddress::from_str(ss11.as_str());
let _ = X213NetworkAddress::from_str(ss12.as_str());
let _ = X213NetworkAddress::from_str(sb1.as_str());
let _ = X213NetworkAddress::from_str(sb2.as_str());
let _ = X213NetworkAddress::from_str(sb3.as_str());
let _ = X213NetworkAddress::from_str(sb4.as_str());
let _ = X213NetworkAddress::from_str(sb5.as_str());
let _ = X213NetworkAddress::from_str(sb6.as_str());
let _ = X213NetworkAddress::from_str(sb7.as_str());
let _ = X213NetworkAddress::from_str(sb8.as_str());
let _ = X213NetworkAddress::from_str(sb9.as_str());
let _ = X213NetworkAddress::from_str(sb10.as_str());
let _ = X213NetworkAddress::from_str(sb11.as_str());
let _ = X213NetworkAddress::from_str(sb12.as_str());
let _ = X213NetworkAddress::from_str(url.as_str());
let _ = X213NetworkAddress::from_str(x25_1.as_str());
let _ = X213NetworkAddress::from_str(x25_2.as_str());
let _ = X213NetworkAddress::from_str(x25_3.as_str());
let _ = X213NetworkAddress::from_str(itot1.as_str());
let _ = X213NetworkAddress::from_str(itot2.as_str());
let _ = X213NetworkAddress::from_str(itot3.as_str());
let _ = X213NetworkAddress::from_str(x121.as_str());
}
}