///|
/// A canonical CIDR network; host bits are zero and the prefix fits the family.
struct Cidr {
network_ : Address
prefix_ : Int32
} derive(Eq)
///|
pub extend Cidr with Eq::{equal, not_equal}
///|
pub extend Cidr with Show::{output}
///|
/// Constructs a CIDR, clearing host bits unless strict validation is requested.
pub fn Cidr::new(
address : Address,
prefix : Int32,
strict~ : Bool = false,
) -> Cidr raise IpError {
if prefix < 0 || prefix > address.width() {
raise InvalidPrefix("\{address}/\{prefix}")
}
let network = address.mask(prefix)
if strict && network != address {
raise HostBitsSet("\{address}/\{prefix}")
}
{ network_: network, prefix_: prefix, }
}
///|
/// Parses address/prefix syntax. The prefix uses decimal digits without leading zeros.
pub fn Cidr::parse(text : String, strict~ : Bool = false) -> Cidr raise IpError {
let (address_text, prefix_text) = match text.split_once("/") {
Some(parts) => parts
None => raise InvalidPrefix(text)
}
if prefix_text.is_empty() || prefix_text.length() > 3 {
raise InvalidPrefix(text)
}
if prefix_text.length() > 1 && prefix_text[0].to_int() == 48 {
raise InvalidPrefix(text)
}
let mut prefix = 0
for unit in prefix_text.code_units() {
let digit = unit.to_int() - 48
if digit < 0 || digit > 9 {
raise InvalidPrefix(text)
}
prefix = prefix * 10 + digit
}
Cidr::new(Address::parse(address_text.to_owned()), prefix, strict~)
}
///|
/// The first address of this network.
pub fn Cidr::network(self : Cidr) -> Address {
self.network_
}
///|
/// The inclusive final address of this network.
pub fn Cidr::last(self : Cidr) -> Address {
self.network_.block_end(self.prefix_)
}
///|
/// Number of leading network bits.
pub fn Cidr::prefix(self : Cidr) -> Int32 {
self.prefix_
}
///|
/// Canonical network address followed by a decimal prefix.
pub fn Cidr::to_string(self : Cidr) -> String {
"\{self.network_.to_string()}/\{self.prefix_}"
}
///|
pub impl Show for Cidr with fn output(self, logger) {
logger.write_string(self.to_string())
}
///|
// Internal: caller guarantees an aligned network and a prefix in the family range.
fn cidr_from_normalized(address : Address, prefix : Int32) -> Cidr {
{ network_: address, prefix_: prefix, }
}