ipld_car/bounded_reader/sync/
bounded_reader.rs1use crate::bounded_reader::{
2 error::BoundedReaderErr,
3 mem_bounded_reader::MemBoundedReader,
4 sync::{shared_bounded_reader::SharedBoundedReader, ChainedBoundedReader},
5 traits::{Bounded, BoundedIndex, CloneAndRewind},
6};
7
8use bytes::Bytes;
9use derivative::Derivative;
10use std::{
11 io::{self, Read, Seek, SeekFrom},
12 ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
13 sync::{Arc, Mutex},
14};
15
16#[derive(derive_more::Debug, Derivative)]
17#[derivative(Clone(bound = ""))]
18pub enum BoundedReader<T> {
19 Shared(SharedBoundedReader<T>),
20 Mem(MemBoundedReader),
21 Chained(ChainedBoundedReader<T>),
22}
23
24impl<T> BoundedReader<T> {
25 pub fn new(reader: Arc<Mutex<T>>, range: Range<u64>) -> Result<Self, BoundedReaderErr> {
31 let shared = SharedBoundedReader::new(reader, range)?;
32 Ok(Self::Shared(shared))
33 }
34
35 pub fn empty() -> Self {
36 Self::Mem(MemBoundedReader::new(Bytes::new()))
37 }
38}
39
40impl<T: Seek> BoundedReader<T> {
41 pub fn from_reader(reader: T) -> Result<Self, io::Error> {
42 SharedBoundedReader::from_reader(reader).map(Self::Shared)
43 }
44}
45
46impl<T> From<Bytes> for BoundedReader<T> {
47 fn from(content: Bytes) -> Self {
48 Self::Mem(MemBoundedReader::new(content))
49 }
50}
51
52impl<T> From<()> for BoundedReader<T> {
53 fn from(_: ()) -> Self {
54 Self::empty()
55 }
56}
57
58impl<T> From<ChainedBoundedReader<T>> for BoundedReader<T> {
59 fn from(c: ChainedBoundedReader<T>) -> Self {
60 Self::Chained(c)
61 }
62}
63
64impl<T> Default for BoundedReader<T> {
65 fn default() -> Self {
66 Self::empty()
67 }
68}
69
70impl<T> Bounded for BoundedReader<T> {
71 fn bounds(&self) -> Range<u64> {
73 match self {
74 Self::Shared(s) => s.bounds(),
75 Self::Mem(m) => m.bounds(),
76 Self::Chained(c) => c.bounds(),
77 }
78 }
79
80 fn bound_len(&self) -> u64 {
82 match self {
83 Self::Shared(s) => s.bound_len(),
84 Self::Mem(m) => m.bound_len(),
85 Self::Chained(c) => c.bound_len(),
86 }
87 }
88
89 fn sub<R: BoundedIndex<Self>>(&self, range: R) -> Result<Self, BoundedReaderErr> {
91 range.get(self)
92 }
93
94 fn clamped_sub<R: BoundedIndex<Self>>(&self, range: R) -> Self {
95 range.clamped_get(self)
96 }
97}
98
99impl<T: Read + Seek> Read for BoundedReader<T> {
100 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
101 match self {
102 Self::Shared(s) => s.read(buf),
103 Self::Mem(m) => m.read(buf),
104 Self::Chained(c) => c.read(buf),
105 }
106 }
107}
108
109impl<T> CloneAndRewind for BoundedReader<T> {
110 fn clone_and_rewind(&self) -> Self {
111 match self {
112 Self::Shared(s) => Self::Shared(s.clone_and_rewind()),
113 Self::Mem(m) => Self::Mem(m.clone_and_rewind()),
114 Self::Chained(c) => Self::Chained(c.clone_and_rewind()),
115 }
116 }
117}
118
119impl<T: Seek> Seek for BoundedReader<T> {
120 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
121 match self {
122 Self::Shared(s) => s.seek(pos),
123 Self::Mem(m) => m.seek(pos),
124 Self::Chained(c) => c.seek(pos),
125 }
126 }
127}
128
129impl<T> BoundedIndex<BoundedReader<T>> for Range<u64> {
130 fn get(self, bounded: &BoundedReader<T>) -> Result<BoundedReader<T>, BoundedReaderErr> {
131 match bounded {
132 BoundedReader::Shared(s) => self.get(s).map(BoundedReader::Shared),
133 BoundedReader::Mem(m) => self.get(m).map(BoundedReader::Mem),
134 BoundedReader::Chained(c) => self.get(c).map(BoundedReader::Chained),
135 }
136 }
137
138 fn clamped_get(self, bounded: &BoundedReader<T>) -> BoundedReader<T> {
139 match bounded {
140 BoundedReader::Shared(s) => BoundedReader::Shared(self.clamped_get(s)),
141 BoundedReader::Mem(m) => BoundedReader::Mem(self.clamped_get(m)),
142 BoundedReader::Chained(c) => BoundedReader::Chained(self.clamped_get(c)),
143 }
144 }
145}
146
147impl<T> BoundedIndex<BoundedReader<T>> for RangeFrom<u64> {
148 fn get(self, bounded: &BoundedReader<T>) -> Result<BoundedReader<T>, BoundedReaderErr> {
149 match bounded {
150 BoundedReader::Shared(s) => self.get(s).map(BoundedReader::Shared),
151 BoundedReader::Mem(m) => self.get(m).map(BoundedReader::Mem),
152 BoundedReader::Chained(c) => self.get(c).map(BoundedReader::Chained),
153 }
154 }
155
156 fn clamped_get(self, bounded: &BoundedReader<T>) -> BoundedReader<T> {
157 match bounded {
158 BoundedReader::Shared(s) => BoundedReader::Shared(self.clamped_get(s)),
159 BoundedReader::Mem(m) => BoundedReader::Mem(self.clamped_get(m)),
160 BoundedReader::Chained(c) => BoundedReader::Chained(self.clamped_get(c)),
161 }
162 }
163}
164
165impl<T> BoundedIndex<BoundedReader<T>> for RangeTo<u64> {
166 fn get(self, bounded: &BoundedReader<T>) -> Result<BoundedReader<T>, BoundedReaderErr> {
167 match bounded {
168 BoundedReader::Shared(s) => self.get(s).map(BoundedReader::Shared),
169 BoundedReader::Mem(m) => self.get(m).map(BoundedReader::Mem),
170 BoundedReader::Chained(c) => self.get(c).map(BoundedReader::Chained),
171 }
172 }
173
174 fn clamped_get(self, bounded: &BoundedReader<T>) -> BoundedReader<T> {
175 match bounded {
176 BoundedReader::Shared(s) => BoundedReader::Shared(self.clamped_get(s)),
177 BoundedReader::Mem(m) => BoundedReader::Mem(self.clamped_get(m)),
178 BoundedReader::Chained(c) => BoundedReader::Chained(self.clamped_get(c)),
179 }
180 }
181}
182
183impl<T> BoundedIndex<BoundedReader<T>> for RangeInclusive<u64> {
184 fn get(self, bounded: &BoundedReader<T>) -> Result<BoundedReader<T>, BoundedReaderErr> {
185 match bounded {
186 BoundedReader::Shared(s) => self.get(s).map(BoundedReader::Shared),
187 BoundedReader::Mem(m) => self.get(m).map(BoundedReader::Mem),
188 BoundedReader::Chained(c) => self.get(c).map(BoundedReader::Chained),
189 }
190 }
191
192 fn clamped_get(self, bounded: &BoundedReader<T>) -> BoundedReader<T> {
193 match bounded {
194 BoundedReader::Shared(s) => BoundedReader::Shared(self.clamped_get(s)),
195 BoundedReader::Mem(m) => BoundedReader::Mem(self.clamped_get(m)),
196 BoundedReader::Chained(c) => BoundedReader::Chained(self.clamped_get(c)),
197 }
198 }
199}
200
201impl<T> BoundedIndex<BoundedReader<T>> for RangeToInclusive<u64> {
202 fn get(self, bounded: &BoundedReader<T>) -> Result<BoundedReader<T>, BoundedReaderErr> {
203 match bounded {
204 BoundedReader::Shared(s) => self.get(s).map(BoundedReader::Shared),
205 BoundedReader::Mem(m) => self.get(m).map(BoundedReader::Mem),
206 BoundedReader::Chained(c) => self.get(c).map(BoundedReader::Chained),
207 }
208 }
209
210 fn clamped_get(self, bounded: &BoundedReader<T>) -> BoundedReader<T> {
211 match bounded {
212 BoundedReader::Shared(s) => BoundedReader::Shared(self.clamped_get(s)),
213 BoundedReader::Mem(m) => BoundedReader::Mem(self.clamped_get(m)),
214 BoundedReader::Chained(c) => BoundedReader::Chained(self.clamped_get(c)),
215 }
216 }
217}
218
219impl<T> BoundedIndex<BoundedReader<T>> for RangeFull {
220 fn get(self, bounded: &BoundedReader<T>) -> Result<BoundedReader<T>, BoundedReaderErr> {
221 match bounded {
222 BoundedReader::Shared(s) => self.get(s).map(BoundedReader::Shared),
223 BoundedReader::Mem(m) => self.get(m).map(BoundedReader::Mem),
224 BoundedReader::Chained(c) => self.get(c).map(BoundedReader::Chained),
225 }
226 }
227
228 fn clamped_get(self, bounded: &BoundedReader<T>) -> BoundedReader<T> {
229 match bounded {
230 BoundedReader::Shared(s) => BoundedReader::Shared(self.clamped_get(s)),
231 BoundedReader::Mem(m) => BoundedReader::Mem(self.clamped_get(m)),
232 BoundedReader::Chained(c) => BoundedReader::Chained(self.clamped_get(c)),
233 }
234 }
235}
236
237#[cfg(test)]
238mod tests {
239 use super::*;
240 use crate::bounded_reader::traits::{Bounded, BoundedIndex};
241 use std::io::{Cursor, Read};
242 use test_case::test_case;
243
244 const HELLO: &[u8] = b"Hello world";
245 const LOREM_IPSUM: &[u8] = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
246
247 #[allow(unused_parens)]
248 #[test_case( HELLO, 0..4 => b"Hell".to_vec(); "From 0 to 4")]
249 #[test_case( HELLO, 2..=4 => b"llo".to_vec(); "From 2 to =4")]
250 #[test_case( HELLO, ..=4 => b"Hello".to_vec(); "to =4")]
251 #[test_case( HELLO, (0..) => b"Hello world".to_vec(); "From 0 to .." )]
252 #[test_case( HELLO, (6..) => b"world".to_vec(); "From 5 to .." )]
253 #[test_case( HELLO, (..) => b"Hello world".to_vec(); "full range" )]
254 fn bounded_index_as_shared<D, R>(data: D, range: R) -> Vec<u8>
255 where
256 D: AsRef<[u8]>,
257 R: BoundedIndex<BoundedReader<Cursor<D>>>,
258 {
259 let bounded = BoundedReader::from_reader(Cursor::new(data)).unwrap();
260 let mut sub = bounded.sub(range).unwrap();
261
262 let mut sub_content = vec![];
263 let _ = sub.read_to_end(&mut sub_content).unwrap();
264 sub_content
265 }
266
267 #[test_case( LOREM_IPSUM, &[(28..55),(12..22)] => b"adipiscing".to_vec(); "Nested (27..55)(12..22)" )]
268 #[test_case( LOREM_IPSUM, &[(28..55),(0..11)] => b"consectetur".to_vec(); "Nested (27..55)(0..11)" )]
269 #[test_case( LOREM_IPSUM, &[28..=55,23..=26] => b"elit".to_vec(); "Nested 27..=55 23..=26" )]
270 #[test_case( LOREM_IPSUM, &[..=55, ..=4] => b"Lorem".to_vec(); "Nested ..=55 ..=4" )]
271 #[test_case( LOREM_IPSUM, &[(28..), (88..)] => b"aliqua.".to_vec(); "Nested (28..) (88..)" )]
272 #[test_case( LOREM_IPSUM, &[(..), (..)] => LOREM_IPSUM.to_vec(); "Nested (..) (..)" )]
273 fn nested_bounded_index_as_shared<D, R>(data: D, nested_ranges: &[R]) -> Vec<u8>
274 where
275 D: AsRef<[u8]>,
276 R: BoundedIndex<BoundedReader<Cursor<D>>> + Clone,
277 {
278 let mut bounded = BoundedReader::from_reader(Cursor::new(data)).unwrap();
279 for range in nested_ranges {
280 bounded = bounded.sub(range.clone()).unwrap();
281 }
282
283 let mut content = vec![];
284 let _ = bounded.read_to_end(&mut content).unwrap();
285 content
286 }
287}