1use crate::{Incomplete, Pipe, Repetition};
2use fatal_error::FatalError;
3use std::error::Error as StdError;
4
5pub trait LenBytes {
7 fn len_bytes(&self) -> usize;
9}
10
11pub trait TakeAtom {
13 type Atom: LenBytes;
15 type Container;
17
18 fn next(&mut self) -> Option<(usize, Self::Atom)>;
20
21 fn split_at(self, index: usize) -> (Self::Container, Self::Container);
24}
25
26#[inline]
30pub fn take_while<I, E>(
31 mut f: impl FnMut(I::Atom) -> bool,
32 qty: impl TryInto<Repetition, Error = impl StdError>,
33) -> impl Pipe<I, (I::Container,), E, I::Container>
34where
35 I: TakeAtom,
36 Incomplete: Into<E>,
37{
38 let qty = qty.try_into().unwrap();
39 #[inline]
40 move |mut input: I| {
41 let mut c = 0;
42 let mut idx = 0;
43 let mut err = None;
44 let mut all = false;
45 while !qty.is_max(c) {
46 if let Some((i, x)) = input.next() {
47 let end = i + x.len_bytes();
48 if !f(x) {
49 err = Some(Incomplete::Unknown.into());
50 break;
51 }
52 idx = end;
53 c += 1;
54 } else {
55 all = true;
56 break;
57 }
58 }
59 qty.map_err(c, |_, _, _| {
60 if all {
61 FatalError::Error(Incomplete::Unknown.into())
62 } else {
63 FatalError::Error(err.unwrap())
64 }
65 })?;
66 let (r, x) = input.split_at(idx);
67 Ok((r, (x,)))
68 }
69}
70
71pub fn take_atom<A: TakeAtom, E, E2>(
75 qty: impl TryInto<Repetition, Error = E>,
76) -> Result<impl Pipe<A, (Vec<A::Atom>,), E2, A::Container>, E>
77where
78 Incomplete: Into<E2>,
79{
80 let qty = qty.try_into()?;
81 Ok(move |mut input: A| {
82 let mut r = Vec::new();
83 let mut last = 0;
84 for x in 0.. {
85 match input.next() {
86 Some((i, o)) => {
87 last = i + o.len_bytes();
88 r.push(o);
89 }
90 None => {
91 if qty.needs_more(x) {
92 return Err(FatalError::Error(Incomplete::Unknown.into()));
93 } else {
94 break;
95 }
96 }
97 }
98 if qty.is_max(x) {
99 break;
100 }
101 }
102 Ok((input.split_at(last).0, (r,)))
103 })
104}