/// `lowalpha | upalpha`
pub fn alpha(i: &str) -> nom::IResult<&str, &str> {
    nom::combinator::recognize(nom::character::complete::satisfy(|c| c.is_ascii_alphabetic()))(i)
}

/// `alpha | digit`
pub fn alphanum(i: &str) -> nom::IResult<&str, &str> {
    nom::combinator::recognize(nom::character::complete::satisfy(|c| c.is_ascii_alphanumeric()))(i)
}

/// `"%" hex hex`
pub fn escaped(i: &str) -> nom::IResult<&str, &str> {
    crate::combinators::recognize_tuple((
        nom::bytes::complete::tag("%"),
        crate::parsers::char::hex,
        crate::parsers::char::hex,
    ))(i)
}

/// `digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f"`
pub fn hex(i: &str) -> nom::IResult<&str, &str> {
    nom::combinator::recognize(nom::character::complete::satisfy(|c| c.is_ascii_hexdigit()))(i)
}

/// `"-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"`
pub fn mark(i: &str) -> nom::IResult<&str, &str> {
    nom::combinator::recognize(nom::character::complete::one_of("-_.!~*'()"))(i)
}

/// `unreserved | escaped | ":" | "@" | "&" | "=" | "+" | "$" | ","`
pub fn p_char(i: &str) -> nom::IResult<&str, &str> {
    nom::branch::alt((
        crate::parsers::char::unreserved,
        crate::parsers::char::escaped,
        nom::combinator::recognize(nom::character::complete::one_of(":@&=+$,")),
    ))(i)
}

/// `";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","`
pub fn reserved(i: &str) -> nom::IResult<&str, &str> {
    nom::combinator::recognize(nom::character::complete::one_of(";/?:@&=+$,"))(i)
}

/// `alphanum | mark`
pub fn unreserved(i: &str) -> nom::IResult<&str, &str> {
    nom::branch::alt((crate::parsers::char::alphanum, crate::parsers::char::mark))(i)
}

/// `reserved | unreserved | escaped`
pub fn uri_c(i: &str) -> nom::IResult<&str, &str> {
    nom::branch::alt((crate::parsers::char::reserved, crate::parsers::char::unreserved, crate::parsers::char::escaped))(
        i,
    )
}

/// `unreserved | escaped | ";" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","`
pub fn uri_c_no_slash(i: &str) -> nom::IResult<&str, &str> {
    nom::branch::alt((
        crate::parsers::char::unreserved,
        crate::parsers::char::escaped,
        nom::combinator::recognize(nom::character::complete::one_of(";?:@&=+$,")),
    ))(i)
}

#[cfg(test)]
mod escaped {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/escaped_tests.rs"));
}

#[cfg(test)]
mod mark {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/mark_tests.rs"));
}

#[cfg(test)]
mod p_char {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/p_char_tests.rs"));
}

#[cfg(test)]
mod reserved {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/reserved_tests.rs"));
}

#[cfg(test)]
mod unreserved {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/unreserved_tests.rs"));
}

#[cfg(test)]
mod uri_c {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/uri_c_tests.rs"));
}

#[cfg(test)]
mod uri_c_no_slash {
    use anyhow::Context;

    include!(concat!(env!("OUT_DIR"), "/uri_c_no_slash_tests.rs"));
}
