1
2use std::{
3 collections::hash_map::DefaultHasher,
4 env,
5 ffi::CString,
6 fmt::Debug,
7 fs::{read, write},
8 hash::{Hash, Hasher},
9 io,
10 iter::FromIterator,
11 mem::{forget, size_of, size_of_val},
12 ops::{Deref, DerefMut},
13 slice,
14 path::PathBuf,
15 thread::sleep,
16 time::Duration,
17};
18use rand::prelude::*;
19
20#[derive(Debug)]
22pub struct CStringArray {
23 strings: Vec<CString>,
24 cstrarr: Vec<*const i8>,
25}
26
27impl CStringArray {
28 pub fn new<T>(input: &[T]) -> Self
30 where
31 T: Clone + Into<Vec<u8>> {
32 let strings: Vec<CString> = input.iter().map(|s|CString::new(s.clone()).unwrap()).collect();
33 let cstrarr: Vec<*const i8> = strings.iter().map(|s|s.as_ptr()).collect();
34 Self {
35 strings,
36 cstrarr,
37 }
38 }
39
40 pub fn len(&self) -> usize {
42 self.strings.len()
43 }
44
45 pub fn is_empty(&self) -> bool {
47 self.strings.is_empty()
48 }
49
50 pub fn as_ptr(&self) -> *const *const i8 {
52 self.cstrarr.as_ptr()
53 }
54}
55
56impl<'a> FromIterator<&'a String> for CStringArray {
57 fn from_iter<T>(input: T) -> Self
58 where
59 T: IntoIterator<Item = &'a String> {
60 let strings: Vec<CString> = input.into_iter().map(|s|CString::new(s.clone()).unwrap()).collect();
61 let cstrarr: Vec<*const i8> = strings.iter().map(|s|s.as_ptr()).collect();
62 Self {
63 strings,
64 cstrarr,
65 }
66 }
67}
68
69impl Clone for CStringArray {
70 fn clone(&self) -> Self {
71 let strings = self.strings.clone();
72 let cstrarr: Vec<*const i8> = strings.iter().map(|s|s.as_ptr()).collect();
73 Self {
74 strings,
75 cstrarr,
76 }
77 }
78}
79
80pub fn random_sleep<R: Rng>(max_nanos: u64, rng: &mut R) {
82 let sleep_nanos = rng.random_range(0..max_nanos);
83 let secs = sleep_nanos / 1000000000;
84 let nanos = (sleep_nanos % 1000000000) as u32;
85 sleep(Duration::new(secs, nanos));
86}
87
88#[derive(Debug)]
90pub enum SpinError<E: Debug> {
91 SpinFail,
93
94 OtherError(E)
96}
97
98pub fn spin_work_with_exp_backoff<T, E: Debug, W: FnMut() -> Result<T, SpinError<E>>>(mut spin_func: W, max_sleep_nanos: u64) -> Result<T, E> {
99 let mut sleep_nanos = 1000;
100 let mut rng = SmallRng::from_os_rng();
101 loop {
102 match spin_func() {
103 Ok(r) => return Ok(r),
104 Err(e) => match e {
105 SpinError::SpinFail => {}
106 SpinError::OtherError(e) => return Err(e),
107 }
108 }
109 random_sleep(sleep_nanos, &mut rng);
110 if sleep_nanos < max_sleep_nanos {
111 sleep_nanos = (sleep_nanos * 3) >> 1;
112 }
113 }
114}
115
116#[derive(Debug)]
118pub struct ResourceGuard<R, D: Fn(&R)> {
119 resource: Option<R>,
120 destroyer: D,
121}
122
123impl<R, D: Fn(&R)> ResourceGuard<R, D> {
124 pub fn new(resource: R, destroyer: D) -> Self {
126 Self {
127 resource: Some(resource),
128 destroyer,
129 }
130 }
131
132 pub fn release(mut self) -> R {
134 self.resource.take().unwrap()
135 }
136}
137
138impl<R, D: Fn(&R)> Deref for ResourceGuard<R, D> {
139 type Target = R;
140 fn deref(&self) -> &R {
141 self.resource.as_ref().unwrap()
142 }
143}
144
145impl<R, D: Fn(&R)> DerefMut for ResourceGuard<R, D> {
146 fn deref_mut(&mut self) -> &mut R {
147 self.resource.as_mut().unwrap()
148 }
149}
150
151impl<R, D: Fn(&R)> Drop for ResourceGuard<R, D> {
152 fn drop(&mut self) {
153 if let Some(resource) = &self.resource {
154 (self.destroyer)(resource);
155 }
156 }
157}
158
159pub fn get_hashed_cache_file_path(cache_usage: &str, extension: Option<&str>) -> PathBuf {
161 let exe_path = env::current_exe().unwrap_or(PathBuf::from(env!("CARGO_PKG_NAME")));
162 let mut hasher = DefaultHasher::new();
163 exe_path.to_string_lossy().to_string().hash(&mut hasher);
164 cache_usage.hash(&mut hasher);
165 let hash = hasher.finish();
166 let mut path = std::env::temp_dir();
167 path.push(format!("{hash}"));
168 path.set_extension(extension.unwrap_or("tmp"));
169 path
170}
171
172pub fn load_cache<T: Clone + Copy + Sized>(cache_usage: &str, extension: Option<&str>) -> io::Result<Vec<T>> {
173 let path = get_hashed_cache_file_path(cache_usage, extension);
174 let mut data = read(&path)?;
175 let item_size = size_of::<T>();
176 let ptr = data.as_mut_ptr();
177 let len = data.len() / item_size;
178 let capacity = data.capacity() / item_size;
179 unsafe {
180 forget(data);
181 Ok(Vec::from_raw_parts(ptr as *mut T, len, capacity))
182 }
183}
184
185pub fn save_cache<T: Clone + Copy + Sized>(cache_usage: &str, extension: Option<&str>, data: &[T]) -> io::Result<()> {
186 let path = get_hashed_cache_file_path(cache_usage, extension);
187 let ptr = data.as_ptr() as *const u8;
188 let len = size_of_val(data);
189 let data: &[u8] = unsafe {slice::from_raw_parts(ptr, len)};
190 write(&path, data)
191}
192
193pub fn format_size(size: u64) -> String {
194 let eib = 1024 * 1024 * 1024 * 1024 * 1024;
195 let tib = 1024 * 1024 * 1024 * 1024;
196 let gib = 1024 * 1024 * 1024;
197 let mib = 1024 * 1024;
198 let kib = 1024;
199 if size >= eib {
200 format!("{:.3} EiB", size as f64 / eib as f64)
201 } else if size >= tib {
202 format!("{:.3} TiB", size as f64 / tib as f64)
203 } else if size >= gib {
204 format!("{:.3} GiB", size as f64 / gib as f64)
205 } else if size >= mib {
206 format!("{:.3} MiB", size as f64 / mib as f64)
207 } else if size >= kib {
208 format!("{:.3} KiB", size as f64 / kib as f64)
209 } else {
210 format!("{size} B")
211 }
212}