1use core::fmt;
4use core::net::{IpAddr, SocketAddr};
5
6pub trait Filter: Sized {
10 fn is_match(&self, ip: IpAddr) -> bool;
12 #[inline(always)]
13 fn or<F2: Filter>(self, right: F2) -> Or<Self, F2> {
15 or(self, right)
16 }
17}
18
19impl Filter for () {
20 #[inline(always)]
21 fn is_match(&self, _: IpAddr) -> bool {
23 false
24 }
25}
26
27impl Filter for IpAddr {
28 #[inline(always)]
29 fn is_match(&self, ip: IpAddr) -> bool {
30 *self == ip
31 }
32}
33
34impl Filter for SocketAddr {
35 #[inline(always)]
36 fn is_match(&self, ip: IpAddr) -> bool {
37 self.ip() == ip
38 }
39}
40
41pub struct Or<F1, F2> {
43 left: F1,
44 right: F2,
45}
46
47impl<F1: Filter, F2: Filter> Filter for Or<F1, F2> {
48 #[inline(always)]
49 fn is_match(&self, ip: IpAddr) -> bool {
50 self.left.is_match(ip) || self.right.is_match(ip)
51 }
52}
53
54#[derive(Debug, PartialEq, Eq)]
55enum ParseError<'a> {
57 ParseError(ip_cidr::ParseError<'a>),
59 InvalidPrefix
61}
62
63#[repr(transparent)]
64#[derive(PartialEq, Eq)]
65pub struct CidrParseError<'a>(ParseError<'a>);
67
68impl fmt::Debug for CidrParseError<'_> {
69 #[inline(always)]
70 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
71 fmt::Debug::fmt(&self.0, fmt)
72 }
73}
74
75impl fmt::Display for CidrParseError<'_> {
76 #[inline(always)]
77 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
78 match &self.0 {
79 ParseError::InvalidPrefix => fmt.write_str("Invalid CIDR prefix"),
80 ParseError::ParseError(error) => fmt::Display::fmt(error, fmt),
81 }
82 }
83}
84
85#[repr(transparent)]
86#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
87pub struct Cidr(ip_cidr::Cidr);
89
90impl Cidr {
91 #[inline]
92 pub const fn from_text(text: &str) -> Result<Self, CidrParseError<'_>> {
94 match ip_cidr::parse_cidr(text) {
95 Ok(Some(inner)) => Ok(Self(inner)),
96 Ok(None) => Err(CidrParseError(ParseError::InvalidPrefix)),
97 Err(error) => Err(CidrParseError(ParseError::ParseError(error))),
98 }
99 }
100
101 #[inline]
102 pub const fn new(ip: IpAddr, prefix: u8) -> Result<Self, CidrParseError<'static>> {
104 match ip_cidr::Cidr::new(ip, prefix) {
105 Some(cidr) => Ok(Self(cidr)),
106 None => Err(CidrParseError(ParseError::InvalidPrefix)),
107 }
108 }
109}
110
111impl Filter for Cidr {
112 #[inline(always)]
113 fn is_match(&self, ip: IpAddr) -> bool {
114 self.0.contains(ip)
115 }
116}
117
118impl fmt::Debug for Cidr {
119 #[inline(always)]
120 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
121 fmt::Debug::fmt(&self.0, fmt)
122 }
123}
124
125impl fmt::Display for Cidr {
126 #[inline(always)]
127 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
128 fmt::Display::fmt(&self.0, fmt)
129 }
130}
131
132#[inline]
133pub const fn or<F1, F2>(left: F1, right: F2) -> Or<F1, F2> {
135 Or {
136 left,
137 right
138 }
139}