byte_chisel/
source.rs

1/*!
2 * `ChiselSource` and implementations.
3 */
4
5#[cfg(feature = "std")]
6use std::io::{BufRead, ErrorKind, Read};
7#[cfg(feature = "alloc")]
8use crate::ReadUntilStopReason;
9
10/** The common error type for operations on [`ChiselSource`]s. */
11pub enum ChiselSourceError<U> {
12	/** An error occurred while handling underlying source operations (e.g. an I/O error) */
13	Underlying(U),
14	/** Encountered unexpected end-ofinput while performing the operation */
15	EndOfInput
16}
17
18impl<U> From<U> for ChiselSourceError<U> {
19	fn from(value: U) -> Self { Self::Underlying(value) }
20}
21
22/**
23 * A "source" for chiseling bytes out of.
24 *
25 * This is analogous to the standard library `Read` and/or `BufRead` traits, but specialized for
26 * chiseling operations.
27 */
28pub trait ChiselSource {
29	/** The type of errors returned by this source. */
30	type Error;
31
32	/** Reads the exact number of bytes to fill `buffer`.
33	 *
34	 * # Errors
35	 * If an end-of-input condition occurs before completely filling the buffer, `ChiselSourceError::EndOfInput` is returned.
36	 *
37	 * If any other error occurs while reading, this function immediately returns with `ChiselSourceError::Underlying(_)`.
38	 *
39	 * If any error is returned, the contents of `buffer` are unspecified.
40	 * How many bytes were read is also unspecified, except that at most `buffer.len()` bytes are read.
41	 */
42	fn read_exact(&mut self, buffer: &mut [u8]) -> Result<(), ChiselSourceError<Self::Error>>;
43
44	/** Reads until the given delimiter byte is found or end-of-input occurs.
45	 *
46	 * If end-of-input occurs before the delimiter byte is found, [`ReadUntilStopReason::EndOfInput`] is returned.
47	 *
48	 * Otherwise, [`ReadUntilStopReason::Delimiter`] is returned. The found delimiter is not added to `into`.
49	 *
50	 *
51	 * # Errors
52	 * If an error occurs while reading, this function immediately returns with `ChiselSourceError::Underlying(_)`.
53	 * If this occurs, the contents of `into` are unspecified. How many bytes were read is also unspecified, _with no restrictions_.
54	 *
55	 * Note that end-of-input conditions are not errors, and result in `Ok(ReadUntilStopReason::EndOfInput)`.
56	 */
57	#[cfg(feature = "alloc")]
58	fn read_until(&mut self, byte: u8, into: &mut Vec<u8>) -> Result<ReadUntilStopReason, Self::Error>;
59
60	/** Skips some number of bytes of the input.
61	 *
62	 * This is usually used for padding or alignment.
63	 *
64	 * # Errors
65	 * If end-of-input condition occurs before `how_many` bytes are skipped, `ChiselSourceError::EndOfInput` is returned.
66	 *
67	 * If any other error occurs while skipping, this function immediately returns with ``ChiselSourceError::Underlying(_)`.
68	 *
69	 * If any error is returned, it is unspecified how many bytes are skipped, except that at most `how_many`
70	 * bytes are be skipped.
71	 */
72	fn skip(&mut self, how_many: usize) -> Result<(), ChiselSourceError<Self::Error>>;
73}
74
75impl ChiselSource for &[u8] {
76	type Error = core::convert::Infallible;
77
78	fn read_exact(&mut self, buffer: &mut [u8]) -> Result<(), ChiselSourceError<Self::Error>> {
79		if buffer.len() <= self.len() {
80			buffer.copy_from_slice(&self[..buffer.len()]);
81			*self = self.get(buffer.len()..).unwrap_or(&[]);
82			Ok(())
83		} else {
84			Err(ChiselSourceError::EndOfInput)
85		}
86	}
87
88	#[cfg(feature = "alloc")]
89	fn read_until(&mut self, byte: u8, into: &mut Vec<u8>) -> Result<ReadUntilStopReason, Self::Error> {
90		match memchr::memchr(byte, self) {
91			Some(x) => {
92				into.extend_from_slice(&self[0..x]);
93				*self = self.get(x + 1..).unwrap_or(&[]);
94				Ok(ReadUntilStopReason::Delimiter)
95			}
96			None => {
97				into.extend_from_slice(self);
98				*self = &[];
99				Ok(ReadUntilStopReason::EndOfInput)
100			}
101		}
102	}
103
104	fn skip(&mut self, how_many: usize) -> Result<(), ChiselSourceError<Self::Error>> {
105		if how_many <= self.len() {
106			*self = self.get(how_many..).unwrap_or(&[]);
107			Ok(())
108		} else {
109			Err(ChiselSourceError::EndOfInput)
110		}
111	}
112}
113
114#[cfg(feature = "std")]
115fn read_read_exact<R : Read>(this: &mut R, buffer: &mut [u8]) -> Result<(), ChiselSourceError<std::io::Error>> {
116	this.read_exact(buffer).map_err(|x| {
117		if x.kind() == ErrorKind::UnexpectedEof {
118			ChiselSourceError::EndOfInput
119		} else {
120			ChiselSourceError::Underlying(x)
121		}
122	})
123}
124
125#[cfg(feature = "std")]
126/**
127 * A wrapper struct that implements [`ChiselSource`] via a [`Read`] implementation.
128 *
129 * See [`Chisel::from_read`][crate::Chisel::from_read] for more information.
130 */
131pub struct ChiselSourceRead<'a, R : Read>(pub &'a mut R);
132
133#[cfg(feature = "std")]
134impl<'a, R : Read> ChiselSource for ChiselSourceRead<'a, R> {
135	type Error = std::io::Error;
136
137	fn read_exact(&mut self, buffer: &mut [u8]) -> Result<(), ChiselSourceError<Self::Error>> {
138		read_read_exact(&mut self.0, buffer)
139	}
140
141	#[cfg(feature = "alloc")]
142	fn read_until(&mut self, byte: u8, into: &mut Vec<u8>) -> Result<ReadUntilStopReason, Self::Error> {		
143		/* this is really inefficient, but we don't really have another choice */
144		loop {
145			let mut buffer = [ 0 ];
146			if self.0.read(&mut buffer)? == 0 {
147				break Ok(ReadUntilStopReason::EndOfInput)
148			} else if buffer[0] == byte {
149				break Ok(ReadUntilStopReason::Delimiter)
150			} else {
151				into.push(buffer[0]);
152			}
153		}
154	}
155
156	fn skip(&mut self, how_many: usize) -> Result<(), ChiselSourceError<Self::Error>> {
157		let mut buffer = [0u8; 32];
158		let mut remaining = how_many;
159		while remaining > 0 {
160			let skip_slice = match buffer.get_mut(0..remaining) {
161				Some(x) => x,
162				None => &mut buffer
163			};
164			let read = self.0.read(skip_slice)?;
165			if read == 0 {
166				return Err(ChiselSourceError::EndOfInput);
167			}
168			remaining -= read;
169		}
170		Ok(())
171	}
172}
173
174#[cfg(feature = "std")]
175/**
176 * A wrapper struct that implements [`ChiselSource`] via a [`BufRead`] implementation.
177 *
178 * See [`Chisel::from_buf_read`][crate::Chisel::from_buf_read] for more information.
179 */
180pub struct ChiselSourceBufRead<'a, R : BufRead>(pub &'a mut R);
181
182#[cfg(feature = "std")]
183impl<'a, R : BufRead> ChiselSource for ChiselSourceBufRead<'a, R> {
184	type Error = std::io::Error;
185
186	fn read_exact(&mut self, buffer: &mut [u8]) -> Result<(), ChiselSourceError<Self::Error>> {
187		read_read_exact(&mut self.0, buffer)
188	}
189
190	#[cfg(feature = "alloc")]
191	fn read_until(&mut self, byte: u8, into: &mut Vec<u8>) -> Result<ReadUntilStopReason, Self::Error> {
192		self.0.read_until(byte, into)?;
193		if into.last().is_some_and(|x| x == &byte) {
194			/* BufRead::read_until reads the delimiter, we don't. */
195			into.pop();
196			Ok(ReadUntilStopReason::Delimiter)
197		} else {
198			Ok(ReadUntilStopReason::EndOfInput)
199		}
200	}
201
202	fn skip(&mut self, how_many: usize) -> Result<(), ChiselSourceError<Self::Error>> {
203		let mut remaining = how_many;
204		while remaining > 0 {
205			let max_consumable = self.0.fill_buf()?;
206			let to_consume = core::cmp::min(remaining, max_consumable.len());
207			self.0.consume(to_consume);
208			remaining -= to_consume;
209		}
210		Ok(())
211	}
212}