|
| 1 | +- Feature Name: (libc_struct_traits) |
| 2 | +- Start Date: (2017-12-05) |
| 3 | +- RFC PR: (leave this empty) |
| 4 | +- Rust Issue: (leave this empty) |
| 5 | + |
| 6 | +# Summary |
| 7 | +[summary]: #summary |
| 8 | + |
| 9 | +Expand the traits implemented by structs `libc` crate to include `Debug`, `Eq`, `Hash`, and `PartialEq`. |
| 10 | + |
| 11 | +# Motivation |
| 12 | +[motivation]: #motivation |
| 13 | + |
| 14 | +This will allow downstream crates to easily support similar operations with any types they |
| 15 | +provide that contain `libc` structs. Additionally [The Rust API Guidelines](https://rust-lang-nursery.github.io/api-guidelines/checklist.html) specify that it is |
| 16 | +considered useful to expose as many traits as possible from the standard library. In order to facilitate the |
| 17 | +following of these guidelines, official Rust libraries should lead by example. |
| 18 | + |
| 19 | +For many of these traits, it is trivial for downstream crates to implement them for these types by using |
| 20 | +newtype wrappers. As a specific example, the `nix` crate offers the `TimeSpec` wrapper type around the `timespec` struct. This |
| 21 | +wrapper could easily implement `Eq` through comparing both fields in the struct. |
| 22 | + |
| 23 | +Unfortunately there are a great many structs that are large and vary widely between platforms. Some of these in use by `nix` |
| 24 | +are `dqblk`, `utsname`, and `statvfs`. These structs have fields and field types that vary across platforms. As `nix` aims to |
| 25 | +support as many platforms as `libc` does, this variation makes implementing these traits manually on wrapper types time consuming and |
| 26 | +error prone. |
| 27 | + |
| 28 | +# Guide-level explanation |
| 29 | +[guide-level-explanation]: #guide-level-explanation |
| 30 | + |
| 31 | +The feature flag `derive_all` is added to the `libc` library that when enabled adds `Debug`, `Eq`, `Hash`, and `PartialEq` traits for all structs. It will default to off. |
| 32 | + |
| 33 | +# Reference-level explanation |
| 34 | +[reference-level-explanation]: #reference-level-explanation |
| 35 | + |
| 36 | +The `Debug`, `Eq`, `Hash`, and `PartialEq` traits will be added as automatic derives within the `s!` macro in `src/macros.rs` if the `derive_all` feature |
| 37 | +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` |
| 38 | +as of `bbda50d20937e570df5ec857eea0e2a098e76b2d` on `x86_64-unknown-linux-gnu` these many structs will need manual implementations: |
| 39 | + |
| 40 | + * `Debug` - 17 |
| 41 | + * `Eq` and `PartialEq` - 46 |
| 42 | + * `Hash` - 17 |
| 43 | + |
| 44 | +# Drawbacks |
| 45 | +[drawbacks]: #drawbacks |
| 46 | + |
| 47 | +The addition of this behind a feature flag does not have a significant effect on build times, but the burden of adding these implementations for new types that |
| 48 | +require manual implementations will be high, possibly hindering new contributors. |
| 49 | + |
| 50 | +# Rationale and alternatives |
| 51 | +[alternatives]: #alternatives |
| 52 | + |
| 53 | +Adding these trait implementations behind a singular feature flag has the best compination of utility and ergonomics out of the possible alternatives listed below: |
| 54 | + |
| 55 | +## Always enabled |
| 56 | + |
| 57 | +This was regarded as unsuitable because it doubles to triples compilation time. Compilation times of `libc` was tested at commit `bbda50d20937e570df5ec857eea0e2a098e76b2d` |
| 58 | +with modifications to add derives for the traits discussed here. Some types failed to have these traits derived because of specific fields, so these were removed from the |
| 59 | +struct declaration. The table below shows the results: |
| 60 | + |
| 61 | +| Build arguments | Time | |
| 62 | +|--------------------------------------------------------------------------------------------|-------| |
| 63 | +| `cargo clean && cargo build --no-default-features` | 0.84s | |
| 64 | +| `cargo clean && cargo build --no-default-features --features derive_all` | 2.17s | |
| 65 | +| `cargo clean && cargo build --no-default-features --release` | 0.64s | |
| 66 | +| `cargo clean && cargo build --no-default-features --release --features derive_all` | 1.80s | |
| 67 | +| `cargo clean && cargo build --no-default-features --features use_std` | 1.14s | |
| 68 | +| `cargo clean && cargo build --no-default-features --features use_std,derive_all` | 2.34s | |
| 69 | +| `cargo clean && cargo build --no-default-features --release --features use_std` | 0.66s | |
| 70 | +| `cargo clean && cargo build --no-default-features --release --features use_std,derive_all` | 1.94s | |
| 71 | + |
| 72 | +## Default-on feature flag |
| 73 | + |
| 74 | +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 |
| 75 | +feature flag, but it's more likely the library authors will expose it as a flag as well. |
| 76 | + |
| 77 | +## Independent feature flags |
| 78 | + |
| 79 | +It wasn't tested how much compilation times increased per-trait, but further mitigation of slow compilation times could done by exposing all traits mentioned here |
| 80 | +behind individual feature flags. By doing this it becomes harder for downstream crates to pass-through these feature flags, so it's likely not a worthwhile tradeoff. |
| 81 | + |
| 82 | +# Unresolved questions |
| 83 | +[unresolved]: #unresolved-questions |
| 84 | + |
| 85 | +Is `derive_all` a suitable name for this feature flag? |
0 commit comments