use std::{ marker::PhantomData, net::{IpAddr, Ipv4Addr, Ipv6Addr}, }; use serde::{Deserialize, Deserializer, Serialize}; enum IpOctets { V4([u8; 4]), V6([u8; 16]), } impl IpOctets { fn as_slice(&self) -> &[u8] { match &self { IpOctets::V4(s) => s, IpOctets::V6(s) => s, } } } #[derive(Debug, Clone, Copy)] pub struct PeerIP(pub T); pub type PeerIP4 = PeerIP; pub type PeerIP6 = PeerIP; pub type PeerIPAny = PeerIP; trait IpLike: Sized { fn octets(&self) -> IpOctets; fn try_from_slice(b: &[u8]) -> Option; fn expecting() -> &'static str; } impl IpLike for Ipv4Addr { fn octets(&self) -> IpOctets { IpOctets::V4(self.octets()) } fn try_from_slice(b: &[u8]) -> Option { let arr: [u8; 4] = b.try_into().ok()?; Some(arr.into()) } fn expecting() -> &'static str { "expecting 4 bytes of ipv4" } } impl IpLike for Ipv6Addr { fn octets(&self) -> IpOctets { IpOctets::V6(self.octets()) } fn try_from_slice(b: &[u8]) -> Option { let arr: [u8; 16] = b.try_into().ok()?; Some(arr.into()) } fn expecting() -> &'static str { "expecting 16 bytes of ipv6" } } impl IpLike for IpAddr { fn octets(&self) -> IpOctets { match self { IpAddr::V4(ipv4_addr) => IpOctets::V4(ipv4_addr.octets()), IpAddr::V6(ipv6_addr) => IpOctets::V6(ipv6_addr.octets()), } } fn try_from_slice(b: &[u8]) -> Option { match b.len() { 4 => Ipv4Addr::try_from_slice(b).map(Into::into), 16 => Ipv6Addr::try_from_slice(b).map(Into::into), _ => None, } } fn expecting() -> &'static str { "expecting 4 or 16 bytes of ipv4 or ipv6" } } impl Serialize for PeerIP where T: IpLike, { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.serialize_bytes(self.0.octets().as_slice()) } } impl<'de, T> Deserialize<'de> for PeerIP where T: IpLike, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct Visitor { p: PhantomData, } impl serde::de::Visitor<'_> for Visitor where T: IpLike, { type Value = PeerIP; fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str(T::expecting()) } fn visit_bytes(self, v: &[u8]) -> Result where E: serde::de::Error, { T::try_from_slice(v) .map(PeerIP) .ok_or_else(|| E::custom(T::expecting())) } } deserializer.deserialize_bytes(Visitor { p: Default::default(), }) } }