Skip to main content

ipld_car/bounded_reader/sync/
bounded_reader.rs

1use 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	/// Creates a new bounded reader wrapping the shared reader, restricted to the given range.
26	///
27	/// # NOTE
28	/// It does NOT check that `range` is valid in `reader`, that will fail during read/seek
29	/// operations.
30	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	/// Returns the absolute range this bounded reader is restricted to.
72	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	/// Returns the length of the bounded range.
81	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	/// Creates a new bounded reader that is a sub-range of this one.
90	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}