tokit/parser/
map.rs

1use core::marker::PhantomData;
2
3use super::*;
4
5/// A parser that transforms the output of another parser using a mapping function.
6///
7/// This combinator applies a function to the successful output of a parser,
8/// allowing you to transform the parsed value into a different type.
9///
10/// # Type Parameters
11///
12/// - `F`: The inner parser
13/// - `MapFn`: The mapping function
14/// - `O`: The output type of the inner parser
15///
16/// # Examples
17///
18/// ```ignore
19/// // Parse a token and extract just its kind
20/// let parser = Any::parser()
21///     .map(|tok| tok.kind());
22/// ```
23#[derive(Clone, Debug, PartialEq, Eq, Hash)]
24pub struct Map<F, G, L, Ctx, O, O2, Lang: ?Sized = ()> {
25  parser: F,
26  map_fn: G,
27  _o: PhantomData<O>,
28  _o2: PhantomData<O2>,
29  _l: PhantomData<L>,
30  _ctx: PhantomData<Ctx>,
31  _lang: PhantomData<Lang>,
32}
33
34impl<F, G, L, Ctx, O, O2, Lang: ?Sized> Map<F, G, L, Ctx, O, O2, Lang> {
35  /// Creates a new `Map` combinator.
36  #[cfg_attr(not(tarpaulin), inline(always))]
37  pub(super) const fn new(parser: F, map_fn: G) -> Self {
38    Self {
39      parser,
40      map_fn,
41      _o: PhantomData,
42      _o2: PhantomData,
43      _l: PhantomData,
44      _ctx: PhantomData,
45      _lang: PhantomData,
46    }
47  }
48}
49
50impl<'inp, F, G, L, O, U, Ctx, Lang> ParseInput<'inp, L, U, Ctx, Lang>
51  for Map<F, G, L, Ctx, O, U, Lang>
52where
53  F: ParseInput<'inp, L, O, Ctx, Lang>,
54  G: FnMut(O) -> U,
55  L: Lexer<'inp>,
56  Ctx: ParseContext<'inp, L, Lang>,
57{
58  #[cfg_attr(not(tarpaulin), inline(always))]
59  fn parse_input(
60    &mut self,
61    input: &mut InputRef<'inp, '_, L, Ctx, Lang>,
62  ) -> Result<U, <Ctx::Emitter as Emitter<'inp, L, Lang>>::Error> {
63    self.parser.parse_input(input).map(&mut self.map_fn)
64  }
65}
66
67#[cfg(test)]
68mod tests {
69  use crate::lexer::{DummyLexer, DummyToken};
70
71  use super::*;
72
73  fn assert_map_parse_impl<'inp>() -> impl Parse<'inp, DummyLexer, (), ()> {
74    Parser::new().apply(Any::new().map(|_tok: DummyToken| ()))
75  }
76
77  fn assert_map_parse_with_ctx_impl<'inp>() -> impl Parse<'inp, DummyLexer, (), ()> {
78    Parser::with_context(()).apply(Any::new().map(|_tok: DummyToken| ()))
79  }
80
81  #[test]
82  fn assert_parse_impl() {
83    let _ = assert_map_parse_impl();
84    let _ = assert_map_parse_with_ctx_impl();
85  }
86}