Module :: asbytes
The asbytes
crate provides two convenient traits:
AsBytes
: For viewing common data structures as raw byte slices (&[u8]
).IntoBytes
: For consuming data structures into owned byte vectors (Vec<u8>
).
Both traits focus on types that are safe to represent as bytes (Plain Old Data, or POD), leveraging the safety guarantees of the underlying bytemuck
crate.
Why asbytes
?
While bytemuck
provides the core functionality for safe byte-level casting (like bytemuck::cast_slice
for collections and bytemuck::bytes_of
for single items), asbytes
offers a unified trait-based approach for common use cases:
- Consistency: The
AsBytes
trait provides.as_bytes()
for borrowing as&[u8]
, whileIntoBytes
provides.into_bytes()
for consuming intoVec<u8>
. This works consistently across supported types. - Readability: Calling
.as_bytes()
or.into_bytes()
clearly signals the intent to get a raw byte representation, useful for serialization, hashing, or low-level APIs (graphics, networking, etc.). - Simpler Generics: Functions can accept
T: AsBytes
orT: IntoBytes
to work generically with the byte representation of different compatible data structures. - Convenience:
AsBytes
also provides.byte_size()
and.len()
methods for easily getting the size in bytes and the number of elements.
Essentially, asbytes
acts as a focused convenience layer on top of bytemuck
for the specific tasks of viewing or consuming data as bytes via consistent trait methods.
How asbytes Differs from bytemuck
While bytemuck
offers safe transmutation via its Pod
trait and functions like cast_slice
, it does not expose dedicated traits for converting data structures into byte slices or vectors. asbytes
introduces AsBytes
(for borrowing as &[u8]
) and IntoBytes
(for consuming into Vec<u8>
), abstracting these conversions and providing additional conveniences—such as direct byte size computation with AsBytes
—on top of bytemuck
's proven foundation.
Examples
AsBytes
Example: Viewing Data as Byte Slices
This example demonstrates the AsBytes
trait. It shows how to get a &[u8]
view of various data types (a Vec
, a slice, an array, a single struct wrapped in a tuple, and a scalar wrapped in a tuple) without consuming the original data. This is useful for operations like inspecting byte patterns, hashing data without modification, or passing byte slices to functions that only need read access. The .byte_size()
and .len()
methods provide convenient ways to get the size in bytes and the number of elements, respectively.
// Make sure asbytes is available for derives
// asbytes = { version = "0.2", features = [ "derive" ] }
use AsBytes; // Import the trait
// Define a POD struct
IntoBytes
Example: Consuming Data into Owned Byte Vectors for Hashing
This example showcases the IntoBytes trait, demonstrating how it facilitates writing different data types to an I/O stream (simulated here by a Vec). The generic send_data function accepts any type T that implements IntoBytes. Inside the function, data.into_bytes() consumes the input data and returns an owned Vec. This owned vector is necessary when the receiving function or operation (like writer.write_all) requires ownership or when the data needs to live beyond the current scope (e.g., in asynchronous operations). The example sends a POD struct (with explicit padding for Pod safety), a String, a Vec, and an array, showing how IntoBytes provides a uniform way to prepare diverse data for serialization or transmission. Note that types like String and Vec are moved and consumed, while Copy types are technically moved but the original variable remains usable due to the copy.
// Add dependencies to Cargo.toml:
// asbytes = { version = "0.2", features = [ "derive" ] }
use IntoBytes;
use Write; // Using std::io::Write as a simulated target
// Define a POD struct
// Added explicit padding to ensure no implicit padding bytes, satisfying `Pod` requirements.
// Total size = 16 bytes (128 bits)
/// Simulates writing any data that implements IntoBytes to a writer (e.g., file, network stream).
/// This function consumes the input data.
/// It takes a mutable reference to a writer `W` which could be Vec<u8>, a File, TcpStream, etc.
To add to your project
# Make sure bytemuck is also added if you need POD derives or its features
# cargo add bytemuck --features derive
Try out from the repository
# Run the AsBytes example (replace with actual example path if different)
# cargo run --example asbytes_as_bytes_trivial
# Or run the IntoBytes example (requires adding sha2 to the example's deps)
# cargo run --example asbytes_into_bytes_trivial