One-to-One Relationships (#18087)
# Objective Minimal implementation of directed one-to-one relationships via implementing `RelationshipSourceCollection` for `Entity`. Now you can do ```rust #[derive(Component)] #[relationship(relationship_target = Below)] pub struct Above(Entity); #[derive(Component)] #[relationship_target(relationship = Above)] pub struct Below(Entity); ``` ## Future Work It would be nice if the relationships could be fully symmetrical in the future - in the example above, since `Above` is the source of truth you can't add `Below` to an entity and have `Above` added automatically. ## Testing Wrote unit tests for new relationship sources and and verified adding/removing relationships maintains connection as expected.
This commit is contained in:
parent
df6e136ab0
commit
7a1972ed3d
@ -116,6 +116,35 @@ impl<const N: usize> RelationshipSourceCollection for SmallVec<[Entity; N]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RelationshipSourceCollection for Entity {
|
||||||
|
type SourceIter<'a> = core::iter::Once<Entity>;
|
||||||
|
|
||||||
|
fn with_capacity(_capacity: usize) -> Self {
|
||||||
|
Entity::PLACEHOLDER
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(&mut self, entity: Entity) {
|
||||||
|
*self = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&mut self, entity: Entity) {
|
||||||
|
if *self == entity {
|
||||||
|
*self = Entity::PLACEHOLDER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter(&self) -> Self::SourceIter<'_> {
|
||||||
|
core::iter::once(*self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
if *self == Entity::PLACEHOLDER {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -184,4 +213,58 @@ mod tests {
|
|||||||
let collection = rel_target.collection();
|
let collection = rel_target.collection();
|
||||||
assert_eq!(collection, &SmallVec::from_buf([a]));
|
assert_eq!(collection, &SmallVec::from_buf([a]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn entity_relationship_source_collection() {
|
||||||
|
#[derive(Component)]
|
||||||
|
#[relationship(relationship_target = RelTarget)]
|
||||||
|
struct Rel(Entity);
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
#[relationship_target(relationship = Rel)]
|
||||||
|
struct RelTarget(Entity);
|
||||||
|
|
||||||
|
let mut world = World::new();
|
||||||
|
let a = world.spawn_empty().id();
|
||||||
|
let b = world.spawn_empty().id();
|
||||||
|
|
||||||
|
world.entity_mut(a).insert(Rel(b));
|
||||||
|
|
||||||
|
let rel_target = world.get::<RelTarget>(b).unwrap();
|
||||||
|
let collection = rel_target.collection();
|
||||||
|
assert_eq!(collection, &a);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn one_to_one_relationships() {
|
||||||
|
#[derive(Component)]
|
||||||
|
#[relationship(relationship_target = Below)]
|
||||||
|
struct Above(Entity);
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
#[relationship_target(relationship = Above)]
|
||||||
|
struct Below(Entity);
|
||||||
|
|
||||||
|
let mut world = World::new();
|
||||||
|
let a = world.spawn_empty().id();
|
||||||
|
let b = world.spawn_empty().id();
|
||||||
|
|
||||||
|
world.entity_mut(a).insert(Above(b));
|
||||||
|
assert_eq!(a, world.get::<Below>(b).unwrap().0);
|
||||||
|
|
||||||
|
// Verify removing target removes relationship
|
||||||
|
world.entity_mut(b).remove::<Below>();
|
||||||
|
assert!(world.get::<Above>(a).is_none());
|
||||||
|
|
||||||
|
// Verify removing relationship removes target
|
||||||
|
world.entity_mut(a).insert(Above(b));
|
||||||
|
world.entity_mut(a).remove::<Above>();
|
||||||
|
assert!(world.get::<Below>(b).is_none());
|
||||||
|
|
||||||
|
// Actually - a is above c now! Verify relationship was updated correctly
|
||||||
|
let c = world.spawn_empty().id();
|
||||||
|
world.entity_mut(a).insert(Above(c));
|
||||||
|
assert!(world.get::<Below>(b).is_none());
|
||||||
|
assert_eq!(a, world.get::<Below>(c).unwrap().0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user