9 releases
0.1.0-rc.4 | Nov 8, 2023 |
---|---|
0.1.0-rc.2 | Aug 22, 2023 |
0.1.0-rc.0 | Jun 13, 2023 |
0.1.0-alpha.7 | May 18, 2023 |
0.1.0-alpha.2 | Sep 9, 2022 |
#2235 in Rust patterns
61 downloads per month
Used in 2 crates
(via flatty)
59KB
1.5K
SLoC
flatty
Flat message buffers with direct mapping to Rust types without packing/unpacking.
Overview
Type called flat when it occupies a single contiguous memory area. Such types is useful when you need to store or send such object as a binary data while having convenient way to access its contents without serializing/deserializing.
This crate provides basic flat types and the way to create new user-defined composite flat types (using #[flat]
attribute macro), which can be used almost like regular Rust struct
s or enum
s.
Also the crate can be used without std
and even alloc
.
Concepts
Conversion
Binary representation can be obtained from instances of flat type using as_bytes
(and unsafe as_mut_bytes
). Also bytes can be converted to flat types, see in-place initialization and validation.
DST
Flat type can be dynamically sized (like FlatVec
), in that case it exploits Rust's ability to operate ?Sized
types. User-defined flat struct can also be unsized (only last field is allowed to be unsized). Even flat enum can be unsized, but Rust doesn't natively support them yet so its contents could be accessed only via as_ref
/as_mut
methods returning a regular enum containing references to original enum contents.
In-place initialization
Sized types can be instantiated as usual Rust type. But in case of DST Rust cannot construct it in usual manner on stack because its size isn't known at compile time. Instead we may initialize such types onto given memory area.
To do this we can use so-called emplacer - something that can initialize object onto given memory. For sized types its instance is also emplacer.
Emplacer could be applied to raw bytes using new_in_place
or replace existing struct contents using assign_in_place
. Also some types has default emplacer and could be initialized in default state by default_in_place
.
Validation
Not any combination of bytes are valid representation of flat type. For example, Bool
has only two valid states: 0
and 1
, or FlatVec
length must not be greater than its capacity. validate
can be used to check that data is valid for specific flat type, or from_bytes
/from_mut_bytes
also perform such check.
When you trust your data, then you can omit validation using unsafe from_bytes_unchecked
/from_mut_bytes_unchecked
, but this will cause an UB if data is invalid.
Portability
Flat type guarantee that it has the same binary representation on the platforms with same byte order, alignment and address width. If you need stronger guarantees you may use Portable
types - they have the same binary representation on any platform and always aligned to byte. To make own flat type portable use #[flat(portable = true)]
. Also this can be used to created packed flat types without alignment issues.
Examples
You can find some examples on how to create and use flat types in tests
directory.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Dependencies
~185KB