use std::fmt;
use std::num::ParseIntError;
use std::str::FromStr;
use crate::{Buf, BufMut, BufResult, Codec, Cursor};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Port(pub u16);
impl Port {
pub const fn new(port: u16) -> Self {
Port(port)
}
pub const fn as_u16(self) -> u16 {
self.0
}
pub const fn is_system(self) -> bool {
self.0 <= 1023
}
pub const fn is_user(self) -> bool {
self.0 >= 1024 && self.0 <= 49151
}
pub const fn is_dynamic(self) -> bool {
self.0 >= 49152
}
}
impl Default for Port {
fn default() -> Self {
Self(0)
}
}
impl From<u16> for Port {
#[inline]
fn from(val: u16) -> Self {
Port(val)
}
}
impl From<Port> for u16 {
#[inline]
fn from(port: Port) -> Self {
port.0
}
}
impl fmt::Display for Port {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl FromStr for Port {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.parse::<u16>().map(Port)
}
}
impl Codec for Port {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.0.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self(u16::decode(reader, ())?))
}
}
#[cfg(test)]
mod tests {
use core::fmt::Debug;
use super::Port;
use crate::{Codec, Cursor};
fn codec_roundtrip<T: Codec<C> + Debug + Eq, C: Copy>(
etalon_struct: T,
etalon_bytes: &[u8],
context: C,
) {
let mut encoded_bytes = vec![];
{
let writer = &mut Cursor::new(&mut encoded_bytes);
etalon_struct.encode(writer, context).unwrap();
}
assert_eq!(etalon_bytes, &encoded_bytes);
let decoded_struct = {
let reader = &mut Cursor::new(&mut encoded_bytes);
T::decode(reader, context).unwrap()
};
assert_eq!(etalon_struct, decoded_struct);
encoded_bytes.fill(0x00);
{
let writer = &mut Cursor::new(&mut encoded_bytes);
decoded_struct.encode(writer, context).unwrap();
}
assert_eq!(etalon_bytes, &encoded_bytes);
}
#[test]
fn port() {
let etalon_bytes = &[0x00, 0x50]; let etalon_struct = Port::new(80);
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn port_ranges() {
let system_port = Port::new(80);
assert!(system_port.is_system());
assert!(!system_port.is_user());
assert!(!system_port.is_dynamic());
let user_port = Port::new(8080);
assert!(!user_port.is_system());
assert!(user_port.is_user());
assert!(!user_port.is_dynamic());
let dynamic_port = Port::new(50000);
assert!(!dynamic_port.is_system());
assert!(!dynamic_port.is_user());
assert!(dynamic_port.is_dynamic());
}
}