Experiments in applying Entity-Component-System patterns to durable data storage APIs.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Various utility fns around Entity/Component

moritz.vongoewels.de 9e9f94d3 6322ac2a

verified
+96 -3
+37
src/component.rs
··· 115 115 Ok(rusqlite::types::Value::Null) 116 116 } 117 117 } 118 + 119 + pub trait ComponentSet { 120 + const SIZE: usize; 121 + type Array<T>: From<Self::Tuple<T>> + IntoIterator<Item = T> + AsRef<[T]> + TryFrom<Vec<T>>; 122 + type Tuple<T>: From<Self::Array<T>>; 123 + 124 + fn component_names() -> Self::Array<&'static str>; 125 + } 126 + 127 + macro_rules! type_as_other { 128 + ( $a: ty, $b: ty ) => { 129 + $b 130 + }; 131 + } 132 + 133 + macro_rules! impl_component_set { 134 + ($s: literal, $($c: ident),*) => { 135 + impl<$($c: Component),*> ComponentSet for ($($c,)*) 136 + { 137 + const SIZE: usize = $s; 138 + type Array<T> = [T; $s]; 139 + type Tuple<T> = ($(type_as_other!($c, T),)*); 140 + 141 + fn component_names() -> Self::Array<&'static str> { 142 + [ 143 + $($c::component_name()),* 144 + ] 145 + } 146 + } 147 + }} 148 + 149 + impl_component_set!(1, C1); 150 + impl_component_set!(2, C1, C2); 151 + impl_component_set!(3, C1, C2, C3); 152 + impl_component_set!(4, C1, C2, C3, C4); 153 + impl_component_set!(5, C1, C2, C3, C4, C5); 154 + impl_component_set!(6, C1, C2, C3, C4, C5, C6);
+59 -3
src/entity.rs
··· 1 - use std::iter; 1 + use std::{fmt::write, iter}; 2 2 3 - use rusqlite::params; 3 + use rusqlite::{params, OptionalExtension}; 4 + use serde::{de::DeserializeOwned, Deserialize}; 4 5 use tracing::debug; 5 6 6 - use crate::{BelongsTo, Component, ComponentWrite, Ecs, EntityId, Error}; 7 + use crate::{component::ComponentSet, BelongsTo, Component, ComponentWrite, Ecs, EntityId, Error}; 7 8 8 9 #[derive(Debug, Copy, Clone)] 9 10 pub struct WithoutEntityId; ··· 35 36 self.0 36 37 } 37 38 39 + pub fn has<T: Component>(&self) -> bool { 40 + self.try_has::<T>().unwrap() 41 + } 42 + 43 + pub fn try_has<T: Component>(&self) -> Result<bool, Error> { 44 + self.has_dynamic(T::component_name()) 45 + } 46 + 47 + pub fn has_many<C: ComponentSet>(&self) -> C::Array<bool> { 48 + let names = C::component_names(); 49 + let names = names 50 + .into_iter() 51 + .map(|name| self.has_dynamic(&name).unwrap()) 52 + .collect::<Vec<_>>(); 53 + C::Array::try_from(names).map_err(|_| ()).unwrap() 54 + } 55 + 56 + fn has_dynamic(&self, name: &str) -> Result<bool, Error> { 57 + let row = self 58 + .0 59 + .conn 60 + .query_row( 61 + "select true from components where entity = ?1 and component = ?2", 62 + params![self.id(), name], 63 + |_| Ok(()), 64 + ) 65 + .optional()?; 66 + Ok(row.is_some()) 67 + } 68 + 38 69 pub fn component<T: Component>(&self) -> Option<T> { 39 70 self.try_component::<T>().unwrap() 40 71 } ··· 75 106 self.try_destroy().unwrap(); 76 107 } 77 108 109 + pub fn component_names(&self) -> impl Iterator<Item = String> { 110 + self.try_component_names().unwrap() 111 + } 112 + 78 113 #[tracing::instrument(name = "attach", level = "debug", skip_all)] 79 114 pub fn try_attach<T: Component>(self, component: T) -> Result<Self, Error> { 80 115 let data = T::to_rusqlite(component)?; ··· 117 152 debug!(entity = self.id(), "destroyed"); 118 153 Ok(()) 119 154 } 155 + 156 + #[tracing::instrument(name = "component_names", level = "debug")] 157 + pub fn try_component_names(&self) -> Result<impl Iterator<Item = String>, Error> { 158 + let mut stmt = self 159 + .0 160 + .conn 161 + .prepare("select component from components where entity = ?1")?; 162 + let names = stmt 163 + .query_map(params![self.id()], |row| row.get(0))? 164 + .collect::<Result<Vec<_>, _>>()?; 165 + Ok(names.into_iter()) 166 + } 120 167 } 121 168 122 169 impl<'a> NewEntity<'a> { ··· 143 190 self 144 191 } 145 192 193 + pub fn component_names(&self) -> impl Iterator<Item = String> { 194 + std::iter::empty() 195 + } 196 + 146 197 #[tracing::instrument(name = "attach", level = "debug", skip_all)] 147 198 pub fn try_attach<T: Component + ComponentWrite<T>>( 148 199 self, ··· 172 223 #[tracing::instrument(name = "detach", level = "debug", skip_all)] 173 224 pub fn try_detach<T: Component>(&mut self) -> Result<&mut Self, Error> { 174 225 Ok(self) 226 + } 227 + 228 + #[tracing::instrument(name = "component_names", level = "debug")] 229 + pub fn try_component_names(&self) -> Result<impl Iterator<Item = String>, Error> { 230 + Ok(std::iter::empty()) 175 231 } 176 232 } 177 233