Experiments in applying Entity-Component-System patterns to durable data storage APIs.
at main 26 kB view raw
1pub mod component; 2 3pub use component::Bundle; 4pub use component::{Component, ComponentRead, ComponentWrite}; 5 6pub mod dyn_component; 7pub use dyn_component::DynComponent; 8 9pub mod entity; 10pub use entity::{Entity, NewEntity}; 11 12pub mod extension; 13pub use extension::Extension; 14 15pub mod hierarchy; 16 17pub mod query; 18 19pub mod resource; 20pub use resource::*; 21 22pub mod schedule; 23pub use schedule::Schedule; 24 25pub mod sqlite_ext; 26 27pub mod system; 28 29pub mod rusqlite { 30 pub use rusqlite::*; 31} 32 33use self_cell::MutBorrow; 34use serde::{Deserialize, Serialize}; 35pub use system::*; 36 37mod tuple_macros; 38 39use std::borrow::Cow; 40use std::path::Path; 41 42use tracing::{debug, instrument}; 43 44use crate::query::QueryFilterValue; 45 46pub type EntityId = i64; 47 48#[derive(Debug, thiserror::Error)] 49pub enum Error { 50 #[error("Database Error: {0}")] 51 Database(#[from] rusqlite::Error), 52 #[error(transparent)] 53 ComponentStorage(#[from] component::StorageError), 54} 55 56pub struct Ecs { 57 conn: rusqlite::Connection, 58 extensions: anymap::Map<dyn anymap::any::Any + Send>, 59} 60 61impl Ecs { 62 pub fn open_in_memory() -> Result<Self, Error> { 63 Self::from_rusqlite(rusqlite::Connection::open_in_memory()?) 64 } 65 66 pub fn open(path: impl AsRef<Path>) -> Result<Self, Error> { 67 Self::from_rusqlite(rusqlite::Connection::open(path)?) 68 } 69 70 pub fn from_rusqlite(mut conn: rusqlite::Connection) -> Result<Self, Error> { 71 conn.pragma_update(None, "journal_mode", "wal")?; 72 conn.execute_batch(include_str!("schema.sql"))?; 73 conn.set_transaction_behavior(::rusqlite::TransactionBehavior::Immediate); 74 75 sqlite_ext::add_regexp_function(&conn)?; 76 77 Ok(Self { 78 conn, 79 extensions: anymap::Map::new(), 80 }) 81 } 82} 83 84impl Ecs { 85 pub fn close(self) -> Result<(), Error> { 86 self.conn.close().map_err(|(_conn, e)| Error::Database(e)) 87 } 88 89 pub fn data_version(&self) -> Result<i64, Error> { 90 Ok(self 91 .conn 92 .query_row("select data_version from pragma_data_version", [], |x| { 93 x.get("data_version") 94 })?) 95 } 96} 97 98impl Ecs { 99 pub fn new_entity<'a>(&'a self) -> NewEntity<'a> { 100 Entity::without_id(self) 101 } 102 103 pub fn entity<'a>(&'a self, eid: EntityId) -> Entity<'a> { 104 Entity::with_id(self, eid) 105 } 106} 107 108impl Ecs { 109 pub fn entity_with<'a, B: Bundle>(&'a self, eid: EntityId) -> Option<Entity<'a>> { 110 let e = Entity::with_id(self, eid); 111 e.has::<B>().then_some(e) 112 } 113} 114 115impl Ecs { 116 pub fn query<'a, D, F>(&'a self) -> impl Iterator<Item = D::Output<'a>> + 'a 117 where 118 D: query::QueryData + 'a, 119 F: query::QueryFilter + 'a, 120 { 121 self.try_query::<D, F>().unwrap() 122 } 123 124 #[instrument(name = "query", level = "debug", skip_all)] 125 pub fn try_query<'a, D, F>(&'a self) -> Result<impl Iterator<Item = D::Output<'a>> + 'a, Error> 126 where 127 D: query::QueryData + 'a, 128 F: query::QueryFilter + 'a, 129 { 130 debug!( 131 data = std::any::type_name::<D>(), 132 filter = std::any::type_name::<F>() 133 ); 134 let query = query::Query::<D, F>::new(self); 135 query.try_iter() 136 } 137 138 pub fn query_filtered<'a, D, F>( 139 &'a self, 140 filter: impl QueryFilterValue + 'a, 141 ) -> impl Iterator<Item = D::Output<'a>> + 'a 142 where 143 D: query::QueryData + 'a, 144 F: query::QueryFilter + 'a, 145 { 146 self.try_query_fitered::<D, F>(filter).unwrap() 147 } 148 149 #[instrument(name = "find", level = "debug", skip_all)] 150 pub fn try_query_fitered<'a, D, F>( 151 &'a self, 152 filter_value: impl query::QueryFilterValue + 'a, 153 ) -> Result<impl Iterator<Item = D::Output<'a>> + 'a, Error> 154 where 155 D: query::QueryData + 'a, 156 F: query::QueryFilter + 'a, 157 { 158 let query = query::Query::<D, F, _>::with_filter(self, filter_value); 159 query.try_iter() 160 } 161} 162 163impl Ecs { 164 pub fn find<'a>( 165 &'a self, 166 filter_value: impl query::QueryFilterValue + 'a, 167 ) -> impl Iterator<Item = Entity<'a>> + 'a { 168 self.try_find(filter_value).unwrap() 169 } 170 171 pub fn try_find<'a>( 172 &'a self, 173 filter_value: impl query::QueryFilterValue + 'a, 174 ) -> Result<impl Iterator<Item = Entity<'a>> + 'a, Error> { 175 self.try_query_fitered::<Entity<'a>, ()>(filter_value) 176 } 177} 178 179#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] 180pub struct CreatedAt(pub chrono::DateTime<chrono::Utc>); 181 182#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] 183pub struct LastUpdated(pub chrono::DateTime<chrono::Utc>); 184 185impl Ecs { 186 #[instrument(level = "debug", skip_all)] 187 fn fetch<'a, Q: query::QueryData + 'a>( 188 &'a self, 189 sql_query: query::ir::Query, 190 ) -> Result<impl Iterator<Item = Q::Output<'a>> + 'a, Error> { 191 let entity_ids = self.fetch_entity_ids(sql_query)?; 192 193 let rows = entity_ids 194 .into_iter() 195 .scan(self, |ecs, eid| Some(Entity::with_id(ecs, eid))) 196 .map(|e| { 197 debug!( 198 data = std::any::type_name::<Q>(), 199 entity = ?e, 200 "Fetching QueryData" 201 ); 202 Q::from_entity(e).unwrap() 203 }); 204 205 Ok(rows) 206 } 207 208 fn fetch_entity_ids<'a>(&'a self, sql_query: query::ir::Query) -> Result<Vec<EntityId>, Error> { 209 let (sql, placeholders) = sql_query.into_sql(); 210 debug!(sql); 211 212 let mut stmt = self.conn.prepare(&sql)?; 213 let params: Box<[(&str, &dyn rusqlite::ToSql)]> = placeholders 214 .iter() 215 .map(|(p, v)| (p.as_str(), v.as_ref())) 216 .collect(); 217 218 let rows = stmt 219 .query_map(&params[..], |row| row.get("entity"))? 220 .map(|r| r.expect("EntityId from Query")) 221 .collect(); 222 223 Ok(rows) 224 } 225} 226 227#[allow(unused)] 228impl Ecs { 229 #[instrument(level = "debug", skip_all)] 230 fn fetch_lazy<'a, Q: query::QueryData + 'a>( 231 &'a self, 232 sql_query: query::ir::Query, 233 ) -> Result<impl Iterator<Item = Q::Output<'a>> + 'a, Error> { 234 let rows = self 235 .fetch_entity_ids_lazy(sql_query)? 236 .scan(self, |ecs, eid| Some(Entity::with_id(ecs, eid))) 237 .map(|e| { 238 debug!( 239 data = std::any::type_name::<Q>(), 240 entity = ?e, 241 "Fetching QueryData" 242 ); 243 Q::from_entity(e).unwrap() 244 }); 245 246 Ok(rows) 247 } 248 249 fn fetch_entity_ids_lazy<'a>( 250 &'a self, 251 sql_query: query::ir::Query, 252 ) -> Result<impl Iterator<Item = EntityId> + 'a, Error> { 253 let (sql, placeholders) = sql_query.into_sql(); 254 debug!(sql); 255 256 type RowsRef<'a> = ::rusqlite::Rows<'a>; 257 258 self_cell::self_cell!( 259 struct OwningRows<'conn> { 260 owner: self_cell::MutBorrow<::rusqlite::Statement<'conn>>, 261 #[covariant] 262 dependent: RowsRef, 263 } 264 ); 265 266 impl<'conn> Iterator for OwningRows<'conn> { 267 type Item = Result<EntityId, rusqlite::Error>; 268 fn next(&mut self) -> Option<Self::Item> { 269 match self.with_dependent_mut(|_stmt, rows| rows.next()) { 270 Ok(Some(row)) => Some(row.get("entity")), 271 Ok(None) => None, 272 Err(e) => Some(Err(e)), 273 } 274 } 275 } 276 277 let stmt = self.conn.prepare(&sql)?; 278 let params: Box<[(&str, &dyn rusqlite::ToSql)]> = placeholders 279 .iter() 280 .map(|(p, v)| (p.as_str(), v.as_ref())) 281 .collect(); 282 283 let owning_rows = 284 OwningRows::try_new(MutBorrow::new(stmt), |s| s.borrow_mut().query(&params[..])) 285 .unwrap(); 286 287 Ok(owning_rows.map(|result| result.expect("EntityId from Row"))) 288 } 289} 290 291impl Ecs { 292 pub fn raw_sql<'a>(&'a self) -> &'a rusqlite::Connection { 293 &self.conn 294 } 295} 296 297impl AsRef<chrono::DateTime<chrono::Utc>> for CreatedAt { 298 fn as_ref(&self) -> &chrono::DateTime<chrono::Utc> { 299 &self.0 300 } 301} 302 303impl Component for CreatedAt { 304 type Storage = component::JsonStorage; 305 const NAME: &'static str = "ecsdb::CreatedAt"; 306} 307 308impl Default for CreatedAt { 309 fn default() -> Self { 310 Self(chrono::DateTime::<chrono::Utc>::MIN_UTC) 311 } 312} 313 314impl AsRef<chrono::DateTime<chrono::Utc>> for LastUpdated { 315 fn as_ref(&self) -> &chrono::DateTime<chrono::Utc> { 316 &self.0 317 } 318} 319 320impl Component for LastUpdated { 321 type Storage = component::JsonStorage; 322 const NAME: &'static str = "ecsdb::LastUpdated"; 323} 324 325impl Default for LastUpdated { 326 fn default() -> Self { 327 Self(chrono::DateTime::<chrono::Utc>::MIN_UTC) 328 } 329} 330 331pub fn system_name<Marker, S: IntoSystem<Marker>>(system: S) -> Cow<'static, str> { 332 system.into_system().name() 333} 334 335#[doc(hidden)] 336pub mod doctests { 337 use crate as ecsdb; // Fixes `#[derive(Component)]` 338 339 pub use crate::{Component, Ecs, Entity, EntityId}; 340 pub use serde::{Deserialize, Serialize}; 341 342 #[derive(Serialize, Deserialize, Component)] 343 pub struct Marker; 344 345 #[derive(Serialize, Deserialize, Component)] 346 pub struct Date(pub chrono::DateTime<chrono::Utc>); 347 348 #[derive(Serialize, Deserialize, Component)] 349 pub enum State { 350 New, 351 Processing, 352 Finished, 353 } 354 355 #[cfg(doctest)] 356 #[doc = include_str!("../README.md")] 357 pub struct ReadmeDoctests; 358} 359 360#[cfg(test)] 361mod tests { 362 // #[derive(Component)] derives `impl ecsdb::Component for ...` 363 use crate::{self as ecsdb, CreatedAt, Ecs, Entity, EntityId}; 364 use crate::{Bundle, Component}; 365 366 use anyhow::anyhow; 367 use serde::{Deserialize, Serialize}; 368 369 #[derive(Debug, Serialize, Deserialize, Component)] 370 struct MarkerComponent; 371 372 #[derive(Debug, Serialize, Deserialize, PartialEq, Component)] 373 struct ComponentWithData(u64); 374 375 #[derive(Debug, Serialize, Deserialize, Component)] 376 struct A; 377 378 #[derive(Debug, Serialize, Deserialize, PartialEq, Component)] 379 struct B; 380 381 #[derive(Debug, Serialize, Deserialize, PartialEq, Component)] 382 struct C; 383 384 #[test] 385 fn derive_valid_component_name() { 386 assert_eq!( 387 MarkerComponent::component_name(), 388 "ecsdb::tests::MarkerComponent" 389 ); 390 assert_eq!( 391 ComponentWithData::component_name(), 392 "ecsdb::tests::ComponentWithData" 393 ); 394 } 395 396 #[test] 397 fn entity_attach_detach() { 398 let db = super::Ecs::open_in_memory().unwrap(); 399 let entity = db 400 .new_entity() 401 .attach(ComponentWithData(1234)) 402 .attach(MarkerComponent); 403 404 assert!(entity.component::<MarkerComponent>().is_some()); 405 entity.detach::<MarkerComponent>(); 406 assert!(entity.component::<MarkerComponent>().is_none()); 407 408 assert_eq!( 409 entity.component::<ComponentWithData>(), 410 Some(ComponentWithData(1234)) 411 ); 412 } 413 414 #[test] 415 fn component_overwrites() { 416 let db = super::Ecs::open_in_memory().unwrap(); 417 418 let entity = db 419 .new_entity() 420 .attach(ComponentWithData(42)) 421 .attach(ComponentWithData(23)); 422 assert_eq!(entity.component::<ComponentWithData>().unwrap().0, 23); 423 } 424 425 #[test] 426 fn attaching_same_component_in_bundle_overwrites() { 427 let db = super::Ecs::open_in_memory().unwrap(); 428 429 let entity = db 430 .new_entity() 431 .attach((ComponentWithData(42), ComponentWithData(23))); 432 assert_eq!(entity.component::<ComponentWithData>().unwrap().0, 23); 433 } 434 435 #[test] 436 fn bundle_struct() { 437 let db = super::Ecs::open_in_memory().unwrap(); 438 439 #[derive(Debug, Bundle)] 440 struct Bundle { 441 a: A, 442 b: B, 443 data: ComponentWithData, 444 } 445 446 let bundle = Bundle { 447 a: A, 448 b: B, 449 data: ComponentWithData(1234), 450 }; 451 452 let entity = db.new_entity().attach(bundle); 453 454 assert!(entity.has::<(A, B, ComponentWithData)>()); 455 } 456 457 #[test] 458 fn bundle_tuplestruct() { 459 let db = super::Ecs::open_in_memory().unwrap(); 460 461 #[derive(Debug, Bundle)] 462 struct Bundle(A, B, ComponentWithData); 463 464 let bundle = Bundle(A, B, ComponentWithData(1234)); 465 let entity = db.new_entity().attach(bundle); 466 467 assert!(entity.has::<(A, B, ComponentWithData)>()); 468 } 469 470 #[test] 471 fn bundle_optionals() { 472 let db = super::Ecs::open_in_memory().unwrap(); 473 474 #[derive(Debug, Bundle)] 475 struct Bundle(A, Option<B>); 476 477 let entity = db.new_entity().attach(Bundle(A, None)); 478 assert!(!entity.has::<B>()); 479 480 entity.attach(Bundle(A, Some(B))); 481 assert!(entity.has::<B>()); 482 483 entity.attach(Bundle(A, None)); 484 assert!(entity.has::<B>()); 485 } 486 487 use super::query::*; 488 489 #[test] 490 fn query_tuples() { 491 let db = super::Ecs::open_in_memory().unwrap(); 492 let _: Vec<MarkerComponent> = db.query::<MarkerComponent, ()>().collect(); 493 494 let _: Vec<Entity> = db.query::<Entity, ()>().collect(); 495 let _: Vec<(Entity, MarkerComponent)> = 496 db.query::<(Entity, MarkerComponent), ()>().collect(); 497 498 let _: Vec<Entity> = db.query::<Entity, With<MarkerComponent>>().collect(); 499 let _: Vec<Entity> = db.query::<Entity, Without<MarkerComponent>>().collect(); 500 let _: Vec<MarkerComponent> = db 501 .query::<MarkerComponent, Or<( 502 Without<(MarkerComponent, MarkerComponent)>, 503 With<(MarkerComponent, MarkerComponent)>, 504 Or<(With<MarkerComponent>, Without<MarkerComponent>)>, 505 )>>() 506 .collect(); 507 508 let _: Vec<MarkerComponent> = db 509 .query::<MarkerComponent, ( 510 With<(MarkerComponent, ComponentWithData)>, 511 Without<(MarkerComponent, MarkerComponent)>, 512 )>() 513 .collect(); 514 515 let _: Vec<MarkerComponent> = db 516 .query::<MarkerComponent, Without<ComponentWithData>>() 517 .collect(); 518 519 let _: Vec<()> = db 520 .query::<(), ( 521 With<MarkerComponent>, 522 With<MarkerComponent>, 523 With<MarkerComponent>, 524 With<MarkerComponent>, 525 With<MarkerComponent>, 526 With<MarkerComponent>, 527 Without<MarkerComponent>, 528 With<MarkerComponent>, 529 )>() 530 .collect(); 531 } 532 533 #[test] 534 fn query() { 535 let db = super::Ecs::open_in_memory().unwrap(); 536 537 db.new_entity() 538 .attach(MarkerComponent) 539 .attach(ComponentWithData(1234)); 540 541 db.new_entity().attach(ComponentWithData(1234)); 542 543 assert_eq!(db.query::<EntityId, ()>().count(), 2); 544 assert_eq!(db.query::<EntityId, MarkerComponent>().count(), 1); 545 assert_eq!(db.query::<EntityId, MarkerComponent>().count(), 1); 546 } 547 548 #[test] 549 fn entity_match_filtered() { 550 let db = super::Ecs::open_in_memory().unwrap(); 551 552 db.new_entity() 553 .attach(MarkerComponent) 554 .attach(ComponentWithData(1234)); 555 556 db.new_entity().attach(ComponentWithData(1234)); 557 558 assert_eq!(db.query::<EntityId, Without<MarkerComponent>>().count(), 1); 559 assert_eq!( 560 db.query::<EntityId, (MarkerComponent, ComponentWithData)>() 561 .count(), 562 1 563 ); 564 assert_eq!( 565 db.query::<MarkerComponent, Without<MarkerComponent>>() 566 .count(), 567 0 568 ); 569 570 assert_eq!( 571 db.query::<MarkerComponent, ( 572 Without<MarkerComponent>, 573 Or<(With<MarkerComponent>, With<ComponentWithData>)> 574 )>() 575 .count(), 576 0 577 ); 578 assert_eq!(db.query::<EntityId, ComponentWithData>().count(), 2); 579 } 580 581 #[test] 582 fn or() { 583 let db = Ecs::open_in_memory().unwrap(); 584 let a = db.new_entity().attach(A).id(); 585 let b = db.new_entity().attach(B).id(); 586 let c = db.new_entity().attach(C).id(); 587 588 assert_eq!( 589 db.query::<EntityId, Or<(With<A>, With<B>, With<C>)>>() 590 .collect::<Vec<_>>(), 591 vec![a, b, c] 592 ); 593 assert_eq!( 594 db.query::<EntityId, Or<(With<A>, With<B>)>>() 595 .collect::<Vec<_>>(), 596 vec![a, b] 597 ); 598 assert_eq!( 599 db.query::<EntityId, Or<(With<A>,)>>().collect::<Vec<_>>(), 600 vec![a] 601 ); 602 assert_eq!( 603 db.query::<EntityId, Or<(With<B>,)>>().collect::<Vec<_>>(), 604 vec![b] 605 ); 606 } 607 608 #[test] 609 fn query_any_of() { 610 let db = Ecs::open_in_memory().unwrap(); 611 let a = db.new_entity().attach(A).id(); 612 let b = db.new_entity().attach(B).id(); 613 let c = db.new_entity().attach(C).id(); 614 615 assert_eq!( 616 db.query::<EntityId, AnyOf<(A, B)>>().collect::<Vec<_>>(), 617 vec![a, b] 618 ); 619 620 assert_eq!( 621 db.query::<EntityId, AnyOf<(A, C)>>().collect::<Vec<_>>(), 622 vec![a, c] 623 ); 624 625 assert_eq!( 626 db.query::<EntityId, AnyOf<(A,)>>().collect::<Vec<_>>(), 627 vec![a] 628 ); 629 } 630 631 #[test] 632 fn query_filtered() { 633 let db = Ecs::open_in_memory().unwrap(); 634 let eid = db.new_entity().attach(ComponentWithData(123)).id(); 635 let _ = db.new_entity().attach(ComponentWithData(123)); 636 let _ = db.new_entity().attach(ComponentWithData(255)); 637 638 assert_eq!(db.query_filtered::<EntityId, ()>(eid).count(), 1); 639 assert_eq!( 640 db.query_filtered::<EntityId, ()>(eid).collect::<Vec<_>>(), 641 vec![eid] 642 ); 643 assert_eq!( 644 db.query_filtered::<EntityId, ()>((eid, MarkerComponent)) 645 .count(), 646 0 647 ); 648 assert_eq!( 649 db.query_filtered::<EntityId, ()>(MarkerComponent).count(), 650 0 651 ); 652 assert_eq!( 653 db.query_filtered::<EntityId, ()>(ComponentWithData(0)) 654 .count(), 655 0 656 ); 657 assert_eq!( 658 db.query_filtered::<EntityId, ()>(ComponentWithData(123)) 659 .count(), 660 2 661 ); 662 assert_eq!( 663 db.query_filtered::<EntityId, ()>(ComponentWithData(255)) 664 .count(), 665 1 666 ); 667 668 let _ = db 669 .new_entity() 670 .attach(MarkerComponent) 671 .attach(ComponentWithData(12345)); 672 assert_eq!( 673 db.query_filtered::<EntityId, ()>((MarkerComponent, ComponentWithData(12345))) 674 .count(), 675 1 676 ); 677 } 678 679 #[test] 680 fn find_ranges() { 681 let db = Ecs::open_in_memory().unwrap(); 682 for n in 0..100 { 683 let _ = db.new_entity().attach(ComponentWithData(n)); 684 } 685 686 let mut res = db 687 .query_filtered::<Entity, ()>(ComponentWithData(0)..ComponentWithData(10)) 688 .map(|e| e.component::<ComponentWithData>().unwrap()); 689 assert_eq!(res.next(), Some(ComponentWithData(0))); 690 assert_eq!(res.last(), Some(ComponentWithData(10))); 691 692 let mut res = db 693 .query_filtered::<Entity, ()>(ComponentWithData(10)..) 694 .map(|e| e.component::<ComponentWithData>().unwrap()); 695 assert_eq!(res.next(), Some(ComponentWithData(10))); 696 assert_eq!(res.last(), Some(ComponentWithData(99))); 697 698 let mut res = db 699 .query_filtered::<Entity, ()>(..ComponentWithData(10)) 700 .map(|e| e.component::<ComponentWithData>().unwrap()); 701 assert_eq!(res.next(), Some(ComponentWithData(0))); 702 assert_eq!(res.last(), Some(ComponentWithData(10))); 703 } 704 705 // #[test] 706 // fn parent() { 707 // let db = Ecs::open_in_memory().unwrap(); 708 709 // let parent = db.new_entity().attach(A); 710 // let child1 = db.new_entity().attach(A).attach(BelongsTo(parent.id())); 711 // let child2 = db.new_entity().attach(A).attach(BelongsTo(child1.id())); 712 713 // assert!(parent.parent().is_none()); 714 // assert_eq!(child1.parent().map(|e| e.id()), Some(parent.id())); 715 // assert_eq!(child2.parent().map(|e| e.id()), Some(child1.id())); 716 717 // assert_eq!( 718 // child2.parents().map(|e| e.id()).collect::<Vec<_>>(), 719 // vec![child1.id(), parent.id()] 720 // ); 721 // } 722 723 #[test] 724 fn enum_component() { 725 #[derive(Serialize, Deserialize, Component, PartialEq, Debug)] 726 enum Foo { 727 A, 728 B, 729 } 730 731 let db = Ecs::open_in_memory().unwrap(); 732 let entity = db.new_entity().attach(Foo::A); 733 assert_eq!(entity.component::<Foo>().unwrap(), Foo::A); 734 } 735 736 #[test] 737 fn blob_component() { 738 #[derive(Component, Debug, PartialEq, Clone)] 739 #[component(storage = "blob")] 740 struct X(Vec<u8>); 741 742 impl AsRef<[u8]> for X { 743 fn as_ref(&self) -> &[u8] { 744 self.0.as_slice() 745 } 746 } 747 748 impl From<Vec<u8>> for X { 749 fn from(value: Vec<u8>) -> Self { 750 Self(value) 751 } 752 } 753 754 let x = X(b"asdfasdf".into()); 755 756 let db = Ecs::open_in_memory().unwrap(); 757 let entity = db.new_entity().attach(x.clone()); 758 759 assert_eq!(entity.component::<X>().unwrap(), x.clone()); 760 } 761 762 #[test] 763 fn has_many() { 764 let db = Ecs::open_in_memory().unwrap(); 765 let a = db.new_entity().attach(A); 766 assert!(a.has::<A>()); 767 assert!(!a.has::<B>()); 768 769 assert!(a.has::<(A,)>()); 770 assert!(!a.has::<(A, B)>()); 771 assert!(!a.has::<(A, B, A)>()); 772 773 let ab = db.new_entity().attach(A).attach(B); 774 assert!(ab.has::<(A, B)>()); 775 assert!(ab.has::<(A, A)>()); 776 assert!(ab.has::<(A, B, A)>()); 777 } 778 779 #[test] 780 fn from_component_composite() -> Result<(), anyhow::Error> { 781 #[derive(Serialize, Deserialize, Component)] 782 struct A; 783 #[derive(Serialize, Deserialize, Component)] 784 struct B; 785 786 let db = super::Ecs::open_in_memory()?; 787 let _e = db.new_entity().attach((A, B)); 788 789 // let ab = e.component::<(A, B)>(); 790 // assert!(ab.is_some()); 791 792 Ok(()) 793 } 794 795 #[test] 796 fn entity_matches() { 797 #[derive(Serialize, Deserialize, Component)] 798 struct A; 799 #[derive(Serialize, Deserialize, Component)] 800 struct B; 801 802 let db = super::Ecs::open_in_memory().unwrap(); 803 let e = db.new_entity().attach(A); 804 let e2 = db.new_entity().attach((A, B)); 805 806 assert!(e.matches::<With<A>>()); 807 assert!(!e.matches::<With<B>>()); 808 assert!(!e.matches::<With<(A, B)>>()); 809 810 assert!(e2.matches::<With<A>>()); 811 assert!(e2.matches::<With<B>>()); 812 assert!(e2.matches::<With<(A, B)>>()); 813 } 814 815 // #[test] 816 // fn entity_matches_filtered() { 817 // #[derive(Serialize, Deserialize, Component)] 818 // struct A; 819 // #[derive(Serialize, Deserialize, Component)] 820 // struct B; 821 822 // let db = super::Ecs::open_in_memory().unwrap(); 823 // let e = db.new_entity().attach(A); 824 // let e2 = db.new_entity().attach((A, B)); 825 826 // assert!(e.matches_filtered((With::<A>::default(), e.id()))); 827 // assert!(!e.matches::<With<B>>()); 828 // assert!(!e.matches::<With<(A, B)>>()); 829 830 // assert!(e2.matches::<With<A>>()); 831 // assert!(e2.matches::<With<B>>()); 832 // assert!(e2.matches::<With<(A, B)>>()); 833 // } 834 835 #[test] 836 fn last_modified() { 837 #[derive(Serialize, Deserialize, Component)] 838 struct A; 839 #[derive(Serialize, Deserialize, Component)] 840 struct B; 841 842 let db = super::Ecs::open_in_memory().unwrap(); 843 let e = db.new_entity().attach(A); 844 845 assert!(e.last_modified() > chrono::Utc::now() - chrono::Duration::minutes(1)); 846 847 let old = e.last_modified(); 848 849 std::thread::sleep(std::time::Duration::from_millis(2)); 850 851 e.attach(B); 852 assert!(e.last_modified() > old); 853 } 854 855 #[test] 856 fn created() { 857 #[derive(Serialize, Deserialize, Component)] 858 struct A; 859 #[derive(Serialize, Deserialize, Component)] 860 struct B; 861 862 let db = super::Ecs::open_in_memory().unwrap(); 863 let e = db.new_entity().attach(A); 864 865 assert!(e.has::<CreatedAt>()); 866 assert_ne!(e.created_at(), chrono::DateTime::<chrono::Utc>::MIN_UTC); 867 868 assert!(e.created_at() > chrono::Utc::now() - chrono::Duration::minutes(1),); 869 870 let old = e.created_at(); 871 872 std::thread::sleep(std::time::Duration::from_millis(2)); 873 874 e.attach(B); 875 assert_eq!(e.created_at(), old); 876 } 877 878 #[test] 879 fn modify_component() -> Result<(), anyhow::Error> { 880 let ecs = super::Ecs::open_in_memory()?; 881 882 #[derive(Component, Debug, Default, Deserialize, Serialize, PartialEq)] 883 struct Foo(Vec<u64>); 884 885 let entity = ecs.new_entity().modify_component(|foo: &mut Foo| { 886 *foo = Foo(vec![1, 2, 3]); 887 }); 888 assert_eq!(entity.component(), Some(Foo(vec![1, 2, 3]))); 889 890 let entity = ecs 891 .new_entity() 892 .attach(Foo(vec![1, 2, 3])) 893 .modify_component(|foo: &mut Foo| { 894 foo.0.clear(); 895 }); 896 897 assert_eq!(entity.component(), Some(Foo(vec![]))); 898 899 Ok(()) 900 } 901 902 #[test] 903 fn try_modify_component() -> Result<(), anyhow::Error> { 904 let ecs = super::Ecs::open_in_memory()?; 905 906 #[derive(Component, Debug, Default, Deserialize, Serialize, PartialEq)] 907 struct Foo(Vec<u64>); 908 909 assert!( 910 ecs.new_entity() 911 .try_modify_component(|_foo: &mut Foo| { Err(anyhow!("error")) }) 912 .is_err() 913 ); 914 915 assert!( 916 ecs.new_entity() 917 .attach(Foo(vec![1, 2, 3])) 918 .try_modify_component(|_foo: &mut Foo| { Err(anyhow!("error")) }) 919 .is_err() 920 ); 921 922 Ok(()) 923 } 924}