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