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