294 lines
9.3 KiB
Rust
294 lines
9.3 KiB
Rust
use crate::{IpNet, Ipv4Net, Ipv6Net};
|
|
use core::fmt;
|
|
#[cfg(not(feature = "std"))]
|
|
use core::net::{Ipv4Addr, Ipv6Addr};
|
|
#[cfg(feature = "std")]
|
|
use std::net::{Ipv4Addr, Ipv6Addr};
|
|
use serde::{self, Serialize, Deserialize, Serializer, Deserializer};
|
|
use serde::ser::SerializeTuple;
|
|
use serde::de::{EnumAccess, Error, VariantAccess, Visitor};
|
|
|
|
impl Serialize for IpNet {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where S: Serializer
|
|
{
|
|
if serializer.is_human_readable() {
|
|
match *self {
|
|
IpNet::V4(ref a) => a.serialize(serializer),
|
|
IpNet::V6(ref a) => a.serialize(serializer),
|
|
}
|
|
} else {
|
|
match *self {
|
|
IpNet::V4(ref a) => serializer.serialize_newtype_variant("IpNet", 0, "V4", a),
|
|
IpNet::V6(ref a) => serializer.serialize_newtype_variant("IpNet", 1, "V6", a),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for IpNet {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where D: Deserializer<'de>
|
|
{
|
|
if deserializer.is_human_readable() {
|
|
struct IpNetVisitor;
|
|
|
|
impl<'de> Visitor<'de> for IpNetVisitor {
|
|
type Value = IpNet;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("IPv4 or IPv6 network address")
|
|
}
|
|
|
|
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
|
where E: Error
|
|
{
|
|
s.parse().map_err(Error::custom)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_str(IpNetVisitor)
|
|
} else {
|
|
struct EnumVisitor;
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
enum IpNetKind {
|
|
V4,
|
|
V6,
|
|
}
|
|
|
|
impl<'de> Visitor<'de> for EnumVisitor {
|
|
type Value = IpNet;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("IPv4 or IPv6 network address")
|
|
}
|
|
|
|
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
|
|
where A: EnumAccess<'de>
|
|
{
|
|
match data.variant()? {
|
|
(IpNetKind::V4, v) => v.newtype_variant().map(IpNet::V4),
|
|
(IpNetKind::V6, v) => v.newtype_variant().map(IpNet::V6),
|
|
}
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_enum("IpNet", &["V4", "V6"], EnumVisitor)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Serialize for Ipv4Net {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where S: Serializer
|
|
{
|
|
if serializer.is_human_readable() {
|
|
#[cfg(feature = "ser_as_str")]
|
|
{
|
|
let mut buf = heapless::String::<18>::new();
|
|
fmt::write(&mut buf, format_args!("{self}")).unwrap();
|
|
serializer.serialize_str(&buf)
|
|
}
|
|
#[cfg(not(feature = "ser_as_str"))]
|
|
serializer.collect_str(self)
|
|
} else {
|
|
let mut seq = serializer.serialize_tuple(5)?;
|
|
for octet in &self.addr().octets() {
|
|
seq.serialize_element(octet)?;
|
|
}
|
|
seq.serialize_element(&self.prefix_len())?;
|
|
seq.end()
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for Ipv4Net {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where D: Deserializer<'de>
|
|
{
|
|
if deserializer.is_human_readable() {
|
|
struct IpAddrVisitor;
|
|
|
|
impl<'de> Visitor<'de> for IpAddrVisitor {
|
|
type Value = Ipv4Net;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("IPv4 network address")
|
|
}
|
|
|
|
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
|
where E: Error
|
|
{
|
|
s.parse().map_err(Error::custom)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_str(IpAddrVisitor)
|
|
} else {
|
|
let b = <[u8; 5]>::deserialize(deserializer)?;
|
|
Ipv4Net::new(Ipv4Addr::new(b[0], b[1], b[2], b[3]), b[4]).map_err(serde::de::Error::custom)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Serialize for Ipv6Net {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where S: Serializer
|
|
{
|
|
if serializer.is_human_readable() {
|
|
#[cfg(feature = "ser_as_str")]
|
|
{
|
|
let mut buf = heapless::String::<43>::new();
|
|
fmt::write(&mut buf, format_args!("{self}")).unwrap();
|
|
serializer.serialize_str(&buf)
|
|
}
|
|
#[cfg(not(feature = "ser_as_str"))]
|
|
serializer.collect_str(self)
|
|
} else {
|
|
let mut seq = serializer.serialize_tuple(17)?;
|
|
for octet in &self.addr().octets() {
|
|
seq.serialize_element(octet)?;
|
|
}
|
|
seq.serialize_element(&self.prefix_len())?;
|
|
seq.end()
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for Ipv6Net {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where D: Deserializer<'de>
|
|
{
|
|
if deserializer.is_human_readable() {
|
|
struct IpAddrVisitor;
|
|
|
|
impl<'de> Visitor<'de> for IpAddrVisitor {
|
|
type Value = Ipv6Net;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("IPv6 network address")
|
|
}
|
|
|
|
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
|
where E: Error
|
|
{
|
|
s.parse().map_err(Error::custom)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_str(IpAddrVisitor)
|
|
} else {
|
|
let b = <[u8; 17]>::deserialize(deserializer)?;
|
|
Ipv6Net::new(Ipv6Addr::new(
|
|
((b[0] as u16) << 8) | b[1] as u16, ((b[2] as u16) << 8) | b[3] as u16,
|
|
((b[4] as u16) << 8) | b[5] as u16, ((b[6] as u16) << 8) | b[7] as u16,
|
|
((b[8] as u16) << 8) | b[9] as u16, ((b[10] as u16) << 8) | b[11] as u16,
|
|
((b[12] as u16) << 8) | b[13] as u16, ((b[14] as u16) << 8) | b[15] as u16
|
|
), b[16]).map_err(Error::custom)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
extern crate serde_test;
|
|
|
|
use crate::{IpNet, Ipv4Net, Ipv6Net};
|
|
use self::serde_test::{assert_tokens, Configure, Token};
|
|
|
|
#[test]
|
|
fn test_serialize_ipnet_v4() {
|
|
let net_str = "10.1.1.0/24";
|
|
let net: IpNet = net_str.parse().unwrap();
|
|
assert_tokens(&net.readable(), &[Token::Str(net_str)]);
|
|
assert_tokens(&net.compact(), &[
|
|
Token::NewtypeVariant { name: "IpNet", variant: "V4", },
|
|
Token::Tuple { len: 5 },
|
|
Token::U8(10),
|
|
Token::U8(1),
|
|
Token::U8(1),
|
|
Token::U8(0),
|
|
Token::U8(24),
|
|
Token::TupleEnd,
|
|
]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_serialize_ipnet_v6() {
|
|
let net_str = "fd00::/32";
|
|
let net: IpNet = net_str.parse().unwrap();
|
|
assert_tokens(&net.readable(), &[Token::Str(net_str)]);
|
|
assert_tokens(&net.compact(), &[
|
|
Token::NewtypeVariant { name: "IpNet", variant: "V6", },
|
|
// This is too painful, but Token::Bytes() seems to be
|
|
// an array with a length, which is not what we serialize.
|
|
Token::Tuple { len: 17 },
|
|
Token::U8(253u8),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(32),
|
|
Token::TupleEnd,
|
|
]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_serialize_ipv4_net() {
|
|
let net_str = "10.1.1.0/24";
|
|
let net: Ipv4Net = net_str.parse().unwrap();
|
|
assert_tokens(&net.readable(), &[Token::Str(net_str)]);
|
|
assert_tokens(&net.compact(), &[
|
|
Token::Tuple { len: 5 },
|
|
Token::U8(10),
|
|
Token::U8(1),
|
|
Token::U8(1),
|
|
Token::U8(0),
|
|
Token::U8(24),
|
|
Token::TupleEnd,
|
|
]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_serialize_ipv6_net() {
|
|
let net_str = "fd00::/32";
|
|
let net: Ipv6Net = net_str.parse().unwrap();
|
|
assert_tokens(&net.readable(), &[Token::Str(net_str)]);
|
|
assert_tokens(&net.compact(), &[
|
|
// This is too painful, but Token::Bytes() seems to be
|
|
// an array with a length, which is not what we serialize.
|
|
Token::Tuple { len: 17 },
|
|
Token::U8(253u8),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(0),
|
|
Token::U8(32),
|
|
Token::TupleEnd,
|
|
]);
|
|
}
|
|
}
|