ecs: implement mutable iterators and joins

Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaargh.
ecs
q3k 2020-12-10 00:10:45 +00:00
parent 184a67d6c1
commit 2bd393a536
5 changed files with 245 additions and 70 deletions

View File

@ -5,6 +5,7 @@ rust_library(
srcs = [
"src/lib.rs",
"src/component.rs",
"src/componentmap.rs",
"src/entity.rs",
"src/system.rs",
"src/world.rs",

127
lib/ecs/src/componentmap.rs Normal file
View File

@ -0,0 +1,127 @@
use std::cell::{Cell, UnsafeCell};
use std::collections::BTreeMap;
use std::collections::btree_map::{
Iter as BTMIter,
IterMut as BTMIterMut,
};
use crate::entity;
use crate::component;
type BorrowFlag = isize;
const UNUSED: BorrowFlag = 0;
struct BorrowRef<'b> {
borrow: &'b Cell<BorrowFlag>,
}
impl<'b> BorrowRef<'b> {
fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRef<'b>> {
let b = borrow.get().wrapping_add(1);
if b <= 0 {
None
} else {
borrow.set(b);
Some(BorrowRef { borrow })
}
}
}
impl<'a> Drop for BorrowRef<'a> {
fn drop(&mut self) {
let borrow = self.borrow.get();
self.borrow.set(borrow - 1);
}
}
struct BorrowRefMut<'b> {
borrow: &'b Cell<BorrowFlag>,
}
impl<'b> BorrowRefMut<'b> {
fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRefMut<'b>> {
match borrow.get() {
UNUSED => {
borrow.set(UNUSED - 1);
Some(BorrowRefMut { borrow })
},
_ => None,
}
}
}
impl<'a> Drop for BorrowRefMut<'a> {
fn drop(&mut self) {
let borrow = self.borrow.get();
self.borrow.set(borrow + 1);
}
}
pub struct ComponentMap {
value: UnsafeCell<BTreeMap<entity::ID, Box<dyn component::Component>>>,
borrow: Cell<BorrowFlag>,
}
#[derive(Clone,Debug)]
pub struct AccessError(String);
impl ComponentMap {
pub fn new() -> Self {
Self {
value: UnsafeCell::new(BTreeMap::new()),
borrow: Cell::new(UNUSED),
}
}
pub fn try_iter<'a>(&'a self) -> Result<ComponentMapIter<'a>, AccessError> {
match BorrowRef::new(&self.borrow) {
None => Err(AccessError("already borrowed mutably".to_string())),
Some(b) => Ok(ComponentMapIter {
iter: unsafe {
let map = &*self.value.get();
map.iter()
},
borrow: b,
}),
}
}
pub fn try_iter_mut<'a>(&'a self) -> Result<ComponentMapIterMut<'a>, AccessError> {
match BorrowRefMut::new(&self.borrow) {
None => Err(AccessError("already borrowed mutable".to_string())),
Some(b) => Ok(ComponentMapIterMut {
iter: unsafe {
let map = &mut *self.value.get();
map.iter_mut()
},
borrow: b,
}),
}
}
pub fn insert(&self, e: entity::ID, c: Box<dyn component::Component>) -> Result<(), AccessError> {
match BorrowRefMut::new(&self.borrow) {
None => Err(AccessError("already borrow mutably".to_string())),
Some(b) => {
unsafe {
let map = &mut *self.value.get();
map.insert(e, c);
}
drop(b);
Ok(())
}
}
}
}
pub struct ComponentMapIter<'a> {
pub iter: BTMIter<'a, entity::ID, Box<dyn component::Component>>,
#[allow(dead_code)]
borrow: BorrowRef<'a>,
}
pub struct ComponentMapIterMut<'a> {
pub iter: BTMIterMut<'a, entity::ID, Box<dyn component::Component>>,
#[allow(dead_code)]
borrow: BorrowRefMut<'a>,
}

View File

@ -1,4 +1,5 @@
pub mod component;
pub mod componentmap;
pub mod entity;
pub mod system;
pub mod world;

