sql_splitter/redactor/strategy/
shuffle.rs1use super::{RedactValue, Strategy, StrategyKind};
10use rand::seq::SliceRandom;
11
12#[derive(Debug, Clone, Default)]
14pub struct ShuffleStrategy {
15 values: Vec<RedactValue>,
17 shuffled: Vec<RedactValue>,
19 index: usize,
21}
22
23impl ShuffleStrategy {
24 pub fn new() -> Self {
25 Self::default()
26 }
27
28 pub fn collect(&mut self, value: RedactValue) {
30 self.values.push(value);
31 }
32
33 pub fn shuffle(&mut self, rng: &mut impl rand::Rng) {
35 self.shuffled = self.values.clone();
36 self.shuffled.shuffle(rng);
37 self.index = 0;
38 }
39
40 pub fn next_value(&mut self) -> Option<RedactValue> {
42 if self.index < self.shuffled.len() {
43 let value = self.shuffled[self.index].clone();
44 self.index += 1;
45 Some(value)
46 } else {
47 None
48 }
49 }
50
51 pub fn len(&self) -> usize {
53 self.values.len()
54 }
55
56 pub fn is_empty(&self) -> bool {
58 self.values.is_empty()
59 }
60}
61
62impl Strategy for ShuffleStrategy {
63 fn apply(&self, value: &RedactValue, _rng: &mut dyn rand::RngCore) -> RedactValue {
64 value.clone()
75 }
76
77 fn kind(&self) -> StrategyKind {
78 StrategyKind::Shuffle
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use rand::SeedableRng;
86
87 #[test]
88 fn test_shuffle_strategy() {
89 let mut strategy = ShuffleStrategy::new();
90 let mut rng = rand::rngs::StdRng::seed_from_u64(42);
91
92 strategy.collect(RedactValue::Integer(1));
94 strategy.collect(RedactValue::Integer(2));
95 strategy.collect(RedactValue::Integer(3));
96 strategy.collect(RedactValue::Integer(4));
97 strategy.collect(RedactValue::Integer(5));
98
99 assert_eq!(strategy.len(), 5);
100
101 strategy.shuffle(&mut rng);
103
104 let mut results = Vec::new();
106 while let Some(v) = strategy.next_value() {
107 results.push(v);
108 }
109
110 assert_eq!(results.len(), 5);
111
112 let mut ints: Vec<i64> = results
114 .iter()
115 .map(|v| match v {
116 RedactValue::Integer(i) => *i,
117 _ => panic!("Expected Integer"),
118 })
119 .collect();
120 ints.sort();
121 assert_eq!(ints, vec![1, 2, 3, 4, 5]);
122 }
123
124 #[test]
125 fn test_shuffle_with_nulls() {
126 let mut strategy = ShuffleStrategy::new();
127 let mut rng = rand::rngs::StdRng::seed_from_u64(42);
128
129 strategy.collect(RedactValue::String("a".to_string()));
130 strategy.collect(RedactValue::Null);
131 strategy.collect(RedactValue::String("b".to_string()));
132
133 strategy.shuffle(&mut rng);
134
135 let mut null_count = 0;
136 let mut string_count = 0;
137
138 while let Some(v) = strategy.next_value() {
139 match v {
140 RedactValue::Null => null_count += 1,
141 RedactValue::String(_) => string_count += 1,
142 _ => {}
143 }
144 }
145
146 assert_eq!(null_count, 1);
147 assert_eq!(string_count, 2);
148 }
149}