Open-source project
Lokathor/bytemuck avatar
Lokathor/bytemuck

bytemuck: bit casts in Rust, and the slice case that made it popular

A crate for mucking around with piles of bytes

1,070 stars116 forksRustApache-2.0

At a glance

What is it?
bytemuck is a Rust crate for safely reinterpreting the bits of a value as another type, with a slice API that turns a typed slice into a byte slice for a GPU upload. It suits graphics and FFI code where the copy has to be zero, and it is a 1.x crate that pins an old minimum Rust version for its default build.
Who is it for?
bytemuck fits Rust code that has to move typed data into an untyped buffer, above all graphics code uploading vertices or colours to a GPU, because it makes the reinterpretation a checked operation rather than an unsafe transmute and it adds the NoUninit marker that proves the bytes are initialised.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 42 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What a bit cast is, and what it is not

bytemuck is a crate for mucking around with piles of bytes, and more precisely it lets you safely perform bit cast operations between data types, taking a value and reinterpreting the bits as being some other type of value, without changing the bits.

The documentation is careful about what that is not, and the three comparisons are the clearest way to understand the operation.

It is not like the `as` keyword, because `as` is a numeric conversion that can change the value, and a bit cast never does. It is not like the `From` trait, which is a semantic conversion where a value of one type is meaningfully transformed into another. And it is most like `f32::to_bits`, just generalized to let you convert between all sorts of data types.

That last one is the right mental model. `f32::to_bits` takes a float and gives you the `u32` with the same bits, and bytemuck generalises that to a whole family of conversions, in both directions and in both the value and slice cases.

So a bit cast is a reinterpretation. The size has to match, or the operation is not allowed, and the alignment has to be compatible, and the source has to be inhabited because you cannot have a bit pattern for a value that does not exist. Those are the rules that make the operation safe rather than a transmute with extra steps.

The crate is a Rust crate with the Zlib, Apache-2.0 and MIT licences offered together, the version is 1.25.2, and the categories listed in the manifest include `encoding` and `no-std`.

The slice case, and the graphics community that uses it

The part of the documentation that is more likely to matter to you is the slice case, and it is where the crate's popularity comes from.

When a slice is involved it is not a direct bitcast. Instead, the `cast_slice` and `cast_slice_mut` functions pull apart a slice's data and give you a new slice that is the same span of memory just viewed as the new type. If the size of the slice's element changes then the length of the slice you get back is changed accordingly.

So a slice of colour values becomes a slice of `u8` covering the same memory, and the length arithmetic happens for you. That is what lets you cast a slice of colour values into a slice of `u8` and send it to the GPU, or things like that.

The author is refreshingly direct about why the crate is popular. It is as popular as it is mostly because of Rust's 3D graphics community wanting to cast slices of different types into byte slices for sending to the GPU.

That is a real and narrow use case, and it explains the design. The operation is zero copy, so a vertex buffer is not copied into a byte buffer before upload, and the type system guarantees the byte count and the alignment are right, so a mismatch is a compile error rather than a corrupted framebuffer.

The `no-std` category in the manifest and the `extern_crate_alloc` and `extern_crate_std` features in the feature list fit that world. A graphics library or an embedded target often has no standard library, and bytemuck is careful to keep its default build usable without one, with the standard library pieces behind explicit feature flags.

The `Zeroable` trait is the other half of the safety story. It is a marker trait that says a type can be safely zeroed, which is what makes it meaningful to create a `MaybeUninit`-backed buffer of that type and read it as bytes. The feature list shows the derivations and impls that ship with it, including `Zeroable` for `MaybeUninit` behind `zeroable_maybe_uninit` and for atomic types behind `zeroable_atomics`.

The feature flags and their minimum Rust versions

The feature list in the manifest is the part to read carefully, because the minimum Rust version story is more nuanced than the badge suggests.

The default build of the crate will continue to work with `rustc-1.34` for at least the rest of the `1.y.z` versions, and the badge in the documentation says Minimum Rust Version 1.34. But any other cargo features of the crate are not held to the same standard, and may work only on the latest Stable or even only on latest Nightly.

The manifest spells out the individual floors. The `derive` feature, which enables deriving the various bytemuck traits, needs MSRV 1.68.0. The `align_offset` feature, which uses the `align_offset` method instead of casting to `usize` to check the alignment of pointers, needs MSRV 1.36, and the comment is careful that this may improve codegen in some cases but has never been formally benchmarked.

The SIMD features are a ladder of their own. `min_const_generics` is MSRV 1.51 and supports arrays via min const generics. `wasm_simd` is MSRV 1.54.0. `aarch64_simd` is MSRV 1.59.0. `avx512_simd` is MSRV 1.89.0.

The `must_cast` feature is the most interesting, because it changes what the crate can express. It is MSRV 1.64.0 and supports the `must` module, with `must_cast_extra` at MSRV 1.83.0 to support mutable references in const.

The `must` module is the answer to a problem the other features cannot solve. A bit cast that is checked by the compiler rather than left to the caller, for the cases where the compiler cannot prove the invariant. `must_cast` is the opt in that lets a caller say this cast must succeed, and the separate `must_cast_extra` feature is the extra machinery that needs a newer compiler.

There is also a `TransparentWrapper` implementation for standard library types newer than the crate's base MSRV, with the current entry being `core::num::Saturating` at MSRV 1.74.0, and the manifest notes that the MSRV may increase if impls are added for new types.

The practical takeaway is that bytemuck's MSRV story is a range, not a number, and the number on the badge applies to the default build only.

The safe sibling crate, and the 2.0 that is planned

Two things in the documentation tell you where the project is going.

