iptools 0.5.0

High-performance IPv4/IPv6 utilities and iterators inspired by Python's iptools
Documentation
# Rust `iptools` vs Python `iptools`

Compared to Python `iptools` (0.7.0), this Rust crate differs in the
following behaviors.

## RFC-backed IPv6 differences

- Rust rejects malformed zero-compression forms such as `:::1`, `1:::1`, and
  `2001:::1`; Python `iptools` accepts them.
  RFC basis: [RFC 4291 Section 2.2]https://datatracker.ietf.org/doc/html/rfc4291#section-2.2
  says `::` can appear at most once.
- Rust accepts case-insensitive hex in mixed IPv6 form, e.g.
  `::FFFF:192.0.2.128`; Python `iptools` rejects uppercase in that pattern.
  RFC basis: [RFC 4291 Section 2.2]https://datatracker.ietf.org/doc/html/rfc4291#section-2.2
  allows uppercase or lowercase hex digits.
  [RFC 5952 Section 4.3]https://datatracker.ietf.org/doc/html/rfc5952#section-4.3
  recommends lowercase for canonical text, but uppercase is still valid.
- Rust accepts IPv6 CIDR with dotted-quad tails, e.g.
  `::ffff:192.0.2.128/96`; Python `iptools` rejects these.
  RFC basis: [RFC 4291 Section 2.2]https://datatracker.ietf.org/doc/html/rfc4291#section-2.2
  allows mixed `x:x:x:x:x:x:d.d.d.d` text, and
  [Section 2.3]https://datatracker.ietf.org/doc/html/rfc4291#section-2.3
  defines prefixes as `ipv6-address/prefix-length`.
- Rust accepts IPv6 CIDR prefixes with leading-zero width (for example
  `"f::ddb:a/0089"`); Python `iptools` rejects these.
- Rust rejects shortened mixed tails like `::ffff:1.2.3`; Python `iptools`
  accepts them.
  RFC basis: [RFC 4291 Section 2.2]https://datatracker.ietf.org/doc/html/rfc4291#section-2.2
  mixed form is explicitly
  `x:x:x:x:x:x:d.d.d.d` (four decimal octets, each `0..255`).

## Policy differences between packages (Rust vs Python)

- Rust requires strict dotted-quad IPv4 text for `validate_ip`, `ip2long`,
  `validate_cidr`, `cidr2block`, and `subnet2block` (exactly 4 octets). Python
  `iptools` accepts shorthand forms such as `"127"` and `"127.1"`.
- Rust rejects IPv4 octets with multi-digit leading zeros (for example
  `"01.2.3.4"`); Python `iptools` accepts them.
- Rust rejects mixed tails with multi-digit leading-zero octets such as
  `::ffff:01.2.3.4`; Python `iptools` accepts them.
  Note: RFC 4291 does not explicitly define leading-zero policy for the
  embedded dotted-quad fields; Rust intentionally uses strict dotted-decimal
  parsing (aligned with Python `ipaddress` behavior).
- Rust rejects reversed range bounds in `IpRange::new` (for example
  `"10.0.0.2"`, `"10.0.0.1"`); Python `iptools` normalizes and swaps endpoints.
- Rust `IpRange::new` does not accept IPv4 subnet notation in the first
  argument (for example `"127/255.255.255.0"`); Python `iptools` accepts it.
- Rust `IpRange::<IPv6>::contains` treats valid bare IPv4 text as a family
  mismatch and returns `Ok(false)`. Use `contains_addr` for numeric IPv4-in-IPv6
  low-bit checks.
- Rust accepts IPv4 CIDR prefixes with leading zeros (for example
  `"192.0.2.1/030"`); Python `iptools` restricts the prefix field to one or two
  digits.