palkia/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3
4pub mod access;
5pub mod builder;
6pub mod callback;
7pub mod component;
8pub mod entities;
9pub mod fabricator;
10pub mod messages;
11pub mod query;
12pub mod resource;
13pub mod util;
14pub mod world;
15
16mod vtablesathome;
17
18pub mod serde;
19
20pub use palkia_macros as proc_macros;
21
22use std::{
23  any::{self, TypeId},
24  fmt::Debug,
25  hash::{Hash, Hasher},
26};
27
28use downcast::Any;
29use prelude::Entity;
30
31#[derive(Clone, Copy)]
32/// Wrapper for a [`TypeId`] that also stores the name of the type, to aid in debugging
33/// and for nicer error messages.
34///
35/// You should probably not be using this...
36pub struct TypeIdWrapper {
37  pub tid: TypeId,
38  pub type_name: &'static str,
39}
40
41impl std::ops::Deref for TypeIdWrapper {
42  type Target = TypeId;
43
44  fn deref(&self) -> &Self::Target {
45    &self.tid
46  }
47}
48
49impl TypeIdWrapper {
50  pub fn of<T: 'static>() -> Self {
51    Self {
52      tid: TypeId::of::<T>(),
53      type_name: any::type_name::<T>(),
54    }
55  }
56}
57
58impl PartialEq for TypeIdWrapper {
59  fn eq(&self, other: &Self) -> bool {
60    self.tid == other.tid
61  }
62}
63
64impl Eq for TypeIdWrapper {}
65
66impl PartialOrd for TypeIdWrapper {
67  fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
68    Some(self.cmp(other))
69  }
70}
71
72impl Ord for TypeIdWrapper {
73  fn cmp(&self, other: &Self) -> std::cmp::Ordering {
74    self.tid.cmp(&other.tid)
75  }
76}
77
78impl Hash for TypeIdWrapper {
79  fn hash<H: Hasher>(&self, state: &mut H) {
80    self.tid.hash(state);
81  }
82}
83
84impl Debug for TypeIdWrapper {
85  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86    let mut dbs = f.debug_tuple("TypeIdWrapper");
87
88    #[cfg(debug_assertions)]
89    dbs.field(&self.type_name);
90
91    dbs.finish()
92  }
93}
94
95trait ToTypeIdWrapper {
96  fn type_id_wrapper(&self) -> TypeIdWrapper;
97}
98
99impl<T: Any> ToTypeIdWrapper for T
100where
101  T: ?Sized,
102{
103  fn type_id_wrapper(&self) -> TypeIdWrapper {
104    TypeIdWrapper {
105      tid: self.type_id(),
106      type_name: self.type_name(),
107    }
108  }
109}
110
111fn loop_panic(perpetrator: Entity, comp_tid: TypeIdWrapper) -> ! {
112  panic!("{:?} sent an event to one of its own components of type {} when it was mutably borrowed, probably via a loop of events. check the stacktrace.", perpetrator, comp_tid.type_name)
113}
114
115pub mod prelude {
116  //! Handy module to glob-import and get a bunch of stuff in the crate.
117  //! It omits some stuff that's more useful internally, as well as error enum variants
118  //! (because, tbh, I usually just unwrap everything.)
119
120  pub use crate::{
121    access::{
122      AccessDispatcher, AccessEntityStats, AccessQuery, AccessResources,
123      AccessSpawnEntities,
124    },
125    builder::EntityBuilder,
126    callback::CallbackWorldAccess,
127    component::{Component, ComponentRegisterer},
128    entities::{Entity, EntityLiveness},
129    fabricator::EntityFabricator,
130    messages::{ListenerWorldAccess, Message, MsgHandlerRead, MsgHandlerWrite},
131    query::Query,
132    resource::{ReadResource, Resource, WriteResource},
133    world::World,
134  };
135
136  pub use crate::proc_macros::*;
137}
138
139/// For the benefit of macros. No peeking!
140// https://github.com/autometrics-dev/autometrics-rs/blob/main/autometrics/src/lib.rs
141#[doc(hidden)]
142pub mod __private {
143  pub mod linkme {
144    pub use linkme::*;
145  }
146  pub use paste::paste;
147
148  pub use crate::{
149    component::__private::*,
150    resource::__private::*,
151    vtablesathome::{ComponentVtable, ResourceVtable},
152  };
153
154  #[linkme::distributed_slice]
155  pub static COMPONENT_REGISTRATORS: [fn(
156    ComponentRegistererErased,
157  ) -> ComponentVtable];
158
159  #[linkme::distributed_slice]
160  pub static RESOURCE_REGISTRATORS: [fn(
161    ResourceRegistererErased,
162  ) -> ResourceVtable];
163}