Skip to main content

litex/runtime/
runtime_generate_unused_names.rs

1use crate::prelude::*;
2use std::collections::HashSet;
3use std::time::{SystemTime, UNIX_EPOCH};
4
5impl Runtime {
6    fn generated_name_is_available_with_reserved(
7        &self,
8        candidate_name: &str,
9        reserved_names: &HashSet<String>,
10    ) -> bool {
11        if is_valid_litex_name(candidate_name).is_err() {
12            return false;
13        }
14        if reserved_names.contains(candidate_name) {
15            return false;
16        }
17        true
18    }
19
20    pub fn generate_one_unused_name_with_reserved(
21        &self,
22        reserved_names: &HashSet<String>,
23    ) -> String {
24        for i in 1..=4096usize {
25            let candidate_name = format!("x{}", i);
26            if self.generated_name_is_available_with_reserved(&candidate_name, reserved_names) {
27                return candidate_name;
28            }
29        }
30
31        let available_chars: Vec<char> = "abcdefghijklmnopqrstuvwxyz".chars().collect();
32        let first_char_candidates: Vec<char> = "abcdefghijklmnopqrstuvwxyz".chars().collect();
33        let mut try_index: usize = 0;
34        loop {
35            let current_time_nanos: u128 = match SystemTime::now().duration_since(UNIX_EPOCH) {
36                Ok(current_duration) => current_duration.as_nanos(),
37                Err(_) => 0,
38            };
39            let mixed_seed_value: u128 =
40                current_time_nanos ^ ((try_index as u128 + 1) * 0x9e3779b97f4a7c15u128);
41            let generated_name_length: usize = 8 + (mixed_seed_value as usize % 17);
42
43            let mut generated_chars: Vec<char> = Vec::new();
44            let first_char_index = ((mixed_seed_value >> 1) as usize) % first_char_candidates.len();
45            generated_chars.push(first_char_candidates[first_char_index]);
46
47            let mut current_state_value: u128 = mixed_seed_value;
48            for character_index in 1..generated_name_length {
49                current_state_value = current_state_value
50                    .wrapping_mul(6364136223846793005u128)
51                    .wrapping_add(1442695040888963407u128 + character_index as u128);
52                let available_char_index = (current_state_value as usize) % available_chars.len();
53                generated_chars.push(available_chars[available_char_index]);
54            }
55
56            let candidate_name: String = generated_chars.into_iter().collect();
57            if !self.generated_name_is_available_with_reserved(&candidate_name, reserved_names) {
58                try_index += 1;
59                continue;
60            }
61            return candidate_name;
62        }
63    }
64
65    pub fn generate_random_unused_names(&self, count: usize) -> Vec<String> {
66        let mut reserved_names: HashSet<String> = HashSet::with_capacity(count);
67        let mut generated_names: Vec<String> = Vec::with_capacity(count);
68        for _ in 0..count {
69            let generated_name = self.generate_one_unused_name_with_reserved(&reserved_names);
70            reserved_names.insert(generated_name.clone());
71            generated_names.push(generated_name);
72        }
73        generated_names
74    }
75
76    pub fn generate_random_unused_name(&self) -> String {
77        self.generate_one_unused_name_with_reserved(&HashSet::new())
78    }
79}