summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock14
-rw-r--r--Cargo.toml2
-rw-r--r--ecs-macros/Cargo.toml13
-rw-r--r--ecs-macros/src/lib.rs79
-rw-r--r--ecs/Cargo.toml1
-rw-r--r--ecs/examples/multiple_queries.rs5
-rw-r--r--ecs/examples/simple.rs29
-rw-r--r--ecs/examples/with_local.rs23
-rw-r--r--ecs/src/component.rs53
-rw-r--r--ecs/src/lib.rs2
10 files changed, 164 insertions, 57 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 0498fd9..e7a1b5a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -122,6 +122,7 @@ dependencies = [
name = "ecs"
version = "0.1.0"
dependencies = [
+ "ecs-macros",
"itertools",
"proc-macro2",
"quote",
@@ -129,6 +130,15 @@ dependencies = [
]
[[package]]
+name = "ecs-macros"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "either"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -471,9 +481,9 @@ checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
[[package]]
name = "syn"
-version = "2.0.48"
+version = "2.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
+checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c"
dependencies = [
"proc-macro2",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index 373c4ab..fccec2b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"
[workspace]
-members = ["glfw", "engine", "ecs"]
+members = ["glfw", "engine", "ecs", "ecs-macros"]
[dependencies]
engine = { path = "./engine", features = ["debug"] }
diff --git a/ecs-macros/Cargo.toml b/ecs-macros/Cargo.toml
new file mode 100644
index 0000000..792ca34
--- /dev/null
+++ b/ecs-macros/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "ecs-macros"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+quote = "1.0.35"
+syn = { version = "2.0.51", features = ["full"] }
+proc-macro2 = "1.0.78"
+
diff --git a/ecs-macros/src/lib.rs b/ecs-macros/src/lib.rs
new file mode 100644
index 0000000..e37d6a4
--- /dev/null
+++ b/ecs-macros/src/lib.rs
@@ -0,0 +1,79 @@
+use proc_macro::TokenStream;
+use quote::{quote, ToTokens};
+use syn::spanned::Spanned;
+use syn::{parse, Ident, Item, ItemEnum, ItemStruct, ItemUnion};
+
+#[proc_macro_derive(Component)]
+pub fn component_derive(input: TokenStream) -> TokenStream
+{
+ let item: TypeItem = parse::<Item>(input).unwrap().try_into().unwrap();
+
+ let item_ident = item.ident();
+
+ quote! {
+ impl ecs::component::Component for #item_ident
+ {
+ fn as_any_mut(&mut self) -> &mut dyn std::any::Any
+ {
+ self
+ }
+
+ fn as_any(&self) -> &dyn std::any::Any
+ {
+ self
+ }
+ }
+
+ impl ecs::system::Input for #item_ident {}
+ }
+ .into()
+}
+
+enum TypeItem
+{
+ Struct(ItemStruct),
+ Enum(ItemEnum),
+ Union(ItemUnion),
+}
+
+impl TypeItem
+{
+ fn ident(&self) -> &Ident
+ {
+ match self {
+ Self::Struct(struct_item) => &struct_item.ident,
+ Self::Enum(enum_item) => &enum_item.ident,
+ Self::Union(union_item) => &union_item.ident,
+ }
+ }
+}
+
+impl TryFrom<Item> for TypeItem
+{
+ type Error = syn::Error;
+
+ fn try_from(item: Item) -> Result<Self, Self::Error>
+ {
+ match item {
+ Item::Struct(struct_item) => Ok(Self::Struct(struct_item)),
+ Item::Enum(enum_item) => Ok(Self::Enum(enum_item)),
+ Item::Union(union_item) => Ok(Self::Union(union_item)),
+ _ => Err(syn::Error::new(
+ item.span(),
+ "Expected a struct, a enum or a union",
+ )),
+ }
+ }
+}
+
+impl ToTokens for TypeItem
+{
+ fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream)
+ {
+ match self {
+ Self::Struct(struct_item) => struct_item.to_tokens(tokens),
+ Self::Enum(enum_item) => enum_item.to_tokens(tokens),
+ Self::Union(union_item) => union_item.to_tokens(tokens),
+ }
+ }
+}
diff --git a/ecs/Cargo.toml b/ecs/Cargo.toml
index 8cfdb71..ba31a1d 100644
--- a/ecs/Cargo.toml
+++ b/ecs/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
[dependencies]
seq-macro = "0.3.5"
+ecs-macros = { path = "../ecs-macros" }
[build-dependencies]
quote = "1.0.35"
diff --git a/ecs/examples/multiple_queries.rs b/ecs/examples/multiple_queries.rs
index a4a5d2d..4f4198a 100644
--- a/ecs/examples/multiple_queries.rs
+++ b/ecs/examples/multiple_queries.rs
@@ -1,18 +1,21 @@
use std::fmt::Display;
-use ecs::{Query, World};
+use ecs::{Component, Query, World};
+#[derive(Component)]
struct Health
{
health: u32,
}
+#[derive(Component)]
enum AttackStrength
{
Strong,
Weak,
}
+#[derive(Component)]
struct EnemyName
{
name: String,
diff --git a/ecs/examples/simple.rs b/ecs/examples/simple.rs
index b58d2ba..b8dc50f 100644
--- a/ecs/examples/simple.rs
+++ b/ecs/examples/simple.rs
@@ -1,14 +1,21 @@
-use ecs::{Query, World};
+use ecs::{Component, Query, World};
+#[derive(Component)]
struct SomeData
{
num: u64,
}
-fn say_hello(mut query: Query<(SomeData, String)>)
+#[derive(Component)]
+struct Greeting
{
- for (data, text) in query.iter_mut() {
- println!("Hello {}: {}", text, data.num);
+ greeting: String,
+}
+
+fn say_hello(mut query: Query<(SomeData, Greeting)>)
+{
+ for (data, greeting) in query.iter_mut() {
+ println!("{}: {}", greeting.greeting, data.num);
}
}
@@ -24,9 +31,17 @@ fn main()
world.register_system(Event::Start, say_hello);
- world.create_entity((SomeData { num: 987_654 }, "Yoo".to_string()));
-
- world.create_entity((SomeData { num: 345 }, "Haha".to_string()));
+ world.create_entity((
+ SomeData { num: 987_654 },
+ Greeting {
+ greeting: "Good afternoon".to_string(),
+ },
+ ));
+
+ world.create_entity((
+ SomeData { num: 345 },
+ Greeting { greeting: "Good evening".to_string() },
+ ));
world.emit(&Event::Start);
}
diff --git a/ecs/examples/with_local.rs b/ecs/examples/with_local.rs
index 0bd8f66..334f129 100644
--- a/ecs/examples/with_local.rs
+++ b/ecs/examples/with_local.rs
@@ -1,28 +1,29 @@
use ecs::component::Local;
-use ecs::system::{Input as SystemInput, Into, System};
-use ecs::{Query, World};
+use ecs::system::{Into, System};
+use ecs::{Component, Query, World};
+#[derive(Component)]
struct SomeData
{
num: u64,
}
+#[derive(Component)]
struct Name
{
name: String,
}
+#[derive(Component)]
struct SayHelloState
{
cnt: usize,
}
-impl SystemInput for SayHelloState {}
-
-fn say_hello(mut query: Query<(SomeData, String)>, mut state: Local<SayHelloState>)
+fn say_hello(mut query: Query<(SomeData,)>, mut state: Local<SayHelloState>)
{
- for (data, text) in query.iter_mut() {
- println!("Hello there. Count {}: {}: {}", state.cnt, text, data.num);
+ for (data,) in query.iter_mut() {
+ println!("Hello there. Count {}: {}", state.cnt, data.num);
state.cnt += 1;
}
@@ -64,13 +65,9 @@ fn main()
.initialize((SayHelloState { cnt: 0 },)),
);
- world.create_entity((
- SomeData { num: 987_654 },
- "Yoo".to_string(),
- Name { name: "Bob".to_string() },
- ));
+ world.create_entity((SomeData { num: 987_654 }, Name { name: "Bob".to_string() }));
- world.create_entity((SomeData { num: 345 }, "Haha".to_string()));
+ world.create_entity((SomeData { num: 345 },));
world.emit(&Event::Update);
diff --git a/ecs/src/component.rs b/ecs/src/component.rs
index 59b737e..70ce9ba 100644
--- a/ecs/src/component.rs
+++ b/ecs/src/component.rs
@@ -7,7 +7,7 @@ use seq_macro::seq;
use crate::system::{Input as SystemInput, Param as SystemParam, System};
use crate::ComponentStorage;
-pub trait Component: Any
+pub trait Component: SystemInput + Any
{
#[doc(hidden)]
fn as_any_mut(&mut self) -> &mut dyn Any;
@@ -16,19 +16,6 @@ pub trait Component: Any
fn as_any(&self) -> &dyn Any;
}
-impl<Value: Any> Component for Value
-{
- fn as_any_mut(&mut self) -> &mut dyn Any
- {
- self
- }
-
- fn as_any(&self) -> &dyn Any
- {
- self
- }
-}
-
impl dyn Component
{
pub fn downcast_mut<Real: 'static>(&mut self) -> Option<&mut Real>
@@ -117,27 +104,27 @@ seq!(C in 0..=64 {
/// Holds a component which is local to a single system.
#[derive(Debug)]
-pub struct Local<'world, Value: SystemInput>
+pub struct Local<'world, LocalComponent: Component>
{
- value: &'world mut Value,
+ local_component: &'world mut LocalComponent,
}
-impl<'world, Value> Local<'world, Value>
+impl<'world, LocalComponent> Local<'world, LocalComponent>
where
- Value: SystemInput,
+ LocalComponent: Component,
{
- fn new(value: &'world mut Value) -> Self
+ fn new(local_component: &'world mut LocalComponent) -> Self
{
- Self { value }
+ Self { local_component }
}
}
-unsafe impl<'world, Value: 'static> SystemParam<'world> for Local<'world, Value>
+unsafe impl<'world, LocalComponent> SystemParam<'world> for Local<'world, LocalComponent>
where
- Value: SystemInput,
+ LocalComponent: Component,
{
type Flags = ();
- type Input = Value;
+ type Input = LocalComponent;
fn initialize<SystemImpl>(system: &mut impl System<SystemImpl>, input: Self::Input)
{
@@ -150,7 +137,7 @@ where
) -> Self
{
let local_component = system
- .get_local_component_mut::<Value>()
+ .get_local_component_mut::<LocalComponent>()
.expect("Local component is uninitialized");
Self::new(local_component)
@@ -164,33 +151,33 @@ where
return true;
};
- TypeId::of::<Value>() != *other_type_id
+ TypeId::of::<LocalComponent>() != *other_type_id
}
fn get_comparable() -> Box<dyn Any>
{
- Box::new(TypeId::of::<Value>())
+ Box::new(TypeId::of::<LocalComponent>())
}
}
-impl<'world, Value> Deref for Local<'world, Value>
+impl<'world, LocalComponent> Deref for Local<'world, LocalComponent>
where
- Value: SystemInput,
+ LocalComponent: Component,
{
- type Target = Value;
+ type Target = LocalComponent;
fn deref(&self) -> &Self::Target
{
- self.value
+ self.local_component
}
}
-impl<'world, Value> DerefMut for Local<'world, Value>
+impl<'world, LocalComponent> DerefMut for Local<'world, LocalComponent>
where
- Value: SystemInput,
+ LocalComponent: Component,
{
fn deref_mut(&mut self) -> &mut Self::Target
{
- self.value
+ self.local_component
}
}
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs
index 84009e0..573aa41 100644
--- a/ecs/src/lib.rs
+++ b/ecs/src/lib.rs
@@ -18,6 +18,8 @@ use crate::system::{
pub mod component;
pub mod system;
+pub use ecs_macros::Component;
+
#[derive(Debug)]
struct Entity
{