ip4: add custom wrapper type around IPv4 addresses for serde

This commit is contained in:
Matt Bilker
2018-07-10 15:58:09 +00:00
parent 68e7da5cf5
commit 480a4c5cc8
4 changed files with 98 additions and 2 deletions

View File

@@ -1,6 +1,6 @@
[package]
name = "kbinxml"
version = "0.3.0"
version = "0.4.0"
authors = ["Matt Bilker <me@mbilker.us>"]
[dependencies]

View File

@@ -11,10 +11,11 @@ extern crate quick_xml;
use std::env;
use std::fs::File;
use std::io::{Cursor, Error as IoError, ErrorKind as IoErrorKind, Read, Write, stdout};
use std::net::Ipv4Addr;
use std::str;
use failure::Fail;
use kbinxml::{KbinXml, Options, from_bytes, to_bytes};
use kbinxml::{Ip4Addr, KbinXml, Options, from_bytes, to_bytes};
use minidom::Element;
use quick_xml::Writer;
@@ -24,6 +25,9 @@ pub struct Testing2 {
hi: u16,
ho: i16,
vu: Vec<u8>,
opt: Option<u8>,
opt2: Option<u8>,
ip: Ip4Addr,
}
#[derive(Debug, Deserialize, Serialize)]
@@ -154,6 +158,9 @@ fn main() -> std::io::Result<()> {
hi: 32423,
ho: 32000,
vu: vec![33, 255, 254],
opt: None,
opt2: Some(111),
ip: Ip4Addr::new(Ipv4Addr::new(127, 0, 0, 1)),
},
};
let bytes = to_bytes(&obj).unwrap();

87
src/ip4.rs Normal file
View File

@@ -0,0 +1,87 @@
use std::fmt;
use std::net::Ipv4Addr;
use std::ops::{Deref, DerefMut};
use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};
use serde::ser::{Serialize, SerializeTupleStruct, Serializer};
pub struct Ip4Addr(Ipv4Addr);
struct Ip4Visitor;
impl Ip4Addr {
pub fn new(addr: Ipv4Addr) -> Self {
Ip4Addr(addr)
}
}
impl fmt::Display for Ip4Addr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl fmt::Debug for Ip4Addr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl Deref for Ip4Addr {
type Target = Ipv4Addr;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Ip4Addr {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'de> Visitor<'de> for Ip4Visitor {
type Value = [u8; 4];
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a sequence of 4 bytes with no size indicator")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where A: SeqAccess<'de>
{
trace!("Ip4Addr::visit_seq()");
let v1: u8 = seq.next_element()?.unwrap();
let v2: u8 = seq.next_element()?.unwrap();
let v3: u8 = seq.next_element()?.unwrap();
let v4: u8 = seq.next_element()?.unwrap();
trace!("Ip4Addr:visit_seq() => [{}, {}, {}, {}]", v1, v2, v3, v4);
Ok([v1, v2, v3, v4])
}
}
impl<'de> Deserialize<'de> for Ip4Addr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
deserializer.deserialize_tuple_struct("ip4", 4, Ip4Visitor)
.map(|v| {
Ip4Addr(Ipv4Addr::from(v))
})
}
}
impl Serialize for Ip4Addr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
let octets = self.0.octets();
let mut ts = serializer.serialize_tuple_struct("ip4", 4)?;
ts.serialize_field(&octets[0])?;
ts.serialize_field(&octets[1])?;
ts.serialize_field(&octets[2])?;
ts.serialize_field(&octets[3])?;
ts.end()
}
}

View File

@@ -26,6 +26,7 @@ mod byte_buffer;
mod compression;
mod encoding_type;
mod error;
mod ip4;
mod node_types;
mod options;
mod sixbit;
@@ -43,6 +44,7 @@ pub use encoding_type::EncodingType;
pub use error::{KbinError, KbinErrorKind, Result};
pub use options::Options;
pub use de::from_bytes;
pub use ip4::Ip4Addr;
pub use ser::to_bytes;
const SIGNATURE: u8 = 0xA0;