Skip to content

Commit 9ddb97a

Browse files
authored
Specify output order of fn partial_shuffle; add #[must_use] (#1769)
- [x] Added a `CHANGELOG.md` entry See discussion in #1768.
2 parents c95d323 + 02aa1ef commit 9ddb97a

3 files changed

Lines changed: 37 additions & 18 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ A [separate changelog is kept for rand_core](https://github.com/rust-random/core
88

99
You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.
1010

11+
## [Unreleased]
12+
13+
### Changes
14+
- Document required output order of fn `partial_shuffle` and apply `#[must_use]` ([#1769])
15+
16+
[#1769]: https://github.com/rust-random/rand/pull/1769
17+
1118
## [0.10.1] — 2026-02-11
1219
This release includes a fix for a soundness bug; see [#1763].
1320

@@ -1156,7 +1163,7 @@ Code replaced with a compatibility layer over rand 0.4.
11561163
### Added
11571164
- Separate `rand` out of the standard library
11581165

1159-
[Unreleased]: https://github.com/rust-random/rand/compare/0.10.0...HEAD
1166+
[Unreleased]: https://github.com/rust-random/rand/compare/0.10.1...HEAD
11601167
[0.10.1]: https://github.com/rust-random/rand/compare/0.10.0...0.10.1
11611168
[0.10.0]: https://github.com/rust-random/rand/compare/0.9.2...0.10.0
11621169
[0.9.2]: https://github.com/rust-random/rand/compare/0.9.1...0.9.2

benches/benches/shuffle.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ fn bench_rng<R: Rng + SeedableRng>(c: &mut Criterion, rng_name: &'static str) {
5252
let mut rng = R::seed_from_u64(123);
5353
let mut vec: Vec<usize> = (0..length).collect();
5454
b.iter(|| {
55-
vec.partial_shuffle(&mut rng, length / 2);
55+
let _ = vec.partial_shuffle(&mut rng, length / 2);
5656
vec[0]
5757
})
5858
});

src/seq/slice.rs

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -420,23 +420,35 @@ pub trait SliceRandom: IndexedMutRandom {
420420
where
421421
R: Rng + ?Sized;
422422

423-
/// Shuffle a slice in place, but exit early.
423+
/// Sample `amount` shuffled elements
424424
///
425-
/// Returns two mutable slices from the source slice. The first contains
426-
/// `amount` elements randomly permuted. The second has the remaining
427-
/// elements that are not fully shuffled.
425+
/// Shuffles `amount` random elements into the end of the slice (`n..` where
426+
/// `n = self.len() - amount`). The rest of the slice (`..n`) contains the
427+
/// remaining elements in a permuted but not fully shuffled order.
428+
///
429+
/// Returns a tuple of the sampled elements (`&mut self[n..]`) and the
430+
/// remaining elements (`&mut self[..n]`).
428431
///
429432
/// This is an efficient method to select `amount` elements at random from
430433
/// the slice, provided the slice may be mutated.
431434
///
432-
/// If you only need to choose elements randomly and `amount > self.len()/2`
433-
/// then you may improve performance by taking
434-
/// `amount = self.len() - amount` and using only the second slice.
435+
/// For slices, complexity is `O(m)` where `m = amount`.
436+
/// If `amount >= self.len()` this is equivalent to [`Self::shuffle`].
435437
///
436-
/// If `amount` is greater than the number of elements in the slice, this
437-
/// will perform a full shuffle.
438+
/// # Example
438439
///
439-
/// For slices, complexity is `O(m)` where `m = amount`.
440+
/// ```
441+
/// use rand::seq::SliceRandom;
442+
///
443+
/// let mut rng = rand::rng();
444+
/// let mut y = [1, 2, 3, 4, 5];
445+
/// let (shuffled, rest) = y.partial_shuffle(&mut rng, 3);
446+
/// assert_eq!(shuffled.len(), 3);
447+
/// assert_eq!(rest.len(), 2);
448+
/// let sampled = shuffled.to_vec();
449+
/// assert_eq!(&sampled, &y[2..5]);
450+
/// ```
451+
#[must_use]
440452
fn partial_shuffle<R>(
441453
&mut self,
442454
rng: &mut R,
@@ -464,14 +476,14 @@ impl<T> SliceRandom for [T] {
464476
// There is no need to shuffle an empty or single element slice
465477
return;
466478
}
467-
self.partial_shuffle(rng, self.len());
479+
let _ = self.partial_shuffle(rng, self.len());
468480
}
469481

470482
fn partial_shuffle<R>(&mut self, rng: &mut R, amount: usize) -> (&mut [T], &mut [T])
471483
where
472484
R: Rng + ?Sized,
473485
{
474-
let m = self.len().saturating_sub(amount);
486+
let n = self.len().saturating_sub(amount);
475487

476488
// The algorithm below is based on Durstenfeld's algorithm for the
477489
// [Fisher–Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm)
@@ -483,18 +495,18 @@ impl<T> SliceRandom for [T] {
483495
// but only works for 32 bit integers
484496
// So we must use the slow method if the slice is longer than that.
485497
if self.len() < (u32::MAX as usize) {
486-
let mut chooser = IncreasingUniform::new(rng, m as u32);
487-
for i in m..self.len() {
498+
let mut chooser = IncreasingUniform::new(rng, n as u32);
499+
for i in n..self.len() {
488500
let index = chooser.next_index();
489501
self.swap(i, index);
490502
}
491503
} else {
492-
for i in m..self.len() {
504+
for i in n..self.len() {
493505
let index = rng.random_range(..i + 1);
494506
self.swap(i, index);
495507
}
496508
}
497-
let r = self.split_at_mut(m);
509+
let r = self.split_at_mut(n);
498510
(r.1, r.0)
499511
}
500512
}

0 commit comments

Comments
 (0)