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