cgl_rs/
utils.rs

1//! This module contains CGL utility functions, as well some miscellaneous functions.
2
3#![allow(non_camel_case_types)]
4use std::{ops::{Add, Sub, Mul, Div}, ffi::CString};
5
6use libc::{c_void, c_int, c_char, c_float, size_t};
7
8extern {
9    fn CGL_utils_sleep(milis: size_t) -> c_void;
10    fn CGL_utils_read_file(path: *const c_char, size: *mut size_t) -> *mut c_char;
11    fn CGL_utils_get_file_size(path: *const c_char) -> size_t;
12    fn CGL_utils_append_file(path: *const c_char, data: *const c_char, size: size_t) -> c_int;
13    fn CGL_utils_write_file(path: *const c_char, data: *const c_char, size: size_t) -> c_int;
14    fn CGL_utils_get_time() -> c_float;
15    fn CGL_utils_get_timestamp(buffer: *mut c_char) -> c_void;
16    fn CGL_utils_is_little_endian() -> c_int;
17    fn CGL_utils_get_random_with_probability(probabilities: *mut c_float, count: size_t) -> size_t;
18    fn CGL_utils_reverse_bytes(data: *mut c_void, size: size_t) -> c_void;
19    fn CGL_utils_little_endian_to_current(data: *mut c_void, size: size_t) -> c_void;
20    fn CGL_utils_big_endian_to_current(data: *mut c_void, size: size_t) -> c_void;
21    fn CGL_utils_fast_srand(seed: c_int) -> c_void;
22    fn CGL_utils_fast_rand() -> c_int;
23    fn CGL_utils_xorshf96() -> u64;
24    fn CGL_utils_srand31(seed: u32) -> c_void;
25    fn CGL_utils_rand31() -> u32;
26
27    fn CGL_utils_crc32(data: *const c_void, size: size_t) -> u32;
28    fn CGL_utils_crc64(data: *const c_void, size: size_t) -> u64;
29    fn CGL_utils_rot13(data_in: *const c_char, data_out: *mut c_char) -> c_void;
30    fn CGL_utils_super_fast_hash(data: *const c_void, size: size_t) -> u32;
31
32    /// These are originally CGL Macros but have been proxied here as functions.
33    fn CGL_utils_random_float_MACRO() -> c_float;
34    fn CGL_utils_random_float_in_range_MACRO(min_val: c_float, max_val: c_float) -> c_float;
35    fn CGL_utils_random_int_MACRO(min_val: c_int, max_val: c_int) -> c_int;
36    fn CGL_utils_random_bool_MACRO() -> c_int;
37}
38
39
40/// Suspends the current thread for the specified amount of time.
41///
42/// # Arguments
43///
44/// * `milis` - The amount of time to sleep, in milliseconds.
45/// 
46/// # Example
47/// 
48/// ```
49/// cgl_rs::utils::sleep(1000);
50/// ```
51pub fn sleep(milis: size_t) -> () {
52    unsafe {
53        CGL_utils_sleep(milis);
54    }
55}
56
57
58/// Reads the contents of a file and returns it as a vector of bytes.
59///
60/// # Arguments
61///
62/// * `path` - The path to the file to read.
63/// * `size` - A pointer to a size_t variable that will be set to the size of the file.
64///
65/// # Example
66///
67/// ```
68/// let (size, contents) = cgl_rs::utils::read_file("log.txt");
69/// ```
70pub fn read_file(path: &str) -> (usize, Vec<i8>) {
71    unsafe {
72        let mut size: size_t = 0;
73        let path = std::ffi::CString::new(path).unwrap();
74        let data = CGL_utils_read_file(path.as_ptr(), &mut size);
75        let mut vec = Vec::new();
76        for i in 0..size {
77            vec.push(*data.offset(i as isize));
78        }
79        libc::free(data as *mut c_void);
80        (size as usize, vec)
81    }
82}
83
84
85/// Reads the contents of a file and returns it as a string.
86///
87/// # Arguments
88///
89/// * `path` - The path to the file to read.
90///
91/// # Example
92///
93/// ```
94/// let contents = cgl_rs::utils::read_file_as_string("log.txt");
95/// ```
96pub fn read_file_as_string(path: &str) -> String {
97    let (size, data) = read_file(path);
98    let mut string = String::new();
99    for i in 0..size {
100        string.push(data[i] as u8 as char);
101    }
102    string
103}
104
105/// Returns the size of a file in bytes.
106///
107/// # Arguments
108///
109/// * `path` - The path to the file to get the size of.
110///
111/// # Example
112///
113/// ```no_run
114/// let path = "path/to/file";
115/// let size = cgl_rs::utils::get_file_size(path);
116/// ```
117pub fn get_file_size(path: &str) -> usize {
118    unsafe {
119        let path = std::ffi::CString::new(path).unwrap();
120        CGL_utils_get_file_size(path.as_ptr()) as usize
121    }
122}
123
124
125// Appends data to a file.
126///
127/// # Arguments
128///
129/// * `path` - The path to the file to append data to.
130/// * `data` - A slice of bytes to append to the file.
131/// * `size` - The size of the data slice.
132///
133/// # Example
134///
135/// ```
136/// let data = [1, 2, 3];
137/// let success = cgl_rs::utils::append_file("log.txt", &data, 3);
138/// ```
139pub fn append_file(path: &str, data: &[u8], size: usize) -> bool {
140    unsafe {
141        let path = std::ffi::CString::new(path).unwrap();
142        CGL_utils_write_file(path.as_ptr(), data.as_ptr() as *const c_char, size as size_t) != 0
143    }
144}
145
146
147/// Appends a string to a file.
148///
149/// # Arguments
150///
151/// * `path` - The path to the file to append the string to.
152/// * `data` - The string to append to the file.
153///
154/// # Example
155///
156/// ```
157/// let success = cgl_rs::utils::append_string_to_file("log.txt", "Hello, world!");
158/// ```
159pub fn append_string_to_file(path: &str, data: &str) -> bool {
160    append_file(path, data.as_bytes(), data.len())
161}
162
163
164// Writes data to a file.
165///
166/// # Arguments
167///
168/// * `path` - The path to the file to write data to.
169/// * `data` - A slice of bytes to write to the file.
170/// * `size` - The size of the data slice.
171///
172/// # Example
173///
174/// ```
175/// let data = [1, 2, 3];
176/// let success = cgl_rs::utils::write_file("log.txt", &data, 3);
177/// ```
178pub fn write_file(path: &str, data: &[u8], size: usize) -> bool {
179    unsafe {
180        let path = std::ffi::CString::new(path).unwrap();
181        CGL_utils_write_file(path.as_ptr(), data.as_ptr() as *const c_char, size as size_t) != 0
182    }
183}
184
185/// Writes a string to a file.
186///
187/// # Arguments
188///
189/// * `path` - The path to the file to write the string to.
190/// * `data` - The string to write to the file.
191///
192/// # Example
193///
194/// ```
195/// let success = cgl_rs::utils::write_string_to_file("log.txt", "Hello, world!");
196/// ```
197pub fn write_string_to_file(path: &str, data: &str) -> bool {
198    write_file(path, data.as_bytes(), data.len())
199}
200
201/// Returns the time in seconds since the program started.
202///
203/// # Returns
204///
205/// * A `f32` representing the current time in seconds.
206///
207/// # Example
208///
209/// ```
210/// let time = cgl_rs::utils::get_time();
211/// ```
212pub fn get_time() -> f32 {
213    unsafe {
214        CGL_utils_get_time() as f32
215    }
216}
217
218/// Returns a string representing the current timestamp.
219///
220/// # Returns
221///
222/// * A `String` representing the current timestamp.
223///
224/// # Example
225///
226/// ```
227/// let timestamp = cgl_rs::utils::get_timestamp();
228/// ```
229pub fn get_timestamp() -> String {
230    unsafe {
231        let mut buffer = [0 as c_char; 128];
232        CGL_utils_get_timestamp(buffer.as_mut_ptr());
233        std::ffi::CStr::from_ptr(buffer.as_ptr()).to_str().unwrap().to_string()
234    }
235}
236
237/// Returns a boolean indicating whether the system is little-endian or not.
238///
239/// # Returns
240///
241/// * A `bool` indicating whether the system is little-endian or not.
242///
243/// # Example
244///
245/// ```
246/// let is_little_endian = cgl_rs::utils::is_little_endian();
247/// ```
248pub fn is_little_endian() -> bool {
249    unsafe {
250        CGL_utils_is_little_endian() != 0
251    }
252}
253
254/// Returns a random index from the given slice of probabilities, where the probability of each index being chosen is proportional to its value in the slice.
255///
256/// # Arguments
257///
258/// * `probabilities` - A mutable slice of `f32` values representing the probabilities of each index being chosen.
259///
260/// # Returns
261///
262/// * A `usize` representing the randomly chosen index.
263///
264/// # Example
265///
266/// ```
267/// let mut probabilities = vec![0.1, 0.2, 0.3, 0.4];
268/// let index = cgl_rs::utils::get_random_with_probability(&mut probabilities);
269/// ```
270pub fn get_random_with_probability(probabilities: &mut [f32]) -> usize {
271    unsafe {
272        CGL_utils_get_random_with_probability(probabilities.as_mut_ptr(), probabilities.len() as size_t)
273    }
274}
275
276///
277/// Reverses the order of bytes in the given slice of `u8` values.
278///
279/// # Arguments
280///
281/// * `data` - A mutable slice of `u8` values to reverse.
282///
283/// # Example
284///
285/// ```
286/// let mut data = vec![0x12, 0x34, 0x56, 0x78];
287/// cgl_rs::utils::reverse_bytes(&mut data);
288/// assert_eq!(data, vec![0x78, 0x56, 0x34, 0x12]);
289/// ```
290pub fn reverse_bytes(data: &mut [u8]) -> () {
291    unsafe {
292        CGL_utils_reverse_bytes(data.as_mut_ptr() as *mut c_void, data.len() as size_t);
293    }
294}
295
296/// Converts a slice of `u8` values from little-endian byte order to the system's native byte order.
297///
298/// # Arguments
299///
300/// * `data` - A mutable slice of `u8` values to convert.
301///
302/// # Example
303///
304/// ```
305/// let mut data = vec![0x78, 0x56, 0x34, 0x12];
306/// cgl_rs::utils::little_endian_to_current(&mut data);
307/// ```
308pub fn little_endian_to_current(data: &mut [u8]) -> () {
309    unsafe {
310        CGL_utils_little_endian_to_current(data.as_mut_ptr() as *mut c_void, data.len() as size_t);
311    }
312}
313
314/// Converts a slice of `u8` values from big-endian byte order to the system's native byte order.
315///
316/// # Arguments
317///
318/// * `data` - A mutable slice of `u8` values to convert.
319///
320/// # Example
321///
322/// ```
323/// let mut data = vec![0x12, 0x34, 0x56, 0x78];
324/// cgl_rs::utils::big_endian_to_current(&mut data);
325/// ```
326pub fn big_endian_to_current(data: &mut [u8]) -> () {
327    unsafe {
328        CGL_utils_big_endian_to_current(data.as_mut_ptr() as *mut c_void, data.len() as size_t);
329    }
330}
331
332/// Sets the seed for the fast random number generator.
333///
334/// # Arguments
335///
336/// * `seed` - An `i32` representing the seed value to set.
337///
338/// # Example
339///
340/// ```
341/// cgl_rs::utils::fast_srand(42);
342/// ```
343pub fn fast_srand(seed: i32) -> () {
344    unsafe {
345        CGL_utils_fast_srand(seed);
346    }
347}
348
349/// Generates a fast random number.
350///
351/// # Returns
352///
353/// An `i32` representing the generated random number.
354///
355/// # Example
356///
357/// ```
358/// let random_number = cgl_rs::utils::fast_rand();
359/// ```
360pub fn fast_rand() -> i32 {
361    unsafe {
362        CGL_utils_fast_rand()
363    }
364}
365
366/// Generates a fast random number using the xorshf96 algorithm.
367/// 
368/// # Returns
369/// 
370/// A `u64` representing the generated random number.
371/// 
372/// # Example
373/// 
374/// ```
375/// let random_number = cgl_rs::utils::xorshf96();
376/// ```
377pub fn xorshf96() -> u64 {
378    unsafe {
379        CGL_utils_xorshf96()
380    }
381}
382
383
384
385/// Sets the seed for the rand31 random number generator.
386///
387/// # Arguments
388///
389/// * `seed` - A `u32` representing the seed value to set.
390///
391/// # Example
392///
393/// ```
394/// cgl_rs::utils::srand31(42);
395/// ```
396pub fn srand31(seed: u32) -> () {
397    unsafe {
398        CGL_utils_srand31(seed);
399    }
400}
401
402/// Generates a random number using the rand31 algorithm.
403///
404/// # Returns
405///
406/// A `u32` representing the generated random number.
407///
408/// # Example
409///
410/// ```
411/// let random_number = cgl_rs::utils::rand31();
412/// ```
413pub fn rand31() -> u32 {
414    unsafe {
415        CGL_utils_rand31()
416    }
417}
418
419
420/// Linearly interpolates between two values.
421///
422/// # Arguments
423///
424/// * `a` - A value of type `T` representing the start value.
425/// * `b` - A value of type `T` representing the end value.
426/// * `t` - A value of type `T` representing the interpolation factor.
427///
428/// # Returns
429///
430/// A value of type `T` representing the interpolated value.
431///
432/// # Example
433///
434/// ```
435/// let a = 0f32;
436/// let b = 10f32;
437/// let t = 0.5f32;
438/// let result = cgl_rs::utils::lerp(a, b, t);
439/// ```
440pub fn lerp<T: Copy + Add<Output = T> + Sub<Output = T> + Mul<Output = T>>(a: T, b: T, t: T) -> T {
441    a + (b - a) * t
442}
443
444
445
446/// Maps a value from one range to another.
447///
448/// # Arguments
449///
450/// * `value` - A value of type `T` representing the value to map.
451/// * `start1` - A value of type `T` representing the start of the input range.
452/// * `stop1` - A value of type `T` representing the end of the input range.
453/// * `start2` - A value of type `T` representing the start of the output range.
454/// * `stop2` - A value of type `T` representing the end of the output range.
455///
456/// # Returns
457///
458/// A value of type `T` representing the mapped value.
459///
460/// # Example
461///
462/// ```
463/// let value = 5;
464/// let start1 = 0;
465/// let stop1 = 10;
466/// let start2 = 0;
467/// let stop2 = 100;
468/// let result = cgl_rs::utils::map(value, start1, stop1, start2, stop2);
469/// ```
470pub fn map<T: Copy + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>>(value: T, start1: T, stop1: T, start2: T, stop2: T) -> T {
471    start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1))
472}
473
474/// Calculates the CRC32 checksum of the given data.
475/// 
476/// The C implementation is based on linux's crc32 implementation.
477///
478/// # Arguments
479///
480/// * `data` - A slice of bytes representing the data to calculate the checksum for.
481///
482/// # Returns
483///
484/// A `u32` representing the calculated CRC32 checksum.
485///
486/// # Example
487///
488/// ```
489/// let data = b"hello world";
490/// let crc32_checksum = cgl_rs::utils::crc32(data);
491/// assert_eq!(crc32_checksum, 222957957);
492/// ```
493pub fn crc32(data: &[u8]) -> u32 {
494    unsafe {
495        CGL_utils_crc32(data.as_ptr() as *const c_void, data.len() as size_t) as u32
496    }
497}
498
499// Calculates the CRC64 checksum of the given data.
500///
501/// The C implementation is based on linux's crc64 implementation.
502/// 
503/// # Arguments
504///
505/// * `data` - A slice of bytes representing the data to calculate the checksum for.
506///
507/// # Returns
508///
509/// A `u64` representing the calculated CRC64 checksum.
510///
511/// # Example
512///
513/// ```
514/// let data = b"hello world";
515/// let crc64_checksum = cgl_rs::utils::crc64(data);
516/// assert_eq!(crc64_checksum, 14017174577685478301);
517/// ```
518pub fn crc64(data: &[u8]) -> u64 {
519    unsafe {
520        CGL_utils_crc64(data.as_ptr() as *const c_void, data.len() as size_t) as u64
521    }
522}
523
524/// Applies the ROT13 substitution cipher to the given string.
525///
526/// # Arguments
527///
528/// * `data` - A string slice representing the data to apply the ROT13 cipher to.
529///
530/// # Returns
531///
532/// A `String` representing the result of applying the ROT13 cipher to the input string.
533///
534/// # Safety
535///
536/// This function is marked as unsafe because it calls an external C function that takes a raw pointer as an argument.
537///
538/// # Example
539///
540/// ```
541/// let data = "hello world";
542/// let result = cgl_rs::utils::rot13(data);
543/// assert_eq!(result, "uryyb jbeyq\0");
544/// ```
545pub fn rot13(data: &str) -> String {
546    unsafe {
547        let mut result = vec![0u8; data.len() + 1];
548        let c_str_data = CString::new(data).unwrap();
549        CGL_utils_rot13(c_str_data.as_ptr(), result.as_mut_ptr() as *mut c_char);
550        String::from_utf8_unchecked(result)
551    }
552}
553
554/// Calculates the SuperFastHash of the given data.
555/// 
556/// This algorithm is from http://www.azillionmonkeys.com/qed/hash.html
557/// 
558/// # Arguments
559/// 
560/// * `data` - A slice of bytes representing the data to calculate the SuperFastHash for.
561/// 
562/// # Returns
563/// 
564/// A `u32` representing the calculated SuperFastHash.
565/// 
566/// # Example
567/// 
568/// ```
569/// let data = b"hello world";
570/// let super_fast_hash = cgl_rs::utils::super_fast_hash(data);
571/// assert_eq!(super_fast_hash, 2794219650);
572/// ```
573pub fn super_fast_hash(data: &[u8]) -> u32 {
574    unsafe {
575        CGL_utils_super_fast_hash(data.as_ptr() as *const c_void, data.len() as size_t) as u32
576    }
577}
578
579
580/// Generates a random floating-point number between 0 and 1.
581///
582/// # Returns
583///
584/// A `f32` representing the generated random number.
585///
586/// # Example
587///
588/// ```
589/// let random_number = cgl_rs::utils::random_float();
590/// ```
591pub fn random_float() -> f32 {
592    unsafe {
593        CGL_utils_random_float_MACRO()
594    }
595}
596
597/// Generates a random floating-point number within the given range.
598///
599/// # Arguments
600///
601/// * `min` - A `f32` representing the minimum value of the range.
602/// * `max` - A `f32` representing the maximum value of the range.
603///
604/// # Returns
605///
606/// A `f32` representing the generated random number within the given range.
607///
608/// # Example
609///
610/// ```
611/// let random_number = cgl_rs::utils::random_float_range(0.0, 1.0);
612/// ```
613pub fn random_float_range(min: f32, max: f32) -> f32 {
614    unsafe {
615        CGL_utils_random_float_in_range_MACRO(min as f32, max as f32) as f32
616    }
617}
618
619/// Generates a random integer within the given range.
620///
621/// # Arguments
622///
623/// * `min_value` - An `i32` representing the minimum value of the range.
624/// * `max_value` - An `i32` representing the maximum value of the range.
625///
626/// # Returns
627///
628/// An `i32` representing the generated random number within the given range.
629///
630/// # Example
631///
632/// ```
633/// let random_number = cgl_rs::utils::random_int(0, 10);
634/// ```
635pub fn random_int(min_value: i32, max_value: i32) -> i32 {
636    unsafe {
637        CGL_utils_random_int_MACRO(min_value as i32, max_value as i32) as i32
638    }
639}