diff --git a/daemon/src/ecs/components.rs b/daemon/src/ecs/components.rs new file mode 100644 index 0000000..e01b614 --- /dev/null +++ b/daemon/src/ecs/components.rs @@ -0,0 +1,44 @@ +use crate::{session_core_session, session_core_v1}; +use std::time; + +pub trait Component: Sized { + fn storage(world: &mut super::World) -> &mut Vec>; + fn storage_ref(world: &super::World) -> &Vec>; +} + +macro_rules! component { + ($name:ident, $field:ident) => { + impl Component for $name { + fn storage(world: &mut super::World) -> &mut Vec> { + &mut world.$field + } + fn storage_ref(world: &super::World) -> &Vec> { + &world.$field + } + } + }; +} + +pub struct Uid(pub u32); +component!(Uid, uid_components); + +pub struct Username(pub String); +component!(Username, username_components); + +pub struct Vt(pub u32); +component!(Vt, vt_components); + +pub struct Seat(pub Option); +component!(Seat, seat_components); + +pub struct Timestamp(pub time::SystemTime); +component!(Timestamp, timestamp_components); + +pub struct LeaderId(pub i32); +component!(LeaderId, leader_id_components); + +pub struct SessionObjects(pub Vec); +component!(SessionObjects, session_objects_components); + +pub struct ActiveState(pub session_core_v1::ActiveState); +component!(ActiveState, active_state_components); diff --git a/daemon/src/ecs/mod.rs b/daemon/src/ecs/mod.rs new file mode 100644 index 0000000..0d5e896 --- /dev/null +++ b/daemon/src/ecs/mod.rs @@ -0,0 +1,100 @@ +mod components; + +use crate::session; +pub use components::*; +use crate::{session_core_session, session_core_v1}; +use std::collections::HashMap; +use std::time; + +#[derive(Copy, Clone, Default)] +pub struct Entity(usize); + +#[derive(Default)] +pub struct World { + next_entity: usize, + free_entities: Vec, + session_entities: HashMap, + uid_components: Vec>, + username_components: Vec>, + vt_components: Vec>, + seat_components: Vec>, + timestamp_components: Vec>, + leader_id_components: Vec>, + session_objects_components: Vec>, + active_state_components: Vec>, +} + +impl World { + pub fn new() -> Self { + Self::default() + } + + fn entity(&mut self) -> Entity { + if let Some(entity) = self.free_entities.pop() { + return entity; + } + + let entity = Entity(self.next_entity); + self.next_entity += 1; + entity + } + + pub fn insert_session( + &mut self, + session_id: session::SessionId, + uid: u32, + username: String, + vt: u32, + seat: Option, + timestamp: time::SystemTime, + leader_id: i32, + objects: Vec, + active_state: session_core_v1::ActiveState, + ) -> Entity { + let entity = self.entity(); + self.session_entities.insert(session_id, entity); + self.insert(entity, Uid(uid)); + self.insert(entity, Username(username)); + self.insert(entity, Vt(vt)); + self.insert(entity, Seat(seat)); + self.insert(entity, Timestamp(timestamp)); + self.insert(entity, LeaderId(leader_id)); + self.insert(entity, SessionObjects(objects)); + self.insert(entity, ActiveState(active_state)); + entity + } + + pub fn session_entity(&self, session_id: session::SessionId) -> Option { + self.session_entities.get(&session_id).copied() + } + + pub fn insert(&mut self, entity: Entity, component: C) + where + C: Component, + { + let storage = C::storage(self); + if storage.len() <= entity.0 { + storage.reserve(entity.0 + 1 - storage.len()); + storage.resize_with(entity.0 + 1, || None); + } + storage[entity.0] = Some(component); + } + + pub fn get(&self, entity: Entity) -> Option<&C> + where + C: Component, + { + C::storage_ref(self).get(entity.0)?.as_ref() + } + + pub fn get_mut(&mut self, entity: Entity) -> Option<&mut C> + where + C: Component, + { + C::storage(self).get_mut(entity.0)?.as_mut() + } + + pub fn remove_entity(&mut self, entity: Entity) { + self.free_entities.push(entity); + } +} diff --git a/daemon/src/main.rs b/daemon/src/main.rs index 242af92..5d3e358 100644 --- a/daemon/src/main.rs +++ b/daemon/src/main.rs @@ -16,6 +16,7 @@ mod seat_v1 { mod cgroup; mod client; mod device; +mod ecs; mod seat; mod session; mod terminal; @@ -94,6 +95,7 @@ struct Sessiond { next_client_id: client::ClientId, clients: Vec>>, seat_access: SeatAccess, + world: ecs::World, } impl Sessiond { @@ -395,6 +397,7 @@ fn main() -> anyhow::Result<()> { next_client_id: client::ClientId::from_raw(1), clients: Vec::new(), seat_access, + world: ecs::World::new(), }; let path = path::Path::new("/run/sessiond.sock"); diff --git a/daemon/src/session.rs b/daemon/src/session.rs index 972dc54..675b265 100644 --- a/daemon/src/session.rs +++ b/daemon/src/session.rs @@ -1,7 +1,7 @@ use crate::{session_core_session, session_core_v1}; use std::time; -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct SessionId(u32); impl SessionId {