1use rand::rngs::SmallRng;
16use rand::{Rng, SeedableRng};
17
18const MIN_STRING_LENGTH: usize = 3;
19
20pub trait NexmarkRng {
21 fn gen_string(&mut self, max: usize) -> String;
22 fn gen_string_with_delimiter(&mut self, max: usize, delimiter: char) -> String;
23 fn gen_exact_string(&mut self, length: usize) -> String;
24 fn gen_next_extra(&mut self, current_size: usize, desired_average_size: usize) -> String;
25 fn gen_price(&mut self) -> usize;
26}
27
28impl NexmarkRng for SmallRng {
29 fn gen_string(&mut self, max: usize) -> String {
30 self.gen_exact_string(max)
31 }
32
33 fn gen_string_with_delimiter(&mut self, max: usize, delimiter: char) -> String {
34 let len = self.gen_range(MIN_STRING_LENGTH..max);
35 (0..len)
36 .map(|_| {
37 if self.gen_range(0..13) == 0 {
38 delimiter
39 } else {
40 self.gen_range(b'a'..=b'z') as char
41 }
42 })
43 .collect()
44 }
45
46 fn gen_exact_string(&mut self, length: usize) -> String {
47 (0..length)
48 .map(|_| self.gen_range(b'a'..=b'z') as char)
49 .collect()
50 }
51
52 fn gen_next_extra(&mut self, current_size: usize, desired_average_size: usize) -> String {
53 if current_size > desired_average_size {
54 return String::new();
55 }
56 let desired_average_size = desired_average_size - current_size;
57 let delta = (desired_average_size + 2) / 5;
58 let min_size = desired_average_size - delta;
59 let desired_size = min_size
60 + if delta == 0 {
61 0
62 } else {
63 self.gen_range(0..2 * delta)
64 };
65 self.gen_exact_string(desired_size)
66 }
67
68 fn gen_price(&mut self) -> usize {
69 (10.0_f32.powf((*self).gen::<f32>() * 6.0) * 100.0).round() as usize
70 }
71}
72
73pub fn get_base_url(seed: u64) -> String {
74 let mut rng = SmallRng::seed_from_u64(seed);
75 let id0 = rng.gen_string_with_delimiter(5, '_');
76 let id1 = rng.gen_string_with_delimiter(5, '_');
77 let id2 = rng.gen_string_with_delimiter(5, '_');
78 format!(
79 "https://www.nexmark.com/{}/{}/{}/item.htm?query=1",
80 id0, id1, id2
81 )
82}
83
84lazy_static::lazy_static! {
85 pub static ref CHANNEL_URL_MAP: Vec<(String, String)> = build_channel_url_map(CHANNEL_NUMBER);
86}
87
88const CHANNEL_NUMBER: usize = 10_000;
89
90fn build_channel_url_map(channel_number: usize) -> Vec<(String, String)> {
91 let mut ans = Vec::with_capacity(channel_number);
92 for i in 0..channel_number {
93 let mut url = get_base_url(i as u64);
94 let mut rng = SmallRng::seed_from_u64(i as u64);
95 if rng.gen_range(0..10) > 0 {
96 url.push_str("&channel_id=");
97 url.push_str(&i64::abs((i as i32).reverse_bits() as i64).to_string());
98 }
99 let channel = format!("channel-{}", i);
100 ans.push((channel, url));
101 }
102 ans
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn test_deterministic() {
111 let url1 = get_base_url(0);
112 let url2 = get_base_url(0);
113 assert_eq!(url1, url2);
114
115 let url3 = get_base_url(1);
116 let url4 = get_base_url(1);
117 assert_eq!(url3, url4);
118 assert_ne!(url3, url1);
119
120 let map0 = build_channel_url_map(100);
121 let map1 = build_channel_url_map(100);
122 assert_eq!(map0, map1);
123 }
124}