Open-source project
Lokathor/wide avatar
Lokathor/wide

wide: portable SIMD data types for Rust, with the sharp edges written down

A crate to help you go wide. By which I mean use SIMD stuff.

557 stars62 forksRustApache-2.0

At a glance

What is it?
wide is a Rust crate of wide data types that use SIMD where the hardware allows and fall back to careful scalar code where it does not, and it is close to a drop-in replacement for the standard library's simd module. The most useful part of its documentation is the section on enabling SIMD in your build, which spells out exactly which target features to set and warns that runtime detection does not work with it.
Who is it for?
Adopt wide if you want stable wide SIMD types in Rust today, or if you need the explicit intrinsic path on x86, x86_64, wasm32 or aarch64 NEON rather than relying on the auto-vectoriser, and you are happy to choose the instruction set at build time.
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 5 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 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the crate is

wide is described as a crate to help you go wide, and the repository description spells out the meaning: a crate to help you go wide, by which the author means use SIMD stuff.

The technical description is more precise. There are portable wide data types that do their best to be SIMD when possible, and it is a near drop-in replacement for the standard library's simd module.

That last point is the reason to care. The standard library's portable SIMD is a set of primitives that gives you a wide type and lets the compiler pick an implementation, and it is the right thing to reach for in new code. But it has been unstable for a long time, and a crate that offers the same shape with a stable API lets you write the wide code now.

The implementation strategy is stated in two sentences, and they are the whole design. On x86, x86_64, wasm32 and aarch64 neon, it is implemented with explicit intrinsic usage. On other architectures it is done by carefully writing functions so that LLVM hopefully does the right thing.

So there are two tiers. On the platforms where the vector extensions are known and stable, the crate reaches for the intrinsics directly and you get the real instructions. Everywhere else, the code is written in a shape that the auto-vectoriser can handle, and the expectation is set out in the README with the word hopefully.

That word is doing honest work. Auto-vectorisation is a compiler optimisation, not a guarantee, and a library that claims SIMD everywhere would be over-promising. The explicit intrinsic path is the one you can rely on, and the README tells you exactly which platforms get it.

The primary language is Rust, the licence is Apache-2.0, the default branch is main, and the homepage is the docs.rs page. The last push was on 2026-10-18 with the project not archived. The repository publishes no GitHub releases, so crates.io is the distribution channel, and the crate is at version 1.7.1 in the manifest with a minimum Rust version of 1.89.

The repository layout is small and conventional for a Rust library: src/, tests/, benches/, a changelog.md, a rustfmt.toml, and three licence files, LICENSE-APACHE.txt, LICENSE-MIT.txt and LICENSE-ZLIB.txt.

Enabling SIMD, per platform

The section on enabling SIMD instructions in your build is the most practically useful part of the README, and it is split by platform because the answer is different on each.

On aarch64, the answer is that there is nothing to do. Aarch64 always enables the NEON extension, so wide can always take advantage of SIMD on this platform. That is a property of the architecture rather than of the crate, and it is the reason ARM-based targets are the easy case.

On WebAssembly, SIMD is an optional extension but is supported by all modern browsers, and you enable it by setting a target feature at build time:

bash
RUSTFLAGS="-C target-feature=+simd128" cargo build --target wasm32-wasip1

On x86 it is the complicated one, and the reason is a specific guarantee in the Rust target definitions. Rust's i686 and x86_64 targets guarantee only the presence of basic operations on 128-bit vectors, which is SSE2. If you need anything else, you have to enable the relevant SIMD extensions at build time yourself.

The aggressive version uses all SIMD extensions available on your CPU:

bash
RUSTFLAGS='-C target-cpu=native' cargo build --release

And the warning that follows is the part to take seriously. Attempting to use an instruction that is not supported by the CPU will crash the program or lead to undefined behavior. Therefore distributing binaries built with SIMD extensions enabled is not recommended.

That is the standard x86 SIMD trade-off stated clearly. target-cpu=native gives you the best code on the machine you built it on and a binary that will fault on a machine with a smaller instruction set. For a library you publish, that is a build configuration your users must not enable. For a local build or a CI job pinned to one machine type, it is the right setting.

The scoped alternative, and the one a library author should default to, is to enable a specific feature rather than native, so the binary has a documented floor. The README's example does not show that form, but the reasoning in the text points straight at it.

So the three platforms are three different answers: nothing to do on ARM, a single target feature on WebAssembly, and a considered choice on x86.

The runtime detection limitation

There is one note in the README that deserves its own section, because it is the kind of thing that will cost you an afternoon if you do not read it.

The note says that wide only supports detecting the available SIMD extensions at build time. Runtime feature detection via the is_x86_feature_detected macro, or crates like multiversion, do not work with wide.

