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