nuts_bytes/
from_bytes.rs

1// MIT License
2//
3// Copyright (c) 2023,2024 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 std::convert::TryInto;
27use std::mem;
28
29use crate::error::Error;
30use crate::take_bytes::TakeBytes;
31
32/// Trait that supports reading datatypes from a binary data stream.
33///
34/// Datatypes that implements this trait can be read from a binary data stream.
35pub trait FromBytes
36where
37    Self: Sized,
38{
39    /// Reads data from the given `source`.
40    ///
41    /// Reads as much as necessary from `source`. The method deserializes the
42    /// instance and returns it.
43    ///
44    /// # Errors
45    ///
46    /// If not enough data are available in `source`, the
47    /// [`TakeBytes::take_bytes()`] call returns a
48    /// [`TakeBytesError::Eof`](crate::take_bytes::TakeBytesError::Eof)
49    /// error, which should be simply forwarded.
50    fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error>;
51}
52
53impl FromBytes for bool {
54    fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
55        let val: u8 = FromBytes::from_bytes(source)?;
56
57        Ok(val != 0)
58    }
59}
60
61macro_rules! impl_from_bytes_for_primitive {
62    ($type:ty) => {
63        impl FromBytes for $type {
64            fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
65                let mut buf = [0; mem::size_of::<$type>()];
66
67                source.take_bytes(&mut buf)?;
68
69                Ok(<$type>::from_be_bytes(buf))
70            }
71        }
72    };
73}
74
75impl_from_bytes_for_primitive!(i8);
76impl_from_bytes_for_primitive!(i16);
77impl_from_bytes_for_primitive!(i32);
78impl_from_bytes_for_primitive!(i64);
79impl_from_bytes_for_primitive!(u8);
80impl_from_bytes_for_primitive!(u16);
81impl_from_bytes_for_primitive!(u32);
82impl_from_bytes_for_primitive!(u64);
83impl_from_bytes_for_primitive!(f32);
84impl_from_bytes_for_primitive!(f64);
85
86impl FromBytes for usize {
87    fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
88        let mut buf = [0; mem::size_of::<u64>()];
89
90        source.take_bytes(&mut buf)?;
91
92        Ok(u64::from_be_bytes(buf) as usize)
93    }
94}
95
96impl FromBytes for char {
97    fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
98        let n: u32 = FromBytes::from_bytes(source)?;
99
100        char::from_u32(n).ok_or_else(|| Error::InvalidChar(n))
101    }
102}
103
104impl<FB: FromBytes, const COUNT: usize> FromBytes for [FB; COUNT] {
105    fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
106        let mut vec = vec![];
107
108        for _i in 0..COUNT {
109            vec.push(FromBytes::from_bytes(source)?);
110        }
111
112        Ok(vec
113            .try_into()
114            .unwrap_or_else(|_| panic!("should never be reached")))
115    }
116}
117
118impl<FB: FromBytes> FromBytes for Vec<FB> {
119    fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
120        let len = usize::from_bytes(source)?;
121        let mut vec = Vec::with_capacity(len);
122
123        for _ in 0..len {
124            vec.push(FromBytes::from_bytes(source)?);
125        }
126
127        Ok(vec)
128    }
129}
130
131impl FromBytes for String {
132    fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
133        let len = usize::from_bytes(source)?;
134
135        let mut vec = vec![0; len];
136        source.take_bytes(&mut vec)?;
137
138        String::from_utf8(vec).map_err(Error::InvalidString)
139    }
140}
141
142impl<T: FromBytes> FromBytes for Option<T> {
143    fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
144        let n: u8 = FromBytes::from_bytes(source)?;
145
146        if n == 0 {
147            Ok(None)
148        } else {
149            Ok(Some(FromBytes::from_bytes(source)?))
150        }
151    }
152}
153
154impl FromBytes for () {
155    fn from_bytes<TB: TakeBytes>(_source: &mut TB) -> Result<Self, Error> {
156        Ok(())
157    }
158}