regex_chunker/
custom.rs

1/*!
2The custom chunker type.
3*/
4use std::io::Read;
5
6use crate::{Adapter, ByteChunker, RcErr, SimpleAdapter};
7
8/**
9A chunker that has additionally been supplied with an [`Adapter`], so it
10can produce arbitrary types. The `CustomChunker`s does not have a separate
11constructor; it is built by combining a `ByteChunker` with an `Adapter`
12using [`ByteChunker::with_adapter`].
13
14Here's the example using the [`StringAdapter`](crate::StringAdapter) type
15to yield [`String`]s instead of byte vectors.
16
17```rust
18# use std::error::Error;
19# fn main() -> Result<(), Box<dyn Error>> {
20    use regex_chunker::{ByteChunker, CustomChunker, StringAdapter};
21    use std::io::Cursor;
22
23    let text = b"One, two, three four. Can I have a little more?";
24    let c = Cursor::new(text);
25
26    let chunks: Vec<_> = ByteChunker::new(c, "[ .,?]+")?
27        .with_adapter(StringAdapter::default())
28        .map(|res| res.unwrap())
29        .collect();
30
31    assert_eq!(
32        &chunks,
33        &[
34            "One", "two", "three", "four",
35            "Can", "I", "have", "a", "little", "more"
36        ].clone()
37    );
38#   Ok(()) }
39```
40*/
41
42pub struct CustomChunker<R, A> {
43    chunker: ByteChunker<R>,
44    adapter: A,
45}
46
47impl<R, A> CustomChunker<R, A> {
48    /// Consume this `CustomChunker` and return the underlying
49    /// [`ByteChunker`] and [`Adapter`].
50    pub fn into_innards(self) -> (ByteChunker<R>, A) {
51        (self.chunker, self.adapter)
52    }
53
54    /// Get a reference to the underlying [`Adapter`].
55    pub fn get_adapter(&self) -> &A { &self.adapter }
56
57    /// Get a mutable reference to the underlying [`Adapter`].
58    pub fn get_adapter_mut(&mut self) -> &mut A { &mut self.adapter }
59
60}
61
62impl<R, A> From<(ByteChunker<R>, A)> for CustomChunker<R, A> {
63    fn from((chunker, adapter): (ByteChunker<R>, A)) -> Self {
64        Self { chunker, adapter }
65    }
66}
67
68impl<R, A> Iterator for CustomChunker<R, A>
69where
70    R: Read,
71    A: Adapter,
72{
73    type Item = A::Item;
74
75    fn next(&mut self) -> Option<A::Item> {
76        let opt = self.chunker.next();
77        self.adapter.adapt(opt)
78    }
79}
80
81/**
82A version of [`CustomChunker`] that takes a [`SimpleAdapter`] type.
83
84This type will disappear once
85[Issue #1672](https://github.com/rust-lang/rfcs/pull/1672) is resolved.
86As it is, if `CustomChunker` tries to implement `Iterator` for _both_
87`Adapter` and `SimpleAdapter` types, these implementations conflict
88(though they shouldn't). Once the compiler is capable of figuring this
89out, `CustomChunker` will work with types that implement both of
90these traits.
91*/
92pub struct SimpleCustomChunker<R, A> {
93    chunker: ByteChunker<R>,
94    adapter: A,
95}
96
97impl<R, A> SimpleCustomChunker<R, A> {
98    /// Consume this `SimpleCustomChunker` and return the underlying
99    /// [`ByteChunker`] and [`Adapter`].
100    pub fn into_innards(self) -> (ByteChunker<R>, A) {
101        (self.chunker, self.adapter)
102    }
103
104    /// Get a reference to the underlying [`SimpleAdapter`].
105    pub fn get_adapter(&self) -> &A { &self.adapter }
106
107    /// Get a mutable reference to the underlying [`SimpleAdapter`].
108    pub fn get_adapter_mut(&mut self) -> &mut A { &mut self.adapter }
109}
110
111impl<R, A> From<(ByteChunker<R>, A)> for SimpleCustomChunker<R, A> {
112    fn from((chunker, adapter): (ByteChunker<R>, A)) -> Self {
113        Self { chunker, adapter }
114    }
115}
116
117impl<R, A> Iterator for SimpleCustomChunker<R, A>
118where
119    R: Read,
120    A: SimpleAdapter,
121{
122    type Item = Result<A::Item, RcErr>;
123
124    fn next(&mut self) -> Option<Self::Item> {
125        match self.chunker.next()? {
126            Ok(v) => Some(Ok(self.adapter.adapt(v))),
127            Err(e) => Some(Err(e)),
128        }
129    }
130}