View File

@ -1,6 +1,9 @@
use std::marker::PhantomData;
use std::iter::Peekable;
use crate::{
component,
world::{ReadData, ReadWriteData, World}
world::{ReadData, ReadDataIter, ReadWriteData, ReadWriteDataIter, World}
};
pub trait System<'a> {
@ -24,21 +27,32 @@ where
}
pub trait Access<'a> {
type Component: component::Component;
//type Component: component::Component;
type Component;
type Iterator: Iterator<Item = (u64, Self::Component)>;
fn fetch(world: &'a World) -> Self;
fn iter(&self) -> Self::Iterator;
}
impl<'a, T: component::Component> Access<'a> for ReadData<'a, T> {
type Component = T;
type Component = &'a T;
type Iterator = ReadDataIter<'a, T>;
fn fetch(world: &'a World) -> Self {
world.components()
}
fn iter(&self) -> ReadDataIter<'a, T> {
Self::iter(self)
}
}
impl<'a, T: component::Component> Access<'a> for ReadWriteData<'a, T> {
type Component = T;
type Component = &'a mut T;
type Iterator = ReadWriteDataIter<'a, T>;
fn fetch(world: &'a World) -> Self {
world.components_mut()
}
fn iter(&self) -> ReadWriteDataIter<'a, T> {
Self::iter_mut(self)
}
}
pub trait DynamicSystemData<'a> {
@ -63,25 +77,74 @@ pub struct Processor<'a> {
}
impl<'a> Processor<'a> {
fn add_system<T: System<'a> + 'static>(&mut self, system: T) {
pub fn add_system<T: System<'a> + 'static>(&mut self, system: T) {
self.runners.push(Box::new(system));
}
fn run(&mut self) {
pub fn run(&mut self) {
for runner in &mut self.runners {
runner.run_world(self.world);
}
}
}
pub trait Join<'a> {
type Iterators;
type Result;
fn join_all(&'a self) -> JoinIter<'a, Self> where Self: Sized;
fn next(iters: &mut Self::Iterators) -> Option<Self::Result>;
}
impl <'a, T: Access<'a>, U: Access<'a>> Join<'a> for (T, U) {
type Iterators = (Peekable<T::Iterator>, Peekable<U::Iterator>);
type Result = (T::Component, U::Component);
fn join_all(&'a self) -> JoinIter<'a, Self> {
return JoinIter{
iterators: (self.0.iter().peekable(), self.1.iter().peekable()),
phantom: PhantomData,
}
}
fn next(iters: &mut Self::Iterators) -> Option<Self::Result> {
loop {
let k1 = { let (k, _) = iters.0.peek()?; *k };
let k2 = { let (k, _) = iters.1.peek()?; *k };
if k1 == k2 {
let (_, v1) = iters.0.next().unwrap();
let (_, v2) = iters.1.next().unwrap();
return Some((v1, v2));
}
if k1 < k2 {
iters.0.next().unwrap();
}
if k2 > k1 {
iters.1.next().unwrap();
}
}
}
}
pub struct JoinIter<'a, J: Join<'a>> {
iterators: J::Iterators,
phantom: PhantomData<&'a J::Result>,
}
impl <'a, J: Join<'a>> Iterator for JoinIter<'a, J> {
type Item = J::Result;
fn next(&mut self) -> Option<Self::Item> {
J::next(&mut self.iterators)
}
}
#[cfg(test)]
mod test {
use crate::{
component::Component,
system,
system::Join,
world::{ReadData, ReadWriteData, World},
};
#[derive(Clone,Debug)]
struct Position {
x: u32,
y: u32,
@ -89,6 +152,7 @@ mod test {
}
impl Component for Position {}
#[derive(Clone,Debug)]
struct Velocity {
x: u32,
y: u32,
@ -100,8 +164,8 @@ mod test {
impl<'a> system::System<'a> for Physics {
type SystemData = (ReadWriteData<'a, Position>, ReadData<'a, Velocity>);
fn run(&mut self, (mut pos, vel): Self::SystemData) {
for ((_, mut p), (_, v)) in pos.iter_mut().zip(vel.iter()) {
fn run(&mut self, (pos, vel): Self::SystemData) {
for (mut p, v) in (pos, vel).join_all() {
p.x += v.x;
p.y += v.y;
p.z += v.z;
@ -113,7 +177,7 @@ mod test {
fn processor() {
let mut world = World::new();
world.new_entity().with(Velocity { x: 0, y: 0, z: 1 }).with(Position { x: 1, y: 2, z: 3 }).build();
world.new_entity().with(Velocity { x: 0, y: 0, z: 1 }).with(Position { x: 4, y: 5, z: 6 }).build();
world.new_entity().with(Velocity { x: 0, y: 0, z: 2 }).with(Position { x: 4, y: 5, z: 6 }).build();
let mut p = system::Processor {
world: &world,
@ -124,6 +188,6 @@ mod test {
let positions = world.components::<Position>();
assert_eq!(vec![3, 6], positions.iter().map(|(_, el)| el.z).collect::<Vec<u32>>());
p.run();
assert_eq!(vec![4, 7], positions.iter().map(|(_, el)| el.z).collect::<Vec<u32>>());
assert_eq!(vec![4, 8], positions.iter().map(|(_, el)| el.z).collect::<Vec<u32>>());
}
}

View File

@ -1,112 +1,103 @@
use std::collections::BTreeMap;
use std::cell::{Ref, RefCell, RefMut};
use std::marker::PhantomData;
use std::iter::Iterator;
use crate::componentmap::{
ComponentMap,
ComponentMapIter,
ComponentMapIterMut,
};
use crate::entity;
use crate::component;
type EntityComponent = (entity::ID, Box<dyn component::Component>);
pub struct ReadData<'a, T: component::Component> {
underlying: &'a RefCell<Vec<EntityComponent>>,
world: &'a World,
phantom: PhantomData<&'a T>,
}
impl<'a, T: component::Component> ReadData<'a, T> {
pub fn iter(&self) -> ReadDataIter<'a, T> {
let cm = self.world.components.get(&component::id::<T>());
ReadDataIter {
underlying: Some(Ref::map(self.underlying.borrow(), |el| el.as_slice())),
phantom: PhantomData,
iter: cm.map(|e| e.try_iter().unwrap() ),
}
}
}
pub struct ReadDataIter<'a, T: component::Component> {
underlying: Option<Ref<'a, [EntityComponent]>>,
phantom: PhantomData<&'a T>,
iter: Option<ComponentMapIter<'a>>,
}
impl <'a, T: component::Component> Iterator for ReadDataIter<'a, T> {
type Item = (entity::ID, Ref<'a, T>);
type Item = (entity::ID, &'a T);
fn next(&mut self) -> Option<Self::Item> {
if self.underlying.as_ref().unwrap().len() == 0 {
if self.iter.is_none() {
return None;
}
let mut id: u64 = 0;
let (head, tail) = Ref::map_split(self.underlying.take().unwrap(), |slice| {
let (head, tail) = slice.split_first().unwrap();
id = head.0;
let ptr = head.1.as_ref();
let el = unsafe { & *(ptr as *const (dyn component::Component) as *const T) };
return (el, tail);
});
self.underlying = Some(tail);
Some((id, head))
match self.iter.as_mut().unwrap().iter.next() {
None => None,
Some((eid, component)) => {
let component = component.as_ref();
let component = unsafe { & *(component as *const (dyn component::Component) as *const T) };
Some((*eid, component))
},
}
}
}
pub struct ReadWriteData<'a, T: component::Component> {
underlying: &'a RefCell<Vec<EntityComponent>>,
world: &'a World,
phantom: PhantomData<&'a T>,
}
impl<'a, T: component::Component> ReadWriteData<'a, T> {
pub fn iter_mut(&mut self) -> ReadWriteDataIter<'a, T> {
pub fn iter_mut(&self) -> ReadWriteDataIter<'a, T> {
let cm = self.world.components.get(&component::id::<T>());
ReadWriteDataIter {
underlying: Some(RefMut::map(self.underlying.borrow_mut(), |el| el.as_mut_slice())),
phantom: PhantomData,
iter: cm.map(|e| e.try_iter_mut().unwrap() ),
}
}
}
pub struct ReadWriteDataIter<'a, T: component::Component> {
underlying: Option<RefMut<'a, [EntityComponent]>>,
phantom: PhantomData<&'a T>,
iter: Option<ComponentMapIterMut<'a>>,
}
impl <'a, T: component::Component> Iterator for ReadWriteDataIter<'a, T> {
type Item = (entity::ID, RefMut<'a, T>);
type Item = (entity::ID, &'a mut T);
fn next(&mut self) -> Option<Self::Item> {
if self.underlying.as_ref().unwrap().len() == 0 {
if self.iter.is_none() {
return None;
}
let mut id: u64 = 0;
let (head, tail) = RefMut::map_split(self.underlying.take().unwrap(), |slice| {
let (head, tail) = slice.split_first_mut().unwrap();
id = head.0;
let ptr: &mut dyn component::Component = &mut (*head.1);
let el = unsafe {
&mut *(ptr as *mut (dyn component::Component) as *mut T)
};
return (el, tail);
});
self.underlying = Some(tail);
Some((id, head))
match self.iter.as_mut().unwrap().iter.next() {
None => None,
Some((eid, component)) => {
let component = component.as_mut();
let component = unsafe { &mut *(component as *mut (dyn component::Component) as *mut T) };
Some((*eid, component))
},
}
}
}
pub struct World {
entities: BTreeMap<entity::ID, entity::Entity>,
components_by_id: BTreeMap<component::ID, RefCell<Vec<EntityComponent>>>,
components: BTreeMap<component::ID, ComponentMap>,
next_id: entity::ID,
empty: RefCell<Vec<EntityComponent>>,
}
impl World {
pub fn new() -> Self {
Self {
entities: BTreeMap::new(),
components_by_id: BTreeMap::new(),
components: BTreeMap::new(),
next_id: 1u64,
empty: RefCell::new(Vec::new()),
}
}
@ -122,32 +113,24 @@ impl World {
c: Box<dyn component::Component>,
e: entity::Entity
) {
let vec = self.components_by_id.entry(cid).or_insert(RefCell::new(vec!()));
vec.borrow_mut().push((e.id(), c));
let map = self.components.entry(cid).or_insert(ComponentMap::new());
map.insert(e.id(), c).unwrap();
}
pub fn commit(&mut self, ent: entity::Entity) {
self.entities.insert(ent.id(), ent);
}
pub fn components<'a, T: component::Component>(&'a self) -> ReadData<T> {
let underlying = match self.components_by_id.get(&component::id::<T>()) {
None => &self.empty,
Some(r) => r,
};
pub fn components<'a, T: component::Component>(&'a self) -> ReadData<'a, T> {
ReadData {
underlying: underlying,
world: self,
phantom: PhantomData,
}
}
pub fn components_mut<'a, T: component::Component>(&'a self) -> ReadWriteData<T> {
let underlying = match self.components_by_id.get(&component::id::<T>()) {
None => &self.empty,
Some(r) => &r,
};
pub fn components_mut<'a, T: component::Component>(&'a self) -> ReadWriteData<'a, T> {
ReadWriteData {
underlying: underlying,
world: self,
phantom: PhantomData,
}
}
@ -183,7 +166,6 @@ mod tests {
let mut named = world.components::<Name>().iter();
let mut named2 = world.components::<Name>().iter();
//assert_eq!(named.len(), 2);
assert_eq!(String::from("foo"), (named.next().unwrap().1).0);
assert_eq!(String::from("foo"), (named2.next().unwrap().1).0);
assert_eq!(String::from("bar"), (named.next().unwrap().1).0);