Coverage Report

Created: 2025-10-31 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ipnet-2.11.0/src/parser.rs
Line
Count
Source
1
//! A private parser implementation of IPv4 and IPv6 network addresses.
2
//!
3
//! The existing `std::net::parser` module cannot be extended because it
4
//! is private. It is copied and extended here with methods for parsing
5
//! IP network addresses.
6
7
use alloc::{str::FromStr, boxed::Box};
8
use core::fmt;
9
#[cfg(not(feature = "std"))]
10
use core::error::Error;
11
#[cfg(feature = "std")]
12
use std::error::Error;
13
#[cfg(not(feature = "std"))]
14
use core::net::{Ipv4Addr, Ipv6Addr};
15
#[cfg(feature = "std")]
16
use std::net::{Ipv4Addr, Ipv6Addr};
17
18
use crate::ipnet::{IpNet, Ipv4Net, Ipv6Net};
19
20
pub struct Parser<'a> {
21
    // parsing as ASCII, so can use byte array
22
    s: &'a [u8],
23
    pos: usize,
24
}
25
26
impl<'a> Parser<'a> {
27
0
    fn new(s: &'a str) -> Parser<'a> {
28
0
        Parser {
29
0
            s: s.as_bytes(),
30
0
            pos: 0,
31
0
        }
32
0
    }
33
34
0
    fn is_eof(&self) -> bool {
35
0
        self.pos == self.s.len()
36
0
    }
37
38
    // Commit only if parser returns Some
39
0
    fn read_atomically<T, F>(&mut self, cb: F) -> Option<T> where
40
0
        F: FnOnce(&mut Parser) -> Option<T>,
41
    {
42
0
        let pos = self.pos;
43
0
        let r = cb(self);
44
0
        if r.is_none() {
45
0
            self.pos = pos;
46
0
        }
47
0
        r
48
0
    }
Unexecuted instantiation: <ipnet::parser::Parser>::read_atomically::<ipnet::ipnet::IpNet, <ipnet::parser::Parser>::read_till_eof<ipnet::ipnet::IpNet, <ipnet::ipnet::IpNet as core::str::traits::FromStr>::from_str::{closure#0}>::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_atomically::<ipnet::ipnet::IpNet, <ipnet::parser::Parser>::read_or<ipnet::ipnet::IpNet>::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_atomically::<ipnet::ipnet::Ipv4Net, <ipnet::parser::Parser>::read_till_eof<ipnet::ipnet::Ipv4Net, <ipnet::ipnet::Ipv4Net as core::str::traits::FromStr>::from_str::{closure#0}>::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_atomically::<ipnet::ipnet::Ipv6Net, <ipnet::parser::Parser>::read_till_eof<ipnet::ipnet::Ipv6Net, <ipnet::ipnet::Ipv6Net as core::str::traits::FromStr>::from_str::{closure#0}>::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_atomically::<core::net::ip_addr::Ipv4Addr, <ipnet::parser::Parser>::read_ipv4_addr::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_atomically::<core::net::ip_addr::Ipv4Addr, <ipnet::parser::Parser>::read_ipv6_addr_impl::read_groups::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_atomically::<core::net::ip_addr::Ipv6Addr, <ipnet::parser::Parser>::read_ipv6_addr::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_atomically::<(core::net::ip_addr::Ipv4Addr, char, u8), <ipnet::parser::Parser>::read_seq_3<core::net::ip_addr::Ipv4Addr, char, u8, <ipnet::parser::Parser>::read_ipv4_net::{closure#0}, <ipnet::parser::Parser>::read_ipv4_net::{closure#1}, <ipnet::parser::Parser>::read_ipv4_net::{closure#2}>::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_atomically::<(core::net::ip_addr::Ipv6Addr, char, u8), <ipnet::parser::Parser>::read_seq_3<core::net::ip_addr::Ipv6Addr, char, u8, <ipnet::parser::Parser>::read_ipv6_net::{closure#0}, <ipnet::parser::Parser>::read_ipv6_net::{closure#1}, <ipnet::parser::Parser>::read_ipv6_net::{closure#2}>::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_atomically::<char, <ipnet::parser::Parser>::read_given_char::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_atomically::<u8, <ipnet::parser::Parser>::read_digit::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_atomically::<u32, <ipnet::parser::Parser>::read_number::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_atomically::<u16, <ipnet::parser::Parser>::read_ipv6_addr_impl::read_groups::{closure#1}>
49
50
    // Commit only if parser read till EOF
51
0
    fn read_till_eof<T, F>(&mut self, cb: F) -> Option<T> where
52
0
        F: FnOnce(&mut Parser) -> Option<T>,
53
    {
54
0
        self.read_atomically(move |p| {
55
0
            match cb(p) {
56
0
                Some(x) => if p.is_eof() {Some(x)} else {None},
57
0
                None => None,
58
            }
59
0
        })
Unexecuted instantiation: <ipnet::parser::Parser>::read_till_eof::<ipnet::ipnet::IpNet, <ipnet::ipnet::IpNet as core::str::traits::FromStr>::from_str::{closure#0}>::{closure#0}
Unexecuted instantiation: <ipnet::parser::Parser>::read_till_eof::<ipnet::ipnet::Ipv4Net, <ipnet::ipnet::Ipv4Net as core::str::traits::FromStr>::from_str::{closure#0}>::{closure#0}
Unexecuted instantiation: <ipnet::parser::Parser>::read_till_eof::<ipnet::ipnet::Ipv6Net, <ipnet::ipnet::Ipv6Net as core::str::traits::FromStr>::from_str::{closure#0}>::{closure#0}
60
0
    }
Unexecuted instantiation: <ipnet::parser::Parser>::read_till_eof::<ipnet::ipnet::IpNet, <ipnet::ipnet::IpNet as core::str::traits::FromStr>::from_str::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_till_eof::<ipnet::ipnet::Ipv4Net, <ipnet::ipnet::Ipv4Net as core::str::traits::FromStr>::from_str::{closure#0}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_till_eof::<ipnet::ipnet::Ipv6Net, <ipnet::ipnet::Ipv6Net as core::str::traits::FromStr>::from_str::{closure#0}>
61
62
    // Return result of first successful parser
63
0
    fn read_or<T>(&mut self, parsers: &mut [Box<dyn FnMut(&mut Parser) -> Option<T> + 'static>])
64
0
               -> Option<T> {
65
0
        for pf in parsers {
66
0
            if let Some(r) = self.read_atomically(|p: &mut Parser| pf(p)) {
67
0
                return Some(r);
68
0
            }
69
        }
70
0
        None
71
0
    }
72
73
    // Apply 3 parsers sequentially
74
0
    fn read_seq_3<A, B, C, PA, PB, PC>(&mut self,
75
0
                                       pa: PA,
76
0
                                       pb: PB,
77
0
                                       pc: PC)
78
0
                                       -> Option<(A, B, C)> where
79
0
        PA: FnOnce(&mut Parser) -> Option<A>,
80
0
        PB: FnOnce(&mut Parser) -> Option<B>,
81
0
        PC: FnOnce(&mut Parser) -> Option<C>,
82
    {
83
0
        self.read_atomically(move |p| {
84
0
            let a = pa(p);
85
0
            let b = if a.is_some() { pb(p) } else { None };
86
0
            let c = if b.is_some() { pc(p) } else { None };
87
0
            match (a, b, c) {
88
0
                (Some(a), Some(b), Some(c)) => Some((a, b, c)),
89
0
                _ => None
90
            }
91
0
        })
Unexecuted instantiation: <ipnet::parser::Parser>::read_seq_3::<core::net::ip_addr::Ipv4Addr, char, u8, <ipnet::parser::Parser>::read_ipv4_net::{closure#0}, <ipnet::parser::Parser>::read_ipv4_net::{closure#1}, <ipnet::parser::Parser>::read_ipv4_net::{closure#2}>::{closure#0}
Unexecuted instantiation: <ipnet::parser::Parser>::read_seq_3::<core::net::ip_addr::Ipv6Addr, char, u8, <ipnet::parser::Parser>::read_ipv6_net::{closure#0}, <ipnet::parser::Parser>::read_ipv6_net::{closure#1}, <ipnet::parser::Parser>::read_ipv6_net::{closure#2}>::{closure#0}
92
0
    }
Unexecuted instantiation: <ipnet::parser::Parser>::read_seq_3::<core::net::ip_addr::Ipv4Addr, char, u8, <ipnet::parser::Parser>::read_ipv4_net::{closure#0}, <ipnet::parser::Parser>::read_ipv4_net::{closure#1}, <ipnet::parser::Parser>::read_ipv4_net::{closure#2}>
Unexecuted instantiation: <ipnet::parser::Parser>::read_seq_3::<core::net::ip_addr::Ipv6Addr, char, u8, <ipnet::parser::Parser>::read_ipv6_net::{closure#0}, <ipnet::parser::Parser>::read_ipv6_net::{closure#1}, <ipnet::parser::Parser>::read_ipv6_net::{closure#2}>
93
94
    // Read next char
95
0
    fn read_char(&mut self) -> Option<char> {
96
0
        if self.is_eof() {
97
0
            None
98
        } else {
99
0
            let r = self.s[self.pos] as char;
100
0
            self.pos += 1;
101
0
            Some(r)
102
        }
103
0
    }
104
105
    // Return char and advance iff next char is equal to requested
106
0
    fn read_given_char(&mut self, c: char) -> Option<char> {
107
0
        self.read_atomically(|p| {
108
0
            match p.read_char() {
109
0
                Some(next) if next == c => Some(next),
110
0
                _ => None,
111
            }
112
0
        })
113
0
    }
114
115
    // Read digit
116
0
    fn read_digit(&mut self, radix: u8) -> Option<u8> {
117
0
        fn parse_digit(c: char, radix: u8) -> Option<u8> {
118
0
            let c = c as u8;
119
            // assuming radix is either 10 or 16
120
0
            if c >= b'0' && c <= b'9' {
121
0
                Some(c - b'0')
122
0
            } else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) {
123
0
                Some(c - b'a' + 10)
124
0
            } else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) {
125
0
                Some(c - b'A' + 10)
126
            } else {
127
0
                None
128
            }
129
0
        }
130
131
0
        self.read_atomically(|p| {
132
0
            p.read_char().and_then(|c| parse_digit(c, radix))
133
0
        })
134
0
    }
135
136
0
    fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
137
0
        let mut r = 0;
138
0
        let mut digit_count = 0;
139
        loop {
140
0
            match self.read_digit(radix) {
141
0
                Some(d) => {
142
0
                    r = r * (radix as u32) + (d as u32);
143
0
                    digit_count += 1;
144
0
                    if digit_count > max_digits || r >= upto {
145
0
                        return None
146
0
                    }
147
                }
148
                None => {
149
0
                    if digit_count == 0 {
150
0
                        return None
151
                    } else {
152
0
                        return Some(r)
153
                    }
154
                }
155
            };
156
        }
157
0
    }
158
159
    // Read number, failing if max_digits of number value exceeded
160
0
    fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
161
0
        self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto))
162
0
    }
163
164
0
    fn read_ipv4_addr_impl(&mut self) -> Option<Ipv4Addr> {
165
0
        let mut bs = [0; 4];
166
0
        let mut i = 0;
167
0
        while i < 4 {
168
0
            if i != 0 && self.read_given_char('.').is_none() {
169
0
                return None;
170
0
            }
171
172
0
            let octet = self.read_number(10, 3, 0x100).map(|n| n as u8);
173
0
            match octet {
174
0
                Some(d) => bs[i] = d,
175
0
                None => return None,
176
            };
177
0
            i += 1;
178
        }
179
0
        Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3]))
180
0
    }
181
182
    // Read IPv4 address
183
0
    fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
184
0
        self.read_atomically(|p| p.read_ipv4_addr_impl())
185
0
    }
186
187
0
    fn read_ipv6_addr_impl(&mut self) -> Option<Ipv6Addr> {
188
0
        fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr {
189
0
            assert!(head.len() + tail.len() <= 8);
190
0
            let mut gs = [0; 8];
191
0
            gs[..head.len()].copy_from_slice(head);
192
0
            gs[(8 - tail.len()) .. 8].copy_from_slice(tail);
193
0
            Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7])
194
0
        }
195
196
0
        fn read_groups(p: &mut Parser, groups: &mut [u16; 8], limit: usize)
197
0
                       -> (usize, bool) {
198
0
            let mut i = 0;
199
0
            while i < limit {
200
0
                if i < limit - 1 {
201
0
                    let ipv4 = p.read_atomically(|p| {
202
0
                        if i == 0 || p.read_given_char(':').is_some() {
203
0
                            p.read_ipv4_addr()
204
                        } else {
205
0
                            None
206
                        }
207
0
                    });
208
0
                    if let Some(v4_addr) = ipv4 {
209
0
                        let octets = v4_addr.octets();
210
0
                        groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16);
211
0
                        groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16);
212
0
                        return (i + 2, true);
213
0
                    }
214
0
                }
215
216
0
                let group = p.read_atomically(|p| {
217
0
                    if i == 0 || p.read_given_char(':').is_some() {
218
0
                        p.read_number(16, 4, 0x10000).map(|n| n as u16)
219
                    } else {
220
0
                        None
221
                    }
222
0
                });
223
0
                match group {
224
0
                    Some(g) => groups[i] = g,
225
0
                    None => return (i, false)
226
                }
227
0
                i += 1;
228
            }
229
0
            (i, false)
230
0
        }
