cypress/parser/
bind.rs

1use crate::{error::Error, parser::*};
2use std::sync::Arc;
3
4/// A parser combinator that applies a transformation function to the result of a parser.
5///
6/// This is useful for mapping parsed values into a new representation,
7/// such as converting a parsed string into an integer, or wrapping a result in a custom enum.
8///
9/// # Type Parameters
10/// - `P`: The inner parser
11/// - `O1`: The output type of the inner parser `P`
12/// - `O2`: The output type after applying the transformation function
13#[derive(Clone)]
14pub struct PBind<P, O1, O2> {
15    p: P,
16    f: Arc<dyn Fn(O1) -> O2>,
17}
18
19/// Constructs a `PBind` parser that applies a function `f` to the result of parser `p`.
20///
21/// This is similar to the `map` or `bind` operation in functional programming.
22///
23/// # Parameters
24/// - `p`: The parser to apply
25/// - `f`: The transformation function that converts the parser’s result
26///
27/// # Returns
28/// A new parser that parses with `p` and transforms its result using `f`.
29///
30/// # Example
31/// ```rust
32/// use cypress::prelude::*;
33///
34/// let input = b"A".into_input();
35/// let parser = just('A').map(|_| 1);
36///
37/// match parser.parse(input) {
38///     Ok(PSuccess { val, rest: _ }) => assert_eq!(val, 1),
39///     Err(_) => assert!(false),
40/// }
41/// ```
42pub fn pbind<P, F, O1, O2>(p: P, f: F) -> PBind<P, O1, O2>
43where
44    F: Fn(O1) -> O2 + 'static,
45{
46    PBind { p, f: Arc::new(f) }
47}
48
49impl<'a, P, K, O1, O2> ParserCore<'a, K, O2> for PBind<P, O1, O2>
50where
51    K: PartialEq + Clone + 'a,
52    O1: Clone + 'a,
53    P: Parser<'a, K, O1>,
54{
55    /// Applies the inner parser, then transforms its result using the function `f`.
56    ///
57    /// If parsing succeeds, the transformation function is applied to the result,
58    /// and the transformed value is returned.
59    ///
60    /// # Errors
61    /// Returns a parse failure if the inner parser `p` fails.
62    fn parse(&self, i: PInput<'a, K>) -> Result<PSuccess<'a, K, O2>, Error<'a, K>> {
63        // Apply the inner parser
64        let PSuccess { val, rest } = self.p.parse(i)?;
65
66        // Transform the result and return
67        Ok(PSuccess {
68            val: (self.f)(val),
69            rest,
70        })
71    }
72}
73
74impl<'a, P, K, O1, O2> Parser<'a, K, O2> for PBind<P, O1, O2>
75where
76    K: PartialEq + Clone + 'a,
77    O1: Clone + 'a,
78    O2: Clone + 'a,
79    P: Parser<'a, K, O1>,
80{
81}