uri_rs/parser/parsers/
ipv6_address_parsers.rs

1use itertools::Itertools;
2use nom::branch::*;
3use nom::bytes::complete::tag;
4use nom::character::complete;
5use nom::combinator::*;
6use nom::error::context;
7use nom::multi::*;
8use nom::sequence::*;
9
10use crate::parser::parsers::{Elms, ipv4_address_parsers, UResult};
11use crate::parser::parsers::basic_parsers::*;
12
13#[inline]
14pub(crate) fn h16(i: Elms) -> UResult<Elms, String> {
15  context(
16    "h16",
17    map(many_m_n(1, 4, hex_digit), |sl| sl.into_iter().collect()),
18  )(i)
19}
20
21#[inline]
22pub(crate) fn ls32(i: Elms) -> UResult<Elms, String> {
23  context(
24    "ls32",
25    alt((
26      map(
27        tuple((h16, preceded(complete::char(':'), h16))),
28        |(c1, c2)| [c1, c2].join(":"),
29      ),
30      ipv4_address_parsers::ipv4_address,
31    )),
32  )(i)
33}
34
35// 6( h16 ":" ) ls32
36#[inline]
37pub(crate) fn ipv6_address1(i: Elms) -> UResult<Elms, String> {
38  context(
39    "ipv6_address1",
40    map(
41      tuple((
42        map(count(terminated(h16, complete::char(':')), 6), |sl| {
43          sl.iter().join(":")
44        }),
45        ls32,
46      )),
47      |(s1, s2)| [s1, s2].join(":"),
48    ),
49  )(i)
50}
51
52// "::" 5( h16 ":" ) ls32
53#[inline]
54pub(crate) fn ipv6_address2(i: Elms) -> UResult<Elms, String> {
55  context(
56    "ipv6_address2",
57    map(
58      tuple((
59        preceded(
60          tag("::"),
61          map(count(terminated(h16, tag(":")), 5), |sl| sl.join(":")),
62        ),
63        ls32,
64      )),
65      |(b, c)| format!("::{}:{}", b, c),
66    ),
67  )(i)
68}
69
70// [ h16 ] "::" 4( h16 ":" ) ls32
71#[inline]
72pub(crate) fn ipv6_address3(i: Elms) -> UResult<Elms, String> {
73  context(
74    "ipv6_address3",
75    map(
76      tuple((
77        terminated(opt(h16), tag("::")),
78        map(
79          count(
80            map(terminated(h16, complete::char(':')), |s| format!("{}:", s)),
81            4,
82          ),
83          |sl| sl.into_iter().collect::<String>(),
84        ),
85        ls32,
86      )),
87      |(s1, s2, s3)| format!("{}::{}{}", s1.unwrap_or("".to_string()), s2, s3),
88    ),
89  )(i)
90}
91
92#[inline]
93fn ipv6_address_<'a>(n1: usize, n2: usize) -> impl FnMut(Elms<'a>) -> UResult<Elms<'a>, String> {
94  let h16_with_colon = || {
95    map(tuple((h16, complete::char(':'))), |(s, c)| {
96      format!("{}{}", s, c)
97    })
98  };
99  let colon_with_h16 = || {
100    map(tuple((complete::char(':'), h16)), |(c, s)| {
101      format!("{}{}", c, s)
102    })
103  };
104  map(
105    tuple((
106      terminated(
107        map(
108          opt(map(
109            tuple((h16, many_m_n(0, n1, colon_with_h16()))),
110            |(s1, s2)| format!("{}{}", s1, s2.into_iter().collect::<String>()),
111          )),
112          |v| v.unwrap_or("".to_string()),
113        ),
114        tag("::"),
115      ),
116      count(h16_with_colon(), n2),
117      ls32,
118    )),
119    |(s1, s2, s3)| format!("{}::{}{}", s1, s2.into_iter().collect::<String>(), s3),
120  )
121}
122
123// [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
124// [ h16 [ ":" h16 ] ] "::" 3( h16 ":" ) ls32
125#[inline]
126pub(crate) fn ipv6_address4(i: Elms) -> UResult<Elms, String> {
127  context("ipv6_address4", ipv6_address_(1, 3))(i)
128}
129
130// [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
131// [ h16 *2(":" h16) ] "::" 2( h16 ":" ) ls32
132#[inline]
133pub(crate) fn ipv6_address5(i: Elms) -> UResult<Elms, String> {
134  context("ipv6_address5", ipv6_address_(2, 2))(i)
135}
136
137// [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
138// [ h16 *3(":" h16) ] "::"    h16 ":"   ls32
139#[inline]
140pub(crate) fn ipv6_address6(i: Elms) -> UResult<Elms, String> {
141  context("ipv6_address6", ipv6_address_(3, 1))(i)
142}
143
144// [ *4( h16 ":" ) h16 ] "::"              ls32
145// [ h16 *4(":" h16) ] "::"              ls32
146#[inline]
147pub(crate) fn ipv6_address7(i: Elms) -> UResult<Elms, String> {
148  context(
149    "ipv6_address7",
150    map(
151      tuple((
152        terminated(
153          map(
154            opt(map(
155              tuple((
156                h16,
157                many_m_n(
158                  0,
159                  4,
160                  map(preceded(complete::char(':'), h16), |s| format!(":{}", s)),
161                ),
162              )),
163              |(s1, s2)| format!("{}{}", s1, s2.into_iter().collect::<String>()),
164            )),
165            |v| v.unwrap_or("".to_string()),
166          ),
167          tag("::"),
168        ),
169        ls32,
170      )),
171      |(s1, s2)| [s1, s2].join("::"),
172    ),
173  )(i)
174}
175
176// [ *5( h16 ":" ) h16 ] "::" h16
177// [ h16 *5(":" h16) ] "::"  h16
178#[inline]
179pub(crate) fn ipv6_address8(i: Elms) -> UResult<Elms, String> {
180  context(
181    "ipv6_address8",
182    map(
183      tuple((
184        terminated(
185          map(
186            opt(map(
187              tuple((
188                h16,
189                many_m_n(
190                  0,
191                  5,
192                  map(preceded(complete::char(':'), h16), |s| format!(":{}", s)),
193                ),
194              )),
195              |(s1, s2)| format!("{}{}", s1, s2.into_iter().collect::<String>()),
196            )),
197            |v| v.unwrap_or("".to_string()),
198          ),
199          tag("::"),
200        ),
201        h16,
202      )),
203      |(s1, s2)| [s1, s2].join("::"),
204    ),
205  )(i)
206}
207
208// [ *6( h16 ":" ) h16 ] "::"
209// [ h16 *6(":" h16) ] "::"
210#[inline]
211pub(crate) fn ipv6_address9(i: Elms) -> UResult<Elms, String> {
212  context(
213    "ipv6_address9",
214    map(
215      tuple((
216        map(
217          opt(map(
218            tuple((
219              h16,
220              many_m_n(
221                0,
222                6,
223                map(tuple((complete::char(':'), h16)), |(c, s)| {
224                  let mut r = String::new();
225                  r.push(c);
226                  r.push_str(&s);
227                  r
228                }),
229              ),
230            )),
231            |(s1, s2)| [s1, s2.join("")].join(""),
232          )),
233          |v: Option<String>| v.unwrap_or("".to_string()),
234        ),
235        tag("::"),
236      )),
237      |(s1, s2): (String, Elms)| s1 + s2.as_str().unwrap(),
238    ),
239  )(i)
240}
241
242#[inline]
243pub fn ipv6_address(i: Elms) -> UResult<Elms, String> {
244  context(
245    "ipv6_address",
246    alt((
247      ipv6_address1,
248      ipv6_address2,
249      ipv6_address3,
250      ipv6_address4,
251      ipv6_address5,
252      ipv6_address6,
253      ipv6_address7,
254      ipv6_address8,
255      ipv6_address9,
256    )),
257  )(i)
258}
259
260#[cfg(test)]
261pub mod gens {
262  use itertools::Itertools;
263  use prop_check_rs::gen::{Gen, Gens};
264
265  use crate::parser::parsers::ipv4_address_parsers::gens::*;
266  use crate::parser::parsers::basic_parsers::gens::*;
267
268  pub fn h16_gen() -> Gen<String> {
269    Gens::choose_u8(1, 4).bind(|n| rep_char_gen(n, || hex_digit_char_gen()))
270  }
271
272  pub fn ls32_gen() -> Gen<String> {
273    Gens::choose_u8(1, 2).bind(|n| match n {
274      1 => ipv4_address_str_gen(),
275      2 => Gens::list_of_n(2, || h16_gen()).fmap(|sl| sl.join(":")),
276      x => panic!("x = {}", x),
277    })
278  }
279  pub fn ipv6_address_gen1() -> Gen<String> {
280    Gens::list_of_n(6, || h16_gen())
281      .bind(|sl| ls32_gen().fmap(move |ls32| format!("{}:{}", sl.join(":"), ls32)))
282  }
283
284  pub fn ipv6_address_gen2() -> Gen<String> {
285    Gens::list_of_n(5, || h16_gen())
286      .bind(|sl| ls32_gen().fmap(move |ls32| format!("::{}:{}", sl.join(":"), ls32)))
287  }
288
289  pub fn ipv6_address_gen3() -> Gen<String> {
290    Gens::list_of_n(5, || h16_gen()).bind(|sl| {
291      ls32_gen().fmap(move |ls32| {
292        let (h, t) = sl.split_first().unwrap();
293        format!("{}::{}:{}", h, t.join(":"), ls32)
294      })
295    })
296  }
297
298  // [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
299  pub fn ipv6_address_gen4() -> Gen<String> {
300    Gens::one_bool()
301      .bind(|b| {
302        if b {
303          Gens::choose_u8(1, 2).bind(|n| match n {
304            1 => h16_gen(),
305            2 => Gens::list_of_n(2, || h16_gen()).fmap(|sl| sl.join(":")),
306            x => panic!("x = {}", x),
307          })
308        } else {
309          Gen::<String>::unit(|| "".to_string())
310        }
311      })
312      .bind(|s0| {
313        Gens::list_of_n(3, || h16_gen().fmap(|v| format!("{}:", v)))
314          .fmap(|sl| sl.iter().join(""))
315          .fmap(|s| format!("::{}", s))
316          .bind(|s2| ls32_gen().fmap(move |s3| format!("{}{}", s2, s3)))
317          .fmap(move |s| format!("{}{}", s0, s))
318      })
319  }
320
321  //  [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
322  pub fn ipv6_address_gen5() -> Gen<String> {
323    Gens::one_bool()
324      .bind(|b| {
325        if b {
326          Gens::choose_u8(1, 2).bind(|n| match n {
327            1 => h16_gen(),
328            2 => Gens::list_of_n(3, || h16_gen()).fmap(|sl| sl.join(":")),
329            x => panic!("x = {}", x),
330          })
331        } else {
332          Gen::<String>::unit(|| "".to_string())
333        }
334      })
335      .bind(|s0| {
336        Gens::list_of_n(2, || h16_gen().fmap(|v| format!("{}:", v)))
337          .fmap(|sl| sl.iter().join(""))
338          .fmap(|s| format!("::{}", s))
339          .bind(|s2| ls32_gen().fmap(move |s3| format!("{}{}", s2, s3)))
340          .fmap(move |s| format!("{}{}", s0, s))
341      })
342  }
343
344  //  [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
345  pub fn ipv6_address_gen6() -> Gen<String> {
346    Gens::one_bool()
347      .bind(|b| {
348        if b {
349          Gens::choose_u8(1, 2).bind(|n| match n {
350            1 => h16_gen(),
351            2 => Gens::list_of_n(3, || h16_gen()).fmap(|sl| sl.join(":")),
352            x => panic!("x = {}", x),
353          })
354        } else {
355          Gen::<String>::unit(|| "".to_string())
356        }
357      })
358      .bind(|s0| {
359        Gens::list_of_n(1, || h16_gen().fmap(|v| format!("{}:", v)))
360          .fmap(|sl| sl.join(""))
361          .fmap(|s| format!("::{}", s))
362          .bind(|s2| ls32_gen().fmap(move |s3| format!("{}{}", s2, s3)))
363          .fmap(move |s| format!("{}{}", s0, s))
364      })
365  }
366
367  // [ *4( h16 ":" ) h16 ] "::"              ls32
368  pub fn ipv6_address_gen7() -> Gen<String> {
369    Gens::one_bool()
370      .bind(|b| {
371        if b {
372          Gens::choose_u8(1, 2).bind(|n| match n {
373            1 => h16_gen(),
374            2 => Gens::list_of_n(4, || h16_gen()).fmap(|sl| sl.join(":")),
375            x => panic!("x = {}", x),
376          })
377        } else {
378          Gen::<String>::unit(|| "".to_string())
379        }
380      })
381      .bind(|s0| ls32_gen().fmap(move |s1| format!("{}::{}", s0, s1)))
382  }
383
384  //  [ *5( h16 ":" ) h16 ] "::"              h16
385  pub fn ipv6_address_gen8() -> Gen<String> {
386    Gens::one_bool()
387      .bind(|b| {
388        if b {
389          Gens::choose_u8(1, 2).bind(|n| match n {
390            1 => h16_gen(),
391            2 => Gens::list_of_n(5, || h16_gen()).fmap(|sl| sl.join(":")),
392            x => panic!("x = {}", x),
393          })
394        } else {
395          Gen::<String>::unit(|| "".to_string())
396        }
397      })
398      .bind(|s0| h16_gen().fmap(move |s1| format!("{}::{}", s0, s1)))
399  }
400
401  //  [ *6( h16 ":" ) h16 ] "::"
402  pub fn ipv6_address_gen9() -> Gen<String> {
403    Gens::one_bool()
404      .bind(|b| {
405        if b {
406          Gens::choose_u8(1, 2).bind(|n| match n {
407            1 => h16_gen(),
408            2 => Gens::list_of_n(6, || h16_gen()).fmap(|sl| sl.join(":")),
409            x => panic!("x = {}", x),
410          })
411        } else {
412          Gen::<String>::unit(|| "".to_string())
413        }
414      })
415      .fmap(|s0| format!("{}::", s0))
416  }
417
418  pub fn ipv6_address_str_gen() -> Gen<String> {
419    Gens::choose_u8(1, 9).bind(|n| match n {
420      1 => ipv6_address_gen1(),
421      2 => ipv6_address_gen2(),
422      3 => ipv6_address_gen3(),
423      4 => ipv6_address_gen4(),
424      5 => ipv6_address_gen5(),
425      6 => ipv6_address_gen6(),
426      7 => ipv6_address_gen7(),
427      8 => ipv6_address_gen8(),
428      9 => ipv6_address_gen9(),
429      x => panic!("x = {}", x),
430    })
431  }
432}
433
434#[cfg(test)]
435mod test {
436  use std::env;
437
438  use anyhow::Result;
439
440  use prop_check_rs::prop;
441  use prop_check_rs::prop::TestCases;
442  use prop_check_rs::rng::RNG;
443
444  use super::*;
445  use super::gens::*;
446
447  const TEST_COUNT: TestCases = 100;
448
449  fn init() {
450    env::set_var("RUST_LOG", "debug");
451    let _ = env_logger::builder().is_test(true).try_init();
452  }
453
454  #[test]
455  fn test_h16() -> Result<()> {
456    init();
457    let mut counter = 0;
458    let prop = prop::for_all(
459      || h16_gen(),
460      move |s| {
461        counter += 1;
462        log::debug!("{:>03}, h16 = {}", counter, s);
463        let (_, r) = h16(Elms::new(s.as_bytes())).ok().unwrap();
464        assert_eq!(r, s);
465        true
466      },
467    );
468    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
469  }
470
471  #[test]
472  fn test_ls32() -> Result<()> {
473    init();
474    let mut counter = 0;
475    let prop = prop::for_all(
476      || ls32_gen(),
477      move |s| {
478        counter += 1;
479        log::debug!("{:>03}, ls32 = {}", counter, s);
480        let (_, r) = ls32(Elms::new(s.as_bytes())).ok().unwrap();
481        assert_eq!(r, s);
482        true
483      },
484    );
485    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
486  }
487
488  #[test]
489  fn test_ipv6_address1() -> Result<()> {
490    init();
491    let mut counter = 0;
492    let prop = prop::for_all(
493      || ipv6_address_gen1(),
494      move |s| {
495        counter += 1;
496        log::debug!("{:>03}, ipv6_address1 = {}", counter, s);
497        let (_, r) = ipv6_address1(Elms::new(s.as_bytes())).ok().unwrap();
498        assert_eq!(r, s);
499        true
500      },
501    );
502    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
503  }
504
505  #[test]
506  fn test_ipv6_address2() -> Result<()> {
507    init();
508    let mut counter = 0;
509    let prop = prop::for_all(
510      || ipv6_address_gen2(),
511      move |s| {
512        counter += 1;
513        log::debug!("{:>03}, ipv6_address2 = {}", counter, s);
514        let (_, r) = ipv6_address2(Elms::new(s.as_bytes())).ok().unwrap();
515        assert_eq!(r, s);
516        true
517      },
518    );
519    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
520  }
521
522  #[test]
523  fn test_ipv6_address3() -> Result<()> {
524    init();
525    let mut counter = 0;
526    let prop = prop::for_all(
527      || ipv6_address_gen3(),
528      move |s| {
529        counter += 1;
530        log::debug!("{:>03}, ipv6_address3 = {}", counter, s);
531        let (_, r) = ipv6_address3(Elms::new(s.as_bytes())).ok().unwrap();
532        assert_eq!(r, s);
533        true
534      },
535    );
536    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
537  }
538
539  #[test]
540  fn test_ipv6_address4() -> Result<()> {
541    init();
542    let mut counter = 0;
543    let prop = prop::for_all(
544      || ipv6_address_gen4(),
545      move |s| {
546        counter += 1;
547        log::debug!("{:>03}, ipv6_address4 = {}", counter, s);
548        let r = ipv6_address4(Elms::new(s.as_bytes()));
549        let (_, r) = r.ok().unwrap();
550        assert_eq!(r, s);
551        true
552      },
553    );
554    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
555  }
556
557  #[test]
558  fn test_ipv6_address5() -> Result<()> {
559    init();
560    let mut counter = 0;
561    let prop = prop::for_all(
562      || ipv6_address_gen5(),
563      move |s| {
564        counter += 1;
565        log::debug!("{:>03}, ipv6_address5 = {}", counter, s);
566        let (_, r) = ipv6_address5(Elms::new(s.as_bytes())).ok().unwrap();
567        assert_eq!(r, s);
568        true
569      },
570    );
571    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
572  }
573
574  #[test]
575  fn test_ipv6_address6() -> Result<()> {
576    init();
577    let mut counter = 0;
578    let prop = prop::for_all(
579      || ipv6_address_gen6(),
580      move |s| {
581        counter += 1;
582        log::debug!("{:>03}, ipv6_address6 = {}", counter, s);
583        let (_, r) = ipv6_address6(Elms::new(s.as_bytes())).ok().unwrap();
584        assert_eq!(r, s);
585        true
586      },
587    );
588    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
589  }
590
591  #[test]
592  fn test_ipv6_address7() -> Result<()> {
593    init();
594    let mut counter = 0;
595    let prop = prop::for_all(
596      || ipv6_address_gen7(),
597      move |s| {
598        counter += 1;
599        log::debug!("{:>03}, ipv6_address7 = {}", counter, s);
600        let (_, r) = ipv6_address7(Elms::new(s.as_bytes())).ok().unwrap();
601        assert_eq!(r, s);
602        true
603      },
604    );
605    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
606  }
607
608  #[test]
609  fn test_ipv6_address8() -> Result<()> {
610    init();
611    let mut counter = 0;
612    let prop = prop::for_all(
613      || ipv6_address_gen8(),
614      move |s| {
615        counter += 1;
616        log::debug!("{:>03}, ipv6_address8 = {}", counter, s);
617        let (_, r) = ipv6_address8(Elms::new(s.as_bytes())).ok().unwrap();
618        assert_eq!(r, s);
619        true
620      },
621    );
622    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
623  }
624
625  #[test]
626  fn test_ipv6_address9() -> Result<()> {
627    init();
628    let mut counter = 0;
629    let prop = prop::for_all(
630      || ipv6_address_gen9(),
631      move |s| {
632        counter += 1;
633        log::debug!("{:>03}, ipv6_address9 = {}", counter, s);
634        let (_, r) = ipv6_address9(Elms::new(s.as_bytes())).ok().unwrap();
635        assert_eq!(r, s);
636        true
637      },
638    );
639    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
640  }
641
642  #[test]
643  fn test_ipv6_address() -> Result<()> {
644    init();
645    let mut counter = 0;
646    let prop = prop::for_all(
647      || ipv6_address_str_gen(),
648      move |s| {
649        counter += 1;
650        log::debug!("{:>03}, ipv6_address = {}", counter, s);
651        let (_, r) = ipv6_address(Elms::new(s.as_bytes())).ok().unwrap();
652        assert_eq!(r, s);
653        true
654      },
655    );
656    prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
657  }
658}