1use std::fmt;
2
3use fast_mesh_store::StoreError;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum BvhError {
11 MeshMismatch,
13 InvalidOptions(&'static str),
15 OutOfMemory,
17 Store(StoreError),
19}
20
21impl fmt::Display for BvhError {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 match self {
24 Self::MeshMismatch => write!(f, "mesh is not the one this BVH was built from"),
25 Self::InvalidOptions(msg) => write!(f, "invalid BVH options: {msg}"),
26 Self::OutOfMemory => write!(f, "out of memory"),
27 Self::Store(e) => write!(f, "mesh store error: {e}"),
28 }
29 }
30}
31
32impl std::error::Error for BvhError {}
33
34impl From<StoreError> for BvhError {
35 fn from(e: StoreError) -> Self {
36 match e {
37 StoreError::OutOfMemory => Self::OutOfMemory,
38 other => Self::Store(other),
39 }
40 }
41}
42
43pub type Result<T> = std::result::Result<T, BvhError>;
44
45#[cfg(test)]
46thread_local! {
47 static ALLOCATIONS_LEFT: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
49}
50
51#[cfg(test)]
55pub(crate) fn fail_allocations_after(n: Option<usize>) {
56 let was = ALLOCATIONS_LEFT.with(|c| c.replace(n)).is_some();
58 if was != n.is_some() {
59 fast_mesh_store::par::set_force_sequential(n.is_some());
60 }
61}
62
63#[cfg(test)]
66pub(crate) fn allocation_allowed() -> Result<()> {
67 ALLOCATIONS_LEFT.with(|c| match c.get() {
68 Some(0) => Err(BvhError::OutOfMemory),
69 Some(n) => {
70 c.set(Some(n - 1));
71 Ok(())
72 }
73 None => Ok(()),
74 })
75}
76
77#[cfg(not(test))]
78pub(crate) fn allocation_allowed() -> Result<()> {
79 Ok(())
80}
81
82pub(crate) fn try_reserve<T>(v: &mut Vec<T>, additional: usize) -> Result<()> {
83 allocation_allowed()?;
84 v.try_reserve(additional).map_err(|_| BvhError::OutOfMemory)
85}
86
87pub(crate) fn try_reserve_exact<T>(v: &mut Vec<T>, additional: usize) -> Result<()> {
88 allocation_allowed()?;
89 v.try_reserve_exact(additional)
90 .map_err(|_| BvhError::OutOfMemory)
91}
92
93pub(crate) fn try_reserve_map<K: Eq + std::hash::Hash, V>(
94 m: &mut std::collections::HashMap<K, V>,
95 additional: usize,
96) -> Result<()> {
97 allocation_allowed()?;
98 m.try_reserve(additional).map_err(|_| BvhError::OutOfMemory)
99}
100
101pub(crate) fn try_vec<T: Clone>(len: usize, value: T) -> Result<Vec<T>> {
102 allocation_allowed()?;
103 let mut v = Vec::new();
104 v.try_reserve_exact(len)
105 .map_err(|_| BvhError::OutOfMemory)?;
106 v.resize(len, value);
107 Ok(v)
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn messages_name_the_problem() {
116 assert_eq!(
117 BvhError::InvalidOptions("max_leaf_size must be 1 to 16").to_string(),
118 "invalid BVH options: max_leaf_size must be 1 to 16"
119 );
120 assert_eq!(
121 BvhError::from(StoreError::OutOfMemory),
122 BvhError::OutOfMemory
123 );
124 assert_eq!(
125 BvhError::from(StoreError::InvalidVertex(3)).to_string(),
126 "mesh store error: vertex 3 does not exist"
127 );
128 }
129}