// Write two separate parser functions
// One function returns `impl Parser<>`
// The other function returns `FnMut(I) -> IResult<I, ...`
// Test each with the `map` function and the `parse` function
use nom::{character::complete::digit1, error::ParseError, IResult, Parser};

#[derive(Clone, Copy, Debug, PartialEq)]
struct Container(i32);

#[allow(dead_code)]
fn parse_container_a<'a, E: ParseError<&'a str>>(
    mut parser: impl Parser<&'a str, i32, E>,
) -> impl FnMut(&'a str) -> IResult<&'a str, Container, E> {
    move |input| {
        let (input, value) = parser.parse(input)?;
        Ok((input, Container(value)))
    }
}

/*
// This form doesn't work. It is not possible in this case to get the ownership
// declarations correct on parser. The reason I would want to do this is for more
// concise representation of parse_container_a. It probably fails because map consumes
// the parser.
fn parse_container_b<'a, E: ParseError<&'a str>, P>(
    mut parser: P,
) -> impl Parser<&'a str, Container, E>
where
    P: Parser<&'a str, i32, E>,
{
    move |input| parser.map(|val| Container(val)).parse(input)
}
*/

#[allow(dead_code)]
fn parse_container_c<'a, E: ParseError<&'a str>>(
    parser: impl Parser<&'a str, i32, E>,
) -> impl Parser<&'a str, Container, E> {
    parser.map(Container)
}

/*
// This form also doesn't work, for the same reason as parse_container_b doesn't work.
fn parse_container_d<'a, E: ParseError<&'a str>>(
    parser: impl Parser<&'a str, i32, E>,
) -> impl FnMut(&'a str) -> IResult<&'a str, Container, E> {
    |input| parser.map(|val| Container(val)).parse(input)
}
*/

// If I really want to do forms b and d, this works. I do the parser combination before
// creating the resulting function.
#[allow(dead_code)]
fn parse_container_e<'a, E: ParseError<&'a str>>(
    parser: impl Parser<&'a str, i32, E>,
) -> impl Parser<&'a str, Container, E> {
    let mut parser = parser.map(Container);

    move |input| parser.parse(input)
}

#[allow(dead_code)]
fn parse_number_a<'a, E: ParseError<&'a str>>() -> impl FnMut(&'a str) -> IResult<&'a str, i32, E> {
    parse_number
}

#[allow(dead_code)]
fn parse_number_b<'a, E: ParseError<&'a str>>() -> impl Parser<&'a str, i32, E> {
    parse_number
}

#[allow(dead_code)]
fn parse_number<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, i32, E> {
    let (input, val) = digit1(input)?;
    Ok((input, val.parse::<i32>().unwrap()))
}

#[cfg(test)]
mod tests {
    use super::*;
    use cool_asserts::assert_matches;

    const DATA: &'static str = "15";

    #[test]
    fn function() {
        let resp = parse_number_a::<nom::error::VerboseError<&str>>()
            .map(|val| Container(val))
            .parse(DATA);
        assert_matches!(resp, Ok((_, content)) =>
                assert_eq!(content, Container(15))
        );
    }

    #[test]
    fn parser() {
        let resp = parse_number_b::<nom::error::VerboseError<&str>>()
            .map(|val| Container(val))
            .parse(DATA);
        assert_matches!(resp, Ok((_, content)) =>
                assert_eq!(content, Container(15))
        );
    }

    #[test]
    fn parser_composition_a() {
        let resp =
            parse_container_a::<nom::error::VerboseError<&str>>(parse_number_a()).parse(DATA);
        assert_matches!(resp, Ok((_, content)) =>
                assert_eq!(content, Container(15))
        );
    }

    #[test]
    fn parser_composition_c() {
        let resp =
            parse_container_c::<nom::error::VerboseError<&str>>(parse_number_b()).parse(DATA);
        assert_matches!(resp, Ok((_, content)) =>
                assert_eq!(content, Container(15))
        );
    }
}
