rust_lcm_codec/
lib.rs

1//! Runtime support for LCM serialization and deserialization in Rust
2#![no_std]
3#![deny(warnings)]
4#![deny(missing_docs)]
5mod error;
6pub use error::*;
7
8/// Reader backend trait
9pub trait StreamingReader {
10    /// The kind of Error the implementation produces
11    type Error;
12    /// Read bytes from the underlying data source into the provided `buf`.
13    /// Should return an error if insufficient bytes are available to
14    /// fully fill `buf`.
15    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), Self::Error>;
16
17    /// Expose an aliased view of a subset of the underlying data as
18    /// immutable bytes.
19    ///
20    /// The implementer must ensure that the view of bytes returned
21    /// does not overlap with the region of bytes that it allows itself
22    /// to mutate at any further point.
23    fn share_bytes(&mut self, len: usize) -> Result<&[u8], Self::Error>;
24}
25
26/// The BufferReader had a problem. The only problem worth mentioning
27/// is that it did not have enough bytes to complete a requested
28/// operations.
29#[derive(Debug)]
30pub struct BufferReaderError;
31
32/// StreamingReader backend for a byte slice
33pub struct BufferReader<'a> {
34    buffer: &'a [u8],
35    cursor: usize,
36}
37
38impl<'a> BufferReader<'a> {
39    /// Make a new BufferReader around a byte slice
40    #[inline]
41    pub fn new(buffer: &'a [u8]) -> BufferReader<'a> {
42        BufferReader { buffer, cursor: 0 }
43    }
44
45    /// How many bytes have been read thus far
46    #[inline]
47    pub fn cursor(&self) -> usize {
48        self.cursor
49    }
50}
51
52impl<'a> From<&'a [u8]> for BufferReader<'a> {
53    #[inline]
54    fn from(buffer: &'a [u8]) -> Self {
55        BufferReader::new(buffer)
56    }
57}
58
59impl<'a> StreamingReader for BufferReader<'a> {
60    type Error = BufferReaderError;
61
62    #[inline]
63    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
64        let len = buf.len();
65        let end = self.cursor + len;
66        if end <= self.buffer.len() {
67            buf.copy_from_slice(&self.buffer[self.cursor..end]);
68            self.cursor += len;
69            Ok(())
70        } else {
71            Err(BufferReaderError)
72        }
73    }
74
75    #[inline]
76    fn share_bytes(&mut self, len: usize) -> Result<&[u8], Self::Error> {
77        let end = self.cursor + len;
78        if end <= self.buffer.len() {
79            // This is unsafe because we are providing a shared immutable reference
80            // to a part of a slice we currently holding a mutable (read: unshareable, solitary)
81            // reference to via the lifetime from `&mut self`.
82            //
83            // We know that this type will not in fact be able to mutate the byte slice underneath
84            // that shared immutable reference because the BufferReader operates solely in a forward
85            // fashion and the cursor is moved past the immutable region. It helps that we also
86            // never mutate the underlying buffer anyhow.
87            let s =
88                unsafe { core::slice::from_raw_parts(self.buffer.as_ptr().add(self.cursor), len) };
89            self.cursor += len;
90            Ok(s)
91        } else {
92            Err(BufferReaderError)
93        }
94    }
95}
96
97/// Writer backend trait
98pub trait StreamingWriter {
99    /// The kind of errors that the implementation emits during encoding
100    type Error;
101    /// Write all of the bytes from the provided buffer into the underlying
102    /// encoding stream.
103    ///
104    /// Ought to produce an error if not all of the bytes could be written.
105    ///
106    /// N.B. for possible enhancement: We could return size written here
107    /// rather than leaving that tracking and manner of exposure
108    /// to the implementing type.
109    fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), Self::Error>;
110
111    /// Expose an aliased view of a subset of the underlying data as
112    /// mutable bytes.
113    ///
114    /// The implementer must ensure that the view of bytes returned
115    /// does not overlap with the region of bytes that the StreamingWriter
116    /// allows itself to mutate at any further point.
117    fn share_bytes_mut(
118        &mut self,
119        len: usize,
120    ) -> Result<&mut [core::mem::MaybeUninit<u8>], Self::Error>;
121
122    /// Ensure that all bytes are fully written in a maximally durable fashion.
123    fn flush() -> Result<(), Self::Error>;
124}
125
126/// The BufferWriter had a problem. The only problem worth mentioning
127/// is that it did not have enough bytes to complete a requested
128/// operations.
129#[derive(Debug, PartialEq, Eq, Copy, Clone)]
130pub struct BufferWriterError;
131
132/// Writer backend for a byte slice
133pub struct BufferWriter<'a> {
134    buffer: &'a mut [u8],
135    cursor: usize,
136}
137
138impl<'a> BufferWriter<'a> {
139    /// Create a new BufferWriter
140    #[inline]
141    pub fn new(buffer: &'a mut [u8]) -> BufferWriter<'a> {
142        BufferWriter { buffer, cursor: 0 }
143    }
144
145    /// How many bytes have been written thus far
146    #[inline]
147    pub fn cursor(&self) -> usize {
148        self.cursor
149    }
150}
151
152impl<'a> StreamingWriter for BufferWriter<'a> {
153    type Error = BufferWriterError;
154
155    #[inline]
156    fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
157        let len = bytes.len();
158        let end = self.cursor + len;
159        if end <= self.buffer.len() {
160            self.buffer[self.cursor..end].copy_from_slice(bytes);
161            self.cursor += len;
162            Ok(())
163        } else {
164            Err(BufferWriterError)
165        }
166    }
167    #[inline]
168    fn share_bytes_mut(
169        &mut self,
170        len: usize,
171    ) -> Result<&mut [core::mem::MaybeUninit<u8>], Self::Error> {
172        let end = self.cursor + len;
173        if end <= self.buffer.len() {
174            // This is unsafe because we are returning a mutable reference
175            // to a part of a slice we currently holding a (read: unshareable, solitary)
176            // reference to via the lifetime from `&mut self`.
177            //
178            // We know that this type will not in fact be able to mutate the byte slice underneath
179            // that returned region because the BufferWriter operates solely in a forward
180            // fashion and the cursor is moved past the returned region.
181            let s = unsafe {
182                &mut *(core::slice::from_raw_parts_mut(
183                    self.buffer.as_mut_ptr().add(self.cursor),
184                    len,
185                ) as *mut [u8] as *mut [core::mem::MaybeUninit<u8>])
186            };
187            self.cursor += len;
188            Ok(s)
189        } else {
190            Err(BufferWriterError)
191        }
192    }
193
194    #[inline]
195    fn flush() -> Result<(), Self::Error> {
196        Ok(())
197    }
198}
199
200/// Value serialization helper trait, oriented towards primitives.
201pub trait SerializeValue: Sized {
202    /// Use a StreamingReader to produce an instance of the implementing type
203    /// from an encoded stream of LCM data
204    fn read_value<R: StreamingReader>(reader: &mut R) -> Result<Self, DecodeValueError<R::Error>>;
205    /// Use a StreamingWriter to write an instance of the implementing type
206    /// to an encoded stream of LCM data
207    fn write_value<W: StreamingWriter>(val: Self, writer: &mut W) -> Result<(), W::Error>;
208}
209
210macro_rules! primitive_serialize_impl {
211    ($ty:ty) => {
212        impl SerializeValue for $ty {
213            #[inline]
214            fn read_value<R: StreamingReader>(
215                reader: &mut R,
216            ) -> Result<Self, DecodeValueError<R::Error>> {
217                let mut bytes = Self::default().to_ne_bytes();
218                reader.read_bytes(&mut bytes)?;
219                Ok(Self::from_be_bytes(bytes))
220            }
221
222            #[inline]
223            fn write_value<W: StreamingWriter>(val: Self, writer: &mut W) -> Result<(), W::Error> {
224                writer.write_bytes(&val.to_be_bytes())
225            }
226        }
227    };
228}
229
230primitive_serialize_impl!(i8);
231primitive_serialize_impl!(i16);
232primitive_serialize_impl!(i32);
233primitive_serialize_impl!(i64);
234primitive_serialize_impl!(f32);
235primitive_serialize_impl!(f64);
236primitive_serialize_impl!(u8);
237
238/// Write a string to a StreamingWriter using LCM's convention of encoding strings.
239#[inline]
240pub fn write_str_value<W: StreamingWriter>(string: &str, writer: &mut W) -> Result<(), W::Error> {
241    writer.write_bytes(&(&(string.len() as i32 + 1)).to_be_bytes())?;
242    writer.write_bytes(&string.as_bytes())?;
243    writer.write_bytes(&[0])
244}
245
246/// Read a view of a string from a StreamingReader using LCM's convention of encoding strings.
247#[inline]
248pub fn read_str_value<R: StreamingReader>(
249    reader: &mut R,
250) -> Result<&str, DecodeValueError<<R as StreamingReader>::Error>> {
251    let len: i32 = i32::read_value(reader)?;
252    if len < 0 {
253        return Err(DecodeValueError::InvalidValue("str length was less than 0"));
254    }
255    let len = len as usize;
256    // Read the bytes, including the null terminator
257    let bytes = reader.share_bytes(len)?;
258    let s = match core::str::from_utf8(&bytes[..len - 1]) {
259        Ok(s) => s,
260        Err(_) => return Err(DecodeValueError::InvalidValue("str was not valid UTF8")),
261    };
262    Ok(s)
263}
264
265impl SerializeValue for bool {
266    #[inline]
267    fn read_value<R: StreamingReader>(
268        reader: &mut R,
269    ) -> Result<Self, DecodeValueError<<R as StreamingReader>::Error>> {
270        let mut buffer = [0u8; 1];
271        reader.read_bytes(&mut buffer)?;
272        match buffer[0] {
273            0 => Ok(false),
274            1 => Ok(true),
275            _ => Err(DecodeValueError::InvalidValue("invalid bool value")),
276        }
277    }
278
279    #[inline]
280    fn write_value<W: StreamingWriter>(val: Self, writer: &mut W) -> Result<(), W::Error> {
281        SerializeValue::write_value(if val { 1i8 } else { 0i8 }, writer)
282    }
283}