@@ -8,6 +8,12 @@ use std::{
88pub struct ShuffleVec < T > {
99 vec : Vec < T > ,
1010 indices : Option < Vec < usize > > ,
11+ /// This is primarily necessary to ensure that shuffle does not behave out of place.
12+ ///
13+ /// For that reason we swap the first track with the currently playing track. By that we ensure
14+ /// that the shuffle state is consistent between resets of the state because the first track is
15+ /// always the track with which we started playing when switching to shuffle.
16+ original_first_position : Option < usize > ,
1117}
1218
1319impl < T : PartialEq > PartialEq for ShuffleVec < T > {
@@ -41,16 +47,25 @@ impl<T> IntoIterator for ShuffleVec<T> {
4147
4248impl < T > From < Vec < T > > for ShuffleVec < T > {
4349 fn from ( vec : Vec < T > ) -> Self {
44- Self { vec, indices : None }
50+ Self {
51+ vec,
52+ original_first_position : None ,
53+ indices : None ,
54+ }
4555 }
4656}
4757
4858impl < T > ShuffleVec < T > {
49- pub fn shuffle_with_seed ( & mut self , seed : u64 ) {
50- self . shuffle_with_rng ( SmallRng :: seed_from_u64 ( seed) )
59+ pub fn shuffle_with_seed < F : Fn ( & T ) -> bool > ( & mut self , seed : u64 , is_first : F ) {
60+ self . shuffle_with_rng ( SmallRng :: seed_from_u64 ( seed) , is_first )
5161 }
5262
53- pub fn shuffle_with_rng ( & mut self , mut rng : impl Rng ) {
63+ pub fn shuffle_with_rng < F : Fn ( & T ) -> bool > ( & mut self , mut rng : impl Rng , is_first : F ) {
64+ if self . vec . len ( ) <= 1 {
65+ info ! ( "skipped shuffling for less or equal one item" ) ;
66+ return ;
67+ }
68+
5469 if self . indices . is_some ( ) {
5570 self . unshuffle ( )
5671 }
@@ -66,7 +81,12 @@ impl<T> ShuffleVec<T> {
6681 self . vec . swap ( i, rnd_ind) ;
6782 }
6883
69- self . indices = Some ( indices)
84+ self . indices = Some ( indices) ;
85+
86+ self . original_first_position = self . vec . iter ( ) . position ( is_first) ;
87+ if let Some ( first_pos) = self . original_first_position {
88+ self . vec . swap ( 0 , first_pos)
89+ }
7090 }
7191
7292 pub fn unshuffle ( & mut self ) {
@@ -75,9 +95,16 @@ impl<T> ShuffleVec<T> {
7595 None => return ,
7696 } ;
7797
98+ if let Some ( first_pos) = self . original_first_position {
99+ self . vec . swap ( 0 , first_pos) ;
100+ self . original_first_position = None ;
101+ }
102+
78103 for i in 1 ..self . vec . len ( ) {
79- let n = indices[ self . vec . len ( ) - i - 1 ] ;
80- self . vec . swap ( n, i) ;
104+ match indices. get ( self . vec . len ( ) - i - 1 ) {
105+ None => return ,
106+ Some ( n) => self . vec . swap ( * n, i) ,
107+ }
81108 }
82109 }
83110}
@@ -86,25 +113,86 @@ impl<T> ShuffleVec<T> {
86113mod test {
87114 use super :: * ;
88115 use rand:: Rng ;
116+ use std:: ops:: Range ;
89117
90- #[ test]
91- fn test_shuffle_with_seed ( ) {
92- let seed = rand:: rng ( ) . random_range ( 0 ..10000000000000 ) ;
118+ fn base ( range : Range < usize > ) -> ( ShuffleVec < usize > , u64 ) {
119+ let seed = rand:: rng ( ) . random_range ( 0 ..10_000_000_000_000 ) ;
93120
94- let vec = ( 0 ..100 ) . collect :: < Vec < _ > > ( ) ;
95- let base_vec: ShuffleVec < i32 > = vec. into ( ) ;
121+ let vec = range. collect :: < Vec < _ > > ( ) ;
122+ ( vec. into ( ) , seed)
123+ }
124+
125+ #[ test]
126+ fn test_shuffle_without_first ( ) {
127+ let ( base_vec, seed) = base ( 0 ..100 ) ;
96128
97129 let mut shuffled_vec = base_vec. clone ( ) ;
98- shuffled_vec. shuffle_with_seed ( seed) ;
130+ shuffled_vec. shuffle_with_seed ( seed, |_| false ) ;
99131
100132 let mut different_shuffled_vec = base_vec. clone ( ) ;
101- different_shuffled_vec. shuffle_with_seed ( seed) ;
133+ different_shuffled_vec. shuffle_with_seed ( seed, |_| false ) ;
102134
103- assert_eq ! ( shuffled_vec, different_shuffled_vec) ;
135+ assert_eq ! (
136+ shuffled_vec, different_shuffled_vec,
137+ "shuffling with the same seed has the same result"
138+ ) ;
104139
105140 let mut unshuffled_vec = shuffled_vec. clone ( ) ;
106141 unshuffled_vec. unshuffle ( ) ;
107142
108- assert_eq ! ( base_vec, unshuffled_vec) ;
143+ assert_eq ! (
144+ base_vec, unshuffled_vec,
145+ "unshuffle restores the original state"
146+ ) ;
147+ }
148+
149+ #[ test]
150+ fn test_shuffle_with_first ( ) {
151+ const MAX_RANGE : usize = 200 ;
152+
153+ let ( base_vec, seed) = base ( 0 ..MAX_RANGE ) ;
154+ let rand_first = rand:: rng ( ) . random_range ( 0 ..MAX_RANGE ) ;
155+
156+ let mut shuffled_with_first = base_vec. clone ( ) ;
157+ shuffled_with_first. shuffle_with_seed ( seed, |i| i == & rand_first) ;
158+
159+ assert_eq ! (
160+ Some ( & rand_first) ,
161+ shuffled_with_first. first( ) ,
162+ "after shuffling the first is expected to be the given item"
163+ ) ;
164+
165+ let mut shuffled_without_first = base_vec. clone ( ) ;
166+ shuffled_without_first. shuffle_with_seed ( seed, |_| false ) ;
167+
168+ let mut switched_positions = Vec :: with_capacity ( 2 ) ;
169+ for ( i, without_first_value) in shuffled_without_first. iter ( ) . enumerate ( ) {
170+ if without_first_value != & shuffled_with_first[ i] {
171+ switched_positions. push ( i) ;
172+ } else {
173+ assert_eq ! (
174+ without_first_value, & shuffled_with_first[ i] ,
175+ "shuffling with the same seed has the same result"
176+ ) ;
177+ }
178+ }
179+
180+ assert_eq ! (
181+ switched_positions. len( ) ,
182+ 2 ,
183+ "only the switched positions should be different"
184+ ) ;
185+
186+ assert_eq ! (
187+ shuffled_with_first[ switched_positions[ 0 ] ] ,
188+ shuffled_without_first[ switched_positions[ 1 ] ] ,
189+ "the switched values should be equal"
190+ ) ;
191+
192+ assert_eq ! (
193+ shuffled_with_first[ switched_positions[ 1 ] ] ,
194+ shuffled_without_first[ switched_positions[ 0 ] ] ,
195+ "the switched values should be equal"
196+ )
109197 }
110198}
0 commit comments