Skip to main content

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//! `heapless::Vec<T, N, LenT>` and `heapless::String<N, LenT>` are different:
23//! they always encode a length prefix of type `LenT`, followed by exactly that
24//! many serialized elements or UTF-8 bytes. During deserialization the prefix is
25//! read first, and the implementation then attempts to consume exactly the
26//! number of elements or bytes described by that prefix. This works naturally
27//! for `heapless` collections because their type carries a fixed capacity limit.
28//!
29//! The `derive` feature re-exports derive macros for structs and explicitly
30//! represented enums. Derived enums require `#[repr(T)]` and explicit
31//! discriminants on every variant; the discriminant is encoded as `T`, followed
32//! by any associated data.
33//!
34//! # Examples
35//!
36//! ```
37//! use le_stream::{FromLeStream, ToLeStream};
38//!
39//! let value = 0x1234_u16;
40//! assert_eq!(value.to_le_stream().collect::<Vec<_>>(), [0x34, 0x12]);
41//! assert_eq!(u16::from_le_stream([0x34, 0x12].into_iter()), Some(value));
42//! ```
43//!
44//! With the `derive` feature enabled:
45//!
46//! ```
47//! # #[cfg(feature = "derive")]
48//! # {
49//! use le_stream::{FromLeStream, ToLeStream};
50//!
51//! #[derive(Clone, Debug, Eq, PartialEq, FromLeStream, ToLeStream)]
52//! struct Header {
53//!     command: u8,
54//!     sequence: u16,
55//! }
56//!
57//! let header = Header {
58//!     command: 0xA5,
59//!     sequence: 0x1234,
60//! };
61//!
62//! let bytes: Vec<_> = header.clone().to_le_stream().collect();
63//! assert_eq!(bytes, [0xA5, 0x34, 0x12]);
64//! assert_eq!(Header::from_le_stream_exact(bytes.into_iter()).unwrap(), header);
65//! # }
66//! ```
67
68#![no_std]
69
70pub use consume::Consume;
71pub use error::{Error, Result};
72pub use from_le_stream::FromLeStream;
73pub use prefixed::Prefixed;
74pub use stream::{LeStream, LeStreamIterator};
75pub use to_le_stream::ToLeStream;
76pub use try_from_le_stream::TryFromLeStream;
77
78mod consume;
79mod error;
80mod from_le_stream;
81mod prefixed;
82mod stream;
83mod to_le_stream;
84mod try_from_le_stream;
85
86#[cfg(feature = "derive")]
87pub use le_stream_derive::{FromLeStream, ToLeStream};