From d3590893fdac4bc498971ffd92d4b617d0ba1c76 Mon Sep 17 00:00:00 2001 From: Nicholas Omer Chiasson Date: Tue, 4 Jul 2023 20:40:17 -0400 Subject: [PATCH 1/2] Add support for serialization with feature flag --- .github/workflows/rust.yml | 6 +-- Cargo.toml | 4 ++ src/cidr.rs | 8 ++- src/fcidr.rs | 13 +---- src/lib.rs | 1 + src/serde.rs | 108 +++++++++++++++++++++++++++++++++++++ 6 files changed, 125 insertions(+), 15 deletions(-) create mode 100644 src/serde.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6339db4..f51c82b 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -19,13 +19,13 @@ jobs: - name: Checkout uses: actions/checkout@v3.5.2 - name: Check - run: cargo check --verbose + run: cargo check --all-features --verbose - name: Format run: cargo fmt --check --verbose - name: Lint run: rustup component add clippy && cargo clippy --verbose - name: Test - run: cargo test --verbose + run: cargo test --all-features --verbose tag: if: github.event_name == 'push' || (github.base_ref == 'main' && github.event.pull_request.merged == true) @@ -106,7 +106,7 @@ jobs: - name: Build shell: bash run: | - cargo build --release --verbose + cargo build --all-features --release --verbose publish: if: github.event_name == 'push' || (github.base_ref == 'main' && github.event.pull_request.merged == true) diff --git a/Cargo.toml b/Cargo.toml index 06a4d71..7c13068 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,7 @@ github = { repository = "nicholaschiasson/fcidr" } maintenance = { status = "passively-maintained" } [dependencies] +serde = { version = "1.0", optional = true } + +[dev-dependencies] +serde_json = "1.0" diff --git a/src/cidr.rs b/src/cidr.rs index df3b551..87edab3 100644 --- a/src/cidr.rs +++ b/src/cidr.rs @@ -4,7 +4,7 @@ use std::{ str::FromStr, }; -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Cidr { network: Ipv4Addr, prefix: u8, @@ -20,6 +20,12 @@ pub enum Error { Impossible(String), } +impl Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self:?}") + } +} + impl Cidr { pub fn new(network: Ipv4Addr, prefix: u8) -> Result { if prefix as u32 > u32::BITS { diff --git a/src/fcidr.rs b/src/fcidr.rs index 2662510..7cfbca0 100644 --- a/src/fcidr.rs +++ b/src/fcidr.rs @@ -139,15 +139,6 @@ impl Fcidr { } } -impl Display for Fcidr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for cidr in self.into_iter() { - writeln!(f, "{cidr}")?; - } - Ok(()) - } -} - impl IntoIterator for Fcidr { type Item = Cidr; @@ -226,9 +217,9 @@ mod tests { .exclude("255.255.255.255/32".parse().unwrap()) .unwrap(); // fcidr.include("0.0.0.0/0".parse().unwrap()).unwrap(); - println!("{fcidr}"); + // println!("{fcidr}"); // println!("{:?}", fcidr.iter().collect::>()); - println!("{fcidr:?}"); + // println!("{fcidr:?}"); // fcidr.exclude("10.0.0.1/32".parse().unwrap()); // for i in 0..=32 { // println!("{} {}", i / 8, i % 8); diff --git a/src/lib.rs b/src/lib.rs index e9dbd5f..db71ed5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ mod cidr; mod fcidr; +mod serde; pub use crate::cidr::Cidr; pub use crate::fcidr::Fcidr; diff --git a/src/serde.rs b/src/serde.rs new file mode 100644 index 0000000..634b8f7 --- /dev/null +++ b/src/serde.rs @@ -0,0 +1,108 @@ +#![cfg(feature = "serde")] +#![cfg_attr(doc_cfg, doc(cfg(feature = "serde")))] + +use std::str::FromStr; + +use serde::{de::Visitor, ser::SerializeSeq, Deserialize, Serialize}; + +use crate::{Cidr, Fcidr}; + +struct CidrVisitor; + +impl<'de> Visitor<'de> for CidrVisitor { + type Value = Cidr; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a cidr block") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Self::Value::from_str(v).map_err(serde::de::Error::custom) + } +} + +impl<'de> Deserialize<'de> for Cidr { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_str(CidrVisitor) + } +} + +impl Serialize for Cidr { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} + +struct FcidrVisitor; + +impl<'de> Visitor<'de> for FcidrVisitor { + type Value = Fcidr; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a list of cidr blocks") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + let mut value = Self::Value::default(); + while let Some(element) = seq.next_element()? { + value.include(element).map_err(serde::de::Error::custom)?; + } + Ok(value) + } +} + +impl<'de> Deserialize<'de> for Fcidr { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_seq(FcidrVisitor) + } +} + +impl Serialize for Fcidr { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut seq = serializer.serialize_seq(Some(self.iter().count()))?; + for element in self { + seq.serialize_element(&element)?; + } + seq.end() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let cidr: Cidr = serde_json::from_str("\"127.0.1.2/31\"").unwrap(); + println!("{cidr}"); + println!( + "{}", + serde_json::json!("128.0.0.0/30".parse::().unwrap()) + ); + let mut fcidr = Fcidr::new("10.0.0.0/8".parse().unwrap()).unwrap(); + fcidr.exclude("10.128.128.127/32".parse().unwrap()).unwrap(); + println!("{}", serde_json::json!(fcidr)); + let fcidr: Fcidr = serde_json::from_str("[\"10.0.0.0/9\",\"10.128.0.0/17\",\"10.128.128.0/26\",\"10.128.128.64/27\",\"10.128.128.96/28\",\"10.128.128.112/29\",\"10.128.128.120/30\",\"10.128.128.124/31\",\"10.128.128.126/32\",\"10.128.128.128/25\",\"10.128.129.0/24\",\"10.128.130.0/23\",\"10.128.132.0/22\",\"10.128.136.0/21\",\"10.128.144.0/20\",\"10.128.160.0/19\",\"10.128.192.0/18\",\"10.129.0.0/16\",\"10.130.0.0/15\",\"10.132.0.0/14\",\"10.136.0.0/13\",\"10.144.0.0/12\",\"10.160.0.0/11\",\"10.192.0.0/10\"]").unwrap(); + for (i, cidr) in fcidr.iter().enumerate() { + println!("{i} - {cidr}"); + } + } +} From d222a8a98c99c4b415f8344fe70eda1c369d91df Mon Sep 17 00:00:00 2001 From: Nicholas Omer Chiasson Date: Tue, 4 Jul 2023 20:50:10 -0400 Subject: [PATCH 2/2] Remove unused import --- src/fcidr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fcidr.rs b/src/fcidr.rs index 7cfbca0..4f5f97b 100644 --- a/src/fcidr.rs +++ b/src/fcidr.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, fmt::Display, rc::Rc}; +use std::{cell::RefCell, rc::Rc}; use crate::{cidr, Cidr};