nexmark/
utils.rs

1// Copyright 2023 Singularity Data
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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}