xvc_ecs/ecs/
r11store.rs

1//! R11Store is 1-1 RelationStore.
2//! We store relationships with identical entities.
3//! It doesn't have any semantics except binding two components with a single entity.
4use std::path::Path;
5
6use crate::{error::Result, XvcStore};
7use crate::{Storable, XvcEntity};
8use std::fmt::Debug;
9
10/// Associates two [XvcStore]s with two different type of components with a single [XvcEntity].
11/// It's like using the same primary key in two database tables.
12#[derive(Debug, Clone)]
13pub struct R11Store<T, U>
14where
15    T: Storable,
16    U: Storable,
17{
18    /// The first XvcStore to be associated
19    pub left: XvcStore<T>,
20    /// The second XvcStore to be associated
21    pub right: XvcStore<U>,
22}
23
24impl<T, U> R11Store<T, U>
25where
26    T: Storable,
27    U: Storable,
28{
29    /// Creates an empty R11Store
30    ///
31    /// The following creates two new stores: `XvcStore<String>` and `XvcStore<i32>` that can be
32    /// used in parallel with the same [`XvcEntity`] keys.
33    ///
34    /// ```
35    /// use xvc_ecs::R11Store;
36    /// let rs = R11Store::<String, i32>::new();
37    /// ```
38    pub fn new() -> Self {
39        Self {
40            left: XvcStore::<T>::new(),
41            right: XvcStore::<U>::new(),
42        }
43    }
44
45    /// inserts an element to both left and right
46    ///
47    /// Having a R11Store<String, String>, the following code inserts "left component" and "right
48    /// component" with the same `XvcEntity(100)`.
49    ///
50    /// ```
51    /// # use xvc_ecs::{R11Store, XvcEntity};
52    /// # let mut rs = R11Store::<String, String>::new();
53    /// let entity: XvcEntity = 100.into();
54    /// rs.insert(&entity, "left component".into(), "right component".into());
55    /// ```
56    pub fn insert(&mut self, entity: &XvcEntity, left_component: T, right_component: U) {
57        self.left.insert(*entity, left_component);
58        self.right.insert(*entity, right_component);
59    }
60
61    /// returns the right element in L-R pair
62    ///
63    /// ```
64    /// # use xvc_ecs::{R11Store, XvcEntity};
65    /// # let mut rs = R11Store::<String, String>::new();
66    /// let entity: XvcEntity = (100u64, 200u64).into();
67    /// rs.insert(&entity, "left component".into(), "right component".to_string());
68    /// ```
69    pub fn left_to_right(&self, entity: &XvcEntity) -> Option<(&XvcEntity, &U)> {
70        self.right.get_key_value(entity)
71    }
72
73    /// returns the left element in L-R pair
74    ///
75    /// ```
76    /// # use xvc_ecs::{R11Store, XvcEntity};
77    /// # let mut rs = R11Store::<String, String>::new();
78    /// let entity: XvcEntity = (100, 200).into();
79    /// rs.insert(&entity, "left component".into(), "right component".into());
80    /// ```
81    pub fn right_to_left(&self, entity: &XvcEntity) -> Option<(&XvcEntity, &T)> {
82        self.left.get_key_value(entity)
83    }
84
85    /// Returns L-R as a tuple
86    /// ```
87    /// # use xvc_ecs::{R11Store, XvcEntity};
88    /// # let mut rs = R11Store::<String, String>::new();
89    /// let entity: XvcEntity = (100, 200).into();
90    /// rs.insert(&entity, "left component".into(), "right component".into());
91    /// let t = rs.tuple(&entity);
92    /// ```
93    pub fn tuple(&self, entity: &XvcEntity) -> (Option<&T>, Option<&U>) {
94        (self.left.get(entity), self.right.get(entity))
95    }
96
97    /// Finds the entity from the left value
98    pub fn entity_by_left(&self, left_element: &T) -> Option<XvcEntity> {
99        match self.left.entities_for(left_element) {
100            Some(entities) => {
101                if entities.len() == 1 {
102                    Some(entities[0])
103                } else if entities.is_empty() {
104                    None
105                } else {
106                    panic!("Multiple entities found for {left_element:?}");
107                }
108            }
109            None => None,
110        }
111    }
112
113    /// Finds the first entity from the right value
114    pub fn entity_by_right(&self, right_element: &U) -> Option<XvcEntity> {
115        match self.right.entities_for(right_element) {
116            None => None,
117            Some(vec_e) => vec_e.first().copied(),
118        }
119    }
120
121    /// removes the components from both right and left
122    pub fn remove(&mut self, entity: XvcEntity) {
123        self.left.remove(entity);
124        self.right.remove(entity);
125    }
126
127    /// Search the right value by left
128    pub fn lookup_by_left(&self, left_element: &T) -> Option<&U> {
129        match self.left.entity_by_value(left_element) {
130            None => None,
131            Some(xe) => self.right.get(&xe),
132        }
133    }
134
135    /// Search the left value by right
136    pub fn lookup_by_right(&self, right_element: &U) -> Option<&T> {
137        match self.right.entity_by_value(right_element) {
138            None => None,
139            Some(xe) => self.left.get(&xe),
140        }
141    }
142
143    /// Run a filter on the store and return elements selected by the predicate
144    pub fn filter(&self, predicate: impl Fn(&T, &U) -> bool) -> R11Store<T, U> {
145        let mut rs = R11Store::<T, U>::new();
146        for (entity, left) in self.left.iter() {
147            if let Some(right) = self.right.get(entity) {
148                if predicate(left, right) {
149                    rs.insert(entity, left.clone(), right.clone());
150                }
151            }
152        }
153        rs
154    }
155}
156
157impl<T, U> R11Store<T, U>
158where
159    T: Storable,
160    U: Storable,
161{
162    /// Creates a 1-1 store by loading member stores with [XvcStore::load_store]
163    pub fn load_r11store(store_root: &Path) -> Result<R11Store<T, U>> {
164        let left = XvcStore::<T>::load_store(store_root)?;
165        let right = XvcStore::<U>::load_store(store_root)?;
166
167        Ok(R11Store { left, right })
168    }
169
170    /// Records a store by recording the member stores with [XvcStore::save].
171    pub fn save_r11store(&self, store_root: &Path) -> Result<()> {
172        self.left.save(store_root)?;
173        self.right.save(store_root)
174    }
175}
176
177impl<T, U> Default for R11Store<T, U>
178where
179    T: Storable,
180    U: Storable,
181{
182    fn default() -> Self {
183        Self::new()
184    }
185}
186
187#[cfg(test)]
188mod test {
189
190    use super::*;
191    use crate::error::Result;
192    #[test]
193    fn test_new() -> Result<()> {
194        let rs1 = R11Store::<String, i32> {
195            left: XvcStore::<String>::new(),
196            right: XvcStore::<i32>::new(),
197        };
198
199        let rs2 = R11Store::<String, i32>::new();
200
201        assert!(rs1.right.len() == rs2.right.len());
202        assert!(rs1.left.len() == rs2.left.len());
203
204        Ok(())
205    }
206
207    #[test]
208    fn test_insert() -> Result<()> {
209        let mut rs = R11Store::<String, String>::new();
210        let entity: XvcEntity = (100, 12830912380).into();
211        rs.insert(&entity, "left component".into(), "right component".into());
212        assert!(rs.left[&entity] == "left component");
213        assert!(rs.right[&entity] == "right component");
214        Ok(())
215    }
216
217    #[test]
218    fn test_left_to_right() -> Result<()> {
219        let mut rs = R11Store::<String, String>::new();
220        let entity: XvcEntity = (100, 218021380921).into();
221        rs.insert(
222            &entity,
223            "left component".into(),
224            "right component".to_string(),
225        );
226        assert!(rs.left_to_right(&entity) == Some((&entity, &"right component".to_string())));
227        assert!(rs.left_to_right(&(101, 921309218309).into()).is_none());
228        Ok(())
229    }
230    #[test]
231    fn test_right_to_left() -> Result<()> {
232        let mut rs = R11Store::<String, String>::new();
233        let entity: XvcEntity = (100, 128012389012).into();
234        rs.insert(&entity, "left component".into(), "right component".into());
235        assert!(rs.right_to_left(&entity) == Some((&entity, &"left component".to_string())));
236        assert!(rs.right_to_left(&(101, 8120938120931).into()).is_none());
237        Ok(())
238    }
239
240    #[test]
241    fn test_tuple() -> Result<()> {
242        let mut rs = R11Store::<String, String>::new();
243        let entity: XvcEntity = (100, 123980123819203).into();
244        rs.insert(&entity, "left component".into(), "right component".into());
245        let t = rs.tuple(&entity);
246        assert!(t.0 == Some(&"left component".to_string()));
247        assert!(t.1 == Some(&"right component".to_string()));
248        Ok(())
249    }
250}