uri_rs/parser/parsers/
ipv4_address_parsers.rs

1use 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}