1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use crate::{Pipe, Result};
use std::marker::PhantomData;
/// Wraps the pipe and input/ouput into a closure
pub trait WrapExt<I, O, E, R> {
    /// wraps self into a function
    /// ```rust
    /// # use pipe_chain::{str::TagStrError, tag, AndExt, Incomplete, Pipe, WrapExt, Result};
    /// # use std::error::Error as StdError;
    /// # #[derive(Debug, PartialEq, Eq)]
    /// # enum Error {
    /// #     Tag(TagStrError),
    /// #     Incomplete(Incomplete),
    /// # }
    /// #
    /// # impl std::fmt::Display for Error {
    /// #     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    /// #         write!(f, "{self:?}")
    /// #     }
    /// # }
    /// # impl StdError for Error {}
    /// #
    /// # impl From<Incomplete> for Error {
    /// #     fn from(value: Incomplete) -> Error { Error::Incomplete(value) }
    /// # }
    /// #
    /// # impl From<TagStrError> for Error {
    /// #     fn from(value: TagStrError) -> Error { Error::Tag(value) }
    /// # }
    /// #
    /// pub fn input_offset<'a, O, E>(
    ///     p: &mut impl Pipe<&'a str, O, E>, input: (&'a str, usize),
    /// ) -> Result<(&'a str, usize), O, E> {
    ///     let (i, o) = p.apply(input.0)?;
    ///     Ok(((i, input.1 + (input.0.len() - i.len())), o))
    /// }
    /// assert_eq!(
    ///     tag::<Error, _, _>("foo").and(tag("bar")).wrap(input_offset).apply(("foobar", 0)),
    ///     Ok((("", 6), ("foo", "bar")))
    /// );
    /// assert_eq!(
    ///     tag::<Error, _, _>("foo").and(tag("bar")).wrap(input_offset).apply(("foobar", 0)),
    ///     Ok((("", 6), ("foo", "bar")))
    /// );
    /// ```
    fn wrap<I2, O2, R2, F>(self, f: F) -> Wrap<I, O, R, Self, F>
    where
        Self: Pipe<I, O, E, R> + Sized,
        F: FnMut(&mut Self, I2) -> Result<R2, O2, E>,
    {
        Wrap::new(self, f)
    }
}

impl<I, O, E, R, P: Pipe<I, O, E, R>> WrapExt<I, O, E, R> for P {}

/// [WrapExt::wrap] implementation
pub struct Wrap<I, O, R, P, F>(P, F, PhantomData<I>, PhantomData<O>, PhantomData<R>);

impl<I, O, R, P, F> Wrap<I, O, R, P, F> {
    fn new(p: P, f: F) -> Self { Self(p, f, PhantomData, PhantomData, PhantomData) }
}

impl<I, O, E, R, I2, O2, R2, P, F> Pipe<I2, O2, E, R2> for Wrap<I, O, R, P, F>
where
    P: Pipe<I, O, E, R>,
    F: FnMut(&mut P, I2) -> Result<R2, O2, E>,
{
    fn apply(&mut self, input: I2) -> Result<R2, O2, E> { (self.1)(&mut self.0, input) }
}