231
232
0
        let mut head = [0; 8];
233
0
        let (head_size, head_ipv4) = read_groups(self, &mut head, 8);
234
235
0
        if head_size == 8 {
236
0
            return Some(Ipv6Addr::new(
237
0
                head[0], head[1], head[2], head[3],
238
0
                head[4], head[5], head[6], head[7]))
239
0
        }
240
241
        // IPv4 part is not allowed before `::`
242
0
        if head_ipv4 {
243
0
            return None
244
0
        }
245
246
        // read `::` if previous code parsed less than 8 groups
247
0
        if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() {
248
0
            return None;
249
0
        }
250
251
0
        let mut tail = [0; 8];
252
0
        let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size);
253
0
        Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size]))
254
0
    }
255
256
0
    fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> {
257
0
        self.read_atomically(|p| p.read_ipv6_addr_impl())
258
0
    }
259
    
260
    /* Additions for IpNet below. */
261
262
    // Read IPv4 network
263
0
    fn read_ipv4_net(&mut self) -> Option<Ipv4Net> {
264
0
        let ip_addr = |p: &mut Parser| p.read_ipv4_addr();
265
0
        let slash = |p: &mut Parser| p.read_given_char('/');
266
0
        let prefix_len = |p: &mut Parser| {
267
0
            p.read_number(10, 2, 33).map(|n| n as u8)
268
0
        };
269
270
0
        self.read_seq_3(ip_addr, slash, prefix_len).map(|t| {
271
0
            let (ip, _, prefix_len): (Ipv4Addr, char, u8) = t;
272
0
            Ipv4Net::new(ip, prefix_len).unwrap()
273
0
        })
274
0
    }
