- Feature Name:
libc_struct_traits - Start Date: 2017-12-05
- RFC PR: rust-lang/rfcs#2235
- Rust Issue: rust-lang/rust#57715
Summary
Expand the traits implemented by structs libc crate to include Debug, Eq, Hash, and PartialEq.
Motivation
This will allow downstream crates to easily support similar operations with any types they
provide that contain libc structs. Additionally The Rust API Guidelines specify that it is
considered useful to expose as many traits as possible from the standard library. In order to facilitate the
following of these guidelines, official Rust libraries should lead by example.
For many of these traits, it is trivial for downstream crates to implement them for these types by using
newtype wrappers. As a specific example, the nix crate offers the TimeSpec wrapper type around the timespec struct. This
wrapper could easily implement Eq through comparing both fields in the struct.
Unfortunately there are a great many structs that are large and vary widely between platforms. Some of these in use by nix
are dqblk, utsname, and statvfs. These structs have fields and field types that vary across platforms. As nix aims to
support as many platforms as libc does, this variation makes implementing these traits manually on wrapper types time consuming and
error prone.
Guide-level explanation
Add an extra_traits feature to the libc library that enables Debug, Eq, Hash, and PartialEq implementations for all structs.
Reference-level explanation
The Debug, Eq/PartialEq, and Hash traits will be added as automatic derives within the s! macro in src/macros.rs if the corresponding feature
flag is enabled. This won’t work for some types because auto-derive doesn’t work for arrays larger than 32 elements, so for these they’ll be implemented manually. For libc
as of bbda50d20937e570df5ec857eea0e2a098e76b2d on x86_64-unknown-linux-gnu these many structs will need manual implementations:
Debug- 17Eq/PartialEq- 46Hash- 17
Drawbacks
While most structs will be able to derive these implementations automatically, some will not (for example arrays larger than 32 elements). This will make it harder to add
some structs to libc.
This extra trait will increase the testing requirements for libc.
Rationale and alternatives
Adding these trait implementations behind a singular feature flag has the best combination of utility and ergonomics out of the possible alternatives listed below:
Always enabled with no feature flags
This was regarded as unsuitable because it increases compilation times by 100-200%. Compilation times of libc was tested at commit bbda50d20937e570df5ec857eea0e2a098e76b2d
with modifications to add derives for the traits discussed here under the extra_traits feature (with no other features). Some types failed to have these traits
derived because of specific fields, so these were removed from the struct declaration. The table below shows the compilation times:
| Build arguments | Time |
|---|---|
cargo clean && cargo build --no-default-features | 0.84s |
cargo clean && cargo build --no-default-features --features extra_traits | 2.17s |
cargo clean && cargo build --no-default-features --release | 0.64s |
cargo clean && cargo build --no-default-features --release --features extra_traits | 1.80s |
cargo clean && cargo build --no-default-features --features use_std | 1.14s |
cargo clean && cargo build --no-default-features --features use_std,extra_traits | 2.34s |
cargo clean && cargo build --no-default-features --release --features use_std | 0.66s |
cargo clean && cargo build --no-default-features --release --features use_std,extra_traits | 1.94s |
Default-on feature
For crates that are more than one level above libc in the dependency chain it will be impossible for them to opt out. This could also happen with a default-off
feature flag, but it’s more likely the library authors will expose it as a flag as well.
Multiple feature flags
Instead of having a single extra_traits feature, have it and feature flags for each trait individually like:
trait_debug- EnablesDebugfor all structstrait_eg- EnablesEqandPartialEqfor all structstrait_hash- EnablesHashfor all structsextra_traits- Enables all of the above through dependent features
This change should reduce compilation times when not all traits are desired. The downsides are that it complicates CI. It can be added in a backwards-compatible manner later should compilation times or consumer demand changes.