|
| 1 | +# Case Study: Issue #146 — Add WrappingAdd to LinkReference Trait Bounds |
| 2 | + |
| 3 | +## Timeline / Sequence of Events |
| 4 | + |
| 5 | +| Date | Event | Repository | |
| 6 | +|------|-------|-----------| |
| 7 | +| 2026-04-13 | doublets-rs#47 opened — quality audit requiring latest dependencies and trait unification | linksplatform/doublets-rs | |
| 8 | +| 2026-04-14 | data-rs#16 opened — Replace funty dependency with platform-num (`LinkReference`) | linksplatform/data-rs | |
| 9 | +| 2026-04-14 | data-rs#17 PR opened — Implements the replacement, discovers `WrappingAdd` gap | linksplatform/data-rs | |
| 10 | +| 2026-04-14 | Numbers#146 opened — Request to add `WrappingAdd` to `LinkReference` trait bounds | linksplatform/Numbers | |
| 11 | +| 2026-04-14 | Numbers#147 PR opened — Implementation of `WrappingArithmetic` composite trait | linksplatform/Numbers | |
| 12 | + |
| 13 | +## Requirements from the Issue |
| 14 | + |
| 15 | +### R1: Add wrapping arithmetic to `LinkReference` supertraits (Original request) |
| 16 | +The original issue requested adding `WrappingAdd` from `num-traits` to `LinkReference` so downstream crates don't need explicit `+ WrappingAdd` bounds. |
| 17 | + |
| 18 | +### R2: Better naming than `WrappingAdd` (From comment by @konard) |
| 19 | +The maintainer disliked the name `WrappingAdd` and suggested something like `AdditionCapable`. They asked to check if similar traits already exist in `num-traits`. |
| 20 | + |
| 21 | +### R3: Support similar operations for other arithmetic ops (From comment by @konard) |
| 22 | +Not just `WrappingAdd` — all wrapping arithmetic operations normally supported by numeric types should be included. |
| 23 | + |
| 24 | +### R4: Compile data and perform deep case study analysis (From comment by @konard) |
| 25 | +Download all logs and data related to the issue, compile to `./docs/case-studies/issue-146` folder, reconstruct timeline, find root causes, propose solutions. |
| 26 | + |
| 27 | +## Root Cause Analysis |
| 28 | + |
| 29 | +### Root Cause 1: Trait ecosystem fragmentation |
| 30 | +The Rust ecosystem has two competing unsigned integer trait crates: |
| 31 | +- `funty` (provides `funty::Unsigned`) |
| 32 | +- `num-traits` (provides `num_traits::Unsigned`) |
| 33 | + |
| 34 | +`platform-data` used `funty::Unsigned` while `platform-num` (Numbers) used `num_traits::Unsigned`. These are **different traits from different crates**, even though they represent the same concept. This made it impossible to write unified `T: data::LinkType + trees::LinkType` bounds. |
| 35 | + |
| 36 | +### Root Cause 2: Missing wrapping arithmetic in `PrimInt` |
| 37 | +The `PrimInt` trait from `num-traits` (which is a supertrait of `Number`) provides **non-wrapping** arithmetic. The wrapping variants (`WrappingAdd`, `WrappingSub`, `WrappingMul`, `WrappingNeg`, `WrappingShl`, `WrappingShr`) are separate traits in `num_traits::ops::wrapping`. This means code that needs wrapping semantics (like `Hybrid` in `platform-data`) must add extra trait bounds. |
| 38 | + |
| 39 | +### Root Cause 3: No composite wrapping trait in `num-traits` |
| 40 | +Unlike `PrimInt` which bundles many non-wrapping operations, `num-traits` does **not** provide a composite trait that bundles all wrapping operations. Each wrapping operation is a separate trait, leading to verbose bounds like `T: WrappingAdd + WrappingSub + WrappingMul + WrappingNeg`. |
| 41 | + |
| 42 | +## Solution Implemented |
| 43 | + |
| 44 | +### Approach: Composite `WrappingArithmetic` trait |
| 45 | + |
| 46 | +Created a new `WrappingArithmetic` composite trait in `platform-num` that bundles all six wrapping arithmetic traits from `num-traits`: |
| 47 | + |
| 48 | +```rust |
| 49 | +pub trait WrappingArithmetic: |
| 50 | + WrappingAdd + WrappingSub + WrappingMul + WrappingNeg + WrappingShl + WrappingShr |
| 51 | +{} |
| 52 | +``` |
| 53 | + |
| 54 | +With a blanket implementation for any type that implements all six traits. |
| 55 | + |
| 56 | +Then added `WrappingArithmetic` as a supertrait of `LinkReference`. |
| 57 | + |
| 58 | +### Why this approach |
| 59 | + |
| 60 | +1. **Addresses naming concern**: `WrappingArithmetic` is descriptive and covers all operations, not just addition |
| 61 | +2. **Broader than requested**: Includes all 6 wrapping traits, not just `WrappingAdd` |
| 62 | +3. **Compatible addition**: All unsigned primitive integer types already implement all 6 wrapping traits |
| 63 | +4. **Follows existing patterns**: Same composite trait pattern as `Number` (which bundles `PrimInt + Default + Debug + AsPrimitive<usize> + ToPrimitive`) |
| 64 | +5. **Preserves ecosystem naming**: Individual traits retain their `num-traits` names; the composite provides a convenient bundle |
| 65 | + |
| 66 | +### Alternatives Considered |
| 67 | + |
| 68 | +| Alternative | Pros | Cons | |
| 69 | +|------------|------|------| |
| 70 | +| Add only `WrappingAdd` | Minimal change | Doesn't address other wrapping ops; name issue remains | |
| 71 | +| Add individual traits directly to `LinkReference` | No new trait needed | Longer trait definition; no reusable composite | |
| 72 | +| Create `AdditionCapable` trait | Addresses naming | Too narrow; name implies only addition | |
| 73 | +| Re-export `WrappingAdd` as a different name | Simple | Confusing; diverges from ecosystem naming | |
| 74 | + |
| 75 | +## Impact on Downstream Crates |
| 76 | + |
| 77 | +### `platform-data` (data-rs#17) |
| 78 | +Currently the PR uses `T: LinkReference + WrappingAdd` everywhere. After this change is released as `platform-num` 0.8.0, `data-rs` can: |
| 79 | +1. Remove the explicit `num-traits` dependency |
| 80 | +2. Replace `T: LinkReference + WrappingAdd` with just `T: LinkReference` |
| 81 | +3. All wrapping operations will be available through the `LinkReference` bound |
| 82 | + |
| 83 | +### `doublets-rs` |
| 84 | +Can use a single `T: LinkReference` bound for all numeric operations including wrapping arithmetic. |
| 85 | + |
| 86 | +## Verification |
| 87 | + |
| 88 | +- All 112 unit tests pass (96 existing + 16 new wrapping arithmetic tests) |
| 89 | +- All 7 doc tests pass (including new `WrappingArithmetic` doctest) |
| 90 | +- `cargo clippy --all-targets` reports zero warnings |
| 91 | +- Verified that all 6 wrapping traits are implemented for `u8`, `u16`, `u32`, `u64`, `u128`, `usize` |
| 92 | + |
| 93 | +## Related Issues and PRs |
| 94 | + |
| 95 | +| Reference | Repository | Description | |
| 96 | +|-----------|-----------|-------------| |
| 97 | +| [#146](https://github.com/linksplatform/Numbers/issues/146) | Numbers | This issue — Add WrappingAdd to LinkReference | |
| 98 | +| [#147](https://github.com/linksplatform/Numbers/pull/147) | Numbers | This PR — Implementation | |
| 99 | +| [#16](https://github.com/linksplatform/data-rs/issues/16) | data-rs | Replace funty with platform-num | |
| 100 | +| [#17](https://github.com/linksplatform/data-rs/pull/17) | data-rs | PR implementing funty replacement | |
| 101 | +| [#47](https://github.com/linksplatform/doublets-rs/issues/47) | doublets-rs | Quality audit driving the unification | |
| 102 | + |
| 103 | +## References |
| 104 | + |
| 105 | +- [num-traits wrapping module documentation](https://docs.rs/num-traits/latest/num_traits/ops/wrapping/) |
| 106 | +- [PrimInt trait documentation](https://docs.rs/num-traits/latest/num_traits/int/trait.PrimInt.html) — provides non-wrapping arithmetic |
| 107 | +- [Rust RFC #1530](https://github.com/rust-lang/rfcs/issues/1530) — Discussion on WrappingAdd, WrappingSub, WrappingMul, WrappingDiv traits |
0 commit comments