This is a real constraint and it is worth understanding why it exists rather than just accepting it.

The x86 SIMD extension set is not a single thing. SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, AVX2, FMA and the AVX-512 family are separate features with different meanings, and a given CPU supports a particular combination. Runtime detection exists so that one binary can run on many machines, choosing the widest instruction set the current CPU supports and falling back when it does not.

wide's approach is compile-time. The wide type's width and the operations available on it are fixed when you compile, not when you run. That is a legitimate design: the crate's whole value is that the wide types are fixed-size and known at compile time, which is what lets the operations be written against explicit intrinsics. Runtime flexibility is the price.

The consequence for an adopter is specific. If your program must run on a range of x86 machines and you were planning to detect AVX2 at runtime and dispatch to a wide implementation when it is present, that pattern does not work here. You have to choose at build time: build for the lowest common denominator, or build a separate binary per instruction set and dispatch at the application level, or use multiversion with your own function-level dispatch rather than expecting wide to do it.

The README is careful to say that wide only supports build-time detection, without saying what you should do instead, and it points at multiversion as the tool that does runtime detection for other purposes. So the advice is there if you know to look for it.

It is also worth noting that this limitation applies to x86. On aarch64, NEON is always present, so there is nothing to detect. The whole question only arises on the platform where the extension set varies.

The package, and the licensing choice

The manifest is small and the details are worth reading individually.

The package is wide at version 1.7.1, with the description A crate to help you go wide, the author Lokathor, and the repository, readme and keywords fields as you would expect. The categories are data-structures and hardware-support, which is a good summary of where the crate sits.

The edition is 2024 and the rust-version is 1.89, with a comment in the manifest reminding the maintainer to also update the CI workflows and the README badge when updating. That comment is a small sign of a release process that is automated but not entirely, and it is the kind of note that saves a version mismatch between a published crate and its documentation.

The licence is Zlib OR Apache-2.0 OR MIT, which is a triple licence, and the repository carries all three licence files. The README badge says Zlib while the repository listing records Apache-2.0, so the two disagree, which is harmless for a triple-licensed crate since you can pick any of the three, but it is a reminder to read the actual terms rather than the badge.

The features section is where the interesting design decisions show. The default feature is std, and the comment on it explains what it does: activating std within the crate currently gives a much faster sqrt implementation when an explicit hardware sqrt is not available. So the standard library feature is not about the standard library at all, it is about reaching a faster maths path.

That is a nice example of a feature flag doing something more specific than its name suggests. Someone reading the feature list would not guess that std relates to square root performance.

The optional serde feature depends on serde_core, and the dependency is marked as optional with default-features off. The optional dependency uses the dep: form, which is the modern Cargo syntax for referring to an optional dependency without implicitly enabling a feature of the same name, and that keeps the feature list clean.

The one mandatory dependency is bytemuck at 1.24.0 with the avx512_simd feature enabled. bytemuck is the crate that provides safe, zero-cost casting between byte slices and typed slices, and it is a common choice for a library like this that needs to reinterpret memory. Enabling the avx512_simd feature on it is how the crate gets access to the AVX-512 vector types even on machines that do not have AVX-512, so the code can be compiled and the feature selected at runtime or build time elsewhere.

The dev dependencies are bincode for serialisation in tests and criterion for benchmarking, and the manifest disables automatic test discovery with autotests = false because the tests are declared explicitly.

The tests and the benchmarks

The manifest shows the testing and benchmarking setup, and the shape of it is informative.

Tests are declared explicitly with autotests = false and a single test target named tests at tests/main.rs. So rather than one binary per test file, the whole suite is one integration test binary with a main. That is a common choice when the tests need to share setup, and it also means the suite compiles as a single unit.

The benchmarks are three separate targets, and their names tell you what the crate is actually optimised for. There is fma_benchmarks, math_benchmarks and u8_shift, all with harness = false, which is the flag that tells Cargo the benchmark brings its own harness rather than using the default one.

fma_benchmarks is for FMA, fused multiply-add, which is the instruction that does a multiply and an add in one operation with a single rounding. It is the interesting one because FMA availability is exactly the kind of thing that varies between x86 CPUs, so benchmarking it separately is how you would check whether a particular operation is worth guarding.

math_benchmarks covers the maths operations generally, and the std feature comment about a faster sqrt belongs here, since the square root is exactly the kind of operation that has a hardware path on some platforms and not others.

u8_shift is the third, and it is the one that says the crate is not only about floats. Byte shifts are the primitive behind everything from image processing to audio codecs to compression, and they vectorise particularly well because a shift of an 8-bit lane is a lane-local operation with no cross-lane interaction.

The criterion version is 0.7.0 with default features off, and default-features off on criterion is how you avoid pulling in its optional HTML output dependencies, which is a reasonable choice for a library that only needs the measurement, not the report.

