#![feature(assert_matches)] #![allow(dead_code)] //TODO eventually turn this off type ParseResult = Result<(O, I), E>; trait Parser { fn parse(&self, input: I) -> ParseResult; } impl Parser for F where F: Fn(I) -> ParseResult, { fn parse(&self, input: I) -> ParseResult { self(input) } } fn literal(expected: &'static str) -> impl Fn(&str) -> ParseResult<&str, &str, &str> { move |input| match input.get(0..expected.len()) { Some(next) if next == expected => Ok((expected, &input[expected.len()..])), _ => Err(input), } } fn map(parser: P, map_fn: F) -> impl Parser where P: Parser, F: Fn(O1) -> O2, { move |input| parser.parse(input).map(|(result, rest)| (map_fn(result), rest)) } #[cfg(test)] mod tests { use super::*; use std::assert_matches::assert_matches; #[test] fn test_parsing() { let output = literal("a")("a yolo"); assert_matches!(output.unwrap(), ("a", " yolo")); } #[test] fn test_map() { let lit_a = literal("a"); let output = map(lit_a, |s| s.to_uppercase()).parse("a yolo"); assert_matches!(output.unwrap(), (s, " yolo") if s == "A"); } }