xvc-ecs: Entity-Component System for Xvc
xvc-ecs provides the core storage mechanism for the Xvc project, implementing
an Entity-Component System (ECS). It allows associating arbitrary data
(components) with simple integer-based identifiers (entities).
This approach offers flexibility over traditional object-oriented designs, allowing new components and relationships to be added easily as the software evolves.
Core Concepts
-
XvcEntity: A unique identifier for an entity, represented as a(u64, u64)tuple. Entities themselves don't hold data, they just serve as keys. -
Storable: A trait that components must implement to be stored in persistent stores likeXvcStore. It requiresSerialize,Deserialize,Clone,Debug,Ord, andPartialEq, and atype_descriptionfunction (often implemented via thepersist!macro). -
Components: Plain Rust structs or types that implement
Storable(if persistence is needed). -
Stores: Data structures that manage the association between entities and components, or relationships between entities.
-
XvcEntityGenerator: A thread-safe generator used to create new, uniqueXvcEntityvalues. It persists its state to ensure uniqueness across application runs.
Store Types
xvc-ecs provides several types of stores:
-
XvcStore<T>: The primary persistent store for components of typeT.- Maps
XvcEntityto a componentT. - Maintains a reverse index (
T->Vec<XvcEntity>) for quick lookups by value. - Uses an
EventLog(Add/Removeevents) for persistence. Changes are journaled and saved to timestamped JSON files. - Supports loading from/saving to directories.
- Maps
-
HStore<T>: An ephemeral (non-persistent) store based onHashMap<XvcEntity, T>.- Useful for temporary operations or when serialization is not required.
- Provides fast lookups.
- Offers various join operations (
left_join,full_join,join).
-
VStore<T>: A store based onVec<(XvcEntity, T)>.- Allows multiple components of the same type to be associated with the same
XvcEntity(though conversion toXvcStoreenforces uniqueness later). - Also uses
EventLogfor persistence, similar toXvcStore.
- Allows multiple components of the same type to be associated with the same
Relationship Stores
These stores manage relationships between entities/components:
-
R11Store<T, U>: Manages a 1-to-1 relationship. Associates a componentTand a componentUwith the sameXvcEntity.- Internally uses two
XvcStores (XvcStore<T>andXvcStore<U>). - Allows looking up the related component given an entity.
- Internally uses two
-
R1NStore<T, U>: Manages a 1-to-N (Parent-Child) relationship. One parent entity (associated with componentT) can have multiple child entities (associated with componentU).- Uses
XvcStore<T>for parents,XvcStore<U>for children, andXvcStore<ChildEntity<U, T>>to store the child-to-parent links. - Allows finding all children of a parent or the parent of a child.
- Uses
-
RMNStore<T, U>: Manages an M-to-N relationship. Allows arbitrary connections between entities associated with componentsTandU.- Uses multiple underlying stores to track relationships in both directions.
- Provided for completenes, not used or tested extensively.
Persistence (EventLog)
XvcStore and VStore achieve persistence through an EventLog.
- Operations like adding or removing components are recorded as
Event::AddorEvent::Remove. - These events are collected in the
currentEventLog. - When a store is saved (
to_dir/save), thecurrentEventLogis serialized to a new JSON file in the store's directory. The filename is a timestamp to ensure chronological order. - When a store is loaded (
from_dir/load_store), all JSON files in the directory are read in sorted order, and the events are replayed to reconstruct the store's state. The replayed events form thepreviousEventLog.
Basic Usage
use ;
use ;
use Path;
use TempDir; // For example purposes
// 1. Define your component struct
// 2. Make it Storable using the persist! macro
persist!;
// Or implement manually:
// impl Storable for Position {
// fn type_description() -> String {
// "position".to_string()
// }
// }