le_stream/lib.rs
1//! Little-endian byte stream encoding and decoding.
2//!
3//! `le-stream` defines compact [`ToLeStream`] and [`FromLeStream`] traits for
4//! types that are represented as a sequence of little-endian bytes. The traits
5//! work directly on iterators, which keeps the crate usable in `no_std`
6//! environments and avoids requiring an intermediate buffer.
7//!
8//! Primitive integer and floating-point types are encoded with their native
9//! `to_le_bytes` representation. Arrays, ranges, options, and feature-gated
10//! collection types are encoded by concatenating the representation of their
11//! contents. `Option<T>` is intentionally compact: `None` emits no bytes and
12//! `Some(value)` emits only `value`.
13//!
14//! # Collection Semantics
15//!
16//! Standard-library collection types behind the `alloc` feature are not
17//! length-prefixed by default. `Vec<T>` and `Box<[T]>` deserialize by consuming
18//! as many complete `T` values as the byte stream can provide. Use
19//! [`Prefixed<P, D>`] when an allocated collection needs an explicit length in
20//! the stream.
21//!
22//! `bytes::Bytes` and `bytes::BytesMut` behind the `bytes` feature are raw byte
23//! buffers. They serialize as their contained bytes and deserialize by
24//! consuming the remaining byte stream, without a length prefix. Wrapped in
25//! [`Prefixed<P, D>`], they serialize a byte count of type `P` followed by
26//! exactly that many raw bytes.
27//!
28//! `heapless::Vec<T, N, LenT>` and `heapless::String<N, LenT>` are different:
29//! they always encode a length prefix of type `LenT`, followed by exactly that
30//! many serialized elements or UTF-8 bytes. During deserialization the prefix is
31//! read first, and the implementation then attempts to consume exactly the
32//! number of elements or bytes described by that prefix. This works naturally
33//! for `heapless` collections because their type carries a fixed capacity limit.
34//!
35//! The `derive` feature re-exports derive macros for structs and explicitly
36//! represented enums. Derived enums require `#[repr(T)]` and explicit
37//! discriminants on every variant; the discriminant is encoded as `T`, followed
38//! by any associated data.
39//!
40//! # Examples
41//!
42//! ```
43//! use le_stream::{FromLeStream, ToLeStream};
44//!
45//! let value = 0x1234_u16;
46//! assert_eq!(value.to_le_stream().collect::<Vec<_>>(), [0x34, 0x12]);
47//! assert_eq!(u16::from_le_stream([0x34, 0x12].into_iter()), Some(value));
48//! ```
49//!
50//! With the `derive` feature enabled:
51//!
52//! ```
53//! # #[cfg(feature = "derive")]
54//! # {
55//! use le_stream::{FromLeStream, ToLeStream};
56//!
57//! #[derive(Clone, Debug, Eq, PartialEq, FromLeStream, ToLeStream)]
58//! struct Header {
59//! command: u8,
60//! sequence: u16,
61//! }
62//!
63//! let header = Header {
64//! command: 0xA5,
65//! sequence: 0x1234,
66//! };
67//!
68//! let bytes: Vec<_> = header.clone().to_le_stream().collect();
69//! assert_eq!(bytes, [0xA5, 0x34, 0x12]);
70//! assert_eq!(Header::from_le_stream_exact(bytes.into_iter()).unwrap(), header);
71//! # }
72//! ```
73
74#![no_std]
75
76pub use consume::Consume;
77pub use error::{Error, Result};
78pub use from_le_stream::FromLeStream;
79pub use prefixed::Prefixed;
80pub use stream::{LeStream, LeStreamIterator};
81pub use to_le_stream::ToLeStream;
82pub use try_from_le_stream::TryFromLeStream;
83
84mod consume;
85mod error;
86mod from_le_stream;
87mod prefixed;
88mod stream;
89mod to_le_stream;
90mod try_from_le_stream;
91
92#[cfg(feature = "derive")]
93pub use le_stream_derive::{FromLeStream, ToLeStream};