275
276
    // Read Ipv6 network
277
0
    fn read_ipv6_net(&mut self) -> Option<Ipv6Net> {
278
0
        let ip_addr = |p: &mut Parser| p.read_ipv6_addr();
279
0
        let slash = |p: &mut Parser| p.read_given_char('/');
280
0
        let prefix_len = |p: &mut Parser| {
281
0
            p.read_number(10, 3, 129).map(|n| n as u8)
282
0
        };
283
284
0
        self.read_seq_3(ip_addr, slash, prefix_len).map(|t| {
285
0
            let (ip, _, prefix_len): (Ipv6Addr, char, u8) = t;
286
0
            Ipv6Net::new(ip, prefix_len).unwrap()
287
0
        })
288
0
    }
289
290
0
    fn read_ip_net(&mut self) -> Option<IpNet> {
291
0
        let ipv4_net = |p: &mut Parser| p.read_ipv4_net().map(IpNet::V4);
292
0
        let ipv6_net = |p: &mut Parser| p.read_ipv6_net().map(IpNet::V6);
293
0
        self.read_or(&mut [Box::new(ipv4_net), Box::new(ipv6_net)])
294
0
    }
295
296
    /* Additions for IpNet above. */
297
}
298
299
/* Additions for IpNet below. */
300
301
impl FromStr for IpNet {
302
    type Err = AddrParseError;
303
0
    fn from_str(s: &str) -> Result<IpNet, AddrParseError> {
304
0
        match Parser::new(s).read_till_eof(|p| p.read_ip_net()) {
305
0
            Some(s) => Ok(s),
306
0
            None => Err(AddrParseError(()))
307
        }
308
0
    }
309
}
310
311
impl FromStr for Ipv4Net {
312
    type Err = AddrParseError;
313
0
    fn from_str(s: &str) -> Result<Ipv4Net, AddrParseError> {
314
0
        match Parser::new(s).read_till_eof(|p| p.read_ipv4_net()) {
315
0
            Some(s) => Ok(s),
316
0
            None => Err(AddrParseError(()))
317
        }
318
0
    }
319
}
320
321
impl FromStr for Ipv6Net {
322
    type Err = AddrParseError;
323
0
    fn from_str(s: &str) -> Result<Ipv6Net, AddrParseError> {
324
0
        match Parser::new(s).read_till_eof(|p| p.read_ipv6_net()) {
325
0
            Some(s) => Ok(s),
326
0
            None => Err(AddrParseError(()))
327
        }
328
0
    }
329
}
330
331
/* Additions for IpNet above. */
332
333
/// An error which can be returned when parsing an IP network address.
334
///
335
/// This error is used as the error type for the [`FromStr`] implementation for
336
/// [`IpNet`], [`Ipv4Net`], and [`Ipv6Net`].
337
///
338
/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
339
/// [`IpNet`]: enum.IpNet.html
340
/// [`Ipv4Net`]: struct.Ipv4Net.html
341
/// [`Ipv6Net`]: struct.Ipv6Net.html
342
#[derive(Debug, Clone, PartialEq, Eq)]
343
pub struct AddrParseError(());
344
345
impl fmt::Display for AddrParseError {
346
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
347
0
        fmt.write_str("invalid IP address syntax")
348
0
    }
349
}
350
351
impl Error for AddrParseError {}