The repository layout backs this up. There is a benches/ directory at the top level, a tests/ directory, a src/ directory, a changelog.md, and a rustfmt.toml. The .cargo-ci/ directory at the root is for continuous integration cargo configuration, which is where you put settings that need to apply only in CI, such as offline or lockfile settings.

So the crate is not only a set of wide types. It is a set of wide types with a benchmark suite that says which operations the author cared about, and a test suite that shares one binary.

How to evaluate it, and what to check first

There are four things to decide.

First, whether the standard library's simd module has become good enough for your use. The crate positions itself as a near drop-in replacement for std::simd, and that framing is the right question to ask. If the standard module is stable and available in your toolchain, the reason to use wide is not the API but the implementation strategy, namely the explicit intrinsic path on the four platforms it names and the build-time detection constraint. If you are starting a new project on a recent toolchain, check what the standard library gives you first.

Second, which platform you are compiling for, because the SIMD story is different on each. On aarch64 there is nothing to configure. On wasm32 you need a target feature. On x86 you need to decide between a conservative feature set and target-cpu=native, and the README's warning about distributing binaries built with native is not a suggestion.

Third, whether the build-time detection constraint is acceptable. If your application must ship one binary that runs across a range of x86 machines, wide's fixed-width types mean you choose the instruction set when you compile. That is fine if you are publishing a library, a native application installed on known hardware, or a build artefact for a known fleet. It is a problem if you are shipping to arbitrary hardware, and the workaround is application-level dispatch or multiple binaries rather than anything inside the crate.

Fourth, the feature flags and the maths behaviour. The std feature is on by default and it affects the square root implementation, so if the square root is in your hot path, read the comment before disabling anything. The serde feature is opt-in and pulls in serde_core with default features off, which is a reasonable, narrow addition.

What you get is a small, focused, actively maintained crate with a clear licensing position, an explicit statement of which platforms get real intrinsics, and unusually honest documentation of the limits. The build-time detection note in particular is the kind of thing you would rather learn from the README than from a bug report, and it tells you a lot about how the author intends the crate to be used.

Editorial conclusion

Adopt wide if you want stable wide SIMD types in Rust today, or if you need the explicit intrinsic path on x86, x86_64, wasm32 or aarch64 NEON rather than relying on the auto-vectoriser, and you are happy to choose the instruction set at build time. Do not adopt it expecting runtime feature detection, because the wide types have a fixed width fixed at compile time and the README says plainly that is_x86_feature_detected and multiversion do not work with it, so a binary shipped to arbitrary x86 hardware needs application-level dispatch instead. Before you commit, check what the standard library's simd module offers on your toolchain, since wide positions itself as a near drop-in for it, enable a specific target feature rather than target-cpu=native for any binary you distribute, and note that the std feature is not just about the standard library, it is what gives you the faster square root when no hardware sqrt is available.

Frequently asked questions

What is the wide Rust crate?

It is a crate of portable wide data types that do their best to be SIMD when possible, and a near drop-in replacement for the standard library's simd module. On x86, x86_64, wasm32 and aarch64 neon it uses explicit intrinsics, and on other architectures it relies on carefully written functions that LLVM hopefully vectorises.

How do I enable SIMD when building for WebAssembly?

SIMD is an optional WebAssembly extension but is supported by all modern browsers, so you set the target feature at build time with RUSTFLAGS="-C target-feature=+simd128" on the cargo build command. On aarch64 there is nothing to do, since NEON is always enabled on that architecture.

Why does using wide on x86 require care with target-cpu=native?

Rust's i686 and x86_64 targets guarantee only basic operations on 128-bit vectors, which is SSE2, so anything beyond that has to be enabled explicitly. Building with RUSTFLAGS='-C target-cpu=native' uses all SIMD extensions your CPU has, but using an instruction the CPU does not support will crash the program or cause undefined behaviour, so the README does not recommend distributing binaries built that way.

Can wide do runtime SIMD feature detection?

No. The README states that wide only supports detecting the available SIMD extensions at build time, and that runtime detection via is_x86_feature_detected or crates like multiversion do not work with it. The wide types have a fixed width fixed at compile time, so if you need one binary across varied hardware you have to dispatch at the application level or ship separate builds.

What licence is the wide crate under?

The manifest declares Zlib OR Apache-2.0 OR MIT, and the repository carries LICENSE-APACHE.txt, LICENSE-MIT.txt and LICENSE-ZLIB.txt. The crate is at version 1.7.1 with a minimum Rust version of 1.89 and edition 2024.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. Lokathor/wide 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-wide.svg)](https://hysenlabs.com/projects/lokathor-wide)

Was this useful?