Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@ edition = "2018"
[features]
default = ["std"]
std = []
# Implements "schemars::JsonSchema". Also implies "serde".
json = ["serde", "schemars"]
ser_as_str = ["heapless"]
serde = ["dep:serde"] # Implements "Serialize" and "Deserialize" using "serde@1.*".
heapless = ["dep:heapless", "serde"] # Avoids dynamic allocations during serialization using "heapless@0.*". Also implies "serde".
schemars08 = ["dep:schemars08"] # Implements "JsonSchema" using "[email protected].*"
schemars1 = ["dep:schemars1"] # Implements "JsonSchema" using "schemars@1.*"

# Legacy features:
json = ["schemars08", "serde"] # Alias for "schemars08" and "serde" kept for backwards compatibility. To be removed in "ipnet@3".
schemars = ["schemars08"] # Alias for "schemars08" kept for backwards compatibility. To be removed in "ipnet@3".
ser_as_str = ["dep:heapless"] # Avoids dynamic allocations during serialization using "heapless@0.*". Only active when feature "serde" is active as well, but does not imply it due to compatibility reasons. To be removed in "ipnet@3".

[dependencies]
serde = { package = "serde", version = "1", features = ["derive"], optional = true, default-features=false }
schemars = { version = "0.8", optional = true }
serde = { package = "serde", version = "1", features = ["derive"], optional = true, default-features = false }
schemars08 = { package = "schemars", version = "0.8", optional = true, default-features = false }
schemars1 = { package = "schemars", version = "1", optional = true, default-features = false }
heapless = { version = "0", optional = true }

[dev-dependencies]
Expand Down
37 changes: 21 additions & 16 deletions src/ipnet_schemars.rs → src/ipnet_schemars_08.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
use crate::IpNet;
use crate::Ipv4Net;
use crate::Ipv6Net;
use crate::IpNet;

use alloc::{
boxed::Box,
string::{
String,
ToString
},
string::{String, ToString},
vec,
};

use schemars::{JsonSchema, gen::SchemaGenerator, schema::{SubschemaValidation, Schema, SchemaObject, StringValidation, Metadata, SingleOrVec, InstanceType}};
use schemars08::{
self as schemars,
gen::SchemaGenerator,
schema::{
InstanceType, Metadata, Schema, SchemaObject, SingleOrVec, StringValidation,
SubschemaValidation,
},
JsonSchema,
};

impl JsonSchema for Ipv4Net {
fn schema_name() -> String {
Expand All @@ -37,7 +42,7 @@ impl JsonSchema for Ipv4Net {
..Default::default()
})),
..Default::default()
})
})
}
}
impl JsonSchema for Ipv6Net {
Expand All @@ -60,11 +65,13 @@ impl JsonSchema for Ipv6Net {
string: Some(Box::new(StringValidation {
max_length: Some(43),
min_length: None,
pattern: Some(r#"^[0-9A-Fa-f:\.]+\/(?:[0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$"#.to_string()),
pattern: Some(
r#"^[0-9A-Fa-f:\.]+\/(?:[0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$"#.to_string(),
),
..Default::default()
})),
..Default::default()
})
})
}
}
impl JsonSchema for IpNet {
Expand All @@ -83,13 +90,11 @@ impl JsonSchema for IpNet {
],
..Default::default()
})),
subschemas: Some(Box::new(
SubschemaValidation {
one_of: Some(vec![Ipv4Net::json_schema(gen), Ipv6Net::json_schema(gen)]),
..Default::default()
}
)),
subschemas: Some(Box::new(SubschemaValidation {
one_of: Some(vec![Ipv4Net::json_schema(gen), Ipv6Net::json_schema(gen)]),
..Default::default()
})),
..Default::default()
})
})
}
}
69 changes: 69 additions & 0 deletions src/ipnet_schemars_1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use crate::IpNet;
use crate::Ipv4Net;
use crate::Ipv6Net;

#[cfg(not(feature = "std"))]
use alloc::borrow::Cow;
#[cfg(feature = "std")]
use std::borrow::Cow;

use schemars1::{json_schema, JsonSchema, Schema, SchemaGenerator};

impl JsonSchema for Ipv4Net {
fn schema_name() -> Cow<'static, str> {
"Ipv4Net".into()
}

fn json_schema(_: &mut SchemaGenerator) -> Schema {
json_schema!({
"title": "IPv4 network",
"description": "An IPv4 address with prefix length",
"examples": [
"0.0.0.0/0",
"192.168.0.0/24"
],
"type": "string",
"maxLength": 18,
"pattern": r#"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(?:3[0-2]|[1-2][0-9]|[0-9])$"#
})
}
}
impl JsonSchema for Ipv6Net {
fn schema_name() -> Cow<'static, str> {
"Ipv6Net".into()
}

fn json_schema(_: &mut SchemaGenerator) -> Schema {
json_schema!({
"title": "IPv6 network",
"description": "An IPv6 address with prefix length",
"examples": [
"::/0",
"fd00::/32"
],
"type": "string",
"maxLength": 43,
"pattern": r#"^[0-9A-Fa-f:\.]+\/(?:[0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$"#
})
}
}
impl JsonSchema for IpNet {
fn schema_name() -> Cow<'static, str> {
"IpNet".into()
}

