//! A library to streamline IP filtering. Supports creating, serializing, and
//! deserializing [Ipv4Range] and [Ipv6Range] for optimized filtering.

#![forbid(unused_doc_comments)]
#![forbid(missing_docs)]
#![forbid(unsafe_code)]
#![cfg_attr(docsrs, feature(doc_cfg))]

macro_rules! declare_filter {
	($mod:ident, $net:ident) => {
		#[doc = concat!("Types and functions for IP", stringify!($mod), " filtering")]
		pub mod $mod {
			use ipnet::$net;

			/// The range type for this module
			pub type IpRange = iprange::IpRange<$net>;

			/// Create a simplified [IpRange] from a fallible [Iterator]
			pub fn from_fallible_iter<I, E>(iter: I) -> Result<IpRange, E>
			where
				I: Iterator<Item = Result<$net, E>>,
			{
				let mut range = IpRange::new();

				for subnet in iter {
					range.add(subnet?);
				}

				range.simplify();
				Ok(range)
			}

			/// Encode the [IpRange] into any type that implements [std::io::Write]
			#[cfg(feature = "std")]
			#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
			pub fn write_to<W: std::io::Write>(
				range: IpRange,
				writer: &mut W,
			) -> Result<usize, bincode::error::EncodeError> {
				bincode::encode_into_std_write(
					bincode::serde::Compat(range),
					writer,
					bincode::config::standard(),
				)
			}

			/// Decode a [IpRange] from any type that implements [std::io::Read]
			#[cfg(feature = "std")]
			#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
			pub fn read_from<R: std::io::Read>(
				reader: &mut R,
			) -> Result<IpRange, bincode::error::DecodeError> {
				bincode::decode_from_std_read::<bincode::serde::Compat<_>, _, R>(
					reader,
					bincode::config::standard(),
				)
				.map(|x| x.0)
			}
		}
	};
}

declare_filter!(v4, Ipv4Net);
pub use v4::IpRange as Ipv4Range;

declare_filter!(v6, Ipv6Net);
pub use v6::IpRange as Ipv6Range;
