uri_rs/parser/parsers/
ipv4_address_parsers.rs1use nom::branch::alt;
2use nom::character::complete;
3use nom::character::complete::one_of;
4use nom::combinator::*;
5use nom::error::context;
6use nom::multi::count;
7use nom::sequence::{terminated, tuple};
8
9use crate::parser::parsers::{Elms, UResult};
10use crate::parser::parsers::basic_parsers::*;
11
12#[inline]
13fn dec_octet1(i: Elms) -> UResult<Elms, String> {
14 context("dec_octet1", map(digit, |c| c.into()))(i)
15}
16
17#[inline]
18fn dec_octet2(i: Elms) -> UResult<Elms, String> {
19 context(
20 "dec_octet2",
21 map(tuple((one_of("123456789"), digit)), |(c1, c2)| {
22 [c1, c2].iter().collect()
23 }),
24 )(i)
25}
26
27#[inline]
28fn dec_octet3(i: Elms) -> UResult<Elms, String> {
29 context(
30 "dec_octet3",
31 map(
32 tuple((complete::char('1'), digit, digit)),
33 |(c1, c2, c3)| [c1, c2, c3].iter().collect(),
34 ),
35 )(i)
36}
37
38#[inline]
39fn dec_octet4(i: Elms) -> UResult<Elms, String> {
40 context(
41 "dec_octet4",
42 map(
43 tuple((complete::char('2'), one_of("01234"), digit)),
44 |(c1, c2, c3)| [c1, c2, c3].iter().collect(),
45 ),
46 )(i)
47}
48
49#[inline]
50fn dec_octet5(i: Elms) -> UResult<Elms, String> {
51 context(
52 "dec_octet5",
53 map(
54 tuple((complete::char('2'), complete::char('5'), one_of("012345"))),
55 |(c1, c2, c3)| [c1, c2, c3].iter().collect(),
56 ),
57 )(i)
58}
59
60#[inline]
61pub(crate) fn dec_octet(i: Elms) -> UResult<Elms, String> {
62 context(
63 "dec_octet",
64 alt((dec_octet5, dec_octet4, dec_octet3, dec_octet2, dec_octet1)),
65 )(i)
66}
67
68#[inline]
69pub fn ipv4_address(i: Elms) -> UResult<Elms, String> {
70 context(
71 "ipv4_address",
72 map(
73 tuple((
74 count(terminated(dec_octet, complete::char('.')), 3),
75 dec_octet,
76 )),
77 |(mut sl, s)| {
78 sl.push(s);
79 sl.join(".")
80 },
81 ),
82 )(i)
83}
84
85#[cfg(test)]
86pub mod gens {
87 use prop_check_rs::gen::{Gen, Gens};
88
89 pub fn dec_octet_str_gen() -> Gen<String> {
90 Gens::choose_u32(1, 255).fmap(|n| n.to_string())
91 }
92
93 pub fn ipv4_address_str_gen() -> Gen<String> {
94 Gens::list_of_n(4, || dec_octet_str_gen()).fmap(|sl| sl.join("."))
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use std::env;
101
102 use anyhow::Result;
103 use prop_check_rs::prop;
104 use prop_check_rs::prop::TestCases;
105 use prop_check_rs::rng::RNG;
106
107 use crate::parser::parsers::{Elms};
108
109 use super::*;
110 use super::gens::*;
111
112 const TEST_COUNT: TestCases = 100;
113
114 fn init() {
115 env::set_var("RUST_LOG", "debug");
116 let _ = env_logger::builder().is_test(true).try_init();
117 }
118
119 #[test]
120 fn test_dec_octet() -> Result<()> {
121 init();
122 let mut counter = 0;
123 let prop = prop::for_all(
124 || dec_octet_str_gen(),
125 move |s| {
126 counter += 1;
127 log::debug!("{:>03}, dec_octet = {}", counter, s);
128 let (_, r) = dec_octet(Elms::new(s.as_bytes())).ok().unwrap();
129 r == s
130 },
131 );
132 prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
133 }
134
135 #[test]
136 fn test_ipv4_address() -> Result<()> {
137 init();
138 let mut counter = 0;
139 let prop = prop::for_all(
140 || ipv4_address_str_gen(),
141 move |s| {
142 counter += 1;
143 log::debug!("{}, ipv4_address = {}", counter, s);
144 let (_, r) = ipv4_address(Elms::new(s.as_bytes())).ok().unwrap();
145 r == s
146 },
147 );
148 prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
149 }
150}