#![allow(dead_code)] //TODO eventually turn this off
mod choice;
mod map;
mod primitives;
mod sequence;

pub use choice::*;
pub use map::*;
pub use primitives::*;
pub use sequence::*;

type ParseResult<I, O, E> = Result<(O, I), E>;

pub trait Parser<I, O, E> {
    fn parse(&self, input: I) -> ParseResult<I, O, E>;
}

impl<I, O, E, F> Parser<I, O, E> for F
where
    F: Fn(I) -> ParseResult<I, O, E>,
{
    fn parse(&self, input: I) -> ParseResult<I, O, E> {
        self(input)
    }
}

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

    #[test]
    fn parsing() {
        let (parsed, rest) = literal("a")("a yolo").unwrap();
        assert_eq!(parsed, "a");
        assert_eq!(rest, " yolo");
    }

    #[test]
    fn test_sequence() {
        let parser = sequence(literal("bongo"), sequence(literal(" "), literal("jonzzz")));
        let output = parser.parse("bongo jonzzz").unwrap();
        assert_eq!(output.0 .0, "bongo");
        assert_eq!(output.0 .1, (" ", "jonzzz"));
        assert_eq!(output.1, "");
    }

    #[test]
    fn test_choice() {
        let a = literal("bongo");
        let b = literal("sucy");
        let c = literal("ara");
        let inputs = [&a as &dyn Parser<&str, &str, &str>, &b, &c];
        let parser = choice(&inputs);

        let output = parser.parse("ara hajimete").unwrap();
        assert_eq!(("ara", " hajimete"), output);
    }

    #[test]
    fn test_map() {
        let parser = map(
            sequence(literal("a"), literal("b")),
            |(_a, _b): (&str, &str)| 59,
        );
        let output = parser.parse("abcd").unwrap();
        assert_eq!((59, "cd"), output);
    }
}