nuts_bytes/take_bytes.rs
1// MIT License
2//
3// Copyright (c) 2023 Robin Doer
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to
7// deal in the Software without restriction, including without limitation the
8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9// sell copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21// IN THE SOFTWARE.
22
23#[cfg(test)]
24mod tests;
25
26use thiserror::Error;
27
28/// Error type for the [`TakeBytes`] trait.
29#[derive(Debug, Error, PartialEq)]
30pub enum TakeBytesError {
31 /// Failed to read the requested number of bytes. No more bytes are
32 /// available for reading.
33 #[error("no more bytes are available for reading")]
34 Eof,
35}
36
37/// Trait that describes a reader of binary data.
38///
39/// The [`Reader`](crate::Reader) utility accepts all types that implements
40/// this trait.
41pub trait TakeBytes {
42 /// Reads some bytes from the source and puts them into the given buffer
43 /// `buf`.
44 ///
45 /// # Errors
46 ///
47 /// If not enough data are available to fill `buf` the implementator should
48 /// return a [`TakeBytesError::Eof`] error.
49 fn take_bytes(&mut self, buf: &mut [u8]) -> Result<(), TakeBytesError>;
50}
51
52/// `TakeBytes` is implemented for `&[u8]` by taking the first part of the
53/// slice.
54///
55/// Note that taking bytes updates the slice to point to the yet unread part.
56/// The slice will be empty when EOF is reached.
57impl TakeBytes for &[u8] {
58 fn take_bytes(&mut self, buf: &mut [u8]) -> Result<(), TakeBytesError> {
59 if buf.len() <= self.len() {
60 let (a, b) = self.split_at(buf.len());
61
62 *self = b;
63 buf.copy_from_slice(a);
64
65 Ok(())
66 } else {
67 Err(TakeBytesError::Eof)
68 }
69 }
70}