1use super::*;
4
5impl Document {
6 pub fn try_for_each<'a, T: Traversable + ?Sized + 'a, E, F: FnMut(&'a T) -> Result<(), E>>(
8 &'a self,
9 f: F,
10 ) -> Result<(), E> {
11 T::traverse(self, f)
12 }
13
14 pub fn for_each<'a, T: Traversable + ?Sized + 'a>(&'a self, mut f: impl FnMut(&'a T)) {
16 #[allow(clippy::unit_arg)]
17 self.try_for_each(|e| Ok(f(e)))
18 .unwrap_or_else(|e: std::convert::Infallible| match e {})
19 }
20
21 pub fn local_map<T: Traversable + HasId + ?Sized>(&self) -> Result<LocalMap<'_, T>> {
24 let mut map = LocalMap::default();
25 self.try_for_each(|v: &T| map.push(v))?;
26 Ok(map)
27 }
28
29 pub fn get_visual_scene(&self) -> Option<&VisualScene> {
32 let scene = self.scene.as_ref()?.instance_visual_scene.as_ref()?;
33 self.local_map().ok()?.get(&scene.url)
34 }
35
36 pub fn local_maps(&self) -> LocalMaps<'_> {
44 LocalMaps::new().collect(self)
45 }
46}
47
48pub trait HasId {
50 fn id(&self) -> Option<&str>;
52
53 fn get_local_map<'a, 'b>(maps: &'b LocalMaps<'a>) -> &'b Option<LocalMap<'a, Self>>;
55
56 fn get_local_map_mut<'a, 'b>(maps: &'b mut LocalMaps<'a>)
58 -> &'b mut Option<LocalMap<'a, Self>>;
59}
60
61#[derive(Clone, Debug)]
63pub struct LocalMap<'a, T: ?Sized>(pub HashMap<&'a str, &'a T>);
64
65impl<'a, T: ?Sized> Default for LocalMap<'a, T> {
66 fn default() -> Self {
67 Self(Default::default())
68 }
69}
70
71impl<'a, T: ?Sized> LocalMap<'a, T> {
72 pub fn push(&mut self, v: &'a T) -> Result<()>
74 where
75 T: HasId,
76 {
77 if let Some(id) = v.id() {
78 if self.0.insert(id, v).is_some() {
79 return Err(format!("duplicate id {}", id).into());
80 }
81 }
82 Ok(())
83 }
84
85 pub fn get_str(&self, n: &str) -> Option<&'a T> {
87 self.0.get(n).copied()
88 }
89
90 pub fn get_name(&self, n: &NameRef<T>) -> Option<&'a T> {
92 self.get_str(&n.val)
93 }
94
95 pub fn get_raw(&self, url: &Url) -> Option<&'a T> {
100 match url {
101 Url::Fragment(n) => self.get_str(n),
102 Url::Other(_) => None,
103 }
104 }
105
106 pub fn get(&self, url: &UrlRef<T>) -> Option<&'a T> {
114 self.get_raw(&url.val)
115 }
116}
117
118impl<'a, T: ?Sized> Index<&NameRef<T>> for LocalMap<'a, T> {
119 type Output = T;
120
121 fn index(&self, index: &NameRef<T>) -> &Self::Output {
122 self.get_name(index).unwrap()
123 }
124}
125
126impl<'a, T: ?Sized> Index<&UrlRef<T>> for LocalMap<'a, T> {
127 type Output = T;
128
129 fn index(&self, index: &UrlRef<T>) -> &Self::Output {
130 self.get(index).unwrap()
131 }
132}
133
134pub trait Traversable {
137 fn traverse<'a, E>(
139 doc: &'a Document,
140 f: impl FnMut(&'a Self) -> Result<(), E>,
141 ) -> Result<(), E>
142 where
143 Self: 'a;
144}
145
146trait IdField {
147 fn try_to_str(&self) -> Option<&str>;
148}
149impl IdField for Option<String> {
150 fn try_to_str(&self) -> Option<&str> {
151 self.as_deref()
152 }
153}
154impl IdField for String {
155 fn try_to_str(&self) -> Option<&str> {
156 Some(self)
157 }
158}
159
160macro_rules! mk_local_maps {
161 ($($name:ident: $ty:ty,)*) => {
162 #[derive(Clone, Debug, Default)]
167 pub struct LocalMaps<'a> {
168 $($name: Option<LocalMap<'a, $ty>>,)*
169 }
170
171 impl LocalMaps<'_> {
172 pub fn new() -> Self {
176 Self {
177 $($name: Some(LocalMap::default()),)*
178 }
179 }
180 }
181 $(
182 impl HasId for $ty {
183 fn id(&self) -> Option<&str> {
184 self.id.try_to_str()
185 }
186
187 fn get_local_map<'a, 'b>(maps: &'b LocalMaps<'a>) -> &'b Option<LocalMap<'a, Self>> {
188 &maps.$name
189 }
190
191 fn get_local_map_mut<'a, 'b>(
192 maps: &'b mut LocalMaps<'a>,
193 ) -> &'b mut Option<LocalMap<'a, Self>> {
194 &mut maps.$name
195 }
196 }
197 )*
198 }
199}
200
201mk_local_maps! {
202 animation: Animation,
203 animation_clip: AnimationClip,
204 camera: Camera,
205 controller: Controller,
206 effect: Effect,
207 force_field: ForceField,
208 geometry: Geometry,
209 image: Image,
210 light: Light,
211 material: Material,
212 node: Node,
213 physics_material: PhysicsMaterial,
214 physics_model: PhysicsModel,
215 physics_scene: PhysicsScene,
216 sampler: Sampler,
217 source: Source,
218 vertices: Vertices,
219 visual_scene: VisualScene,
220 idref_array: IdRefArray,
221 name_array: NameArray,
222 bool_array: BoolArray,
223 float_array: FloatArray,
224 int_array: IntArray,
225}
226
227impl<'a> LocalMaps<'a> {
228 pub(crate) fn insert<T: HasId>(&mut self, t: &'a T) {
229 if let Some(id) = t.id() {
230 if let Some(map) = T::get_local_map_mut(self) {
231 assert!(map.0.insert(id, t).is_none());
232 }
233 }
234 }
235
236 pub fn set<T: HasId + 'a>(mut self) -> Self {
249 T::get_local_map_mut(&mut self).get_or_insert_with(Default::default);
250 self
251 }
252
253 pub fn unset<T: HasId + 'a>(mut self) -> Self {
266 *T::get_local_map_mut(&mut self) = None;
267 self
268 }
269
270 pub fn collect(mut self, t: &'a Document) -> Self {
272 t.collect_local_maps(&mut self);
273 self
274 }
275
276 pub fn get_map<T: HasId + ?Sized>(&self) -> Option<&LocalMap<'a, T>> {
278 T::get_local_map(self).as_ref()
279 }
280
281 pub fn get_str<T: HasId + ?Sized>(&self, n: &str) -> Option<&'a T> {
283 self.get_map()?.get_str(n)
284 }
285
286 pub fn get_name<T: HasId + ?Sized>(&self, n: &NameRef<T>) -> Option<&'a T> {
288 self.get_map()?.get_name(n)
289 }
290
291 pub fn get_raw<T: HasId + ?Sized>(&self, url: &Url) -> Option<&'a T> {
296 self.get_map()?.get_raw(url)
297 }
298
299 pub fn get<T: HasId + ?Sized>(&self, url: &UrlRef<T>) -> Option<&'a T> {
307 self.get_map()?.get(url)
308 }
309}
310
311impl<'a, T: HasId + ?Sized> Index<&NameRef<T>> for LocalMaps<'a> {
312 type Output = T;
313
314 fn index(&self, index: &NameRef<T>) -> &Self::Output {
315 self.get_name(index).unwrap()
316 }
317}
318
319impl<'a, T: HasId + ?Sized> Index<&UrlRef<T>> for LocalMaps<'a> {
320 type Output = T;
321
322 fn index(&self, index: &UrlRef<T>) -> &Self::Output {
323 self.get(index).unwrap()
324 }
325}
326
327pub(crate) trait CollectLocalMaps {
328 fn collect_local_maps<'a>(&'a self, _: &mut LocalMaps<'a>) {}
330}
331
332impl<T: CollectLocalMaps> CollectLocalMaps for Option<T> {
333 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
334 if let Some(x) = self {
335 x.collect_local_maps(maps)
336 }
337 }
338}
339
340impl<T: CollectLocalMaps> CollectLocalMaps for Box<T> {
341 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
342 (**self).collect_local_maps(maps)
343 }
344}
345
346impl<T: CollectLocalMaps> CollectLocalMaps for Vec<T> {
347 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
348 for x in self {
349 x.collect_local_maps(maps)
350 }
351 }
352}