Skip to content

Commit 1fce070

Browse files
authored
Rename extern_item_impls opt-in backend to extern_impl (#794)
Additionally refactors the custom implementation tests and exposes the `implementation` module in docs generated for docs.rs.
1 parent 887775d commit 1fce070

File tree

13 files changed

+155
-142
lines changed

13 files changed

+155
-142
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ jobs:
269269
targets: riscv32i-unknown-none-elf
270270
- uses: Swatinem/rust-cache@v2
271271
- env:
272-
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="custom"
272+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="unsupported"
273273
run: cargo build --target riscv32i-unknown-none-elf
274274

275275
unsupported:

.github/workflows/tests.yml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ jobs:
7878
RUSTDOCFLAGS: -Dwarnings --cfg getrandom_backend="rdrand"
7979
run: cargo test --features=std,sys_rng
8080

81-
extern_item_impls:
82-
name: Extern Item Implementations
81+
custom_impl:
82+
name: Custom and External Implementations
8383
runs-on: ubuntu-24.04
8484
steps:
8585
- uses: actions/checkout@v6
@@ -88,9 +88,13 @@ jobs:
8888
toolchain: nightly
8989
- uses: Swatinem/rust-cache@v2
9090
- env:
91-
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="extern_item_impls"
92-
RUSTDOCFLAGS: -Dwarnings --cfg getrandom_backend="extern_item_impls"
93-
run: cargo test --features=std --test mod extern_item_impls
91+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="custom"
92+
working_directory: custom_impl_test
93+
run: cargo test
94+
- env:
95+
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="extern_impl"
96+
working_directory: custom_impl_test
97+
run: cargo test
9498

9599
ios:
96100
name: iOS Simulator

.github/workflows/workspace.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ jobs:
114114
- uses: Swatinem/rust-cache@v2
115115
- name: Generate Docs
116116
env:
117-
RUSTDOCFLAGS: "-Dwarnings --cfg docsrs"
117+
RUSTDOCFLAGS: -Dwarnings --cfg docsrs --cfg getrandom_backend="extern_impl"
118118
run: cargo doc --no-deps --features std,sys_rng
119119

120120
typos:

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
**/*.rs.bk
33
nopanic_check/Cargo.lock
44
nopanic_check/target/
5+
custom_impl_test/Cargo.lock
6+
custom_impl_test/target/

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
- `RawOsError` type alias [#739]
1111
- `SysRng` behind new feature `sys_rng` [#751]
1212
- WASIp3 support [#779]
13+
- `extern_impl` opt-in backend [#786] [#794]
1314
- Motor OS support [#797]
1415

1516
### Changed
@@ -19,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1920
[#749]: https://github.com/rust-random/getrandom/pull/749
2021
[#751]: https://github.com/rust-random/getrandom/pull/751
2122
[#779]: https://github.com/rust-random/getrandom/pull/779
23+
[#786]: https://github.com/rust-random/getrandom/pull/786
24+
[#794]: https://github.com/rust-random/getrandom/pull/794
2225

2326
## [0.3.4] - 2025-10-14
2427

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ exclude = [".*"]
1313

1414
[package.metadata.docs.rs]
1515
features = ["std", "sys_rng"]
16+
rustdoc-args = ["--cfg getrandom_backend=\"extern_impl\""]
1617

1718
[features]
1819
# Implement From<getrandom::Error> for std::io::Error and
@@ -94,7 +95,7 @@ wasm-bindgen-test = "0.3"
9495
[lints.rust.unexpected_cfgs]
9596
level = "warn"
9697
check-cfg = [
97-
'cfg(getrandom_backend, values("custom", "efi_rng", "rdrand", "rndr", "linux_getrandom", "linux_raw", "windows_legacy", "unsupported", "extern_item_impls"))',
98+
'cfg(getrandom_backend, values("custom", "efi_rng", "rdrand", "rndr", "linux_getrandom", "linux_raw", "windows_legacy", "unsupported", "extern_impl"))',
9899
'cfg(getrandom_msan)',
99100
'cfg(getrandom_test_linux_fallback)',
100101
'cfg(getrandom_test_linux_without_fallback)',

README.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ of randomness based on their specific needs:
110110
| `windows_legacy` | Windows | `*-windows-*` | [`RtlGenRandom`]
111111
| `custom` | All targets | `*` | User-provided custom implementation (see [custom backend])
112112
| `unsupported` | All targets | `*` | Always returns `Err(Error::UNSUPPORTED)` (see [unsupported backend])
113-
| `extern_item_impls` | All targets | `*` | User or library provided custom implementation (see [externally implemented interface])
113+
| `extern_impl` | All targets | `*` | Externally-provided custom implementation (see [externally implemented interface])
114114

115115
Opt-in backends can be enabled using the `getrandom_backend` configuration flag.
116116
The flag can be set either by specifying the `rustflags` field in [`.cargo/config.toml`]:
@@ -205,17 +205,18 @@ unsafe extern "Rust" fn __getrandom_v03_custom(
205205

206206
### Externally Implemented Interface
207207

208-
Using the nightly-only feature [`extern_item_impls`](https://github.com/rust-lang/rust/issues/125418)
209-
it is possible to provide a custom backend for `getrandom`, even to override
210-
an existing first-party implementation. First, enable the `extern_item_impls`
211-
opt-in backend to allow usage of this nightly feature. Then, you may provide
212-
implementations for `fill_uninit`, `u32`, and/or `u64` with an attribute macro
213-
from the `implementation` module.
208+
Using the nightly-only feature [`extern_item_impls`] it is possible to provide
209+
a custom backend for `getrandom`, even to override an existing first-party implementation.
210+
First, enable the `extern_impl` opt-in backend to allow usage of this nightly feature.
211+
Then, you may provide implementations for `fill_uninit`, `u32`, and/or `u64`
212+
with an attribute macro from the `implementation` module.
213+
214+
[`extern_item_impls`]: https://github.com/rust-lang/rust/issues/125418
214215

215216
```rust
216217
use core::mem::MaybeUninit;
217218

218-
#[cfg(getrandom_backend = "extern_item_impls")]
219+
#[cfg(getrandom_backend = "extern_impl")]
219220
#[getrandom::implementation::fill_uninit]
220221
fn my_fill_uninit_implementation(
221222
dest: &mut [MaybeUninit<u8>]

custom_impl_test/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "custom_impl_test"
3+
description = "Helper crate for testing custom implementations"
4+
version = "0.1.0"
5+
edition = "2024"
6+
publish = false
7+
8+
[workspace]
9+
10+
[dependencies]
11+
getrandom = { path = ".." }
12+
13+
[lints.rust.unexpected_cfgs]
14+
level = "warn"
15+
check-cfg = [
16+
'cfg(getrandom_backend, values("custom", "extern_impl"))',
17+
]

custom_impl_test/src/lib.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use core::mem::MaybeUninit;
2+
use getrandom::Error;
3+
4+
/// Chosen by fair dice roll.
5+
const SEED: u64 = 0x9095_810F_1B2B_E175;
6+
7+
struct Xoshiro128PlusPlus {
8+
s: [u32; 4],
9+
}
10+
11+
impl Xoshiro128PlusPlus {
12+
fn new(mut seed: u64) -> Self {
13+
const PHI: u64 = 0x9e3779b97f4a7c15;
14+
let mut s = [0u32; 4];
15+
for val in s.iter_mut() {
16+
seed = seed.wrapping_add(PHI);
17+
let mut z = seed;
18+
z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
19+
z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
20+
z = z ^ (z >> 31);
21+
*val = z as u32;
22+
}
23+
Self { s }
24+
}
25+
26+
fn next_u32(&mut self) -> u32 {
27+
let res = self.s[0]
28+
.wrapping_add(self.s[3])
29+
.rotate_left(7)
30+
.wrapping_add(self.s[0]);
31+
32+
let t = self.s[1] << 9;
33+
34+
self.s[2] ^= self.s[0];
35+
self.s[3] ^= self.s[1];
36+
self.s[1] ^= self.s[2];
37+
self.s[0] ^= self.s[3];
38+
39+
self.s[2] ^= t;
40+
41+
self.s[3] = self.s[3].rotate_left(11);
42+
43+
res
44+
}
45+
}
46+
47+
pub fn custom_impl(dst: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
48+
let mut rng = Xoshiro128PlusPlus::new(SEED);
49+
50+
let mut chunks = dst.chunks_exact_mut(4);
51+
for chunk in &mut chunks {
52+
let val = rng.next_u32();
53+
let dst_ptr = chunk.as_mut_ptr().cast::<u32>();
54+
unsafe { core::ptr::write_unaligned(dst_ptr, val) };
55+
}
56+
let rem = chunks.into_remainder();
57+
if !rem.is_empty() {
58+
let val = rng.next_u32();
59+
let src_ptr = &val as *const u32 as *const MaybeUninit<u8>;
60+
assert!(rem.len() <= 4);
61+
unsafe { core::ptr::copy(src_ptr, rem.as_mut_ptr(), rem.len()) };
62+
}
63+
Ok(())
64+
}
65+
66+
#[cfg(getrandom_backend = "custom")]
67+
#[unsafe(no_mangle)]
68+
unsafe extern "Rust" fn __getrandom_v03_custom(dst_ptr: *mut u8, len: usize) -> Result<(), Error> {
69+
let dst = unsafe { core::slice::from_raw_parts_mut(dst_ptr.cast(), len) };
70+
custom_impl(dst)
71+
}
72+
73+
#[cfg(getrandom_backend = "extern_impl")]
74+
#[getrandom::implementation::fill_uninit]
75+
fn my_fill_uninit_implementation(dst: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
76+
custom_impl(dst)
77+
}
78+
79+
#[test]
80+
fn test_custom_fill() {
81+
let mut buf1 = [0u8; 256];
82+
getrandom::fill(&mut buf1).unwrap();
83+
84+
let mut buf2 = [0u8; 256];
85+
custom_impl(unsafe { core::slice::from_raw_parts_mut(buf2.as_mut_ptr().cast(), buf2.len()) })
86+
.unwrap();
87+
88+
assert_eq!(buf1, buf2);
89+
}
90+
91+
#[test]
92+
fn test_custom_u32() {
93+
let res = getrandom::u32().unwrap();
94+
assert_eq!(res, 0xEAD5_840A);
95+
}
96+
97+
#[test]
98+
fn test_custom_u64() {
99+
let res = getrandom::u64().unwrap();
100+
assert_eq!(res, 0xA856_FCC4_EAD5_840A);
101+
}

src/backends.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ cfg_if! {
3232
} else if #[cfg(getrandom_backend = "unsupported")] {
3333
mod unsupported;
3434
pub use unsupported::*;
35-
} else if #[cfg(getrandom_backend = "extern_item_impls")] {
36-
pub(crate) mod extern_item_impls;
37-
pub use extern_item_impls::*;
35+
} else if #[cfg(getrandom_backend = "extern_impl")] {
36+
pub(crate) mod extern_impl;
37+
pub use extern_impl::*;
3838
} else if #[cfg(all(target_os = "linux", target_env = ""))] {
3939
mod linux_raw;
4040
pub use linux_raw::*;

0 commit comments

Comments
 (0)