1- # ndd (Non-De-Duplicated)
2-
31![ GitHub Actions
42results] ( https://github.com/peter-lyons-kehl/ndd/actions/workflows/main.yml/badge.svg )
53
6- ## Summary
4+ # Summary
5+
6+ ` ndd ` (Non-De-Duplicated) is a zero-cost transparent wrapper. For ` static ` variables that do ** not**
7+ share memory with any other ` static ` or ` const ` (or local) variables (or literals). Use for ` static `
8+ data (single variables/arrays/slices) referenced with references/slices/pointers that are ** compared
9+ by address** .
10+
11+ # Use
12+
13+ Use [ ` ndd::NonDeDuplicated ` ] to wrap your static data (other than string literals (` &str ` ) or C
14+ string literal bytes). Use it for (immutable) ` static ` variables only.
15+
16+ Use [ ` ndd::NonDeDuplicatedStr ` ] and [ ` ndd::NonDeDuplicatedCStr ` ] to wrap static string slices
17+ (` &str ` ) and C strings (owned bytes that defer to ` &CStr ` ). These two types need a ` const ` generic
18+ parameter ` N ` , which is the length (in bytes). There is no way around this (in stable Rust). On
19+ ` nightly ` Rust you can use ` ndd::infer:NonDeDuplicatedStr ` and ` ndd::infer:NonDeDuplicatedCStr ` from
20+ ** odd-numbered** (` -nightly ` ) version of ` ndd ` instead.
721
8- Zero-cost transparent wrapper. For ` static ` variables guaranteed not to share memory with any other
9- ` static ` or ` const ` (or local literals). Especially for ` static ` data (single
10- variables/arrays/slices) referenced with references/slices/pointers that are ** compared by
11- address** .
22+ See unit tests in [ ` src/lib.rs ` ] , and [ ` cross_crate_demo_fix/callee/src/lib.rs ` ] .
1223
13- ## Problem
24+ # Problem
1425
1526Rust (or, rather, LLVM) by default de-duplicates or reuses ** addresses** of ` static ` variables in
1627` release ` builds. And somewhat in ` dev ` (debug) builds, too. For most purposes that is good: The
@@ -31,16 +42,16 @@ the API could trigger your designated signalling unintentionally.
3142
3243That does work out of the box when the client passes a reference/slice defined as ` static ` : each
3344` static ` gets its own memory space (even with the default ` release ` optimizations). See a test
34- [ ` src/lib.rs ` -> ` addresses_unique_between_statics() ` ] .
45+ [ ` src/lib.rs ` -> ` tests_without_ndd ` -> ` addresses_unique_between_statics() ` ] .
3546
3647However, there is a problem (caused by de-duplication in ` release ` , and for some types even in `dev
3748or ` miri). It affects ("ordinary") ` const` values/expressions that equal in value to any ` static`
3849(whether it's a ` static ` variable, or a static literal), which may be your designated ` static ` .
3950Rust/LLVM re-uses address of one such matching ` static ` for references to any equal value(s) defined
40- as ` const ` . See a test [ ` src/lib.rs ` ->
41- ` addresses_not_unique_between_const_and_static() ` ] ( https://github.com/peter-lyons-kehl/ndd/blob/26d743d9b7bbaf41155e00174f8827efca5d5f32/ src/lib.rs#L95 ) .
42- Such ` const ` , ` static ` or literal could be in 3rd party code, even private. (See
43- [ ` cross_crate_demo_bug/ ` ] ( https://github.com/peter-lyons-kehl/ndd/tree/main/cross_crate_demo_bug ) )!
51+ as ` const ` . See <!-- padding for re-wrap - ->
52+ [ ` src/lib.rs ` -> ` tests_without_ndd ` -> ` u8_global_const_and_global_static_release() ` ] . Such
53+ ` const ` , ` static ` or literal could be in 3rd party code, even private. (See
54+ [ ` cross_crate_demo_bug/ ` ] .)
4455
4556Things get worse: ` dev ` builds don't have this consistent:
4657
@@ -69,42 +80,33 @@ lto = "fat"
6980opt-level = 2
7081```
7182
72- ## Solution
83+ # Solution
7384
74- ` ndd:NonDeDuplicated ` uses
75- [ ` core::cell::Cell ` ] ( https://doc.rust-lang.org/nightly/core/cell/struct.Cell.html ) to hold the data
76- passed in by the user. There is no mutation and no mutation access. The only access it gives to the
77- inner data is through shared references.
85+ [ ` ndd::NonDeDuplicated ` ] uses [ ` core::cell::Cell ` ] to hold the data passed in by the user. There is
86+ no mutation and no mutation access. The only access it gives to the inner data is through shared
87+ references.
7888
79- Unlike ` Cell ` (and friends), ` NonDeDuplicated ` ** does** implement
80- [ ` core::marker::Sync ` ] ( https://doc.rust-lang.org/nightly/core/marker/trait.Sync.html ) (if the inner
81- data's type implements ` Send ` and ` Sync ` ). It can safely do so, because it never provides mutable
82- access, and it never mutates the inner data. That is similar to how
83- [ ` std::sync::Mutex ` ] ( https://doc.rust-lang.org/nightly/std/sync/struct.Mutex.html#impl-Sync-for-Mutex%3CT%3E )
84- implements ` Sync ` , too.
89+ Unlike [ ` core::cell::Cell ` ] (and friends), ` NonDeDuplicated ` ** does** implement
90+ [ ` core::marker::Sync ` ] (if the inner data's type implements [ ` core::marker::Send ` ] and
91+ [ ` core::marker::Sync ` ] ). It can safely do so, because it never provides mutable access, and it never
92+ mutates the inner data. That is similar to how [ ` std::sync::Mutex ` ] implements
93+ [ ` core::marker::Sync ` ] , too.
8594
86- See [ ` src/lib.rs ` ->
87- ` tests_behavior_with_ndd ` ] ( https://github.com/search?q=repo%3Apeter-lyons-kehl%2Fndd+tests_behavior_with_ndd+path%3Asrc%2Flib.rs&type=code ) .
95+ See [ ` src/lib.rs ` -> ` tests_with_ndd ` ] .
8896
89- ## Use
97+ # Compatibility
9098
91- Use ` ndd::NonDeDuplicated ` to wrap your static data. Use it for (immutable) ` static ` variables only.
92- Do ** not** use it for locals or on heap. That is validated by implementation of
93- [ core::ops::Drop] ( https://doc.rust-lang.org/nightly/core/ops/trait.Drop.html ) , which ` panic ` -s in
94- ` dev ` builds.
95-
96- See unit tests in [ src/lib.rs] ( src/lib.rs ) .
97-
98- ## Compatibility
99-
100- ` ndd ` is ` no_std ` -compatible and it doesn't need heap (` alloc ` ) either. Release versions
99+ ` ndd ` is ` no_std ` -compatible and it doesn't need heap ([ ` alloc ` ] ) either. Release versions
101100(** even** -numbered major versions, and ** not** ` -nightly ` pre-releases) compile with ` stable ` Rust.
102101(More below.)
103102
104- ### Stable is always forward compatible
103+ Do ** not** use it for locals or on heap. That is validated by implementation of [ ` core::ops::Drop ` ] ,
104+ which ` panic ` s in ` dev ` builds.
105105
106- ` ndd ` is planned to be always below version ` 1.0 ` . (If a need arises for big incompatible
107- functionality, that can go in a new crate.)
106+ ## Always forward compatible
107+
108+ ` ndd ` is planned to be always below version ` 1.0 ` . So stable (** even** -numbered) versions will be
109+ forward compatible. (If a need ever arises for big incompatibility, that can go in a new crate.)
108110
109111That allows you to specify ` ndd ` as a dependency with version ` 0.* ` , which will match ANY ** major**
110112versions (below ` 1.0 ` , of course). That will match the newest (** even** -numbered major) stable
@@ -113,7 +115,7 @@ version (available for your Rust) automatically.
113115This is special only to ` 0.* ` - it is ** not** possible to have a wildcard matching various ** major**
114116versions ` 1.0 ` or higher.
115117
116- ### Versioning convention:
118+ ## Versioning schema
117119
118120- ** Even** -numbered major versions (` 0.2 ` , ` 0.4 ` ...)
119121 - are for ** stable** functionality only.
@@ -123,8 +125,8 @@ versions `1.0` or higher.
123125- ** Odd** -numbered major versions (` 0.3 ` , ` 0.5 ` ...)
124126 - always contain ` -nightly ` (pre-release identifier) in their name.
125127 - are, indeed, for ` nightly ` (** unstable** ) functionality, and need ` nightly ` Rust toolchain
126- (indicated with ` rust-toolchain.toml ` which is present on [ ` nightly `
127- branch] ( https://github.com/peter-lyons-kehl/ndd/tree/nightly ) GIT branch only).
128+ (indicated with ` rust-toolchain.toml ` which is present on [ ` nightly ` GIT
129+ branch] ( https://github.com/peter-lyons-kehl/ndd/tree/nightly ) only).
128130 - include functionality already present in some lower stable versions. Not all of them - only:
129131 - stable versions with a ** lower major** numeric version, and
130132 - if the stable ** major** version is lower by ** ` 0.1 ` only** (and not by more), then the stable
@@ -154,33 +156,36 @@ versions `1.0` or higher.
154156 trick] ( https://github.com/dtolnay/semver-trick ) . See also [ The Cargo Book > Dependency
155157 Resolution] ( https://rustwiki.org/en/cargo/reference/resolver.html#version-incompatibility-hazards ) .
156158
157- However, the only type exported from ` ndd ` is ` ndd::NonDeDuplicated ` . It is a zero-cost wrapper
158- suitable for immutable ` static ` variables. It is normally not being passed around as a
159- parameter/return type or a composite type. And its functions can get inlined/optimized away. So,
160- there shouldn't be any big binary size/speed difference, or usability difference, if there happen
161- to be multiple major versions of ` ndd ` in use at the same time. They would be all isolated. So
162- SemVer trick may be unnecessary.
159+ However, the only types exported from ` ndd ` is [ ` ndd::NonDeDuplicated ` ] ,
160+ [ ` ndd::NonDeDuplicatedStr ` ] and [ ` ndd::NonDeDuplicatedCStr ` ] . They are zero-cost wrappers suitable
161+ for immutable ` static ` variables. They are normally not being passed around as a parameter/return
162+ type or a composite type. And their functions can get inlined/optimized away. So, there shouldn't
163+ be any big binary size/speed difference, or usability difference, if there happen to be multiple
164+ major versions of ` ndd ` crate in use at the same time. They would be all isolated. So SemVer trick
165+ may be unnecessary.
166+
167+ Crate version is validated by GIT [ ` pre-commit ` ] and by [ GitHub Actions] .
163168
164- #### Rule of thumb for stable versions
169+ ### Rule of thumb for stable versions
165170
166171On ` stable ` Rust, always specify ` ndd ` with version ` 0.* ` . Then, automatically:
167172
168173- you will get the newest available even-numbered major (stable) version, and
169174- your libraries will work with any newer ** odd-numbered** major (` -nightly ` ) version of ` ndd ` , too,
170175 if any dependency (direct or transitive) requires it.
171176
172- #### Rule of thumb for unstable versions
177+ ### Rule of thumb for unstable versions
173178
174179To find out the highest ** even-numbered** (stable) version whose functionality is included in a
175180given ** odd-numbered** (` -nightly ` ) version, decrement the ** odd-numbered** version by ` 0.1 ` (and
176181remove the ` -nightly ` suffix).
177182
178- ### Nightly versioning
183+ ## Nightly versioning
179184
180185We prefer not to introduce temporary cargo features. Removing a feature later is a breaking change.
181186And we don't want just to make such a feature no-op and let it sit around.
182187
183- So, instead, any ` nightly ` -only functionality is in separate version stream(s) that always
188+ So, instead, any ` nightly ` -only functionality has separate versions that always
184189
185190- are ** pre-releases** (as per [ The Cargo Book > Specifying Dependencies >
186191 Pre-releases] ( https://doc.rust-lang.org/nightly/cargo/reference/specifying-dependencies.html#pre-releases )
@@ -195,7 +200,7 @@ So, instead, any `nightly`-only functionality is in separate version stream(s) t
195200
196201As per Rust resolver rules, a stable (** non** -pre-release) version will NOT match/auto-update to a
197202** pre-release** version on its own. Therefore, if your crate and/or its dependencies specify ` ndd `
198- version as ` 0.* ` , they will ** not** accidentally request an ** odd** -numbered major (` -nightly ` ) on
203+ version as ` 0.* ` , they will ** not** accidentally request an ** odd** -numbered (` -nightly ` ) major on
199204their own.
200205
201206They can get a (` -nightly ` ) version, but only if another crate requires it. That's up to the
@@ -204,39 +209,37 @@ consumer.
204209If you want more control over stable versions, you can fix the ** even** -numbered major version, and
205210use an asterisk mask for the minor version, like ` 0.2.* ` . But then you lose automatic major updates.
206211
207- ### Nightly functionality
212+ ## Nightly functionality
208213
209- Functionality of odd-numbered major (` -nightly ` ) versions is always subject to change.
214+ WARNING: Functionality of odd-numbered major (` -nightly ` ) versions is always subject to change!
210215
211- The following extra functionality is available on ` 0.3.1 -nightly ` . You need ` nightly ` Rust toolchain
212- (of course) .
216+ The following extra functionality is available on ` 0.3.5 -nightly ` . Of course, you need ` nightly `
217+ Rust toolchain .
213218
214- #### as_array_of_cells
219+ ### as_array_of_cells
215220
216- ` ndd::NonDeDuplicated ` has function ` as_array_of_cells ` , similar to Rust's
217- [ ` core::cell::Cell::as_array_of_cells ` ] ( https://doc.rust-lang.org/nightly/core/cell/struct.Cell.html#method.as_array_of_cells )
218- (which will, hopefully, become stable in 1.91).
221+ [ ` ndd::NonDeDuplicated ` ] has function ` as_array_of_cells ` , similar to Rust's
222+ [ ` core::cell::Cell::as_array_of_cells ` ] (which will, hopefully, become stable in Rust 1.91).
219223
220- #### as_slice_of_cells
224+ ### as_slice_of_cells
221225
222- Similar to ` as_array_of_cells ` , ` ndd::NonDeDuplicated ` has function ` as_slice_of_cells ` . That
226+ Similar to ` as_array_of_cells ` , [ ` ndd::NonDeDuplicated ` ] has function ` as_slice_of_cells ` . That
223227** can** be stable with with Rust ` 1.88 ` +. However, to simplify versioning, it's bundled in
224- ` -nightly ` together with ` as_array_of_cells ` . If you need it earlier, get in touch.
228+ ` -nightly ` together with ` as_array_of_cells ` . and may become stable at the same time. If you need it
229+ earlier, get in touch.
225230
226- #### const Deref and From
231+ ### const Deref and From
227232
228- [ core::ops::Deref] ( https://doc.rust-lang.org/nightly/core/ops/trait.Deref.html ) and
229- [ core::convert::From] ( https://doc.rust-lang.org/nightly/core/convert/trait.From.html ) are
230- implemented as ` const ` . As of mid 2025, ` const ` traits are having high traction in Rust. Hopefully
231- this will be stable not in years, but sooner.
233+ [ ` core::ops::Deref ` ] and [ ` core::convert::From ` ] are implemented as ` const ` . As of mid 2025, ` const `
234+ traits are having high traction in Rust. Hopefully this will be stable not in years, but sooner.
232235
233236These traits are ** not** implemented in stable versions at all. Why? Because ` ndd ` types are
234237intended for ` static ` variables, so non-` const ` functions don't help us.
235238
236- ## Quality
239+ # Quality assurance
237240
238- Checks and tests are run by [ GitHub Actions (CI) ] ( .github/workflows/main.yml ) . All scripts run on
239- Alpine Linux and are POSIX-compliant:
241+ Checks and tests are run by [ GitHub Actions] , which uses ` rust:1.87-alpine ` container. All scripts
242+ run on Alpine Linux (without ` libc ` ) and are POSIX-compliant:
240243
241244- ` cargo clippy `
242245- ` cargo fmt --check `
@@ -276,25 +279,52 @@ Alpine Linux and are POSIX-compliant:
276279 - ` cross_crate_demo_fix/bin_fat_lto/not_deduplicated.sh release const_option_u8 `
277280 - ` cross_crate_demo_fix/bin_fat_lto/not_deduplicated.sh dev const_bytes `
278281 - ` cross_crate_demo_fix/bin_fat_lto/not_deduplicated.sh release const_bytes `
279- - validate the versioning convention :
280- - [ ` pre-commit ` ] ( ./pre-commit )
282+ - validate the versioning schema :
283+ - [ ` pre-commit ` ]
281284
282- ## Use cases
285+ # Use cases
283286
284287Used by
285288[ ` hash-injector::signal ` ] ( https://github.com/peter-lyons-kehl/hash-injector/blob/main/lib/src/signal.rs ) .
286289
287- ## Updates
290+ # Updates
288291
289292Please subscribe for low frequency updates at
290- [ #2 ] ( https://github.com/peter-lyons-kehl/ndd/issues/2 ) .
293+ [ peter-lyons-kehl/ndd/issues #2] ( https://github.com/peter-lyons-kehl/ndd/issues/2 ) .
291294
292- ## Side fruit
295+ # Side fruit
293296
294- The following side fruit is ` std ` -only, but related: ` std::sync::mutex::data_ptr(&self) ` is now
297+ The following side fruit is ` std ` -only, but related: ` std::sync::mutex::data_ptr(&self) ` is now a
295298` const ` function: pull request
296299[ rust-lang/rust #146904 ] ( https://github.com/rust-lang/rust/pull/146904 ) .
297300
301+ <!-- 1. Link URLs to be used on GitHub.
302+ 2. Relative links also work auto-magically on https://crates.io/crates/ndd.
303+ 3. Keep them in the same order as used above.
304+ -->
305+ [ `ndd::NonDeDuplicated` ] : https://docs.rs/ndd/latest/ndd/type.NonDeDuplicated.html
306+ [ `ndd::NonDeDuplicatedStr` ] : https://docs.rs/ndd/latest/ndd/type.NonDeDuplicatedStr.html
307+ [ `ndd::NonDeDuplicatedCStr` ] : https://docs.rs/ndd/latest/ndd/type.NonDeDuplicatedCStr.html
308+ [ `src/lib.rs` ] : src/lib.rs
309+ [ `cross_crate_demo_fix/callee/src/lib.rs` ] : cross_crate_demo_fix/callee/src/lib.rs
298310[ `core::ptr::eq` ] : https://doc.rust-lang.org/1.86.0/core/ptr/fn.eq.html
299311[ `core::ptr::addr_eq` ] : https://doc.rust-lang.org/1.86.0/core/ptr/fn.addr_eq.html
300- [ `src/lib.rs` -> `addresses_unique_between_statics()` ] : src/lib.rs#L246
312+ [ `src/lib.rs` -> `tests_without_ndd` -> `addresses_unique_between_statics()` ] : src/lib.rs#L269
313+ [ ` src/lib.rs ` -> ` tests_without_ndd ` -> ` u8_global_const_and_global_static_release() ` ] :
314+ src/lib.rs#L278
315+ [ `cross_crate_demo_bug/` ] : cross_crate_demo_bug/
316+ [ `core::cell::Cell` ] : https://doc.rust-lang.org/1.86.0/core/cell/struct.Cell.html
317+ [ `core::marker::Sync` ] : https://doc.rust-lang.org/1.86.0/core/marker/trait.Sync.html
318+ [ `core::marker::Send` ] : https://doc.rust-lang.org/1.86.0/core/marker/trait.Send.html
319+ [ ` std::sync::Mutex ` ] :
320+ https://doc.rust-lang.org/1.86.0/std/sync/struct.Mutex.html#impl-Sync-for-Mutex <T >
321+ [ `src/lib.rs` -> `tests_with_ndd` ] : src/lib.rs#L355
322+ [ `alloc` ] : https://doc.rust-lang.org/1.86.0/alloc/index.html
323+ [ `core::ops::Drop` ] : https://doc.rust-lang.org/1.86.0/core/ops/trait.Drop.html
324+ [ `pre-commit` ] : pre-commit
325+ [ GitHub Actions ] : .github/workflows/main.yml
326+ <!-- nightly-only: -->
327+ [ ` core::cell::Cell::as_array_of_cells ` ] :
328+ https://doc.rust-lang.org/nightly/core/cell/struct.Cell.html#method.as_array_of_cells
329+ [ `core::ops::Deref` ] : https://doc.rust-lang.org/nightly/core/ops/trait.Deref.html
330+ [ `core::convert::From` ] : https://doc.rust-lang.org/nightly/core/convert/trait.From.html
0 commit comments