1#![allow(clippy::upper_case_acronyms)]
26#![allow(clippy::from_over_into)]
27#![allow(clippy::doc_lazy_continuation)]
28#![allow(mismatched_lifetime_syntaxes)]
29
30#[macro_use]
31extern crate memoffset;
32#[macro_use]
33extern crate lazy_static;
34
35pub use arrayvec;
36pub use byteorder;
37pub use nalgebra as algebra;
38pub use num_traits;
39pub use parking_lot;
40pub use rand;
41pub use sstorage::ImmutableString;
42pub use uuid;
43
44use crate::visitor::{Visit, VisitResult, Visitor};
45use bytemuck::Pod;
46use fxhash::FxHashMap;
47pub use safelock::*;
48use std::collections::hash_map::Entry;
49use std::ffi::OsString;
50use std::hash::Hasher;
51use std::{
52 borrow::Borrow,
53 cmp,
54 hash::Hash,
55 path::{Path, PathBuf},
56};
57pub mod color;
58pub mod color_gradient;
59pub mod early;
60pub mod io;
61pub mod log;
62pub mod math;
63pub mod net;
64pub mod numeric_range;
65pub mod platform;
66pub mod pool;
67pub mod quadtree;
68pub mod rectpack;
69pub mod reflect;
70mod safelock;
71pub mod sparse;
72pub mod sstorage;
73pub mod task;
74pub mod type_traits;
75pub mod variable;
76pub mod visitor;
77pub mod watcher;
78
79pub use futures;
80pub use instant;
81
82pub use notify;
83
84#[cfg(target_arch = "wasm32")]
85pub use js_sys;
86use std::marker::PhantomData;
87#[cfg(target_arch = "wasm32")]
88pub use wasm_bindgen;
89#[cfg(target_arch = "wasm32")]
90pub use wasm_bindgen_futures;
91#[cfg(target_arch = "wasm32")]
92pub use web_sys;
93
94pub use type_traits::prelude::*;
95#[macro_export]
97macro_rules! define_is_as {
98 ($typ:tt : $kind:ident -> ref $result:path => fn $is:ident, fn $as_ref:ident, fn $as_mut:ident) => {
99 pub fn $is(&self) -> bool {
101 match self {
102 $typ::$kind(_) => true,
103 _ => false,
104 }
105 }
106
107 pub fn $as_ref(&self) -> &$result {
110 match self {
111 $typ::$kind(ref val) => val,
112 _ => panic!("Cast to {} failed!", stringify!($kind)),
113 }
114 }
115
116 pub fn $as_mut(&mut self) -> &mut $result {
119 match self {
120 $typ::$kind(ref mut val) => val,
121 _ => panic!("Cast to {} failed!", stringify!($kind)),
122 }
123 }
124 };
125}
126
127pub fn replace_slashes<P: AsRef<Path>>(path: P) -> PathBuf {
132 PathBuf::from(
133 path.as_ref()
134 .to_string_lossy()
135 .to_string()
136 .replace('\\', "/"),
137 )
138}
139
140#[must_use]
152pub fn append_extension<P: AsRef<Path>, E: AsRef<str>>(
153 path: P,
154 additional_extension: E,
155) -> PathBuf {
156 let mut final_path = path.as_ref().to_path_buf();
157 let new_extension = final_path
158 .extension()
159 .map(|e| {
160 let mut ext = e.to_owned();
161 ext.push(".");
162 ext.push(additional_extension.as_ref());
163 ext
164 })
165 .unwrap_or_else(|| OsString::from(additional_extension.as_ref()));
166 final_path.set_extension(new_extension);
167 final_path
168}
169
170#[derive(Clone, Debug)]
171pub struct BiDirHashMap<K, V> {
172 forward_map: FxHashMap<K, V>,
173 backward_map: FxHashMap<V, K>,
174}
175
176impl<K: Hash + Eq + Clone, V: Hash + Eq + Clone> BiDirHashMap<K, V> {
177 pub fn insert(&mut self, key: K, value: V) -> Option<V> {
178 let existing = self.forward_map.insert(key.clone(), value.clone());
179 self.backward_map.insert(value, key);
180 existing
181 }
182
183 pub fn remove_by_key(&mut self, key: &K) -> Option<V> {
184 if let Some(value) = self.forward_map.remove(key) {
185 self.backward_map.remove(&value);
186 Some(value)
187 } else {
188 None
189 }
190 }
191
192 pub fn contains_key<Q: ?Sized + Hash + Eq>(&self, key: &Q) -> bool
193 where
194 K: Borrow<Q>,
195 {
196 self.forward_map.contains_key(key)
197 }
198
199 pub fn remove_by_value(&mut self, value: &V) -> Option<K> {
200 if let Some(key) = self.backward_map.remove(value) {
201 self.forward_map.remove(&key);
202 Some(key)
203 } else {
204 None
205 }
206 }
207
208 pub fn contains_value<Q: ?Sized + Hash + Eq>(&self, value: &Q) -> bool
209 where
210 V: Borrow<Q>,
211 {
212 self.backward_map.contains_key(value)
213 }
214
215 pub fn value_of(&self, node: &K) -> Option<&V> {
216 self.forward_map.get(node)
217 }
218
219 pub fn key_of(&self, value: &V) -> Option<&K> {
220 self.backward_map.get(value)
221 }
222
223 pub fn len(&self) -> usize {
224 self.forward_map.len()
225 }
226
227 pub fn is_empty(&self) -> bool {
228 self.forward_map.is_empty()
229 }
230
231 pub fn clear(&mut self) {
232 self.forward_map.clear();
233 self.backward_map.clear();
234 }
235
236 pub fn forward_map(&self) -> &FxHashMap<K, V> {
237 &self.forward_map
238 }
239
240 pub fn backward_map(&self) -> &FxHashMap<V, K> {
241 &self.backward_map
242 }
243
244 pub fn into_inner(self) -> (FxHashMap<K, V>, FxHashMap<V, K>) {
245 (self.forward_map, self.backward_map)
246 }
247}
248
249impl<K, V> Default for BiDirHashMap<K, V> {
250 fn default() -> Self {
251 Self {
252 forward_map: Default::default(),
253 backward_map: Default::default(),
254 }
255 }
256}
257
258impl<K: Hash + Eq + Clone, V: Hash + Eq + Clone> From<FxHashMap<K, V>> for BiDirHashMap<K, V> {
259 fn from(forward_map: FxHashMap<K, V>) -> Self {
260 let mut backward_map = FxHashMap::default();
261 for (k, v) in forward_map.iter() {
262 backward_map.insert(v.clone(), k.clone());
263 }
264 Self {
265 forward_map,
266 backward_map,
267 }
268 }
269}
270
271impl<K, V> Visit for BiDirHashMap<K, V>
272where
273 K: Hash + Eq + Clone + Default + Visit,
274 V: Hash + Eq + Clone + Default + Visit,
275{
276 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
277 let mut region = visitor.enter_region(name)?;
278
279 self.forward_map.visit("ForwardMap", &mut region)?;
280 self.backward_map.visit("BackwardMap", &mut region)?;
281
282 Ok(())
283 }
284}
285
286impl<K, V> FromIterator<(K, V)> for BiDirHashMap<K, V>
287where
288 K: Hash + Eq + Clone,
289 V: Hash + Eq + Clone,
290{
291 fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
292 let mut hm = Self::default();
293 for (k, v) in iter {
294 hm.forward_map.insert(k.clone(), v.clone());
295 hm.backward_map.insert(v, k);
296 }
297 hm
298 }
299}
300
301#[inline]
302pub fn hash_combine(lhs: u64, rhs: u64) -> u64 {
303 lhs ^ (rhs
304 .wrapping_add(0x9e3779b9)
305 .wrapping_add(lhs << 6)
306 .wrapping_add(lhs >> 2))
307}
308
309pub fn make_relative_path<P: AsRef<Path>>(path: P) -> Result<PathBuf, std::io::Error> {
313 let path = path.as_ref();
314 let file_name = path.file_name().ok_or(std::io::Error::new(
317 std::io::ErrorKind::InvalidData,
318 format!("Invalid path: {}", path.display()),
319 ))?;
320 let dir = path.parent();
321 let dir = if let Some(dir) = dir {
322 if dir.as_os_str().is_empty() {
323 Path::new(".")
324 } else {
325 dir
326 }
327 } else {
328 Path::new(".")
329 };
330 let canon_path = dir
331 .canonicalize()
332 .map_err(|err| {
333 std::io::Error::other(format!(
334 "Unable to canonicalize '{}'. Reason: {err}",
335 dir.display()
336 ))
337 })?
338 .join(file_name);
339 match canon_path.strip_prefix(std::env::current_dir()?.canonicalize()?) {
340 Ok(relative_path) => Ok(replace_slashes(relative_path)),
341 Err(err) => Err(std::io::Error::other(format!(
342 "unable to strip prefix from '{}'! Reason: {err}",
343 canon_path.display()
344 ))),
345 }
346}
347
348pub fn array_as_u8_slice<T: Sized + Pod>(v: &[T]) -> &'_ [u8] {
350 unsafe { std::slice::from_raw_parts(v.as_ptr() as *const u8, std::mem::size_of_val(v)) }
352}
353
354pub fn array_as_u8_slice_mut<T: Sized + Pod>(v: &mut [T]) -> &'_ mut [u8] {
356 unsafe { std::slice::from_raw_parts_mut(v.as_mut_ptr() as *mut u8, std::mem::size_of_val(v)) }
358}
359
360pub fn transmute_slice<T: Sized, U: Sized>(v: &[T]) -> &'_ [U] {
362 unsafe {
364 std::slice::from_raw_parts(
365 v.as_ptr() as *const U,
366 std::mem::size_of_val(v) / std::mem::size_of::<U>(),
367 )
368 }
369}
370
371pub fn value_as_u8_slice<T: Sized + Pod>(v: &T) -> &'_ [u8] {
373 unsafe { std::slice::from_raw_parts(v as *const T as *const u8, std::mem::size_of::<T>()) }
375}
376
377pub fn transmute_vec_as_bytes<T: Pod>(vec: Vec<T>) -> Vec<u8> {
379 unsafe {
380 let mut vec = std::mem::ManuallyDrop::new(vec);
381 Vec::from_raw_parts(
382 vec.as_mut_ptr() as *mut u8,
383 vec.len() * std::mem::size_of::<T>(),
384 vec.capacity() * std::mem::size_of::<T>(),
385 )
386 }
387}
388
389pub fn hash_as_bytes<T: Sized + Pod, H: Hasher>(value: &T, hasher: &mut H) {
391 hasher.write(value_as_u8_slice(value))
392}
393
394pub fn cmp_strings_case_insensitive(a: impl AsRef<str>, b: impl AsRef<str>) -> bool {
397 let a_ref = a.as_ref();
398 let b_ref = b.as_ref();
399
400 if a_ref.len() != b_ref.len() {
401 return false;
402 }
403
404 a_ref
405 .chars()
406 .zip(b_ref.chars())
407 .all(|(ca, cb)| ca.to_lowercase().eq(cb.to_lowercase()))
408}
409
410pub fn make_pretty_type_name(type_name: &str) -> &str {
411 let mut colon_position = None;
412 let mut byte_pos = 0;
413 for c in type_name.chars() {
414 byte_pos += c.len_utf8();
415 if c == ':' {
416 colon_position = Some(byte_pos);
417 } else if c == '<' {
418 break;
419 }
420 }
421 if let Some(colon_position) = colon_position {
422 type_name.split_at(colon_position).1
423 } else {
424 type_name
425 }
426}
427
428#[repr(transparent)]
429#[derive(Debug)]
430pub struct PhantomDataSendSync<T: ?Sized>(PhantomData<T>);
431
432unsafe impl<T: ?Sized> Send for PhantomDataSendSync<T> {}
434unsafe impl<T: ?Sized> Sync for PhantomDataSendSync<T> {}
436
437impl<T: ?Sized> Hash for PhantomDataSendSync<T> {
438 #[inline]
439 fn hash<H: Hasher>(&self, _: &mut H) {}
440}
441
442impl<T: ?Sized> PartialEq for PhantomDataSendSync<T> {
443 fn eq(&self, _other: &PhantomDataSendSync<T>) -> bool {
444 true
445 }
446}
447
448impl<T: ?Sized> Eq for PhantomDataSendSync<T> {}
449
450impl<T: ?Sized> PartialOrd for PhantomDataSendSync<T> {
451 fn partial_cmp(&self, _other: &PhantomDataSendSync<T>) -> Option<cmp::Ordering> {
452 Some(self.cmp(_other))
453 }
454}
455
456impl<T: ?Sized> Ord for PhantomDataSendSync<T> {
457 fn cmp(&self, _other: &PhantomDataSendSync<T>) -> cmp::Ordering {
458 cmp::Ordering::Equal
459 }
460}
461
462impl<T: ?Sized> Copy for PhantomDataSendSync<T> {}
463
464impl<T: ?Sized> Clone for PhantomDataSendSync<T> {
465 fn clone(&self) -> Self {
466 *self
467 }
468}
469
470impl<T: ?Sized> Default for PhantomDataSendSync<T> {
471 fn default() -> Self {
472 Self(PhantomData)
473 }
474}
475
476pub trait NameProvider {
478 fn name(&self) -> &str;
480}
481
482pub fn find_by_name_ref<'a, T, I, S, K>(mut iter: I, name: S) -> Option<(K, &'a T)>
484where
485 T: NameProvider,
486 I: Iterator<Item = (K, &'a T)>,
487 S: AsRef<str>,
488{
489 iter.find(|(_, value)| value.name() == name.as_ref())
490}
491
492pub fn find_by_name_mut<'a, T, I, S, K>(mut iter: I, name: S) -> Option<(K, &'a mut T)>
494where
495 T: NameProvider,
496 I: Iterator<Item = (K, &'a mut T)>,
497 S: AsRef<str>,
498{
499 iter.find(|(_, value)| value.name() == name.as_ref())
500}
501
502pub fn swap_hash_map_entry<K, V>(entry: Entry<K, V>, value: &mut Option<V>) {
504 match (entry, value) {
505 (Entry::Occupied(entry), p @ None) => *p = Some(entry.remove()),
506 (Entry::Occupied(mut entry), Some(p)) => std::mem::swap(entry.get_mut(), p),
507 (Entry::Vacant(_), None) => (),
508 (Entry::Vacant(entry), p @ Some(_)) => drop(entry.insert(p.take().unwrap())),
509 }
510}
511
512pub fn swap_hash_map_entries<K0, K1, V>(entry0: Entry<K0, V>, entry1: Entry<K1, V>) {
514 match (entry0, entry1) {
515 (Entry::Occupied(e0), Entry::Vacant(e1)) => drop(e1.insert(e0.remove())),
516 (Entry::Occupied(mut e0), Entry::Occupied(mut e1)) => {
517 std::mem::swap(e0.get_mut(), e1.get_mut())
518 }
519 (Entry::Vacant(_), Entry::Vacant(_)) => (),
520 (Entry::Vacant(e0), Entry::Occupied(e1)) => drop(e0.insert(e1.remove())),
521 }
522}
523
524#[macro_export]
525macro_rules! define_as_any_trait {
526 ($trait_name:ident => $derived_trait:ident) => {
527 pub trait $trait_name: std::any::Any {
529 fn as_any(&self) -> &dyn std::any::Any;
531
532 fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
534
535 fn into_any(self: Box<Self>) -> Box<dyn std::any::Any>;
537 }
538
539 impl<T: $derived_trait> $trait_name for T {
540 fn as_any(&self) -> &dyn std::any::Any {
541 self
542 }
543
544 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
545 self
546 }
547
548 fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
549 self
550 }
551 }
552 };
553 ($trait_name:ident: $($sub_trait:ident),* => $derived_trait:ident) => {
554 pub trait $trait_name: std::any::Any + $($sub_trait),* {
556 fn as_any(&self) -> &dyn std::any::Any;
557
558 fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
559
560 fn into_any(self: Box<Self>) -> Box<dyn std::any::Any>;
561 }
562
563 impl<T: $derived_trait> $trait_name for T {
564 fn as_any(&self) -> &dyn std::any::Any {
565 self
566 }
567
568 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
569 self
570 }
571
572 fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
573 self
574 }
575 }
576 };
577}
578
579#[cfg(test)]
580mod test {
581 use std::path::Path;
582
583 use crate::{
584 append_extension, cmp_strings_case_insensitive, combine_uuids, hash_combine,
585 make_relative_path, transmute_vec_as_bytes,
586 visitor::{Visit, Visitor},
587 BiDirHashMap,
588 };
589 use fxhash::FxHashMap;
590 use std::mem::size_of;
591 use uuid::uuid;
592
593 #[test]
594 fn test_combine_uuids() {
595 let a = uuid!("d1a45bd5-5066-4b28-b103-95c59c230e77");
596 let b = uuid!("0a06591a-1c66-4299-ba6f-2b205b795575");
597
598 assert_ne!(combine_uuids(a, b), a);
599 assert_ne!(combine_uuids(a, b), b);
600 }
601
602 #[test]
603 fn test_append_extension() {
604 let path = Path::new("foo.bar");
605 let new_path = append_extension(path, "baz");
606 assert_eq!(new_path, Path::new("foo.bar.baz"));
607 }
608
609 #[test]
610 fn bi_dir_hash_map_insert() {
611 let mut map = BiDirHashMap::<u32, u32>::default();
612
613 assert!(map.forward_map.is_empty());
614 assert!(map.backward_map.is_empty());
615
616 let result = map.insert(1, 42);
617
618 assert_eq!(result, None);
619 assert_eq!(map.forward_map.get_key_value(&1), Some((&1, &42)));
620 assert_eq!(map.backward_map.get_key_value(&42), Some((&42, &1)));
621 }
622
623 #[test]
624 fn bi_dir_hash_map_remove_by_key() {
625 let mut map = BiDirHashMap::<u32, u32>::default();
626 map.insert(1, 42);
627
628 assert_eq!(map.forward_map.get_key_value(&1), Some((&1, &42)));
629 assert_eq!(map.backward_map.get_key_value(&42), Some((&42, &1)));
630
631 let result = map.remove_by_key(&42);
632 assert_eq!(result, None);
633
634 let result = map.remove_by_key(&1);
635 assert_eq!(result, Some(42));
636 assert!(map.forward_map.is_empty());
637 assert!(map.backward_map.is_empty());
638 }
639
640 #[test]
641 fn bi_dir_hash_map_remove_by_value() {
642 let mut map = BiDirHashMap::<u32, u32>::default();
643 map.insert(1, 42);
644
645 assert_eq!(map.forward_map.get_key_value(&1), Some((&1, &42)));
646 assert_eq!(map.backward_map.get_key_value(&42), Some((&42, &1)));
647
648 let result = map.remove_by_value(&1);
649 assert_eq!(result, None);
650
651 let result = map.remove_by_value(&42);
652 assert_eq!(result, Some(1));
653 assert!(map.forward_map.is_empty());
654 assert!(map.backward_map.is_empty());
655 }
656
657 #[test]
658 fn bi_dir_hash_map_contains_key() {
659 let mut map = BiDirHashMap::<u32, u32>::default();
660 map.insert(1, 42);
661
662 assert!(map.contains_key(&1));
663 assert!(!map.contains_key(&42));
664 }
665
666 #[test]
667 fn bi_dir_hash_map_contains_value() {
668 let mut map = BiDirHashMap::<u32, u32>::default();
669 map.insert(1, 42);
670
671 assert!(map.contains_value(&42));
672 assert!(!map.contains_value(&1));
673 }
674
675 #[test]
676 fn bi_dir_hash_map_value_of() {
677 let mut map = BiDirHashMap::<u32, u32>::default();
678 map.insert(1, 42);
679
680 assert_eq!(map.value_of(&1), Some(&42));
681 assert_eq!(map.value_of(&42), None);
682 }
683
684 #[test]
685 fn bi_dir_hash_map_key_of() {
686 let mut map = BiDirHashMap::<u32, u32>::default();
687 map.insert(1, 42);
688
689 assert_eq!(map.key_of(&1), None);
690 assert_eq!(map.key_of(&42), Some(&1));
691 }
692
693 #[test]
694 fn bi_dir_hash_map_getters() {
695 let mut map = BiDirHashMap::<u32, u32>::default();
696 assert!(map.is_empty());
697
698 map.insert(1, 42);
699 assert_eq!(map.len(), 1);
700
701 assert!(map.forward_map().eq(&map.forward_map));
702 assert!(map.backward_map().eq(&map.backward_map));
703
704 map.clear();
705 assert!(map.is_empty());
706 }
707
708 #[test]
709 fn bi_dir_hash_map_into_inner() {
710 let mut map = BiDirHashMap::<u32, u32>::default();
711 map.insert(1, 42);
712
713 let (f, b) = map.clone().into_inner();
714 assert!(map.forward_map().eq(&f));
715 assert!(map.backward_map().eq(&b));
716 }
717
718 #[test]
719 fn from_fx_hash_map_for_bi_dir_hash_map() {
720 let mut h = FxHashMap::default();
721 h.insert(1, 42);
722
723 let map = BiDirHashMap::from(h);
724 assert_eq!(map.forward_map.get_key_value(&1), Some((&1, &42)));
725 assert_eq!(map.backward_map.get_key_value(&42), Some((&42, &1)));
726 }
727
728 #[test]
729 fn test_visit_for_bi_dir_hash_map() {
730 let mut map = BiDirHashMap::<u32, u32>::default();
731 let mut visitor = Visitor::default();
732
733 assert!(map.visit("name", &mut visitor).is_ok());
734 }
735
736 #[test]
737 fn from_iter_for_bi_dir_hash_map() {
738 let map = BiDirHashMap::from_iter(vec![(1, 42)]);
739
740 assert_eq!(map.forward_map.get_key_value(&1), Some((&1, &42)));
741 assert_eq!(map.backward_map.get_key_value(&42), Some((&42, &1)));
742 }
743
744 #[test]
745 fn test_hash_combine() {
746 assert_eq!(hash_combine(1, 1), 0x9E3779FB);
747 }
748
749 #[test]
750 fn test_make_relative_path() {
751 assert!(make_relative_path(Path::new("fake_dir").join(Path::new("foo.txt"))).is_err());
752 make_relative_path(Path::new("Cargo.toml")).unwrap();
753 make_relative_path(Path::new("Cargo.toml").canonicalize().unwrap()).unwrap();
754 }
755
756 #[test]
757 fn tests_case_insensitive_str_comparison() {
758 assert!(cmp_strings_case_insensitive("FooBar", "FOOBaR"));
759 assert!(!cmp_strings_case_insensitive("FooBaz", "FOOBaR"));
760 assert!(cmp_strings_case_insensitive("foobar", "foobar"));
761 }
762
763 #[test]
764 fn test_transmute_vec_as_bytes_length_new_f32() {
765 let vec = vec![1.0f32, 2.0, 3.0];
766 let byte_vec = transmute_vec_as_bytes(vec.clone());
767 let expected_length = vec.len() * size_of::<f32>();
768 assert_eq!(byte_vec.len(), expected_length);
769 }
770
771 #[test]
772 fn test_transmute_vec_as_bytes_length_new_usize() {
773 let vec = vec![1usize, 2, 3];
774 let byte_vec = transmute_vec_as_bytes(vec.clone());
775 let expected_length = vec.len() * size_of::<usize>();
776 assert_eq!(byte_vec.len(), expected_length);
777 }
778}