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}