nuts_bytes/
to_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 crate::error::Error;
27use crate::put_bytes::PutBytes;
28
29/// Trait that supports writing datatypes into a binary data stream.
30///
31/// Datatypes that implements this trait can be serialized into a binary data
32/// stream.
33pub trait ToBytes {
34    /// Writes data into the given `target`.
35    ///
36    /// Serializes this instance into its binary representation and writes the
37    /// binary data into `target`. Returns the number of bytes actually
38    /// serialized.
39    fn to_bytes<PB: PutBytes>(&self, target: &mut PB) -> Result<usize, Error>;
40}
41
42impl ToBytes for bool {
43    fn to_bytes<PB: PutBytes>(&self, target: &mut PB) -> Result<usize, Error> {
44        let val = if *self { 1u8 } else { 0u8 };
45
46        ToBytes::to_bytes(&val, target)
47    }
48}
49
50macro_rules! impl_to_bytes_for_primitive {
51    ($type:ty) => {
52        impl ToBytes for $type {
53            fn to_bytes<PB: PutBytes>(&self, target: &mut PB) -> Result<usize, Error> {
54                let n = target
55                    .put_bytes(&self.to_be_bytes())
56                    .map(|()| std::mem::size_of::<$type>())?;
57                Ok(n)
58            }
59        }
60    };
61}
62
63impl_to_bytes_for_primitive!(i8);
64impl_to_bytes_for_primitive!(i16);
65impl_to_bytes_for_primitive!(i32);
66impl_to_bytes_for_primitive!(i64);
67impl_to_bytes_for_primitive!(u8);
68impl_to_bytes_for_primitive!(u16);
69impl_to_bytes_for_primitive!(u32);
70impl_to_bytes_for_primitive!(u64);
71impl_to_bytes_for_primitive!(f32);
72impl_to_bytes_for_primitive!(f64);
73
74impl ToBytes for usize {
75    fn to_bytes<PB: PutBytes>(&self, target: &mut PB) -> Result<usize, Error> {
76        ToBytes::to_bytes(&(*self as u64), target)
77    }
78}
79
80impl ToBytes for char {
81    fn to_bytes<PB: PutBytes>(&self, target: &mut PB) -> Result<usize, Error> {
82        ToBytes::to_bytes(&(*self as u32), target)
83    }
84}
85
86impl<TB: ToBytes, const COUNT: usize> ToBytes for [TB; COUNT] {
87    fn to_bytes<PB: PutBytes>(&self, target: &mut PB) -> Result<usize, Error> {
88        let mut n = 0;
89
90        for b in self.iter().take(COUNT) {
91            n += ToBytes::to_bytes(b, target)?;
92        }
93
94        Ok(n)
95    }
96}
97
98impl<TB: ToBytes> ToBytes for &[TB] {
99    fn to_bytes<PB: PutBytes>(&self, target: &mut PB) -> Result<usize, Error> {
100        let mut n = self.len().to_bytes(target)?;
101
102        for i in 0..self.len() {
103            n += self[i].to_bytes(target)?;
104        }
105
106        Ok(n)
107    }
108}
109
110impl<TB: ToBytes> ToBytes for Vec<TB> {
111    fn to_bytes<PB: PutBytes>(&self, target: &mut PB) -> Result<usize, Error> {
112        ToBytes::to_bytes(&self.as_slice(), target)
113    }
114}
115
116impl ToBytes for String {
117    fn to_bytes<PB: PutBytes>(&self, target: &mut PB) -> Result<usize, Error> {
118        ToBytes::to_bytes(&self.as_str(), target)
119    }
120}
121
122impl ToBytes for &str {
123    fn to_bytes<PB: PutBytes>(&self, target: &mut PB) -> Result<usize, Error> {
124        self.as_bytes().to_bytes(target)
125    }
126}
127
128impl<T: ToBytes> ToBytes for Option<T> {
129    fn to_bytes<PB: PutBytes>(&self, target: &mut PB) -> Result<usize, Error> {
130        match self {
131            Some(val) => Ok(ToBytes::to_bytes(&1u8, target)? + ToBytes::to_bytes(val, target)?),
132            None => ToBytes::to_bytes(&0u8, target),
133        }
134    }
135}
136
137impl ToBytes for () {
138    fn to_bytes<PB: PutBytes>(&self, _target: &mut PB) -> Result<usize, Error> {
139        Ok(0)
140    }
141}