The first is the sibling crate. While bytemuck is full of unsafe code, the author has also started a sibling crate called bitfrob, which is where operations that are 100% safe will be added.

That is a sensible split and a good sign about the maintainer's judgement. bytemuck's job is to make unsafe operations as safe as they can be, and the operations that are entirely safe do not belong in a crate full of unsafe code, since a user who has decided against unsafe in their dependency graph should not have to take bytemuck for a helper that does not need it. Putting the safe operations in bitfrob means a crate with no unsafe code can be used for the common cases, and bytemuck is reserved for the cases where you genuinely need to reinterpret bytes.

The second is the 2.0 plan. Once the Safe Transmute Project completes and stabilizes, eventually, the crate will be updated to use that as the underlying mechanism for transmutation bounds, and a 2.0 version of bytemuck will be released. The hope is for the 1.0 to 2.0 transition to be as seamless as possible, but the future is always uncertain.

The Safe Transmute Project is a Rust RFC, and the idea behind it is to make the compiler able to reason about transmutes in a checked way, so that a bit cast can be expressed in safe Rust with the compiler checking the size and alignment rules. If that lands, bytemuck's own unsafe implementation becomes thinner, because the language provides the guarantee.

Meanwhile the 1.x line is stable. The crate is 1.0 and the author considers it basically done, with new features usually being accepted when other people want to put in the work, and the author wanting to move on to using bytemuck in bigger projects. That is an honest statement of maintenance level, and it is worth weighing as a risk: the crate is not going to change shape, and it is not going to gain features unless a contributor wants them.

Where bytemuck is the wrong tool

There are three cases, and they are about the boundary of what a bit cast can express.

The first is a conversion that changes the value rather than the interpretation. If you want to turn a `u32` into a `f32` where the number is a different quantity, or parse a string into a number, that is `as` or `From` or `TryFrom`, and bytemuck is not involved. The documentation is explicit that bytemuck is not like either of those, and using it for that would be a type error anyway, since the sizes and semantics do not line up.

The second is a slice cast where the element sizes do not divide evenly. The rule is that the length of the new slice changes accordingly, and if the element size changes then the length has to be a whole number of elements, which means a slice of `u32` cannot become a slice of `u8` of the same length. The `cast_slice` function handles the arithmetic, and when the sizes do not work out the conversion is rejected rather than truncating, which is the correct behaviour but means you sometimes need a different approach for the tail of a buffer.

The third is data that is not initialised. A bit cast over a `MaybeUninit` buffer is only valid if the bytes are known to be initialised, and the `Zeroable` marker and the `NoUninit` machinery are how the crate reasons about that. If you are reading bytes out of a buffer that some other code might not have filled, no marker trait saves you, and you need to establish that invariant yourself.

The alternative approaches are worth naming. `unsafe { std::mem::transmute }` does the same thing with no checks, and the compiler will accept it in cases where it should not. A nightly-only `transmute_unchecked` gives you the same speed with fewer checks. Serialisation through a `Vec<u8>` and back is safe but copies. And for the specific case of GPU uploads, there are graphics libraries that take typed slices directly and do the conversion internally, which removes the need for bytemuck in that layer entirely.

The difference in approach is that bytemuck moves the checks to compile time and keeps the zero copy property, so you get the performance of a transmute with the safety of a checked conversion, at the cost of a dependency with unsafe code inside it. That is a good trade for a graphics pipeline and a poor one for a codebase with a strict no unsafe policy, which is exactly why bitfrob exists.

Editorial conclusion

bytemuck fits Rust code that has to move typed data into an untyped buffer, above all graphics code uploading vertices or colours to a GPU, because it makes the reinterpretation a checked operation rather than an unsafe transmute and it adds the NoUninit marker that proves the bytes are initialised. Skip it if you are only converting between numeric types, since `as` and the `From` trait already do that, and note that the crate's own recommendation is to use the sibling `bitfrob` crate for operations that are entirely safe. Before you pin a version, check which cargo features you need against their stated minimum Rust versions, because the default build works on rustc 1.34 while several features require much newer compilers, and the current crate version is 1.25.2.

Frequently asked questions

What does bytemuck do in Rust?

It lets you safely perform bit cast operations between data types, taking a value and reinterpreting the bits as another type without changing them. The documentation compares it to f32::to_bits generalized to all sorts of data types, and says it is not like the `as` keyword or the `From` trait.

What is the difference between cast_slice and a direct bit cast in bytemuck?

With a slice it is not a direct bit cast. The `cast_slice` and `cast_slice_mut` functions pull apart a slice's data and give you a new slice over the same span of memory viewed as the new type, and if the element size changes the resulting length changes accordingly.

What is the minimum Rust version for bytemuck?

The default build works with rustc 1.34 and will for the rest of the 1.y.z versions, but other cargo features are not held to the same standard. Deriving traits needs 1.68.0, wasm_simd needs 1.54.0, aarch64_simd 1.59.0, avx512_simd 1.89.0 and must_cast 1.64.0, with must_cast_extra at 1.83.0.

What is the bitfrob crate?

It is a sibling crate to bytemuck, started by the same author, where operations that are 100% safe will be added, so that bytemuck's unsafe code is reserved for the operations that genuinely need it.

What licence does bytemuck use?

The manifest declares `Zlib OR Apache-2.0 OR MIT`, and the repository carries LICENSE-APACHE, LICENSE-MIT and LICENSE-ZLIB files. The current crate version is 1.25.2.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. Lokathor/bytemuck on GitHub
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/lokathor-bytemuck.svg)](https://hysenlabs.com/projects/lokathor-bytemuck)

Was this useful?