vizia_core/storage/
animatable_set.rs

1use crate::animation::{AnimationState, Interpolator};
2use crate::prelude::*;
3use vizia_storage::{SparseSet, SparseSetGeneric, SparseSetIndex};
4
5const INDEX_MASK: u32 = u32::MAX / 4;
6const INLINE_MASK: u32 = 1 << 31;
7const INHERITED_MASK: u32 = 1 << 30;
8
9/// Represents an index that can either be used to retrieve inline or shared data
10///
11/// Since inline data will override shared data, this allows the same index to be used
12/// with a flag to indicate which data the index refers to.
13/// The first bit of the u32 internal value is used to signify if the data index
14/// refers to shared (default) or inline data:
15/// - 0 - shared
16/// - 1 - inline
17#[derive(Clone, Copy, PartialEq)]
18struct DataIndex(u32);
19
20impl DataIndex {
21    /// Create a new data index with the first bit set to 1, indicating that
22    /// the index refers to inline data.
23    pub fn inline(index: usize) -> Self {
24        assert!((index as u32) < INDEX_MASK);
25        let value = (index as u32) | INLINE_MASK;
26        Self(value)
27    }
28
29    pub fn inherited(self) -> Self {
30        let value = self.0;
31        Self(value | INHERITED_MASK)
32    }
33
34    /// Create a new data index with the first bit set to 0, indicating that
35    /// the index refers to shared data.
36    pub fn shared(index: usize) -> Self {
37        assert!((index as u32) < INDEX_MASK);
38        Self(index as u32)
39    }
40
41    /// Retrieve the inline or shared data index.
42    pub fn index(&self) -> usize {
43        (self.0 & INDEX_MASK) as usize
44    }
45
46    /// Returns true if the data index refers to inline data.
47    pub fn is_inline(&self) -> bool {
48        (self.0 & INLINE_MASK).rotate_left(1) != 0
49    }
50
51    /// Returns true if the data index refers to an inherited value
52    pub fn is_inherited(&self) -> bool {
53        (self.0 & INHERITED_MASK).rotate_left(2) != 0
54    }
55
56    /// Create a null data index.
57    ///
58    /// A null data index is used to signify that the index refers to no data.
59    pub fn null() -> Self {
60        Self(u32::MAX >> 1)
61    }
62}
63
64impl std::fmt::Debug for DataIndex {
65    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66        if self.is_inline() {
67            write!(f, "Inline: {}", self.index())
68        } else {
69            write!(f, "Shared: {}", self.index())
70        }
71    }
72}
73
74/// An Index is used by the AnimatableSet and contains a data index and an animation index.
75#[derive(Debug, Clone, Copy, PartialEq)]
76pub(crate) struct InlineIndex {
77    data_index: DataIndex,
78    anim_index: u32,
79}
80
81impl Default for InlineIndex {
82    fn default() -> Self {
83        InlineIndex { data_index: DataIndex::null(), anim_index: u32::MAX }
84    }
85}
86
87impl SparseSetIndex for InlineIndex {
88    fn new(index: usize) -> Self {
89        InlineIndex { data_index: DataIndex::inline(index), anim_index: u32::MAX }
90    }
91
92    fn null() -> Self {
93        Self::default()
94    }
95
96    fn index(&self) -> usize {
97        self.data_index.index()
98    }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq)]
102pub(crate) struct SharedIndex {
103    data_index: u32,
104    animation: Animation,
105}
106
107impl Default for SharedIndex {
108    fn default() -> Self {
109        SharedIndex { data_index: u32::MAX, animation: Animation::null() }
110    }
111}
112
113impl SparseSetIndex for SharedIndex {
114    fn new(index: usize) -> Self {
115        SharedIndex { data_index: index as u32, animation: Animation::null() }
116    }
117
118    fn null() -> Self {
119        Self::default()
120    }
121
122    fn index(&self) -> usize {
123        self.data_index as usize
124    }
125}
126
127/// Animatable set is used for storing inline and shared data for entities as well as definitions for
128/// animations, which can be played for entities, and transitions, which play when an entity matches a new shared style
129/// rule which defines a trnasition.
130///
131/// Animations are moved from animations to active_animations when played. This allows the active
132/// animations to be quickly iterated to update the value.
133#[derive(Default, Debug)]
134pub(crate) struct AnimatableSet<T: Interpolator> {
135    /// Shared data determined by style rules
136    pub(crate) shared_data: SparseSetGeneric<SharedIndex, T>,
137    /// Inline data defined on specific entities
138    pub(crate) inline_data: SparseSetGeneric<InlineIndex, T>,
139    /// Animation descriptions
140    animations: SparseSet<AnimationState<T>>,
141    /// Animations which are currently playing
142    active_animations: Vec<AnimationState<T>>,
143}
144
145impl<T> AnimatableSet<T>
146where
147    T: 'static + Default + Clone + Interpolator + PartialEq + std::fmt::Debug,
148{
149    /// Insert an inline value for an entity.
150    pub fn insert(&mut self, entity: Entity, value: T) {
151        self.inline_data.insert(entity, value);
152    }
153
154    /// Remove an entity and any inline data.
155    pub fn remove(&mut self, entity: Entity) -> Option<T> {
156        let entity_index = entity.index();
157
158        if entity_index < self.inline_data.sparse.len() {
159            let active_anim_index = self.inline_data.sparse[entity_index].anim_index as usize;
160
161            if active_anim_index < self.active_animations.len() {
162                let anim_state = &mut self.active_animations[active_anim_index];
163                anim_state.t = 1.0;
164
165                self.remove_innactive_animations();
166            }
167
168            let data_index = self.inline_data.sparse[entity_index].data_index;
169            if data_index.is_inline() && !data_index.is_inherited() {
170                self.inline_data.remove(entity)
171            } else {
172                self.inline_data.sparse[entity_index] = InlineIndex::null();
173                None
174            }
175        } else {
176            None
177        }
178    }
179
180    /// Inherit inline data from a parent entity.
181    pub fn inherit_inline(&mut self, entity: Entity, parent: Entity) -> bool {
182        let entity_index = entity.index();
183        let parent_index = parent.index();
184
185        if parent_index < self.inline_data.sparse.len() {
186            let parent_sparse_index = self.inline_data.sparse[parent_index];
187
188            if parent_sparse_index.data_index.is_inline()
189                && parent_sparse_index.data_index.index() < self.inline_data.dense.len()
190            {
191                if entity_index >= self.inline_data.sparse.len() {
192                    self.inline_data.sparse.resize(entity_index + 1, InlineIndex::null());
193                }
194
195                let entity_sparse_index = self.inline_data.sparse[entity_index];
196
197                if self.inline_data.sparse[entity_index].data_index.index()
198                    != parent_sparse_index.data_index.index()
199                {
200                    if entity_sparse_index.data_index.index() < self.inline_data.dense.len() {
201                        if entity_sparse_index.data_index.is_inherited()
202                            && entity_sparse_index.data_index.is_inline()
203                        {
204                            self.inline_data.sparse[entity_index] = InlineIndex {
205                                data_index: DataIndex::inline(
206                                    parent_sparse_index.data_index.index(),
207                                )
208                                .inherited(),
209                                anim_index: u32::MAX,
210                            };
211                            return true;
212                        }
213                    } else {
214                        self.inline_data.sparse[entity_index] = InlineIndex {
215                            data_index: DataIndex::inline(parent_sparse_index.data_index.index())
216                                .inherited(),
217                            anim_index: u32::MAX,
218                        };
219                        return true;
220                    }
221                }
222            }
223        }
224
225        false
226    }
227
228    /// Inherit shared data from a parent entity.
229    pub fn inherit_shared(&mut self, entity: Entity, parent: Entity) -> bool {
230        let entity_index = entity.index();
231        let parent_index = parent.index();
232
233        if parent_index < self.inline_data.sparse.len() {
234            let parent_sparse_index = self.inline_data.sparse[parent_index];
235
236            if !parent_sparse_index.data_index.is_inline()
237                && parent_sparse_index.data_index.index() < self.shared_data.dense.len()
238            {
239                if entity_index >= self.inline_data.sparse.len() {
240                    self.inline_data.sparse.resize(entity_index + 1, InlineIndex::null());
241                }
242
243                let entity_sparse_index = self.inline_data.sparse[entity_index];
244
245                if !entity_sparse_index.data_index.is_inline()
246                    && self.inline_data.sparse[entity_index].data_index.index()
247                        != parent_sparse_index.data_index.index()
248                {
249                    if entity_sparse_index.data_index.index() < self.shared_data.dense.len() {
250                        if entity_sparse_index.data_index.is_inherited() {
251                            self.inline_data.sparse[entity_index] = InlineIndex {
252                                data_index: DataIndex::shared(
253                                    parent_sparse_index.data_index.index(),
254                                )
255                                .inherited(),
256                                anim_index: u32::MAX,
257                            };
258                            return true;
259                        }
260                    } else {
261                        if !entity_sparse_index.data_index.is_inline() {
262                            self.inline_data.sparse[entity_index] = InlineIndex {
263                                data_index: DataIndex::shared(
264                                    parent_sparse_index.data_index.index(),
265                                )
266                                .inherited(),
267                                anim_index: u32::MAX,
268                            };
269                        }
270                        return true;
271                    }
272                }
273            }
274        }
275
276        false
277    }
278
279    /// Inserts an animation
280    ///
281    /// Animations exist separately to inline (entity) data and shared (rule) data.
282    /// Playing an aimation for a particular entity will clone the animation state to the
283    /// active animations and then link the entity to it.
284    pub(crate) fn insert_animation(
285        &mut self,
286        animation: Animation,
287        animation_description: AnimationState<T>,
288    ) {
289        self.animations.insert(animation, animation_description);
290    }
291
292    pub(crate) fn insert_rule(&mut self, rule: Rule, value: T) {
293        self.shared_data.insert(rule, value);
294    }
295
296    // pub(crate) fn remove_rule(&mut self, rule: Rule) -> Option<T> {
297    //     self.shared_data.remove(rule)
298    // }
299
300    /// Inserts a transition for a given rule
301    ///
302    /// Transitions are animations which are defined for a particular rule. When an entity is linked to
303    /// a rule any transition associated with that rule will play for that entity.
304    ///
305    pub(crate) fn insert_transition(&mut self, rule: Rule, animation: Animation) {
306        // Check if the rule exists
307        if self.shared_data.contains(rule) && self.animations.contains(animation) {
308            self.shared_data.sparse[rule.index()].animation = animation;
309        }
310    }
311
312    /// Play an animation for a given entity.
313    pub(crate) fn play_animation(
314        &mut self,
315        entity: Entity,
316        animation: Animation,
317        start_time: Instant,
318        duration: Duration,
319        delay: Duration,
320    ) {
321        let entity_index = entity.index();
322
323        if !self.animations.contains(animation) {
324            return;
325        }
326
327        // If there is no inline or shared data for the entity then add the entity as animation only
328        if entity_index >= self.inline_data.sparse.len() {
329            self.inline_data.sparse.resize(entity_index + 1, InlineIndex::null());
330        }
331
332        if entity_index < self.inline_data.sparse.len() {
333            let active_anim_index = self.inline_data.sparse[entity_index].anim_index as usize;
334            if active_anim_index < self.active_animations.len() {
335                let anim_state = &mut self.active_animations[active_anim_index];
336                if anim_state.id == animation {
337                    anim_state.active = true;
338                    anim_state.t = 0.0;
339                    anim_state.start_time = start_time;
340                    anim_state.output = Some(
341                        self.animations
342                            .get(animation)
343                            .cloned()
344                            .unwrap()
345                            .keyframes
346                            .first()
347                            .unwrap()
348                            .value
349                            .clone(),
350                    );
351                } else {
352                    anim_state.output = Some(
353                        self.animations
354                            .get(animation)
355                            .cloned()
356                            .unwrap()
357                            .keyframes
358                            .first()
359                            .unwrap()
360                            .value
361                            .clone(),
362                    );
363                    anim_state.entities.remove(&entity);
364                }
365            }
366
367            // Safe to unwrap because already checked that the animation exists
368            let mut anim_state = self.animations.get(animation).cloned().unwrap();
369            anim_state.duration = duration;
370            anim_state.id = animation;
371            anim_state.delay = delay;
372            anim_state.dt = delay.as_secs_f32() / duration.as_secs_f32();
373            anim_state.output = Some(
374                self.animations
375                    .get(animation)
376                    .cloned()
377                    .unwrap()
378                    .keyframes
379                    .first()
380                    .unwrap()
381                    .value
382                    .clone(),
383            );
384            anim_state.play(entity);
385            self.inline_data.sparse[entity_index].anim_index = self.active_animations.len() as u32;
386            self.active_animations.push(anim_state);
387        }
388    }
389
390    /// Stop an animation for a given entity.
391    pub(crate) fn stop_animation(&mut self, entity: Entity, animation: Animation) {
392        let entity_index = entity.index();
393
394        if entity_index < self.inline_data.sparse.len() {
395            let active_anim_index = self.inline_data.sparse[entity_index].anim_index as usize;
396            if active_anim_index < self.active_animations.len() {
397                let anim_state = &mut self.active_animations[active_anim_index];
398                if anim_state.id == animation {
399                    anim_state.entities.remove(&entity);
400                }
401            }
402            self.inline_data.sparse[entity_index].anim_index = u32::MAX;
403        }
404    }
405
406    /// Tick the animation for the given time and return a list of entities which have been animated.
407    pub fn tick(&mut self, time: Instant) -> Vec<Entity> {
408        self.remove_innactive_animations();
409
410        if self.has_animations() {
411            for state in self.active_animations.iter_mut() {
412                // If the animation is already finished then skip
413                if state.t == 1.0 {
414                    continue;
415                }
416
417                if state.keyframes.len() == 1 {
418                    state.output = Some(state.keyframes[0].value.clone());
419                    continue;
420                }
421
422                let elapsed_time = time.duration_since(state.start_time);
423                let mut normalised_time =
424                    (elapsed_time.as_secs_f32() / state.duration.as_secs_f32()) - state.dt;
425
426                normalised_time = normalised_time.clamp(0.0, 1.0);
427
428                let mut i = 0;
429                while i < state.keyframes.len() - 1 && state.keyframes[i + 1].time < normalised_time
430                {
431                    i += 1;
432                }
433                let start = &state.keyframes[i];
434                let end = &state.keyframes[i + 1];
435
436                let normalised_elapsed_time =
437                    (normalised_time - start.time) / (end.time - start.time);
438
439                state.t = normalised_time;
440
441                let timing_t = start.timing_function.value(normalised_elapsed_time);
442                state.output = Some(T::interpolate(&start.value, &end.value, timing_t));
443            }
444
445            self.active_animations
446                .iter()
447                .flat_map(|state| state.entities.clone())
448                .collect::<Vec<Entity>>()
449        } else {
450            Vec::new()
451        }
452    }
453
454    // Returns true if the given entity is linked to an active animation
455    // pub fn is_animating(&self, entity: Entity) -> bool {
456    //     let entity_index = entity.index();
457    //     if entity_index < self.inline_data.sparse.len() {
458    //         let anim_index = self.inline_data.sparse[entity_index].anim_index as usize;
459    //         if anim_index < self.active_animations.len() {
460    //             return true;
461    //         }
462    //     }
463
464    //     false
465    // }
466
467    /// Remove any inactive animations from the active animations list.
468    pub fn remove_innactive_animations(&mut self) {
469        // Create a list of finished animations
470        let inactive: Vec<AnimationState<T>> = self
471            .active_animations
472            .iter()
473            .filter(|e| e.t == 1.0 && !e.persistent)
474            .cloned()
475            .collect();
476
477        // Remove inactive animation states from active animations list
478        // Retains persistent animations
479        self.active_animations.retain(|e| e.t < 1.0 || e.persistent);
480
481        for state in inactive.into_iter() {
482            for entity in state.entities.iter() {
483                self.inline_data.sparse[entity.index()].anim_index = u32::MAX;
484            }
485        }
486
487        for (index, state) in self.active_animations.iter().enumerate() {
488            for entity in state.entities.iter() {
489                self.inline_data.sparse[entity.index()].anim_index = index as u32;
490            }
491        }
492    }
493
494    /// Returns true if there are any active animations.
495    pub fn has_animations(&self) -> bool {
496        for state in self.active_animations.iter() {
497            if state.t < 1.0 {
498                return true;
499            }
500        }
501
502        false
503    }
504
505    /// Returns true if the given entity is linked to an active animation.
506    pub fn has_active_animation(&self, entity: Entity, animation: Animation) -> bool {
507        let entity_index = entity.index();
508        if entity_index < self.inline_data.sparse.len() {
509            let anim_index = self.inline_data.sparse[entity_index].anim_index as usize;
510            if anim_index < self.active_animations.len()
511                && self.active_animations[anim_index].id == animation
512            {
513                return true;
514            }
515        }
516
517        false
518    }
519
520    // Returns a reference to any inline data on the entity if it exists.
521    // pub fn get_inline(&self, entity: Entity) -> Option<&T> {
522    //     let entity_index = entity.index();
523    //     if entity_index < self.inline_data.sparse.len() {
524    //         let data_index = self.inline_data.sparse[entity_index].data_index;
525    //         if data_index.is_inline() {
526    //             return self.inline_data.get(entity);
527    //         }
528    //     }
529
530    //     None
531    // }
532
533    /// Returns a mutable reference to any inline data on the entity if it exists.
534    pub fn get_inline_mut(&mut self, entity: Entity) -> Option<&mut T> {
535        let entity_index = entity.index();
536        if entity_index < self.inline_data.sparse.len() {
537            let data_index = self.inline_data.sparse[entity_index].data_index;
538            if data_index.is_inline() {
539                return self.inline_data.get_mut(entity);
540            }
541        }
542
543        None
544    }
545
546    // /// Returns a reference to any shared data for a given rule if it exists.
547    // pub(crate) fn get_shared(&self, rule: Rule) -> Option<&T> {
548    //     self.shared_data.get(rule)
549    // }
550
551    // /// Returns a mutable reference to any shared data for a given rule if it exists.
552    // pub(crate) fn get_shared_mut(&mut self, rule: Rule) -> Option<&mut T> {
553    //     self.shared_data.get_mut(rule)
554    // }
555
556    pub(crate) fn get_animation_mut(
557        &mut self,
558        animation: Animation,
559    ) -> Option<&mut AnimationState<T>> {
560        self.animations.get_mut(animation)
561    }
562
563    /// Returns a reference to the active animation linked to the given entity if it exists,
564    /// else returns None.
565    pub(crate) fn get_active_animation(&self, entity: Entity) -> Option<&AnimationState<T>> {
566        let entity_index = entity.index();
567        if entity_index < self.inline_data.sparse.len() {
568            let anim_index = self.inline_data.sparse[entity_index].anim_index as usize;
569            if anim_index < self.active_animations.len() {
570                return Some(&self.active_animations[anim_index]);
571            }
572        }
573
574        None
575    }
576
577    /// Returns a reference to the active animations.
578    pub(crate) fn get_active_animations(&mut self) -> Option<&Vec<AnimationState<T>>> {
579        Some(&self.active_animations)
580    }
581
582    /// Get the animated, inline, or shared data value from the storage.
583    pub fn get(&self, entity: Entity) -> Option<&T> {
584        let entity_index = entity.index();
585        if entity_index < self.inline_data.sparse.len() {
586            // Animations override inline and shared styling
587            let animation_index = self.inline_data.sparse[entity_index].anim_index as usize;
588
589            if animation_index < self.active_animations.len() {
590                return self.active_animations[animation_index].get_output();
591            }
592
593            let data_index = self.inline_data.sparse[entity_index].data_index;
594            if data_index.is_inline() {
595                if data_index.index() < self.inline_data.dense.len() {
596                    return Some(&self.inline_data.dense[data_index.index()].value);
597                }
598            } else if data_index.index() < self.shared_data.dense.len() {
599                return Some(&self.shared_data.dense[data_index.index()].value);
600            }
601        }
602
603        None
604    }
605
606    /// Link an entity to some shared data.
607    pub(crate) fn link(&mut self, entity: Entity, rules: &[(Rule, u32)]) -> bool {
608        let entity_index = entity.index();
609
610        // Check if the entity already has some data
611        if entity_index < self.inline_data.sparse.len() {
612            let data_index = self.inline_data.sparse[entity_index].data_index;
613            // If the data is inline then skip linking as inline data overrides shared data
614            if data_index.is_inline() && !data_index.is_inherited() {
615                return false;
616            }
617        }
618
619        // Loop through matched rules and link to the first valid rule
620        for (rule, _) in rules {
621            if let Some(shared_data_index) = self.shared_data.dense_idx(*rule) {
622                // If the entity doesn't have any previous shared data then create space for it
623                if entity_index >= self.inline_data.sparse.len() {
624                    self.inline_data.sparse.resize(entity_index + 1, InlineIndex::null());
625                }
626
627                // Get the animation state index of any animations (transitions) defined for the rule
628                let rule_animation = shared_data_index.animation;
629
630                //if let Some(transition_state) = self.animations.get_mut(rule_animation) {
631                let entity_anim_index = self.inline_data.sparse[entity_index].anim_index as usize;
632                if entity_anim_index < self.active_animations.len() {
633                    // Already animating
634                    let current_value = self.get(entity).cloned().unwrap_or_default();
635                    let current_anim_state = &mut self.active_animations[entity_anim_index];
636                    let rule_data_index = shared_data_index.data_index as usize;
637
638                    if current_anim_state.is_transition() {
639                        // Skip if the transition hasn't changed
640                        if current_anim_state.to_rule != rule_data_index {
641                            if rule_data_index == current_anim_state.from_rule {
642                                // Transitioning back to previous rule
643                                current_anim_state.from_rule = current_anim_state.to_rule;
644                                current_anim_state.to_rule = rule_data_index;
645                                current_anim_state.keyframes.first_mut().unwrap().value =
646                                    self.shared_data.dense[current_anim_state.from_rule]
647                                        .value
648                                        .clone();
649
650                                current_anim_state.keyframes.last_mut().unwrap().value =
651                                    self.shared_data.dense[current_anim_state.to_rule]
652                                        .value
653                                        .clone();
654
655                                current_anim_state.dt = current_anim_state.t - 1.0;
656                                current_anim_state.start_time = Instant::now();
657                            } else {
658                                // Transitioning to new rule
659                                current_anim_state.to_rule = rule_data_index;
660                                current_anim_state.keyframes.first_mut().unwrap().value =
661                                    current_value;
662                                current_anim_state.keyframes.last_mut().unwrap().value =
663                                    self.shared_data.dense[current_anim_state.to_rule]
664                                        .value
665                                        .clone();
666                                current_anim_state.t = 0.0;
667                                current_anim_state.start_time = Instant::now();
668                            }
669                        }
670                    }
671                } else if let Some(transition_state) = self.animations.get_mut(rule_animation) {
672                    // Safe to unwrap because already checked that the rule exists
673                    let end = self.shared_data.get(*rule).unwrap();
674
675                    let entity_data_index = self.inline_data.sparse[entity_index].data_index;
676
677                    if !entity_data_index.is_inline()
678                        && entity_data_index.index() < self.shared_data.dense.len()
679                    {
680                        let start_data =
681                            self.shared_data.dense[entity_data_index.index()].value.clone();
682                        transition_state.keyframes.first_mut().unwrap().value = start_data;
683                    } else {
684                        transition_state.keyframes.first_mut().unwrap().value = end.clone();
685                    }
686
687                    transition_state.keyframes.last_mut().unwrap().value = end.clone();
688                    transition_state.from_rule =
689                        self.inline_data.sparse[entity_index].data_index.index();
690                    transition_state.to_rule = shared_data_index.index();
691
692                    let duration = transition_state.duration;
693                    let delay = transition_state.delay;
694
695                    if transition_state.from_rule != DataIndex::null().index()
696                        && transition_state.from_rule != transition_state.to_rule
697                    {
698                        self.play_animation(
699                            entity,
700                            rule_animation,
701                            Instant::now(),
702                            duration,
703                            delay,
704                        );
705                    }
706                    //}
707                }
708                //}
709
710                let data_index = self.inline_data.sparse[entity_index].data_index;
711
712                // Already linked
713                if !data_index.is_inline() && data_index.index() == shared_data_index.index() {
714                    return false;
715                }
716
717                self.inline_data.sparse[entity_index].data_index =
718                    DataIndex::shared(shared_data_index.index());
719
720                return true;
721            }
722        }
723
724        // No matching rules so set if the data is shared set the index to null if not already null
725        if entity_index < self.inline_data.sparse.len() {
726            let data_index = self.inline_data.sparse[entity_index].data_index;
727            if !data_index.is_inline()
728                && !data_index.is_inherited()
729                && self.inline_data.sparse[entity_index].data_index != DataIndex::null()
730            {
731                self.inline_data.sparse[entity_index].data_index = DataIndex::null();
732                return true;
733            }
734        }
735
736        false
737    }
738
739    /// Clear all rules and animations from the storage.
740    pub fn clear_rules(&mut self) {
741        // Remove transitions
742        for index in self.shared_data.sparse.iter() {
743            let animation = index.animation;
744            self.animations.remove(animation);
745        }
746
747        self.shared_data.clear();
748
749        for index in self.inline_data.sparse.iter_mut() {
750            if !index.data_index.is_inline() {
751                index.data_index = DataIndex::null();
752            }
753        }
754    }
755}
756
757#[cfg(test)]
758mod tests {
759    use super::*;
760
761    // DataIndex tests
762
763    /// Test for creating an inline data index and retrieving the index.
764    #[test]
765    fn inline() {
766        let data_index = DataIndex::inline(5);
767        assert_eq!(data_index.0, INLINE_MASK + 5);
768        assert_eq!(data_index.index(), 5);
769    }
770
771    /// Test that an invalid (too large) inline index causes a panic.
772    #[test]
773    #[should_panic]
774    fn invalid_inline() {
775        DataIndex::inline(usize::MAX);
776    }
777
778    /// Test for creating a shared data index and retrieving the index.
779    #[test]
780    fn shared() {
781        let data_index = DataIndex::shared(5);
782        assert_eq!(data_index.0, 5);
783        assert_eq!(data_index.index(), 5);
784    }
785
786    /// Test that an invalid (too large) shared index causes a panic.
787    #[test]
788    #[should_panic]
789    fn invalid_shared() {
790        DataIndex::shared(usize::MAX);
791    }
792
793    /// Test of the is_inline() method.
794    #[test]
795    fn is_inline() {
796        let data_index1 = DataIndex::inline(5);
797        assert!(data_index1.is_inline());
798        let data_index2 = DataIndex::shared(5);
799        assert!(!data_index2.is_inline());
800    }
801
802    /// Test that a null data index is the correct value #7FFFFFFF (i.e. all bits = 1 except the first bit).
803    #[test]
804    fn null() {
805        let data_index = DataIndex::null();
806        assert_eq!(data_index.0, 2147483647);
807    }
808
809    // AnimatableStorage tests
810
811    /// Test for constructing a new empty animatable storage.
812    #[test]
813    fn new() {
814        let animatable_storage = AnimatableSet::<f32>::default();
815        assert!(animatable_storage.inline_data.is_empty());
816        assert!(animatable_storage.shared_data.is_empty());
817        assert!(animatable_storage.animations.is_empty());
818        assert!(animatable_storage.active_animations.is_empty());
819    }
820
821    /// Test inserting inline data into the storage.
822    #[test]
823    fn insert_inline() {
824        let mut animatable_storage = AnimatableSet::default();
825        animatable_storage.insert(Entity::root(), 5.0);
826        //assert_eq!(animatable_storage.entity_indices.first().unwrap().data_index, DataIndex::inline(0));
827    }
828}