uri_parsing_rs/parser/parsers/
scheme_parsers.rs1use nom::{AsChar, InputTakeAtPosition, IResult};
2use nom::combinator::map;
3use nom::error::{context, ErrorKind, ParseError};
4
5use crate::ast::scheme::Scheme;
6use crate::parser::parsers::{Elms, UResult};
7
8#[inline]
9fn code_point<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
10where
11 T: InputTakeAtPosition,
12 <T as InputTakeAtPosition>::Item: AsChar,
13{
14 input.split_at_position1_complete(
15 |item| {
16 let c = item.as_char();
17 !(c == '+' || c == '-' || c == '.' || c.is_alphanumeric())
18 },
19 ErrorKind::Char,
20 )
21}
22
23#[inline]
24pub(crate) fn scheme(i: Elms) -> UResult<Elms, Scheme> {
25 context("schema", map(code_point, |s: Elms| s.into()))(i)
26}
27
28#[cfg(test)]
29pub mod gens {
30 use prop_check_rs::gen::{Gen, Gens};
31
32 use crate::parser::parsers::basic_parsers::gens::*;
33
34 pub fn scheme_gen() -> Gen<String> {
35 rep_char_gen(5, || {
36 Gens::choose_u8(1, 5).bind(|n| match n {
37 1 => alpha_char_gen(),
38 2 => digit_gen('0', '9'),
39 3 => Gen::<char>::unit(|| '+'),
40 4 => Gen::<char>::unit(|| '-'),
41 5 => Gen::<char>::unit(|| '.'),
42 x => panic!("x = {}", x),
43 })
44 })
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use std::env;
51
52 use anyhow::Result;
53 use prop_check_rs::prop;
54 use prop_check_rs::prop::TestCases;
55 use prop_check_rs::rng::RNG;
56
57 use crate::parser::parsers::Elms;
58
59 use super::*;
60 use super::gens::*;
61
62 const TEST_COUNT: TestCases = 100;
63
64 fn init() {
65 env::set_var("RUST_LOG", "debug");
66 let _ = env_logger::builder().is_test(true).try_init();
67 }
68
69 #[test]
70 fn test_scheme() -> Result<()> {
71 init();
72 let mut counter = 0;
73 let prop = prop::for_all(
74 || scheme_gen(),
75 move |s| {
76 counter += 1;
77 log::debug!("{:>03}, scheme = {}", counter, s);
78 let (_, r) = scheme(Elms::new(s.as_bytes())).ok().unwrap();
79 assert_eq!(r.to_string(), s);
80 true
81 },
82 );
83 prop::test_with_prop(prop, 5, TEST_COUNT, RNG::new())
84 }
85}