rg3d_core/
lib.rs

1//! Core data structures and algorithms used throughout rg3d.
2//!
3//! Some of them can be useful separately outside the engine.
4
5#![allow(clippy::upper_case_acronyms)]
6#![allow(clippy::from_over_into)]
7
8#[macro_use]
9extern crate memoffset;
10#[macro_use]
11extern crate lazy_static;
12
13pub use arrayvec;
14pub use byteorder;
15pub use nalgebra as algebra;
16pub use num_traits;
17pub use parking_lot;
18pub use rand;
19pub use uuid;
20
21use crate::visitor::{Visit, VisitResult, Visitor};
22use fxhash::FxHashMap;
23use std::ffi::OsString;
24use std::{
25    borrow::Borrow,
26    hash::Hash,
27    path::{Path, PathBuf},
28};
29
30pub mod color;
31pub mod color_gradient;
32pub mod curve;
33pub mod inspect;
34pub mod io;
35pub mod math;
36pub mod numeric_range;
37pub mod octree;
38pub mod pool;
39pub mod profiler;
40pub mod quadtree;
41pub mod rectpack;
42pub mod sparse;
43pub mod sstorage;
44pub mod visitor;
45
46pub use futures;
47pub use instant;
48
49#[cfg(target_arch = "wasm32")]
50pub use js_sys;
51use std::iter::FromIterator;
52#[cfg(target_arch = "wasm32")]
53pub use wasm_bindgen;
54#[cfg(target_arch = "wasm32")]
55pub use wasm_bindgen_futures;
56#[cfg(target_arch = "wasm32")]
57pub use web_sys;
58
59/// Defines as_(variant), as_mut_(variant) and is_(variant) methods.
60#[macro_export]
61macro_rules! define_is_as {
62    ($typ:tt : $kind:ident -> ref $result:path => fn $is:ident, fn $as_ref:ident, fn $as_mut:ident) => {
63        /// Returns true if node is instance of given type.
64        pub fn $is(&self) -> bool {
65            match self {
66                $typ::$kind(_) => true,
67                _ => false,
68            }
69        }
70
71        /// Tries to cast shared reference to a node to given type, panics if
72        /// cast is not possible.
73        pub fn $as_ref(&self) -> &$result {
74            match self {
75                $typ::$kind(ref val) => val,
76                _ => panic!("Cast to {} failed!", stringify!($kind)),
77            }
78        }
79
80        /// Tries to cast mutable reference to a node to given type, panics if
81        /// cast is not possible.
82        pub fn $as_mut(&mut self) -> &mut $result {
83            match self {
84                $typ::$kind(ref mut val) => val,
85                _ => panic!("Cast to {} failed!", stringify!($kind)),
86            }
87        }
88    };
89}
90
91/// Utility function that replaces back slashes \ to forward /
92/// It replaces slashes only on windows!
93pub fn replace_slashes<P: AsRef<Path>>(path: P) -> PathBuf {
94    #[cfg(target_os = "windows")]
95    {
96        if path.as_ref().is_absolute() {
97            // Absolute Windows paths are incompatible with other operating systems so
98            // don't bother here and return existing path as owned.
99            path.as_ref().to_owned()
100        } else {
101            // Replace all \ to /. This is needed because on macos or linux \ is a valid symbol in
102            // file name, and not separator (except linux which understand both variants).
103            let mut os_str = std::ffi::OsString::new();
104            let count = path.as_ref().components().count();
105            for (i, component) in path.as_ref().components().enumerate() {
106                os_str.push(component.as_os_str());
107                if i != count - 1 {
108                    os_str.push("/");
109                }
110            }
111            PathBuf::from(os_str)
112        }
113    }
114
115    #[cfg(not(target_os = "windows"))]
116    {
117        path.as_ref().to_owned()
118    }
119}
120
121/// Appends specified extension to the path.
122///
123/// # Examples
124///
125/// ```rust
126/// # use std::path::Path;
127/// # use rg3d_core::append_extension;
128/// let path = Path::new("foo.bar");
129/// let new_path = append_extension(path, "baz");
130/// assert_eq!(new_path, Path::new("foo.bar.baz"))
131/// ```
132#[must_use]
133pub fn append_extension<P: AsRef<Path>, E: AsRef<str>>(
134    path: P,
135    additional_extension: E,
136) -> PathBuf {
137    let mut final_path = path.as_ref().to_path_buf();
138    let new_extension = final_path
139        .extension()
140        .map(|e| {
141            let mut ext = e.to_owned();
142            ext.push(".");
143            ext.push(additional_extension.as_ref());
144            ext
145        })
146        .unwrap_or_else(|| OsString::from(additional_extension.as_ref()));
147    final_path.set_extension(new_extension);
148    final_path
149}
150
151#[derive(Clone, Debug)]
152pub struct BiDirHashMap<K, V> {
153    forward_map: FxHashMap<K, V>,
154    backward_map: FxHashMap<V, K>,
155}
156
157impl<K: Hash + Eq + Clone, V: Hash + Eq + Clone> BiDirHashMap<K, V> {
158    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
159        let existing = self.forward_map.insert(key.clone(), value.clone());
160        self.backward_map.insert(value, key);
161        existing
162    }
163
164    pub fn remove_by_key(&mut self, key: &K) -> Option<V> {
165        if let Some(value) = self.forward_map.remove(key) {
166            self.backward_map.remove(&value);
167            Some(value)
168        } else {
169            None
170        }
171    }
172
173    pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
174    where
175        K: Borrow<Q>,
176        Q: Hash + Eq,
177    {
178        self.forward_map.contains_key(key)
179    }
180
181    pub fn remove_by_value(&mut self, value: &V) -> Option<K> {
182        if let Some(key) = self.backward_map.remove(value) {
183            self.forward_map.remove(&key);
184            Some(key)
185        } else {
186            None
187        }
188    }
189
190    pub fn contains_value<Q: ?Sized>(&self, value: &Q) -> bool
191    where
192        V: Borrow<Q>,
193        Q: Hash + Eq,
194    {
195        self.backward_map.contains_key(value)
196    }
197
198    pub fn value_of(&self, node: &K) -> Option<&V> {
199        self.forward_map.get(node)
200    }
201
202    pub fn key_of(&self, value: &V) -> Option<&K> {
203        self.backward_map.get(value)
204    }
205
206    pub fn len(&self) -> usize {
207        self.forward_map.len()
208    }
209
210    pub fn is_empty(&self) -> bool {
211        self.forward_map.is_empty()
212    }
213
214    pub fn clear(&mut self) {
215        self.forward_map.clear();
216        self.backward_map.clear();
217    }
218
219    pub fn forward_map(&self) -> &FxHashMap<K, V> {
220        &self.forward_map
221    }
222
223    pub fn backward_map(&self) -> &FxHashMap<V, K> {
224        &self.backward_map
225    }
226
227    pub fn into_inner(self) -> (FxHashMap<K, V>, FxHashMap<V, K>) {
228        (self.forward_map, self.backward_map)
229    }
230}
231
232impl<K, V> Default for BiDirHashMap<K, V> {
233    fn default() -> Self {
234        Self {
235            forward_map: Default::default(),
236            backward_map: Default::default(),
237        }
238    }
239}
240
241impl<K: Hash + Eq + Clone, V: Hash + Eq + Clone> From<FxHashMap<K, V>> for BiDirHashMap<K, V> {
242    fn from(forward_map: FxHashMap<K, V>) -> Self {
243        let mut backward_map = FxHashMap::default();
244        for (k, v) in forward_map.iter() {
245            backward_map.insert(v.clone(), k.clone());
246        }
247        Self {
248            forward_map,
249            backward_map,
250        }
251    }
252}
253
254impl<K, V> Visit for BiDirHashMap<K, V>
255where
256    K: Hash + Eq + Clone + Default + Visit,
257    V: Hash + Eq + Clone + Default + Visit,
258{
259    fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
260        visitor.enter_region(name)?;
261
262        self.forward_map.visit("ForwardMap", visitor)?;
263        self.backward_map.visit("BackwardMap", visitor)?;
264
265        visitor.leave_region()
266    }
267}
268
269impl<K, V> FromIterator<(K, V)> for BiDirHashMap<K, V>
270where
271    K: Hash + Eq + Clone,
272    V: Hash + Eq + Clone,
273{
274    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
275        let mut hm = Self::default();
276        for (k, v) in iter {
277            hm.forward_map.insert(k.clone(), v.clone());
278            hm.backward_map.insert(v, k);
279        }
280        hm
281    }
282}
283
284pub trait VecExtensions<T> {
285    /// Retains only the elements specified by the predicate.
286    ///
287    /// In other words, remove all elements `e` such that `f(&mut e)` returns `false`.
288    /// This method operates in place, visiting each element exactly once in the
289    /// original order, and preserves the order of the retained elements.
290    ///
291    /// # Notes
292    ///
293    /// This method is the copy of `retain` method of Vec, but with ability to
294    /// modify each element.
295    fn retain_mut_ext<F>(&mut self, f: F)
296    where
297        F: FnMut(&mut T) -> bool;
298}
299
300impl<T> VecExtensions<T> for Vec<T> {
301    fn retain_mut_ext<F>(&mut self, mut f: F)
302    where
303        F: FnMut(&mut T) -> bool,
304    {
305        let len = self.len();
306        let mut del = 0;
307        {
308            let v = &mut **self;
309
310            for i in 0..len {
311                if !f(&mut v[i]) {
312                    del += 1;
313                } else if del > 0 {
314                    v.swap(i - del, i);
315                }
316            }
317        }
318        if del > 0 {
319            self.truncate(len - del);
320        }
321    }
322}
323
324#[inline]
325pub fn hash_combine(lhs: u64, rhs: u64) -> u64 {
326    lhs ^ (rhs
327        .wrapping_add(0x9e3779b9)
328        .wrapping_add(lhs << 6)
329        .wrapping_add(lhs >> 2))
330}