rsomeip_bytes/lib.rs
1//! [![GitHub][github-badge]][github-url]
2//! [![Crates.io][crates-io-badge]][crates-io-url]
3//! [![Docs.rs][docsrs-badge]][docsrs-url]
4//! ![license-badge]
5//!
6//! Serialization according to the SOME/IP on-wire format.
7//!
8//! This crate provides traits and types to assist in correctly implementing the serialization and
9//! deserialization of data according to the [Open SOME/IP Specification][open-someip-spec].
10//!
11//! # Getting started
12//!
13//! 1. Add `rsomeip-bytes` as a dependency to your project.
14//!
15//! ```toml
16//! # Cargo.toml
17//!
18//! [dependencies]
19//! rsomeip-bytes = "0.2.0"
20//! ```
21//!
22//! 2. Implement [`Serialize`] and [`Deserialize`] for your data types.
23//!
24//! ```rust
25//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
26//! use rsomeip_bytes::{
27//! Serialize, SerializeError, Deserialize, DeserializeError, bytes::{Buf, BufMut}
28//! };
29//!
30//! /// Example of a composite type that is used in a SOME/IP message payload.
31//! #[derive(Debug, PartialEq, Eq)]
32//! struct Foo {
33//! bar: u8,
34//! baz: u16,
35//! }
36//!
37//! impl Serialize for Foo {
38//! // This method is used to write the data to the buffer.
39//! fn serialize<Buffer>(&self, buffer: &mut Buffer) -> Result<usize, SerializeError>
40//! where
41//! Buffer: BufMut + ?Sized,
42//! {
43//! // Most basic types already implement `Serialize`.
44//! let mut size = 0;
45//! size += self.bar.serialize(buffer)?;
46//! size += self.baz.serialize(buffer)?;
47//! Ok(size)
48//! }
49//!
50//! // This method is used for calculating the value of length fields, for example.
51//! fn size(&self) -> Option<usize> {
52//! // It's important that this value matches the size returned by the `serialize` method.
53//! let mut size = 0;
54//! size += self.bar.size()?;
55//! size += self.baz.size()?;
56//! Some(size)
57//! }
58//! }
59//!
60//! impl Deserialize for Foo {
61//! type Output = Self;
62//!
63//! // This method is used to read data from the buffer.
64//! fn deserialize<Buffer>(buffer: &mut Buffer) -> Result<Self::Output, DeserializeError>
65//! where
66//! Buffer: Buf + ?Sized,
67//! {
68//! // Like before, most basic types also implement `Deserialize`.
69//! let value = Self {
70//! bar: u8::deserialize(buffer)?,
71//! baz: u16::deserialize(buffer)?,
72//! };
73//! Ok(value)
74//! }
75//!
76//! // This method is used as an estimate of the minimum amount of data required to deserialize
77//! // the output from the buffer.
78//! fn size_hint() -> Option<usize> {
79//! let mut size = 0;
80//! size += u8::size_hint()?;
81//! size += u16::size_hint()?;
82//! Some(size)
83//! }
84//! }
85//!
86//! // A buffer can be any type that implements `Buf` and `BufMut`.
87//! let mut buffer = [0u8; 3];
88//!
89//! // Use the `Serialize` trait to write data to the buffer.
90//! let value = Foo { bar: 0x01_u8, baz: 0x0203_u16 };
91//! assert_eq!(Some(3), value.size());
92//! assert_eq!(Ok(3), value.serialize(&mut buffer.as_mut_slice()));
93//!
94//! // By default, data is serialized in Big Endian byte order.
95//! assert_eq!(buffer, [0x01_u8, 0x02, 0x03]);
96//!
97//! // Use the `Deserialize` trait to read data from the buffer.
98//! assert_eq!(Some(3), Foo::size_hint());
99//! assert_eq!(Ok(value), Foo::deserialize(&mut buffer.as_slice()));
100//! # Ok(()) }
101//!
102//! # Usage
103//!
104//! The main goal with this crate is to have your types implement the [`Serialize`] and
105//! [`Deserialize`] traits so that the other `rsomeip` crates can abstract the serialization and
106//! deserialization process.
107//!
108//! To make this easier, this crate implements these traits for several types of the Rust standard
109//! library and provides some convenient wrappers for those that don't. This is enough to cover most
110//! use cases foreseen by the specification.
111//!
112//! ## Basic types
113//!
114//! All basic types defined in the specification implement [`Serialize`] and [`Deserialize`]. These
115//! include:
116//!
117//! - [`bool`]
118//! - [`u8`] and [`i8`]
119//! - [`u16`] and [`i16`]
120//! - [`u32`] and [`i32`]
121//! - [`u64`] and [`i64`]
122//! - [`f32`] and [`f64`]
123//!
124//! ### Endianess
125//!
126//! The [`Serialize::serialize`] and [`Deserialize::deserialize`] implementations for these types
127//! use Big Endian byte orders for writing and reading data. If another endianess is desired, then
128//! you must manually implement it yourself.
129//!
130//! ## Tuples
131//!
132//! There's a blanket implementation of both traits for any tuple whose types also implement
133//! [`Serialize`] and [`Deserialize`].
134//!
135//! This can be used as a convenient way to call these methods on a bunch of elements all at once.
136//!
137//! ```rust
138//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
139//! use rsomeip_bytes::{Serialize, Deserialize};
140//!
141//! let mut buffer = [0u8; 7];
142//!
143//! let value = (0x01_u8, 0x0203_u16, 0x0405_0607_u32);
144//! assert_eq!(Ok(7), value.serialize(&mut buffer.as_mut_slice()));
145//! assert_eq!(buffer, [0x01_u8, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
146//! assert_eq!(Ok(value), <(u8, u16, u32)>::deserialize(&mut buffer.as_slice()));
147//! # Ok(()) }
148//! ```
149//!
150//! ## Structs
151//!
152//! Structs required you to manually implement the [`Serialize`] and [`Deserialize`] traits as
153//! described in the [Getting started](#getting-started) section.
154//!
155//! ## Dynamic arrays
156//!
157//! This crate doesn't implement any traits for container types of the standard library. Instead, it
158//! provides the [`DynamicArray`] wrapper to serialize and deserialize any type that implements
159//! [`IntoIterator`] and [`FromIterator`], respectively.
160//!
161//! This [`DynamicArray`] type takes a [`Length`] as a generic parameter to encode the size of the
162//! array in a preceding length field.
163//!
164//! ```rust
165//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
166//! use rsomeip_bytes::{Serialize, Deserialize, LengthU32, DynamicArray};
167//!
168//! let mut buffer = [0u8; 7];
169//!
170//! let value = vec![1_u8, 2, 3];
171//! let array = DynamicArray::<LengthU32, _>::from(&value);
172//! assert_eq!(Ok(7), array.serialize(&mut buffer.as_mut_slice()));
173//! assert_eq!(buffer, [0x00_u8, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03]); // Length before the payload.
174//! assert_eq!(Ok(value), DynamicArray::<LengthU32, Vec<u8>>::deserialize(&mut buffer.as_slice()));
175//! # Ok(()) }
176//! ```
177//!
178//! ## Static arrays
179//!
180//! Static arrays use Rust's [`prim@array`] primitive since it translates directly into the SOME/IP
181//! notion of an array.
182//!
183//! Since their size is fixed, static arrays don't require a length field.
184//!
185//! ```rust
186//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
187//! use rsomeip_bytes::{Serialize, Deserialize};
188//!
189//! let mut buffer = [0u8; 4];
190//!
191//! let value = [1_u8, 2, 3, 4];
192//! assert_eq!(Ok(4), value.serialize(&mut buffer.as_mut_slice()));
193//! assert_eq!(buffer, [0x01_u8, 0x02, 0x03, 0x04]);
194//! assert_eq!(Ok(value), <[u8; 4]>::deserialize(&mut buffer.as_slice()));
195//! # Ok(()) }
196//! ```
197//!
198//! ## Dynamic strings
199//!
200//! Like for dynamic arrays, this crate provides the [`DynamicString`] wrapper for any type that
201//! implements [`AsRef<str>`] and [`From<String>`].
202//!
203//! Besides also accepting a [`Length`] parameter, this wrapper takes an [`Encoding`] parameter to
204//! specify the encoding of the serialized string.
205//!
206//! Available encodings include [`Utf8`], [`Utf16BE`], and [`Utf16LE`].
207//!
208//! ```rust
209//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
210//! use rsomeip_bytes::{Serialize, Deserialize, LengthU32, Utf8, DynamicString};
211//!
212//! let mut buffer = [0_u8; 15];
213//!
214//! let value = String::from("rsomeip");
215//! let string = DynamicString::<LengthU32, Utf8, _>::from(&value);
216//! assert_eq!(Ok(15), string.serialize(&mut buffer.as_mut_slice()));
217//! assert_eq!(
218//! buffer,
219//! [
220//! 0x00_u8, 0x00, 0x00, 0x0b, // Length
221//! 0xef, 0xbb, 0xbf, // UTF-8 BOM
222//! 0x72, 0x73, 0x6f, 0x6d, 0x65, 0x69, 0x70, // "rsomeip"
223//! 0x00, // Delimiter
224//! ]
225//! );
226//! assert_eq!(
227//! Ok(value),
228//! DynamicString::<LengthU32, Utf8, String>::deserialize(&mut buffer.as_slice())
229//! );
230//! # Ok(()) }
231//! ```
232//!
233//! ## Static strings
234//!
235//! These fill the same role as static arrays do for generic containers. The [`StaticString`]
236//! wrapper takes an [`Encoding`] parameter like the dynamic strings, but the [`Length`] parameter
237//! is dropped in favor of specifying a fixed size for the string.
238//!
239//! ```rust
240//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
241//! use rsomeip_bytes::{Serialize, Deserialize, Utf8, StaticString};
242//!
243//! let mut buffer = [0_u8; 15];
244//!
245//! let value = String::from("rsomeip");
246//! let string = StaticString::<15, Utf8, _>::from(&value);
247//! assert_eq!(Ok(15), string.serialize(&mut buffer.as_mut_slice()));
248//! assert_eq!(
249//! buffer,
250//! [
251//! 0xef_u8, 0xbb, 0xbf, // UTF-8 BOM
252//! 0x72, 0x73, 0x6f, 0x6d, 0x65, 0x69, 0x70, // "rsomeip"
253//! 0x00, // Delimiter
254//! 0x00, 0x00, 0x00, 0x00, // Padding
255//! ]
256//! );
257//! assert_eq!(
258//! Ok(value),
259//! StaticString::<15, Utf8, String>::deserialize(&mut buffer.as_slice())
260//! );
261//! # Ok(()) }
262//! ```
263//!
264//! ## Enums and unions
265//!
266//! These need to be manually implemented by you.
267//!
268//! # License
269//!
270//! This project is licensed under either the [Apache-2.0 License] or [MIT License],
271//! at your option.
272//!
273//! [Apache-2.0 License]: http://www.apache.org/licenses/LICENSE-2.0
274//! [crates-io-badge]: https://img.shields.io/crates/v/rsomeip_bytes
275//! [crates-io-url]: https://crates.io/crates/rsomeip-bytes
276//! [docsrs-badge]: https://img.shields.io/docsrs/rsomeip-bytes
277//! [docsrs-url]: https://docs.rs/rsomeip-bytes/latest/rsomeip_bytes/
278//! [github-badge]: https://img.shields.io/badge/GitHub-rsomeip-blue
279//! [github-url]: https://github.com/brunoldsilva/rsomeip
280//! [license-badge]: https://img.shields.io/crates/l/rsomeip_bytes
281//! [MIT License]: http://opensource.org/licenses/MIT
282//! [open-someip-spec]: https://some-ip.com/standards.shtml
283
284#![cfg_attr(not(feature = "std"), no_std)]
285#![warn(clippy::std_instead_of_core, clippy::std_instead_of_alloc)]
286
287extern crate alloc;
288extern crate core;
289
290// Re-export for convenience.
291pub use bytes::{self, Buf, BufMut, Bytes, BytesMut};
292
293mod array;
294pub use array::DynamicArray;
295
296mod de;
297pub use de::{Deserialize, DeserializeError};
298
299mod length;
300pub use length::{
301 DeserializeWithLength, Length, LengthU8, LengthU16, LengthU32, LengthZero, SerializeWithLength,
302};
303
304mod ser;
305pub use ser::{Serialize, SerializeError, SerializeWithFn};
306
307mod string;
308pub use string::{DynamicString, Encoding, StaticString, Utf8, Utf16BE, Utf16LE};
309
310#[cfg(doc)]
311#[doc(hidden)]
312#[doc = include_str!("../README.md")]
313struct ReadMeCheck;