vizia_core/storage/
style_set.rs

1#![allow(unused)]
2use crate::prelude::*;
3
4use vizia_storage::{SparseSetGeneric, SparseSetIndex};
5
6const INDEX_MASK: u32 = u32::MAX / 4;
7const INLINE_MASK: u32 = 1 << 31;
8const INHERITED_MASK: u32 = 1 << 30;
9
10/// Represents an index that can either be used to retrieve inline or shared data
11///
12/// Since inline data will override shared data, this allows the same index to be used
13/// with a flag to indicate which data the index refers to.
14/// The first bit of the u32 internal value is used to signify if the data index
15/// refers to shared (default) or inline data:
16/// - 0 - shared
17/// - 1 - inline
18#[derive(Debug, Clone, Copy, PartialEq)]
19struct DataIndex(u32);
20
21impl DataIndex {
22    /// Create a new data index with the first bit set to 1, indicating that
23    /// the index refers to inline data.
24    pub fn inline(index: usize) -> Self {
25        assert!((index as u32) < INDEX_MASK);
26        let value = (index as u32) | INLINE_MASK;
27        Self(value)
28    }
29
30    pub fn inherited(self) -> Self {
31        let value = self.0;
32        Self(value | INHERITED_MASK)
33    }
34
35    /// Create a new data index with the first bit set to 0, indicating that
36    /// the index refers to shared data.
37    pub fn shared(index: usize) -> Self {
38        assert!((index as u32) < INDEX_MASK);
39        Self(index as u32)
40    }
41
42    /// Retrieve the inline or shared data index.
43    pub fn index(&self) -> usize {
44        (self.0 & INDEX_MASK) as usize
45    }
46
47    /// Returns true if the data index refers to inline data.
48    pub fn is_inline(&self) -> bool {
49        (self.0 & INLINE_MASK).rotate_left(1) != 0
50    }
51
52    /// Returns true if the data index refers to an inherited value
53    pub fn is_inherited(&self) -> bool {
54        (self.0 & INHERITED_MASK).rotate_left(2) != 0
55    }
56
57    /// Create a null data index.
58    ///
59    /// A null data index is used to signify that the index refers to no data.
60    pub fn null() -> Self {
61        Self(u32::MAX >> 1)
62    }
63}
64
65/// An Index is used by the AnimatableStorage and contains a data index and an animation index.
66#[derive(Debug, Clone, Copy, PartialEq)]
67struct Index {
68    data_index: DataIndex,
69    anim_index: u32,
70}
71
72impl Default for Index {
73    fn default() -> Self {
74        Index { data_index: DataIndex::null(), anim_index: u32::MAX }
75    }
76}
77
78impl SparseSetIndex for Index {
79    fn new(index: usize) -> Self {
80        Index { data_index: DataIndex::inline(index), anim_index: u32::MAX }
81    }
82
83    fn null() -> Self {
84        Self::default()
85    }
86
87    fn index(&self) -> usize {
88        self.data_index.index()
89    }
90}
91
92/// Animatable storage is used for storing inline and shared data for entities as well as definitions for
93/// animations, which can be played for entities, and transitions, which play when an entity matches a new shared style
94/// rule which defines a trnasition.
95///
96/// Animations are moved from animations to active_animations when played. This allows the active
97/// animations to be quickly iterated to update the value.
98pub struct StyleSet<T> {
99    /// Shared data determined by style rules
100    shared_data: SparseSetGeneric<Index, T>,
101    /// Inline data defined on specific entities
102    inline_data: SparseSetGeneric<Index, T>,
103}
104
105impl<T> Default for StyleSet<T> {
106    fn default() -> Self {
107        Self { shared_data: Default::default(), inline_data: Default::default() }
108    }
109}
110
111impl<T> StyleSet<T>
112where
113    T: 'static + std::fmt::Debug,
114{
115    /// Create a new empty styleset.
116    pub fn new() -> Self {
117        Self::default()
118    }
119
120    /// Insert an inline value for an entity.
121    pub fn insert(&mut self, entity: Entity, value: T) {
122        self.inline_data.insert(entity, value);
123    }
124
125    /// Remove an entity and any inline data.
126    pub fn remove(&mut self, entity: Entity) -> Option<T> {
127        let entity_index = entity.index();
128
129        if entity_index < self.inline_data.sparse.len() {
130            let data_index = self.inline_data.sparse[entity_index].data_index;
131            if data_index.is_inline() && !data_index.is_inherited() {
132                self.inline_data.remove(entity)
133            } else {
134                self.inline_data.sparse[entity_index] = Index::null();
135                None
136            }
137        } else {
138            None
139        }
140    }
141
142    pub fn inherit_inline(&mut self, entity: Entity, parent: Entity) -> bool {
143        let entity_index = entity.index();
144        let parent_index = parent.index();
145
146        if parent_index < self.inline_data.sparse.len() {
147            let parent_sparse_index = self.inline_data.sparse[parent_index];
148
149            if parent_sparse_index.data_index.is_inline()
150                && parent_sparse_index.data_index.index() < self.inline_data.dense.len()
151            {
152                if entity_index >= self.inline_data.sparse.len() {
153                    self.inline_data.sparse.resize(entity_index + 1, Index::null());
154                }
155
156                let entity_sparse_index = self.inline_data.sparse[entity_index];
157
158                if self.inline_data.sparse[entity_index].data_index.index()
159                    != parent_sparse_index.data_index.index()
160                {
161                    if entity_sparse_index.data_index.index() < self.inline_data.dense.len() {
162                        if entity_sparse_index.data_index.is_inherited()
163                            && entity_sparse_index.data_index.is_inline()
164                        {
165                            self.inline_data.sparse[entity_index] = Index {
166                                data_index: DataIndex::inline(
167                                    parent_sparse_index.data_index.index(),
168                                )
169                                .inherited(),
170                                anim_index: u32::MAX,
171                            };
172                            return true;
173                        }
174                    } else {
175                        self.inline_data.sparse[entity_index] = Index {
176                            data_index: DataIndex::inline(parent_sparse_index.data_index.index())
177                                .inherited(),
178                            anim_index: u32::MAX,
179                        };
180                        return true;
181                    }
182                }
183            }
184        }
185
186        false
187    }
188
189    pub fn inherit_shared(&mut self, entity: Entity, parent: Entity) -> bool {
190        let entity_index = entity.index();
191        let parent_index = parent.index();
192
193        if parent_index < self.inline_data.sparse.len() {
194            let parent_sparse_index = self.inline_data.sparse[parent_index];
195
196            if !parent_sparse_index.data_index.is_inline()
197                && parent_sparse_index.data_index.index() < self.shared_data.dense.len()
198            {
199                if entity_index >= self.inline_data.sparse.len() {
200                    self.inline_data.sparse.resize(entity_index + 1, Index::null());
201                }
202
203                let entity_sparse_index = self.inline_data.sparse[entity_index];
204
205                if !entity_sparse_index.data_index.is_inline()
206                    && self.inline_data.sparse[entity_index].data_index.index()
207                        != parent_sparse_index.data_index.index()
208                {
209                    if entity_sparse_index.data_index.index() < self.shared_data.dense.len() {
210                        if entity_sparse_index.data_index.is_inherited() {
211                            self.inline_data.sparse[entity_index] = Index {
212                                data_index: DataIndex::shared(
213                                    parent_sparse_index.data_index.index(),
214                                )
215                                .inherited(),
216                                anim_index: u32::MAX,
217                            };
218                            return true;
219                        }
220                    } else {
221                        self.inline_data.sparse[entity_index] = Index {
222                            data_index: DataIndex::shared(parent_sparse_index.data_index.index())
223                                .inherited(),
224                            anim_index: u32::MAX,
225                        };
226
227                        return true;
228                    }
229                }
230            }
231        }
232
233        false
234    }
235
236    pub fn clear_rules(&mut self) {
237        // Remove transitions (TODO)
238        for _index in self.shared_data.sparse.iter() {
239            //let anim_index = index.anim_index as usize;
240        }
241
242        self.shared_data.clear();
243
244        for index in self.inline_data.sparse.iter_mut() {
245            if !index.data_index.is_inline() {
246                index.data_index = DataIndex::null();
247            }
248        }
249    }
250
251    pub(crate) fn insert_rule(&mut self, rule: Rule, value: T) {
252        self.shared_data.insert(rule, value);
253    }
254
255    // pub(crate) fn remove_rule(&mut self, rule: Rule) -> Option<T> {
256    //     self.shared_data.remove(rule)
257    // }
258
259    /// Returns a reference to any inline data on the entity if it exists.
260    pub fn get_inline(&self, entity: Entity) -> Option<&T> {
261        let entity_index = entity.index();
262        if entity_index < self.inline_data.sparse.len() {
263            let data_index = self.inline_data.sparse[entity_index].data_index;
264            if data_index.is_inline() {
265                return self.inline_data.get(entity);
266            }
267        }
268
269        None
270    }
271
272    /// Returns a mutable reference to any inline data on the entity if it exists.
273    pub fn get_inline_mut(&mut self, entity: Entity) -> Option<&mut T> {
274        let entity_index = entity.index();
275        if entity_index < self.inline_data.sparse.len() {
276            let data_index = self.inline_data.sparse[entity_index].data_index;
277            if data_index.is_inline() {
278                return self.inline_data.get_mut(entity);
279            }
280        }
281
282        None
283    }
284
285    // /// Returns a reference to any shared data for a given rule if it exists.
286    // pub(crate) fn get_shared(&self, rule: Rule) -> Option<&T> {
287    //     self.shared_data.get(rule)
288    // }
289
290    // /// Returns a mutable reference to any shared data for a given rule if it exists.
291    // pub(crate) fn get_shared_mut(&mut self, rule: Rule) -> Option<&mut T> {
292    //     self.shared_data.get_mut(rule)
293    // }
294
295    /// Get the animated, inline, or shared data value from the storage.
296    pub fn get(&self, entity: Entity) -> Option<&T> {
297        let entity_index = entity.index();
298        if entity_index < self.inline_data.sparse.len() {
299            let data_index = self.inline_data.sparse[entity_index].data_index;
300            if data_index.is_inline() {
301                if data_index.index() < self.inline_data.dense.len() {
302                    return Some(&self.inline_data.dense[data_index.index()].value);
303                }
304            } else if data_index.index() < self.shared_data.dense.len() {
305                return Some(&self.shared_data.dense[data_index.index()].value);
306            }
307        }
308
309        None
310    }
311
312    pub fn get_mut(&mut self, entity: Entity) -> Option<&mut T> {
313        let entity_index = entity.index();
314        if entity_index < self.inline_data.sparse.len() {
315            let data_index = self.inline_data.sparse[entity_index].data_index;
316            if data_index.is_inline() && data_index.index() < self.inline_data.dense.len() {
317                return Some(&mut self.inline_data.dense[data_index.index()].value);
318            }
319        }
320
321        None
322    }
323
324    /// Link an entity to some shared data.
325    pub(crate) fn link(&mut self, entity: Entity, rules: &[(Rule, u32)]) -> bool {
326        let entity_index = entity.index();
327
328        // Check if the entity already has some data
329        if entity_index < self.inline_data.sparse.len() {
330            let data_index = self.inline_data.sparse[entity_index].data_index;
331            // If the data is inline then skip linking as inline data overrides shared data
332            if data_index.is_inline() && !data_index.is_inherited() {
333                return false;
334            }
335        }
336
337        // Loop through matched rules and link to the first valid rule
338        for (rule, _) in rules {
339            if let Some(shared_data_index) = self.shared_data.dense_idx(*rule) {
340                // If the entity doesn't have any previous shared data then create space for it
341                if entity_index >= self.inline_data.sparse.len() {
342                    self.inline_data.sparse.resize(entity_index + 1, Index::null());
343                }
344
345                let data_index = self.inline_data.sparse[entity_index].data_index;
346                // Already linked
347                if !data_index.is_inline() && data_index.index() == shared_data_index.index() {
348                    return false;
349                }
350
351                self.inline_data.sparse[entity_index].data_index =
352                    DataIndex::shared(shared_data_index.index());
353
354                return true;
355            }
356        }
357
358        // No matching rules so set if the data is shared set the index to null if not already null
359        if entity_index < self.inline_data.sparse.len() {
360            let data_index = self.inline_data.sparse[entity_index].data_index;
361            if !data_index.is_inline()
362                && !data_index.is_inherited()
363                && self.inline_data.sparse[entity_index].data_index != DataIndex::null()
364            {
365                self.inline_data.sparse[entity_index].data_index = DataIndex::null();
366                return true;
367            }
368        }
369
370        false
371    }
372}
373
374#[cfg(test)]
375mod tests {
376    use super::*;
377
378    // DataIndex tests
379
380    /// Test for creating an inline data index and retrieving the index.
381    #[test]
382    fn inline() {
383        let data_index = DataIndex::inline(5);
384        assert_eq!(data_index.0, INLINE_MASK + 5);
385        assert_eq!(data_index.index(), 5);
386    }
387
388    /// Test that an invalid (too large) inline index causes a panic.
389    #[test]
390    #[should_panic]
391    fn invalid_inline() {
392        DataIndex::inline(usize::MAX);
393    }
394
395    /// Test for creating a shared data index and retrieving the index.
396    #[test]
397    fn shared() {
398        let data_index = DataIndex::shared(5);
399        assert_eq!(data_index.0, 5);
400        assert_eq!(data_index.index(), 5);
401    }
402
403    /// Test that an invalid (too large) shared index causes a panic.
404    #[test]
405    #[should_panic]
406    fn invalid_shared() {
407        DataIndex::shared(usize::MAX);
408    }
409
410    /// Test of the is_inline() method.
411    #[test]
412    fn is_inline() {
413        let data_index1 = DataIndex::inline(5);
414        assert!(data_index1.is_inline());
415        let data_index2 = DataIndex::shared(5);
416        assert!(!data_index2.is_inline());
417    }
418
419    /// Test that a null data index is the correct value #7FFFFFFF (i.e. all bits = 1 except the first bit).
420    #[test]
421    fn null() {
422        let data_index = DataIndex::null();
423        assert_eq!(data_index.0, 2147483647);
424    }
425
426    // AnimatableStorage tests
427
428    /// Test for constructing a new empty animatable storage.
429    #[test]
430    fn new() {
431        let animatable_storage = StyleSet::<f32>::new();
432        assert!(animatable_storage.inline_data.is_empty());
433        assert!(animatable_storage.shared_data.is_empty());
434    }
435
436    /// Test inserting inline data into the storage.
437    #[test]
438    fn insert_inline() {
439        let mut animatable_storage = StyleSet::new();
440        animatable_storage.insert(Entity::root(), 5.0);
441        //assert_eq!(animatable_storage.entity_indices.first().unwrap().data_index, DataIndex::inline(0));
442    }
443}