flax/metadata/
relation.rs

1use crate::component::{ComponentDesc, ComponentValue};
2
3use super::Metadata;
4
5component! {
6    /// Mutually exclusive relation.
7    ///
8    /// Ensures only one pair of the relation exists.
9    pub exclusive: Exclusive,
10
11    ///// Ensures that for every relation `A => B` the relation `B => A` exists.
12    /////
13    ///// This creates a bidirectional graph.
14    //pub symmetric: Symmetric,
15
16}
17
18/// Mutually exclusive relation.
19///
20/// Ensures only one pair exists of the relation exists.
21pub struct Exclusive;
22
23///// Ensures that for every relation `A => B` the relation `B => A` exists.
24/////
25///// This creates a bidirectional graph.
26//pub struct Symmetric;
27
28impl<T: ComponentValue> Metadata<T> for Exclusive {
29    fn attach(_: ComponentDesc, buffer: &mut crate::buffer::ComponentBuffer) {
30        buffer.set(exclusive(), Exclusive);
31    }
32}
33
34// impl<T: ComponentValue> Metadata<T> for Symmetric {
35//     fn attach(_: crate::ComponentInfo, buffer: &mut crate::buffer::ComponentBuffer) {
36//         buffer.set(exclusive(), Exclusive);
37//     }
38// }
39
40#[cfg(test)]
41mod test {
42    use alloc::sync::Arc;
43
44    use super::*;
45
46    component! {
47        a(id): Arc<()> => [ Exclusive ],
48    }
49
50    #[test]
51    #[cfg(feature = "flume")]
52    fn exclusive_set() {
53        use crate::{
54            entity_ids,
55            events::{Event, EventKind, EventSubscriber},
56            relation::RelationExt,
57            relations_like, Entity, EntityIds, Query, QueryBorrow, Relations, World,
58        };
59        use alloc::{sync::Arc, vec, vec::Vec};
60        use itertools::Itertools;
61        use pretty_assertions::assert_eq;
62
63        let mut world = World::new();
64
65        let (tx, rx) = flume::unbounded();
66        world.subscribe(
67            tx.filter_arch(a.with_relation())
68                .filter(|_, v| v.key.id == a.id()),
69        );
70
71        type Expected<'a> = &'a [(Entity, Vec<(Entity, &'a Arc<()>)>)];
72
73        fn ensure(mut query: QueryBorrow<(EntityIds, Relations<Arc<()>>)>, expected: Expected) {
74            assert_eq!(
75                query
76                    .iter()
77                    .map(|v| (v.0, v.1.collect_vec()))
78                    .sorted()
79                    .collect_vec(),
80                expected
81            );
82        }
83
84        let shared = Arc::new(());
85
86        let id1 = world.spawn();
87        let id2 = world.spawn();
88        let id3 = Entity::builder()
89            .set(a(id2), shared.clone())
90            .set(a(id2), shared.clone())
91            .set(a(id1), shared.clone())
92            .spawn(&mut world);
93
94        let mut query = Query::new((entity_ids(), relations_like(a)));
95
96        ensure(
97            query.borrow(&world),
98            &[(id1, vec![]), (id2, vec![]), (id3, vec![(id1, &shared)])],
99        );
100
101        world.set(id1, a(id2), shared.clone()).unwrap();
102
103        assert_eq!(
104            rx.drain().collect_vec(),
105            [
106                Event {
107                    id: id3,
108                    key: a(id1).key(),
109                    kind: EventKind::Added
110                },
111                Event {
112                    id: id1,
113                    key: a(id2).key(),
114                    kind: EventKind::Added
115                }
116            ]
117        );
118
119        world.set(id3, a(id2), shared.clone()).unwrap();
120
121        ensure(
122            query.borrow(&world),
123            &[
124                (id1, vec![(id2, &shared)]),
125                (id2, vec![]),
126                (id3, vec![(id2, &shared)]),
127            ],
128        );
129
130        world.set(id1, a(id3), shared.clone()).unwrap();
131
132        assert_eq!(
133            rx.drain().collect_vec(),
134            [
135                Event {
136                    id: id3,
137                    key: a(id1).key(),
138                    kind: EventKind::Removed
139                },
140                Event {
141                    id: id3,
142                    key: a(id2).key(),
143                    kind: EventKind::Added
144                },
145                Event {
146                    id: id1,
147                    key: a(id2).key(),
148                    kind: EventKind::Removed
149                },
150                Event {
151                    id: id1,
152                    key: a(id3).key(),
153                    kind: EventKind::Added
154                },
155            ]
156        );
157
158        ensure(
159            query.borrow(&world),
160            &[
161                (id1, vec![(id3, &shared)]),
162                (id2, vec![]),
163                (id3, vec![(id2, &shared)]),
164            ],
165        );
166
167        Entity::builder()
168            .set(a(id2), shared.clone())
169            .set(a(id1), shared.clone())
170            .set(a(id3), shared.clone())
171            .set(a(id1), shared.clone())
172            .set(a(id1), shared.clone())
173            .append_to(&mut world, id1)
174            .unwrap();
175
176        ensure(
177            query.borrow(&world),
178            &[
179                (id1, vec![(id1, &shared)]),
180                (id2, vec![]),
181                (id3, vec![(id2, &shared)]),
182            ],
183        );
184
185        assert_eq!(
186            rx.drain().collect_vec(),
187            [
188                Event {
189                    id: id1,
190                    key: a(id3).key(),
191                    kind: EventKind::Removed
192                },
193                Event {
194                    id: id1,
195                    key: a(id1).key(),
196                    kind: EventKind::Added
197                }
198            ]
199        );
200
201        drop(world);
202
203        assert_eq!(
204            rx.drain().sorted_by_key(|v| v.id).collect_vec(),
205            [
206                Event {
207                    id: id1,
208                    key: a(id1).key(),
209                    kind: EventKind::Removed
210                },
211                Event {
212                    id: id3,
213                    key: a(id2).key(),
214                    kind: EventKind::Removed
215                }
216            ]
217        );
218
219        // Ensure relations where dropped
220        assert_eq!(Arc::strong_count(&shared), 1);
221    }
222}