cidr/parsers/
combinators.rs

1use std::net::{
2	AddrParseError,
3	IpAddr,
4};
5
6use crate::{
7	errors::NetworkParseError,
8	Address,
9	AnyIpCidr,
10	Cidr,
11	Inet,
12	IpCidr,
13	IpInet,
14};
15
16/// Parse [`Cidr`] with custom address and network (when no '/' separator was found) parser
17///
18/// If a '/' is found, parse trailing number as prefix length and leading address with `address_parser`.
19/// Otherwise parse with `host_parser`.
20pub fn parse_cidr_full<C, AP, HP>(
21	s: &str,
22	address_parser: AP,
23	host_parser: HP,
24) -> Result<C, NetworkParseError>
25where
26	C: Cidr,
27	AP: FnOnce(&str) -> Result<C::Address, AddrParseError>,
28	HP: FnOnce(&str) -> Result<C, NetworkParseError>,
29{
30	match s.rfind('/') {
31		None => host_parser(s),
32		Some(pos) => C::new(address_parser(&s[0..pos])?, s[pos + 1..].parse()?),
33	}
34}
35
36/// Parse [`Cidr`] with custom address parser
37///
38/// If a '/' is found, parse trailing number as prefix length and leading address with `address_parser`.
39/// Otherwise parse `address_parser` and treat as host (maximum prefix length).
40pub fn parse_cidr<C, AP>(s: &str, address_parser: AP) -> Result<C, NetworkParseError>
41where
42	C: Cidr,
43	AP: Fn(&str) -> Result<C::Address, AddrParseError>,
44{
45	parse_cidr_full(s, &address_parser, |s| Ok(C::new_host(address_parser(s)?)))
46}
47
48/// Parse [`Cidr`] with custom address and network (when no '/' separator was found) parser
49///
50/// Similar to [`parse_cidr_full`] but ignores host bits in addresses.
51pub fn parse_cidr_full_ignore_hostbits<C, AP, HP>(
52	s: &str,
53	address_parser: AP,
54	host_parser: HP,
55) -> Result<C, NetworkParseError>
56where
57	C: Cidr,
58	AP: FnOnce(&str) -> Result<C::Address, AddrParseError>,
59	HP: FnOnce(&str) -> Result<C, NetworkParseError>,
60{
61	match s.rfind('/') {
62		None => host_parser(s),
63		Some(pos) => {
64			let inet = <C::Address as Address>::Inet::new(
65				address_parser(&s[0..pos])?,
66				s[pos + 1..].parse()?,
67			)?;
68			Ok(inet.network())
69		},
70	}
71}
72
73/// Parse [`Cidr`] with custom address parser
74///
75/// Similar to [`parse_cidr`] but ignores host bits in addresses.
76pub fn parse_cidr_ignore_hostbits<C, AP>(
77	s: &str,
78	address_parser: AP,
79) -> Result<C, NetworkParseError>
80where
81	C: Cidr,
82	AP: Fn(&str) -> Result<C::Address, AddrParseError>,
83{
84	parse_cidr_full_ignore_hostbits(s, &address_parser, |s| Ok(C::new_host(address_parser(s)?)))
85}
86
87/// Parse [`AnyIpCidr`] with custom address and network (when no '/' separator was found) parser
88///
89/// Return [`AnyIpCidr::Any`] for `"any"`.
90/// If a '/' is found, parse trailing number as prefix length and leading address with `address_parser`.
91/// Otherwise parse with `host_parser`.
92pub fn parse_any_cidr_full<AP, HP>(
93	s: &str,
94	address_parser: AP,
95	host_parser: HP,
96) -> Result<AnyIpCidr, NetworkParseError>
97where
98	AP: FnOnce(&str) -> Result<IpAddr, AddrParseError>,
99	HP: FnOnce(&str) -> Result<IpCidr, NetworkParseError>,
100{
101	if s == "any" {
102		return Ok(AnyIpCidr::Any);
103	}
104	match s.rfind('/') {
105		None => Ok(host_parser(s)?.into()),
106		Some(pos) => AnyIpCidr::new(address_parser(&s[0..pos])?, s[pos + 1..].parse()?),
107	}
108}
109
110/// Parse [`AnyIpCidr`] with custom address parser
111///
112/// If a '/' is found, parse trailing number as prefix length and leading address with `address_parser`.
113/// If input is just `"any"` returns [`AnyIpCidr::Any`].
114/// Otherwise parse `address_parser` and treat as host (maximum prefix length).
115pub fn parse_any_cidr<AP>(s: &str, address_parser: AP) -> Result<AnyIpCidr, NetworkParseError>
116where
117	AP: Fn(&str) -> Result<IpAddr, AddrParseError>,
118{
119	parse_any_cidr_full(s, &address_parser, |s| {
120		Ok(IpCidr::new_host(address_parser(s)?))
121	})
122}
123
124/// Parse [`AnyIpCidr`] with custom address and network (when no '/' separator was found) parser
125///
126/// Similar to [`parse_any_cidr_full`] but ignores host bits in addresses.
127pub fn parse_any_cidr_full_ignore_hostbits<AP, HP>(
128	s: &str,
129	address_parser: AP,
130	host_parser: HP,
131) -> Result<AnyIpCidr, NetworkParseError>
132where
133	AP: FnOnce(&str) -> Result<IpAddr, AddrParseError>,
134	HP: FnOnce(&str) -> Result<IpCidr, NetworkParseError>,
135{
136	if s == "any" {
137		return Ok(AnyIpCidr::Any);
138	}
139	match s.rfind('/') {
140		None => Ok(host_parser(s)?.into()),
141		Some(pos) => Ok(
142			IpInet::new(address_parser(&s[0..pos])?, s[pos + 1..].parse()?)?
143				.network()
144				.into(),
145		),
146	}
147}
148
149/// Parse [`AnyIpCidr`] with custom address parser
150///
151/// Similar to [`parse_any_cidr`] but ignores host bits in addresses.
152pub fn parse_any_cidr_ignore_hostbits<AP>(
153	s: &str,
154	address_parser: AP,
155) -> Result<AnyIpCidr, NetworkParseError>
156where
157	AP: Fn(&str) -> Result<IpAddr, AddrParseError>,
158{
159	parse_any_cidr_full_ignore_hostbits(s, &address_parser, |s| {
160		Ok(IpCidr::new_host(address_parser(s)?))
161	})
162}
163
164/// Parse [`Inet`] with custom address and network (when no '/' separator was found) parser
165///
166/// If a '/' is found, parse trailing number as prefix length and leading address with `address_parser`.
167/// Otherwise parse with `host_parser`.
168pub fn parse_inet_full<I, AP, HP>(
169	s: &str,
170	address_parser: AP,
171	host_parser: HP,
172) -> Result<I, NetworkParseError>
173where
174	I: Inet,
175	AP: FnOnce(&str) -> Result<I::Address, AddrParseError>,
176	HP: FnOnce(&str) -> Result<I, NetworkParseError>,
177{
178	match s.rfind('/') {
179		None => host_parser(s),
180		Some(pos) => Ok(I::new(address_parser(&s[0..pos])?, s[pos + 1..].parse()?)?),
181	}
182}
183
184/// Parse [`Inet`] with custom address parser
185///
186/// If a '/' is found, parse trailing number as prefix length and leading address with `address_parser`.
187/// Otherwise parse `address_parser` and treat as host (maximum prefix length).
188pub fn parse_inet<I, AP>(s: &str, address_parser: AP) -> Result<I, NetworkParseError>
189where
190	I: Inet,
191	AP: Fn(&str) -> Result<I::Address, AddrParseError>,
192{
193	parse_inet_full(s, &address_parser, |s| Ok(I::new_host(address_parser(s)?)))
194}