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.

edition = 2024

moritz.vongoewels.de 192ffcf7 d51771bf

verified
+33 -36
+1 -1
Cargo.toml
··· 1 1 [package] 2 2 name = "ecsdb" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 6 6 [dependencies] 7 7 anyhow = "1.0.99"
+1 -1
ecsdb_derive/Cargo.toml
··· 1 1 [package] 2 2 name = "ecsdb_derive" 3 3 version = "0.1.0" 4 - edition = "2021" 4 + edition = "2024" 5 5 6 6 [lib] 7 7 proc-macro = true
+4 -5
ecsdb_derive/src/lib.rs
··· 2 2 3 3 use proc_macro::TokenStream; 4 4 use quote::{format_ident, quote}; 5 - use syn::{punctuated::Punctuated, Attribute, Data, Expr, Fields, Lit, Meta, Token}; 5 + use syn::{Attribute, Data, Expr, Fields, Lit, Meta, Token, punctuated::Punctuated}; 6 6 7 7 #[proc_macro_derive(Component, attributes(component))] 8 8 pub fn derive_component_fn(input: TokenStream) -> TokenStream { ··· 79 79 80 80 let component_derive: proc_macro2::TokenStream = impl_derive_component(ast).into(); 81 81 82 - let gen = quote! { 82 + quote! { 83 83 #component_derive 84 84 85 85 impl ecsdb::resource::Resource for #name { } 86 - }; 87 - 88 - gen.into() 86 + } 87 + .into() 89 88 } 90 89 91 90 fn impl_derive_bundle(ast: syn::DeriveInput) -> TokenStream {
+6 -10
src/entity.rs
··· 1 - use rusqlite::{params, OptionalExtension}; 1 + use rusqlite::{OptionalExtension, params}; 2 2 use tracing::{debug, trace}; 3 3 4 4 use crate::{ 5 + Component, CreatedAt, DynComponent, Ecs, EntityId, Error, LastUpdated, 5 6 component::Bundle, 6 7 query::{self}, 7 - Component, CreatedAt, DynComponent, Ecs, EntityId, Error, LastUpdated, 8 8 }; 9 9 10 10 #[derive(Debug, Copy, Clone)] ··· 146 146 .conn 147 147 .prepare_cached("select data from components where entity = ?1 and component = ?2")?; 148 148 149 - let row = query 149 + query 150 150 .query_and_then(params![self.id(), name], |row| { 151 151 let data = row.get_ref("data")?; 152 152 Ok(T::from_rusqlite(&rusqlite::types::ToSqlOutput::Borrowed( ··· 154 154 ))?) 155 155 })? 156 156 .next() 157 - .transpose(); 158 - 159 - row 157 + .transpose() 160 158 } 161 159 } 162 160 ··· 171 169 .conn 172 170 .prepare_cached("select data from components where entity = ?1 and component = ?2")?; 173 171 174 - let row = query 172 + query 175 173 .query_and_then(params![self.id(), name], |row| { 176 174 let data = row.get("data")?; 177 175 Ok(DynComponent( ··· 180 178 )) 181 179 })? 182 180 .next() 183 - .transpose(); 184 - 185 - row 181 + .transpose() 186 182 } 187 183 } 188 184
+4 -4
src/lib.rs
··· 137 137 138 138 pub fn query_filtered<'a, D, F>( 139 139 &'a self, 140 - filter: impl QueryFilterValue, 140 + filter: impl QueryFilterValue + 'a, 141 141 ) -> impl Iterator<Item = D::Output<'a>> + 'a 142 142 where 143 143 D: query::QueryData + 'a, ··· 149 149 #[instrument(name = "find", level = "debug", skip_all)] 150 150 pub fn try_query_fitered<'a, D, F>( 151 151 &'a self, 152 - filter_value: impl query::QueryFilterValue, 152 + filter_value: impl query::QueryFilterValue + 'a, 153 153 ) -> Result<impl Iterator<Item = D::Output<'a>> + 'a, Error> 154 154 where 155 155 D: query::QueryData + 'a, ··· 163 163 impl Ecs { 164 164 pub fn find<'a>( 165 165 &'a self, 166 - filter_value: impl query::QueryFilterValue, 166 + filter_value: impl query::QueryFilterValue + 'a, 167 167 ) -> impl Iterator<Item = Entity<'a>> + 'a { 168 168 self.try_find(filter_value).unwrap() 169 169 } 170 170 171 171 pub fn try_find<'a>( 172 172 &'a self, 173 - filter_value: impl query::QueryFilterValue, 173 + filter_value: impl query::QueryFilterValue + 'a, 174 174 ) -> Result<impl Iterator<Item = Entity<'a>> + 'a, Error> { 175 175 self.try_query_fitered::<Entity<'a>, ()>(filter_value) 176 176 }
+13 -9
src/query/mod.rs
··· 1 1 use tracing::trace; 2 2 3 - use crate::{component::Bundle, Entity, EntityId}; 3 + use crate::{Entity, EntityId, component::Bundle}; 4 4 5 5 use super::Component; 6 6 use std::marker::PhantomData; ··· 71 71 F: QueryFilter, 72 72 V: QueryFilterValue, 73 73 { 74 - pub fn iter(&self) -> impl Iterator<Item = D::Output<'a>> + 'a { 74 + pub fn iter(&self) -> impl Iterator<Item = D::Output<'a>> + 'a + use<'a, D, F, V> { 75 75 self.try_iter().unwrap() 76 76 } 77 77 78 - pub fn reverse_iter(&self) -> impl Iterator<Item = D::Output<'a>> + 'a { 78 + pub fn reverse_iter(&self) -> impl Iterator<Item = D::Output<'a>> + 'a + use<'a, D, F, V> { 79 79 self.try_reverse_iter().unwrap() 80 80 } 81 81 82 - pub fn entities(&self) -> impl Iterator<Item = Entity<'a>> + 'a { 82 + pub fn entities(&self) -> impl Iterator<Item = Entity<'a>> + 'a + use<'a, D, F, V> { 83 83 self.try_entities().unwrap() 84 84 } 85 85 86 - pub fn reverse_entities(&self) -> impl Iterator<Item = Entity<'a>> + 'a { 86 + pub fn reverse_entities(&self) -> impl Iterator<Item = Entity<'a>> + 'a + use<'a, D, F, V> { 87 87 self.try_reverse_entities().unwrap() 88 88 } 89 89 90 - pub fn try_iter(&self) -> Result<impl Iterator<Item = D::Output<'a>> + 'a, crate::Error> { 90 + pub fn try_iter( 91 + &self, 92 + ) -> Result<impl Iterator<Item = D::Output<'a>> + 'a + use<'a, D, F, V>, crate::Error> { 91 93 Ok(self.try_entities()?.filter_map(|e| D::from_entity(e))) 92 94 } 93 95 94 96 pub fn try_reverse_iter( 95 97 &self, 96 - ) -> Result<impl Iterator<Item = D::Output<'a>> + 'a, crate::Error> { 98 + ) -> Result<impl Iterator<Item = D::Output<'a>> + 'a + use<'a, D, F, V>, crate::Error> { 97 99 Ok(self 98 100 .try_reverse_entities()? 99 101 .filter_map(|e| D::from_entity(e))) 100 102 } 101 103 102 - pub fn try_entities(&self) -> Result<impl Iterator<Item = Entity<'a>> + 'a, crate::Error> { 104 + pub fn try_entities( 105 + &self, 106 + ) -> Result<impl Iterator<Item = Entity<'a>> + 'a + use<'a, D, F, V>, crate::Error> { 103 107 let mut query = self.as_sql_query(); 104 108 105 109 query.order_by = ir::OrderBy::Asc; ··· 108 112 109 113 pub fn try_reverse_entities( 110 114 &self, 111 - ) -> Result<impl Iterator<Item = Entity<'a>> + 'a, crate::Error> { 115 + ) -> Result<impl Iterator<Item = Entity<'a>> + 'a + use<'a, D, F, V>, crate::Error> { 112 116 let mut query = self.as_sql_query(); 113 117 query.order_by = ir::OrderBy::Desc; 114 118 self.ecs.fetch::<Entity>(query)
+2 -4
src/resource.rs
··· 23 23 let mut query = self 24 24 .conn 25 25 .prepare_cached("select data from resources where name = ?1")?; 26 - let row = query 26 + query 27 27 .query_and_then(params![name], |row| { 28 28 let data = row.get_ref("data")?; 29 29 Ok(R::from_rusqlite(&rusqlite::types::ToSqlOutput::Borrowed( ··· 31 31 ))?) 32 32 })? 33 33 .next() 34 - .transpose(); 35 - 36 - row 34 + .transpose() 37 35 } 38 36 39 37 pub fn resource_mut<'a, R: Resource + Default>(&'a mut self) -> impl DerefMut<Target = R> + 'a {
+2 -2
src/system.rs
··· 1 1 use serde::{Deserialize, Serialize}; 2 2 use tracing::{debug, error, info, instrument}; 3 3 4 - use crate::{self as ecsdb, query, Component, Ecs, Entity}; 4 + use crate::{self as ecsdb, Component, Ecs, Entity, query}; 5 5 6 6 use core::marker::PhantomData; 7 7 use std::{ ··· 317 317 use std::marker::PhantomData; 318 318 319 319 use crate::query::With; 320 - use crate::{query, Ecs, Entity, IntoSystem, System, SystemEntity}; 320 + use crate::{Ecs, Entity, IntoSystem, System, SystemEntity, query}; 321 321 322 322 #[test] 323 323 fn run_system() {