sparsey/component/
group_info.rs

1use crate::component::NonZeroStorageMask;
2use core::cmp;
3
4/// Grouping information for any number of views in a query.
5#[derive(Clone, Copy, Default, Debug)]
6pub enum QueryGroupInfo {
7    /// The query is empty.
8    #[default]
9    Empty,
10    /// The query has one view.
11    One(ViewGroupInfo),
12    /// The query has multiple compatible views.
13    Many(GroupInfo),
14}
15
16impl QueryGroupInfo {
17    /// Tries to add two group infos.
18    ///
19    /// Returns the new group info if the operands were compatible.
20    #[inline]
21    #[must_use]
22    pub fn add_query(&self, other: &Self) -> Option<Self> {
23        let query = match (self, other) {
24            (Self::Empty, Self::Empty) => Self::Empty,
25            (query, Self::Empty) | (Self::Empty, query) => *query,
26            (query_a, query_b) => {
27                let query_a = query_a.group_info()?;
28                let query_b = query_b.group_info()?;
29                Self::Many(query_a.add_group(query_b)?)
30            }
31        };
32
33        Some(query)
34    }
35
36    /// Tries to add a view to the current group info.
37    ///
38    /// Returns the new group info if the operands were compatible.
39    #[inline]
40    #[must_use]
41    pub fn add_view(&self, view: &ViewGroupInfo) -> Option<Self> {
42        match self {
43            Self::Empty => Some(Self::One(*view)),
44            Self::One(old_view) => {
45                if let (Some(info_a), Some(info_b)) = (old_view.info, &view.info) {
46                    Some(Self::Many(info_a.add_group(*info_b)?))
47                } else {
48                    None
49                }
50            }
51            Self::Many(old_info) => {
52                if let Some(info) = &view.info {
53                    Some(Self::Many(old_info.add_group(*info)?))
54                } else {
55                    None
56                }
57            }
58        }
59    }
60
61    /// Returns the group info of this query, if any.
62    #[inline]
63    #[must_use]
64    pub fn group_info(&self) -> Option<GroupInfo> {
65        match self {
66            Self::Empty => None,
67            Self::One(view) => view.info,
68            Self::Many(info) => Some(*info),
69        }
70    }
71}
72
73/// Stores the length and grouping information for a component view.
74#[derive(Clone, Copy, Debug)]
75pub struct ViewGroupInfo {
76    /// The group info of the view, if any.
77    pub info: Option<GroupInfo>,
78    /// The number of components in the view.
79    pub len: usize,
80}
81
82/// Grouping information for one or more views.
83#[derive(Clone, Copy, Debug)]
84pub struct GroupInfo {
85    pub(crate) group_start: u8,
86    pub(crate) group_end: u8,
87    pub(crate) storage_mask: NonZeroStorageMask,
88}
89
90impl GroupInfo {
91    /// Tries to add two group infos.
92    ///
93    /// Returns the new group info if the operands were compatible.
94    #[inline]
95    #[must_use]
96    pub fn add_group(self, other: GroupInfo) -> Option<GroupInfo> {
97        if self.group_start != other.group_start {
98            return None;
99        }
100
101        Some(GroupInfo {
102            group_start: self.group_start,
103            group_end: cmp::max(self.group_end, other.group_end),
104            storage_mask: self.storage_mask | other.storage_mask,
105        })
106    }
107}