fn json_schema(gen: &mut SchemaGenerator) -> Schema {
json_schema!({
"title": "IP network",
"description": "An IPv4 or IPv6 address with prefix length",
"examples": [
"192.168.0.0/24",
"fd00::/32"
],
"oneOf": [
gen.subschema_for::<Ipv4Net>(),
gen.subschema_for::<Ipv6Net>()
]
})
}
}
90 changes: 71 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//! [`IpAddr`], [`Ipv4Addr`], and [`Ipv6Addr`] types already provided in
//! Rust's standard library and align to their design to stay
//! consistent.
//!
//!
//! The module also provides the [`IpSubnets`], [`Ipv4Subnets`], and
//! [`Ipv6Subnets`] types for iterating over the subnets contained in
//! an IP address range. The [`IpAddrRange`], [`Ipv4AddrRange`], and
Expand Down Expand Up @@ -57,26 +57,71 @@
//! [`IpBitAnd`]: trait.IpBitAnd.html
//! [`IpBitOr`]: trait.IpBitOr.html
//!
//! # Serde support
//! # Features
//!
//! These flags can be used to extend functionality using third-party
//! dependencies or optional libraries. See the [features] reference
//! for more information.
//!
//! [features]: https://doc.rust-lang.org/cargo/reference/features.html#the-features-section
//!
//! ## "std"
//!
//! Enabled by default. Disabling this feature will mandate the use of the
//! [core] and [alloc] crates where applicable instead of [std].
//!
//! [core]: https://doc.rust-lang.org/core/
//! [alloc]: https://doc.rust-lang.org/alloc/
//! [std]: https://doc.rust-lang.org/std/
//!
//! ## "serde"
//!
//! This library comes with support for [serde](https://serde.rs) but
//! it's not enabled by default. Use the `serde` [feature] to enable.
//!
//! ```toml
//! [dependencies]
//! ipnet = { version = "2", features = ["serde"] }
//! ```
//! Uses [`serde`] to implement the `Serialize` and
//! `Deserialize` traits.
//!
//! For human readable formats (e.g. JSON) the `IpNet`, `Ipv4Net`, and
//! `Ipv6Net` types will serialize to their `Display` strings.
//!
//!
//! For compact binary formats (e.g. Bincode) the `Ipv4Net` and
//! `Ipv6Net` types will serialize to a string of 5 and 17 bytes that
//! consist of the network address octects followed by the prefix
//! length. The `IpNet` type will serialize to an Enum with the V4 or V6
//! variant index prepending the above string of 5 or 17 bytes.
//!
//! [feature]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
//! [`serde`]: https://serde.rs
//!
//! ## "heapless" [^1]
//!
//! Uses [`heapless`] to optimize serialization performance by avoiding
//! dynamic allocations.
//!
//! [`heapless`]: https://docs.rs/heapless/latest/heapless/
//!
//! ## "schemars08"
//!
//! Uses [`[email protected].*`] to implement the `JsonSchema` trait.
//!
//! [`[email protected].*`]: https://docs.rs/schemars/0.8/schemars/
//!
//! ## "schemars1"
//!
//! Uses [`schemars@1.*`] to implement the `JsonSchema` trait.
//!
//! [`schemars@1.*`]: https://docs.rs/schemars/1/schemars/
//!
//! ## Legacy features
//!
//! The following features are set to be removed in the next major
//! release. Use the provided analogs instead.
//!
//! | Name | Analog | Reason for removal |
//! | ------------ | ------------------------ | --------------------------------------------------------------- |
//! | `json` [^1] | `schemars08` and `serde` | Unconventional naming. |
//! | `ser_as_str` | `heapless` [^1] | Doesn't enable the `serde` feature but does nothing on its own. |
//! | `schemars` | `schemars08` | Replaced by `schemars08`. |
//!
//! [^1]: Enabling these features will also enable the `serde` feature.
//!

#![no_std]

Expand All @@ -86,21 +131,28 @@ extern crate std;
#[cfg_attr(test, macro_use)]
extern crate alloc;

#[cfg(feature = "schemars08")]
extern crate schemars08;
#[cfg(feature = "schemars1")]
extern crate schemars1;
#[cfg(feature = "serde")]
extern crate serde;
#[cfg(feature = "schemars")]
extern crate schemars;

pub use self::ipext::{IpAdd, IpSub, IpBitAnd, IpBitOr, IpAddrRange, Ipv4AddrRange, Ipv6AddrRange};
pub use self::ipnet::{IpNet, Ipv4Net, Ipv6Net, PrefixLenError, IpSubnets, Ipv4Subnets, Ipv6Subnets};
pub use self::parser::AddrParseError;
pub use self::ipext::{IpAdd, IpAddrRange, IpBitAnd, IpBitOr, IpSub, Ipv4AddrRange, Ipv6AddrRange};
pub use self::ipnet::{
IpNet, IpSubnets, Ipv4Net, Ipv4Subnets, Ipv6Net, Ipv6Subnets, PrefixLenError,
};
pub use self::mask::{ip_mask_to_prefix, ipv4_mask_to_prefix, ipv6_mask_to_prefix};
pub use self::parser::AddrParseError;

mod ipext;
mod ipnet;
mod parser;
mod mask;
mod parser;

#[cfg(feature = "schemars08")]
mod ipnet_schemars_08;
#[cfg(feature = "schemars1")]
mod ipnet_schemars_1;
#[cfg(feature = "serde")]
mod ipnet_serde;
#[cfg(feature = "schemars")]
mod ipnet_schemars;