use crate::prelude::TryFrom;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use thiserror::Error;
use uuid::Uuid;
use std::{
fmt,
net::{self, IpAddr, Ipv4Addr, Ipv6Addr},
option,
str::{self, FromStr},
vec,
};
pub const INPROC_MAX_SIZE: usize = 256;
pub trait IntoIpAddrs {
type IntoIter: Iterator<Item = IpAddr>;
fn into_ip_addrs(self) -> Self::IntoIter;
}
impl IntoIpAddrs for IpAddr {
type IntoIter = option::IntoIter<Self>;
fn into_ip_addrs(self) -> Self::IntoIter {
Some(self).into_iter()
}
}
impl IntoIpAddrs for Ipv4Addr {
type IntoIter = option::IntoIter<IpAddr>;
fn into_ip_addrs(self) -> Self::IntoIter {
IpAddr::V4(self.to_owned()).into_ip_addrs()
}
}
impl IntoIpAddrs for Ipv6Addr {
type IntoIter = option::IntoIter<IpAddr>;
fn into_ip_addrs(self) -> Self::IntoIter {
IpAddr::V6(self.to_owned()).into_ip_addrs()
}
}
impl<'a> IntoIpAddrs for &'a [IpAddr] {
type IntoIter = vec::IntoIter<IpAddr>;
fn into_ip_addrs(self) -> Self::IntoIter {
let ips: Vec<IpAddr> = self.iter().map(ToOwned::to_owned).collect();
ips.into_ip_addrs()
}
}
impl<T> IntoIpAddrs for &T
where
T: IntoIpAddrs + ?Sized + Clone,
{
type IntoIter = T::IntoIter;
fn into_ip_addrs(self) -> Self::IntoIter {
(*self).clone().into_ip_addrs()
}
}
impl<E> IntoIpAddrs for Vec<E>
where
E: Into<IpAddr>,
{
type IntoIter = vec::IntoIter<IpAddr>;
fn into_ip_addrs(self) -> Self::IntoIter {
let ips: Vec<IpAddr> = self.into_iter().map(E::into).collect();
ips.into_iter()
}
}
#[derive(Debug, Error)]
#[error("cannot parse address : {}", msg)]
pub struct AddrParseError {
msg: &'static str,
}
impl AddrParseError {
fn new(msg: &'static str) -> Self {
Self { msg }
}
pub fn msg(&self) -> &'static str {
self.msg
}
}
macro_rules! serde_display_tryfrom {
($name:ident) => {
impl Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_str(self)
}
}
impl<'de> Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
TryFrom::try_from(s).map_err(de::Error::custom)
}
}
};
}
macro_rules! tryfrom_fromstr {
($name:ident) => {
impl TryFrom<String> for $name {
type Error = AddrParseError;
fn try_from(s: String) -> Result<Self, AddrParseError> {
Self::from_str(s.as_str())
}
}
impl<'a> TryFrom<&'a String> for $name {
type Error = AddrParseError;
fn try_from(s: &'a String) -> Result<Self, AddrParseError> {
Self::from_str(s.as_str())
}
}
impl<'a> TryFrom<&'a str> for $name {
type Error = AddrParseError;
fn try_from(s: &'a str) -> Result<Self, AddrParseError> {
Self::from_str(s)
}
}
};
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Hostname {
name: String,
}
impl Hostname {
pub fn new<S>(name: S) -> Result<Self, AddrParseError>
where
S: Into<String>,
{
let name = name.into();
if !name.is_empty() {
for c in name.as_str().chars() {
if !c.is_ascii_alphanumeric() && c != '-' {
return Err(AddrParseError::new(
"hostname contains illegal char",
));
}
}
Ok(Self { name })
} else {
Err(AddrParseError::new("empty hostname"))
}
}
pub fn as_str(&self) -> &str {
self.name.as_str()
}
}
impl FromStr for Hostname {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, AddrParseError> {
Self::new(s)
}
}
impl fmt::Display for Hostname {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)
}
}
serde_display_tryfrom!(Hostname);
impl TryFrom<String> for Hostname {
type Error = AddrParseError;
fn try_from(s: String) -> Result<Self, AddrParseError> {
Self::new(s)
}
}
impl<'a> TryFrom<&'a String> for Hostname {
type Error = AddrParseError;
fn try_from(s: &'a String) -> Result<Self, AddrParseError> {
Self::new(s.as_str())
}
}
impl<'a> TryFrom<&'a str> for Hostname {
type Error = AddrParseError;
fn try_from(s: &'a str) -> Result<Self, AddrParseError> {
Self::new(s)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Port {
Specified(u16),
Unspecified,
}
impl Port {
pub fn is_specified(self) -> bool {
if let Port::Specified(_) = self {
true
} else {
false
}
}
pub fn is_unspecified(self) -> bool {
if let Port::Unspecified = self {
true
} else {
false
}
}
}
impl FromStr for Port {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, AddrParseError> {
if !s.is_empty() {
if s.starts_with('*') && s.len() == 1 {
Ok(Port::Unspecified)
} else {
let port = u16::from_str(s)
.map_err(|_| AddrParseError::new("invalid port number"))?;
Ok(Port::Specified(port))
}
} else {
Err(AddrParseError::new("empty port"))
}
}
}
tryfrom_fromstr!(Port);
impl fmt::Display for Port {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Port::Specified(num) => write!(f, "{}", num),
Port::Unspecified => write!(f, "*"),
}
}
}
serde_display_tryfrom!(Port);
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Interface {
Ip(IpAddr),
Hostname(Hostname),
}
impl FromStr for Interface {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, AddrParseError> {
if !s.is_empty() {
if let Ok(ip) = IpAddr::from_str(s) {
Ok(Interface::Ip(ip))
} else {
let interface = Hostname::from_str(s)?;
Ok(Interface::Hostname(interface))
}
} else {
Err(AddrParseError::new("empty interface"))
}
}
}
tryfrom_fromstr!(Interface);
impl fmt::Display for Interface {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Interface::Ip(ip) => write!(f, "{}", ip),
Interface::Hostname(interface) => write!(f, "{}", interface),
}
}
}
serde_display_tryfrom!(Interface);
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct SocketAddr {
interface: Interface,
port: Port,
}
impl SocketAddr {
pub fn new(interface: Interface, port: Port) -> Self {
Self { interface, port }
}
pub fn interface(&self) -> &Interface {
&self.interface
}
pub fn port(&self) -> Port {
self.port
}
}
impl FromStr for SocketAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, AddrParseError> {
if let Some(mid) = s.rfind(':') {
let addr = {
if s.starts_with('[') && s.chars().nth(mid - 1).unwrap() == ']'
{
let interface = Interface::from_str(&s[1..mid - 1])?;
let port = Port::from_str(&s[mid + 1..])?;
Self { interface, port }
} else {
let interface = Interface::from_str(&s[0..mid])?;
let port = Port::from_str(&s[mid + 1..])?;
Self { interface, port }
}
};
Ok(addr)
} else {
Err(AddrParseError::new("invalid addr format"))
}
}
}
tryfrom_fromstr!(SocketAddr);
impl fmt::Display for SocketAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}:{}", self.interface, self.port)
}
}
serde_display_tryfrom!(SocketAddr);
impl From<net::SocketAddr> for SocketAddr {
fn from(addr: net::SocketAddr) -> Self {
Self::new(Interface::Ip(addr.ip()), Port::Specified(addr.port()))
}
}
impl<'a> From<&'a SocketAddr> for SocketAddr {
fn from(addr: &'a SocketAddr) -> Self {
addr.to_owned()
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum SrcAddr {
Socket(SocketAddr),
Interface(Interface),
}
impl FromStr for SrcAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, AddrParseError> {
if let Ok(addr) = SocketAddr::from_str(s) {
Ok(SrcAddr::Socket(addr))
} else {
let host = Interface::from_str(s)?;
Ok(SrcAddr::Interface(host))
}
}
}
tryfrom_fromstr!(SrcAddr);
impl fmt::Display for SrcAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
SrcAddr::Socket(addr) => write!(f, "{}", addr),
SrcAddr::Interface(host) => write!(f, "{}", host),
}
}
}
serde_display_tryfrom!(SrcAddr);
impl From<SocketAddr> for SrcAddr {
fn from(addr: SocketAddr) -> Self {
SrcAddr::Socket(addr)
}
}
impl<'a> From<&'a SocketAddr> for SrcAddr {
fn from(addr: &'a SocketAddr) -> Self {
SrcAddr::Socket(addr.to_owned())
}
}
impl<'a> From<&'a SrcAddr> for SrcAddr {
fn from(src: &'a SrcAddr) -> Self {
src.to_owned()
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct TcpAddr {
src: Option<SrcAddr>,
host: SocketAddr,
}
impl TcpAddr {
pub fn new<H>(host: H) -> Self
where
H: Into<SocketAddr>,
{
let host = host.into();
Self { host, src: None }
}
pub fn add_src<S>(mut self, src: S) -> Self
where
S: Into<SrcAddr>,
{
let src = src.into();
self.src = Some(src);
self
}
pub fn host(&self) -> &SocketAddr {
&self.host
}
pub fn src(&self) -> Option<&SrcAddr> {
self.src.as_ref()
}
}
impl FromStr for TcpAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, AddrParseError> {
if let Some(mid) = s.find(';') {
let src = Some(SrcAddr::from_str(&s[..mid])?);
let host = SocketAddr::from_str(&s[mid + 1..])?;
Ok(Self { src, host })
} else {
let host = SocketAddr::from_str(s)?;
Ok(Self { src: None, host })
}
}
}
tryfrom_fromstr!(TcpAddr);
impl fmt::Display for TcpAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.src.is_some() {
write!(f, "{};{}", self.host, self.src.as_ref().unwrap())
} else {
write!(f, "{}", self.host)
}
}
}
serde_display_tryfrom!(TcpAddr);
impl From<SocketAddr> for TcpAddr {
fn from(host: SocketAddr) -> Self {
Self { host, src: None }
}
}
impl IntoIterator for TcpAddr {
type Item = Self;
type IntoIter = option::IntoIter<Self>;
fn into_iter(self) -> Self::IntoIter {
Some(self).into_iter()
}
}
impl<'a> IntoIterator for &'a TcpAddr {
type Item = Self;
type IntoIter = option::IntoIter<Self>;
fn into_iter(self) -> Self::IntoIter {
Some(self).into_iter()
}
}
impl From<TcpAddr> for Endpoint {
fn from(addr: TcpAddr) -> Endpoint {
Endpoint::Tcp(addr)
}
}
impl<'a> From<&'a TcpAddr> for Endpoint {
fn from(addr: &'a TcpAddr) -> Endpoint {
Endpoint::Tcp(addr.to_owned())
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct UdpAddr {
src: Option<SrcAddr>,
host: SocketAddr,
}
impl UdpAddr {
pub fn new<H>(host: H) -> Self
where
H: Into<SocketAddr>,
{
let host = host.into();
Self { host, src: None }
}
pub fn add_src<S>(mut self, src: S) -> Self
where
S: Into<SrcAddr>,
{
let src = src.into();
self.src = Some(src);
self
}
pub fn host(&self) -> &SocketAddr {
&self.host
}
pub fn src(&self) -> Option<&SrcAddr> {
self.src.as_ref()
}
}
impl FromStr for UdpAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, AddrParseError> {
if let Some(mid) = s.find(';') {
let src = Some(SrcAddr::from_str(&s[..mid])?);
let host = SocketAddr::from_str(&s[mid + 1..])?;
Ok(Self { src, host })
} else {
let host = SocketAddr::from_str(s)?;
Ok(Self { src: None, host })
}
}
}
tryfrom_fromstr!(UdpAddr);
impl fmt::Display for UdpAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.src.is_some() {
write!(f, "{};{}", self.host, self.src.as_ref().unwrap())
} else {
write!(f, "{}", self.host)
}
}
}
serde_display_tryfrom!(UdpAddr);
impl From<SocketAddr> for UdpAddr {
fn from(host: SocketAddr) -> Self {
Self { host, src: None }
}
}
impl IntoIterator for UdpAddr {
type Item = Self;
type IntoIter = option::IntoIter<Self>;
fn into_iter(self) -> Self::IntoIter {
Some(self).into_iter()
}
}
impl<'a> IntoIterator for &'a UdpAddr {
type Item = Self;
type IntoIter = option::IntoIter<Self>;
fn into_iter(self) -> Self::IntoIter {
Some(self).into_iter()
}
}
impl From<UdpAddr> for Endpoint {
fn from(addr: UdpAddr) -> Endpoint {
Endpoint::Udp(addr)
}
}
impl<'a> From<&'a UdpAddr> for Endpoint {
fn from(addr: &'a UdpAddr) -> Endpoint {
Endpoint::Udp(addr.to_owned())
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct PgmAddr {
src: Option<SrcAddr>,
host: SocketAddr,
}
impl PgmAddr {
pub fn new<H>(host: H) -> Self
where
H: Into<SocketAddr>,
{
let host = host.into();
Self { host, src: None }
}
pub fn add_src<S>(mut self, src: S) -> Self
where
S: Into<SrcAddr>,
{
let src = src.into();
self.src = Some(src);
self
}
pub fn host(&self) -> &SocketAddr {
&self.host
}
pub fn src(&self) -> Option<&SrcAddr> {
self.src.as_ref()
}
}
impl FromStr for PgmAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, AddrParseError> {
if let Some(mid) = s.find(';') {
let src = Some(SrcAddr::from_str(&s[..mid])?);
let host = SocketAddr::from_str(&s[mid + 1..])?;
Ok(Self { src, host })
} else {
let host = SocketAddr::from_str(s)?;
Ok(Self { src: None, host })
}
}
}
tryfrom_fromstr!(PgmAddr);
impl fmt::Display for PgmAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.src.is_some() {
write!(f, "{};{}", self.host, self.src.as_ref().unwrap())
} else {
write!(f, "{}", self.host)
}
}
}
serde_display_tryfrom!(PgmAddr);
impl From<SocketAddr> for PgmAddr {
fn from(host: SocketAddr) -> Self {
Self { host, src: None }
}
}
impl IntoIterator for PgmAddr {
type Item = Self;
type IntoIter = option::IntoIter<Self>;
fn into_iter(self) -> Self::IntoIter {
Some(self).into_iter()
}
}
impl<'a> IntoIterator for &'a PgmAddr {
type Item = Self;
type IntoIter = option::IntoIter<Self>;
fn into_iter(self) -> Self::IntoIter {
Some(self).into_iter()
}
}
impl From<PgmAddr> for Endpoint {
fn from(addr: PgmAddr) -> Endpoint {
Endpoint::Pgm(addr)
}
}
impl<'a> From<&'a PgmAddr> for Endpoint {
fn from(addr: &'a PgmAddr) -> Endpoint {
Endpoint::Pgm(addr.to_owned())
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct EpgmAddr {
src: Option<SrcAddr>,
host: SocketAddr,
}
impl EpgmAddr {
pub fn new<H>(host: H) -> Self
where
H: Into<SocketAddr>,
{
let host = host.into();
Self { host, src: None }
}
pub fn add_src<S>(mut self, src: S) -> Self
where
S: Into<SrcAddr>,
{
let src = src.into();
self.src = Some(src);
self
}
pub fn host(&self) -> &SocketAddr {
&self.host
}
pub fn src(&self) -> Option<&SrcAddr> {
self.src.as_ref()
}
}
impl FromStr for EpgmAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, AddrParseError> {
if let Some(mid) = s.find(';') {
let src = Some(SrcAddr::from_str(&s[..mid])?);
let host = SocketAddr::from_str(&s[mid + 1..])?;
Ok(Self { src, host })
} else {
let host = SocketAddr::from_str(s)?;
Ok(Self { src: None, host })
}
}
}
tryfrom_fromstr!(EpgmAddr);
impl fmt::Display for EpgmAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.src.is_some() {
write!(f, "{};{}", self.host, self.src.as_ref().unwrap())
} else {
write!(f, "{}", self.host)
}
}
}
serde_display_tryfrom!(EpgmAddr);
impl From<SocketAddr> for EpgmAddr {
fn from(host: SocketAddr) -> Self {
Self { host, src: None }
}
}
impl IntoIterator for EpgmAddr {
type Item = Self;
type IntoIter = option::IntoIter<Self>;
fn into_iter(self) -> Self::IntoIter {
Some(self).into_iter()
}
}
impl<'a> IntoIterator for &'a EpgmAddr {
type Item = Self;
type IntoIter = option::IntoIter<Self>;
fn into_iter(self) -> Self::IntoIter {
Some(self).into_iter()
}
}
impl From<EpgmAddr> for Endpoint {
fn from(addr: EpgmAddr) -> Endpoint {
Endpoint::Epgm(addr)
}
}
impl<'a> From<&'a EpgmAddr> for Endpoint {
fn from(addr: &'a EpgmAddr) -> Endpoint {
Endpoint::Epgm(addr.to_owned())
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct InprocAddr {
host: String,
}
impl InprocAddr {
pub fn new<S>(host: S) -> Result<Self, AddrParseError>
where
S: Into<String>,
{
let host = host.into();
if host.is_empty() {
Err(AddrParseError::new("empty host"))
} else if host.len() > INPROC_MAX_SIZE {
Err(AddrParseError::new(
"host cannot exceed `INPROC_MAX_SIZE` chars",
))
} else {
Ok(Self { host })
}
}
pub fn new_unique() -> Self {
Self::new(Uuid::new_v4().to_string()).unwrap()
}
pub fn as_str(&self) -> &str {
self.host.as_str()
}
}
impl FromStr for InprocAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, AddrParseError> {
Self::new(s)
}
}
impl fmt::Display for InprocAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.host.fmt(f)
}
}
serde_display_tryfrom!(InprocAddr);
impl TryFrom<String> for InprocAddr {
type Error = AddrParseError;
fn try_from(s: String) -> Result<Self, AddrParseError> {
Self::new(s)
}
}
impl<'a> TryFrom<&'a String> for InprocAddr {
type Error = AddrParseError;
fn try_from(s: &'a String) -> Result<Self, AddrParseError> {
Self::new(s.as_str())
}
}
impl<'a> TryFrom<&'a str> for InprocAddr {
type Error = AddrParseError;
fn try_from(s: &'a str) -> Result<Self, AddrParseError> {
Self::new(s)
}
}
impl IntoIterator for InprocAddr {
type Item = Self;
type IntoIter = option::IntoIter<Self>;
fn into_iter(self) -> Self::IntoIter {
Some(self).into_iter()
}
}
impl<'a> IntoIterator for &'a InprocAddr {
type Item = Self;
type IntoIter = option::IntoIter<Self>;
fn into_iter(self) -> Self::IntoIter {
Some(self).into_iter()
}
}
impl From<InprocAddr> for Endpoint {
fn from(addr: InprocAddr) -> Endpoint {
Endpoint::Inproc(addr)
}
}
impl<'a> From<&'a InprocAddr> for Endpoint {
fn from(addr: &'a InprocAddr) -> Endpoint {
Endpoint::Inproc(addr.to_owned())
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Endpoint {
Tcp(TcpAddr),
Udp(UdpAddr),
Inproc(InprocAddr),
Pgm(PgmAddr),
Epgm(EpgmAddr),
}
impl Endpoint {
pub fn is_tcp(&self) -> bool {
if let Endpoint::Tcp(_) = self {
true
} else {
false
}
}
pub fn is_udp(&self) -> bool {
if let Endpoint::Udp(_) = self {
true
} else {
false
}
}
pub fn is_inproc(&self) -> bool {
if let Endpoint::Inproc(_) = self {
true
} else {
false
}
}
pub fn is_pgm(&self) -> bool {
if let Endpoint::Pgm(_) = self {
true
} else {
false
}
}
pub fn is_edpgm(&self) -> bool {
if let Endpoint::Epgm(_) = self {
true
} else {
false
}
}
pub(crate) fn from_zmq(s: &str) -> Self {
let index = s.find("://").unwrap();
match &s[0..index] {
"tcp" => {
let addr = TcpAddr::from_str(&s[index + 3..]).unwrap();
Endpoint::Tcp(addr)
}
"inproc" => {
let addr = InprocAddr::from_str(&s[index + 3..]).unwrap();
Endpoint::Inproc(addr)
}
"udp" => {
let addr = UdpAddr::from_str(&s[index + 3..]).unwrap();
Endpoint::Udp(addr)
}
"pgm" => {
let addr = PgmAddr::from_str(&s[index + 3..]).unwrap();
Endpoint::Pgm(addr)
}
"epgm" => {
let addr = EpgmAddr::from_str(&s[index + 3..]).unwrap();
Endpoint::Epgm(addr)
}
_ => unreachable!(),
}
}
pub(crate) fn to_zmq(&self) -> String {
match self {
Endpoint::Tcp(addr) => format!("tcp://{}", addr),
Endpoint::Inproc(addr) => format!("inproc://{}", addr),
Endpoint::Udp(addr) => format!("udp://{}", addr),
Endpoint::Epgm(addr) => format!("pgm://{}", addr),
Endpoint::Pgm(addr) => format!("epgm://{}", addr),
}
}
}
impl IntoIterator for Endpoint {
type Item = Endpoint;
type IntoIter = option::IntoIter<Endpoint>;
fn into_iter(self) -> Self::IntoIter {
Some(self).into_iter()
}
}
impl<'a> IntoIterator for &'a Endpoint {
type Item = &'a Endpoint;
type IntoIter = option::IntoIter<&'a Endpoint>;
fn into_iter(self) -> Self::IntoIter {
Some(self).into_iter()
}
}
impl<'a> From<&'a Endpoint> for Endpoint {
fn from(e: &'a Endpoint) -> Self {
e.to_owned()
}
}
impl AsRef<Endpoint> for Endpoint {
fn as_ref(&self) -> &Endpoint {
&self
}
}
#[cfg(test)]
mod test {
macro_rules! test_addr_ser_de {
($mod: ident, $name: ty, $string: expr) => {
mod $mod {
use crate::{addr::*, prelude::*, *};
#[test]
fn test_ser_de() {
let addr: $name = $string.try_into().unwrap();
let endpoint: Endpoint = addr.into();
let ron = serde_yaml::to_string(&endpoint).unwrap();
let de: Endpoint = serde_yaml::from_str(&ron).unwrap();
assert_eq!(endpoint, de);
}
}
};
}
test_addr_ser_de!(tcp, TcpAddr, "0.0.0.0:3000");
test_addr_ser_de!(udp, UdpAddr, "0.0.0.0:3000");
test_addr_ser_de!(pgm, PgmAddr, "0.0.0.0:3000");
test_addr_ser_de!(epgm, EpgmAddr, "0.0.0.0:3000");
test_addr_ser_de!(inproc, InprocAddr, "test");
}