aboutsummaryrefslogtreecommitdiff
path: root/azalea-ecs
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2023-03-07 14:14:36 -0600
committerGitHub <noreply@github.com>2023-03-07 14:14:36 -0600
commit719379a8a76ab0685f2bd14bebe2f0cd1e97f06b (patch)
treece5d6c62bc36fb1d1ec31083bc8e81a0109c12df /azalea-ecs
parentbf4ff517890cad3ff4e36b4b78959504192e5374 (diff)
downloadazalea-drasl-719379a8a76ab0685f2bd14bebe2f0cd1e97f06b.tar.xz
Bevy 0.10 (#79)
* replace 0.9.1 with 0.10.0 * start migrating to bevy .10 * well it compiles * doesn't immediately panic * remove unused imports * fmt * delete azalea-ecs * make RelativeEntityUpdate an EntityCommand * fix a doc test * explain what FixedUpdate does
Diffstat (limited to 'azalea-ecs')
-rw-r--r--azalea-ecs/Cargo.toml14
-rwxr-xr-xazalea-ecs/azalea-ecs-macros/Cargo.toml15
-rw-r--r--azalea-ecs/azalea-ecs-macros/src/component.rs125
-rw-r--r--azalea-ecs/azalea-ecs-macros/src/fetch.rs466
-rwxr-xr-xazalea-ecs/azalea-ecs-macros/src/lib.rs525
-rw-r--r--azalea-ecs/azalea-ecs-macros/src/utils/attrs.rs45
-rw-r--r--azalea-ecs/azalea-ecs-macros/src/utils/mod.rs227
-rw-r--r--azalea-ecs/azalea-ecs-macros/src/utils/shape.rs21
-rw-r--r--azalea-ecs/azalea-ecs-macros/src/utils/symbol.rs35
-rw-r--r--azalea-ecs/src/lib.rs157
10 files changed, 0 insertions, 1630 deletions
diff --git a/azalea-ecs/Cargo.toml b/azalea-ecs/Cargo.toml
deleted file mode 100644
index a596fd42..00000000
--- a/azalea-ecs/Cargo.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-[package]
-description = "ECS stuff used in Azalea"
-edition = "2021"
-license = "MIT"
-name = "azalea-ecs"
-version = "0.6.0"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-azalea-ecs-macros = {path = "./azalea-ecs-macros", version = "^0.6.0"}
-bevy_app = "0.9.1"
-bevy_ecs = {version = "0.9.1", default-features = false}
-tokio = {version = "1.25.0", features = ["time"]}
diff --git a/azalea-ecs/azalea-ecs-macros/Cargo.toml b/azalea-ecs/azalea-ecs-macros/Cargo.toml
deleted file mode 100755
index cd7b2c8d..00000000
--- a/azalea-ecs/azalea-ecs-macros/Cargo.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[package]
-description = "Azalea ECS Macros"
-edition = "2021"
-license = "MIT OR Apache-2.0"
-name = "azalea-ecs-macros"
-version = "0.6.0"
-
-[lib]
-proc-macro = true
-
-[dependencies]
-proc-macro2 = "1.0"
-quote = "1.0"
-syn = "1.0"
-toml = "0.7.0"
diff --git a/azalea-ecs/azalea-ecs-macros/src/component.rs b/azalea-ecs/azalea-ecs-macros/src/component.rs
deleted file mode 100644
index e076bbe1..00000000
--- a/azalea-ecs/azalea-ecs-macros/src/component.rs
+++ /dev/null
@@ -1,125 +0,0 @@
-use crate::utils::{get_lit_str, Symbol};
-use proc_macro::TokenStream;
-use proc_macro2::{Span, TokenStream as TokenStream2};
-use quote::{quote, ToTokens};
-use syn::{parse_macro_input, parse_quote, DeriveInput, Error, Ident, Path, Result};
-
-use crate::utils;
-
-pub fn derive_resource(input: TokenStream) -> TokenStream {
- let mut ast = parse_macro_input!(input as DeriveInput);
- let azalea_ecs_path: Path = crate::azalea_ecs_path();
-
- ast.generics
- .make_where_clause()
- .predicates
- .push(parse_quote! { Self: Send + Sync + 'static });
-
- let struct_name = &ast.ident;
- let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
-
- TokenStream::from(quote! {
- impl #impl_generics #azalea_ecs_path::system::_BevyResource for #struct_name #type_generics #where_clause {
- }
- })
-}
-
-pub fn derive_component(input: TokenStream) -> TokenStream {
- let mut ast = parse_macro_input!(input as DeriveInput);
- let azalea_ecs_path: Path = crate::azalea_ecs_path();
-
- let attrs = match parse_component_attr(&ast) {
- Ok(attrs) => attrs,
- Err(e) => return e.into_compile_error().into(),
- };
-
- let storage = storage_path(&azalea_ecs_path, attrs.storage);
-
- ast.generics
- .make_where_clause()
- .predicates
- .push(parse_quote! { Self: Send + Sync + 'static });
-
- let struct_name = &ast.ident;
- let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
-
- TokenStream::from(quote! {
- impl #impl_generics #azalea_ecs_path::component::_BevyComponent for #struct_name #type_generics #where_clause {
- type Storage = #storage;
- }
- })
-}
-
-pub const COMPONENT: Symbol = Symbol("component");
-pub const STORAGE: Symbol = Symbol("storage");
-
-struct Attrs {
- storage: StorageTy,
-}
-
-#[derive(Clone, Copy)]
-enum StorageTy {
- Table,
- SparseSet,
-}
-
-// values for `storage` attribute
-const TABLE: &str = "Table";
-const SPARSE_SET: &str = "SparseSet";
-
-fn parse_component_attr(ast: &DeriveInput) -> Result<Attrs> {
- let meta_items = utils::parse_attrs(ast, COMPONENT)?;
-
- let mut attrs = Attrs {
- storage: StorageTy::Table,
- };
-
- for meta in meta_items {
- use syn::{
- Meta::NameValue,
- NestedMeta::{Lit, Meta},
- };
- match meta {
- Meta(NameValue(m)) if m.path == STORAGE => {
- attrs.storage = match get_lit_str(STORAGE, &m.lit)?.value().as_str() {
- TABLE => StorageTy::Table,
- SPARSE_SET => StorageTy::SparseSet,
- s => {
- return Err(Error::new_spanned(
- m.lit,
- format!(
- "Invalid storage type `{s}`, expected '{TABLE}' or '{SPARSE_SET}'."
- ),
- ))
- }
- };
- }
- Meta(meta_item) => {
- return Err(Error::new_spanned(
- meta_item.path(),
- format!(
- "unknown component attribute `{}`",
- meta_item.path().into_token_stream()
- ),
- ));
- }
- Lit(lit) => {
- return Err(Error::new_spanned(
- lit,
- "unexpected literal in component attribute",
- ))
- }
- }
- }
-
- Ok(attrs)
-}
-
-fn storage_path(azalea_ecs_path: &Path, ty: StorageTy) -> TokenStream2 {
- let typename = match ty {
- StorageTy::Table => Ident::new("TableStorage", Span::call_site()),
- StorageTy::SparseSet => Ident::new("SparseStorage", Span::call_site()),
- };
-
- quote! { #azalea_ecs_path::component::#typename }
-}
diff --git a/azalea-ecs/azalea-ecs-macros/src/fetch.rs b/azalea-ecs/azalea-ecs-macros/src/fetch.rs
deleted file mode 100644
index 8a6b93ba..00000000
--- a/azalea-ecs/azalea-ecs-macros/src/fetch.rs
+++ /dev/null
@@ -1,466 +0,0 @@
-use proc_macro::TokenStream;
-use proc_macro2::{Ident, Span};
-use quote::{quote, ToTokens};
-use syn::{
- parse::{Parse, ParseStream},
- parse_quote,
- punctuated::Punctuated,
- Attribute, Data, DataStruct, DeriveInput, Field, Fields,
-};
-
-use crate::azalea_ecs_path;
-
-#[derive(Default)]
-struct FetchStructAttributes {
- pub is_mutable: bool,
- pub derive_args: Punctuated<syn::NestedMeta, syn::token::Comma>,
-}
-
-static MUTABLE_ATTRIBUTE_NAME: &str = "mutable";
-static DERIVE_ATTRIBUTE_NAME: &str = "derive";
-
-mod field_attr_keywords {
- syn::custom_keyword!(ignore);
-}
-
-pub static WORLD_QUERY_ATTRIBUTE_NAME: &str = "world_query";
-
-pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
- let visibility = ast.vis;
-
- let mut fetch_struct_attributes = FetchStructAttributes::default();
- for attr in &ast.attrs {
- if !attr
- .path
- .get_ident()
- .map_or(false, |ident| ident == WORLD_QUERY_ATTRIBUTE_NAME)
- {
- continue;
- }
-
- attr.parse_args_with(|input: ParseStream| {
- let meta = input.parse_terminated::<syn::Meta, syn::token::Comma>(syn::Meta::parse)?;
- for meta in meta {
- let ident = meta.path().get_ident().unwrap_or_else(|| {
- panic!(
- "Unrecognized attribute: `{}`",
- meta.path().to_token_stream()
- )
- });
- if ident == MUTABLE_ATTRIBUTE_NAME {
- if let syn::Meta::Path(_) = meta {
- fetch_struct_attributes.is_mutable = true;
- } else {
- panic!(
- "The `{MUTABLE_ATTRIBUTE_NAME}` attribute is expected to have no value or arguments"
- );
- }
- } else if ident == DERIVE_ATTRIBUTE_NAME {
- if let syn::Meta::List(meta_list) = meta {
- fetch_struct_attributes
- .derive_args
- .extend(meta_list.nested.iter().cloned());
- } else {
- panic!(
- "Expected a structured list within the `{DERIVE_ATTRIBUTE_NAME}` attribute"
- );
- }
- } else {
- panic!(
- "Unrecognized attribute: `{}`",
- meta.path().to_token_stream()
- );
- }
- }
- Ok(())
- })
- .unwrap_or_else(|_| panic!("Invalid `{WORLD_QUERY_ATTRIBUTE_NAME}` attribute format"));
- }
-
- let path = azalea_ecs_path();
-
- let user_generics = ast.generics.clone();
- let (user_impl_generics, user_ty_generics, user_where_clauses) = user_generics.split_for_impl();
- let user_generics_with_world = {
- let mut generics = ast.generics.clone();
- generics.params.insert(0, parse_quote!('__w));
- generics
- };
- let (user_impl_generics_with_world, user_ty_generics_with_world, user_where_clauses_with_world) =
- user_generics_with_world.split_for_impl();
-
- let struct_name = ast.ident.clone();
- let read_only_struct_name = if fetch_struct_attributes.is_mutable {
- Ident::new(&format!("{struct_name}ReadOnly"), Span::call_site())
- } else {
- struct_name.clone()
- };
-
- let item_struct_name = Ident::new(&format!("{struct_name}Item"), Span::call_site());
- let read_only_item_struct_name = if fetch_struct_attributes.is_mutable {
- Ident::new(&format!("{struct_name}ReadOnlyItem"), Span::call_site())
- } else {
- item_struct_name.clone()
- };
-
- let fetch_struct_name = Ident::new(&format!("{struct_name}Fetch"), Span::call_site());
- let read_only_fetch_struct_name = if fetch_struct_attributes.is_mutable {
- Ident::new(&format!("{struct_name}ReadOnlyFetch"), Span::call_site())
- } else {
- fetch_struct_name.clone()
- };
-
- let state_struct_name = Ident::new(&format!("{struct_name}State"), Span::call_site());
-
- let fields = match &ast.data {
- Data::Struct(DataStruct {
- fields: Fields::Named(fields),
- ..
- }) => &fields.named,
- _ => panic!("Expected a struct with named fields"),
- };
-
- let mut ignored_field_attrs = Vec::new();
- let mut ignored_field_visibilities = Vec::new();
- let mut ignored_field_idents = Vec::new();
- let mut ignored_field_types = Vec::new();
- let mut field_attrs = Vec::new();
- let mut field_visibilities = Vec::new();
- let mut field_idents = Vec::new();
- let mut field_types = Vec::new();
- let mut read_only_field_types = Vec::new();
-
- for field in fields {
- let WorldQueryFieldInfo { is_ignored, attrs } = read_world_query_field_info(field);
-
- let field_ident = field.ident.as_ref().unwrap().clone();
- if is_ignored {
- ignored_field_attrs.push(attrs);
- ignored_field_visibilities.push(field.vis.clone());
- ignored_field_idents.push(field_ident.clone());
- ignored_field_types.push(field.ty.clone());
- } else {
- field_attrs.push(attrs);
- field_visibilities.push(field.vis.clone());
- field_idents.push(field_ident.clone());
- let field_ty = field.ty.clone();
- field_types.push(quote!(#field_ty));
- read_only_field_types.push(quote!(<#field_ty as #path::query::WorldQuery>::ReadOnly));
- }
- }
-
- let derive_args = &fetch_struct_attributes.derive_args;
- // `#[derive()]` is valid syntax
- let derive_macro_call = quote! { #[derive(#derive_args)] };
-
- let impl_fetch = |is_readonly: bool| {
- let struct_name = if is_readonly {
- &read_only_struct_name
- } else {
- &struct_name
- };
- let item_struct_name = if is_readonly {
- &read_only_item_struct_name
- } else {
- &item_struct_name
- };
- let fetch_struct_name = if is_readonly {
- &read_only_fetch_struct_name
- } else {
- &fetch_struct_name
- };
-
- let field_types = if is_readonly {
- &read_only_field_types
- } else {
- &field_types
- };
-
- quote! {
- #derive_macro_call
- #[doc = "Automatically generated [`WorldQuery`] item type for [`"]
- #[doc = stringify!(#struct_name)]
- #[doc = "`], returned when iterating over query results."]
- #[automatically_derived]
- #visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
- #(#(#field_attrs)* #field_visibilities #field_idents: <#field_types as #path::query::WorldQuery>::Item<'__w>,)*
- #(#(#ignored_field_attrs)* #ignored_field_visibilities #ignored_field_idents: #ignored_field_types,)*
- }
-
- #[doc(hidden)]
- #[doc = "Automatically generated internal [`WorldQuery`] fetch type for [`"]
- #[doc = stringify!(#struct_name)]
- #[doc = "`], used to define the world data accessed by this query."]
- #[automatically_derived]
- #visibility struct #fetch_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
- #(#field_idents: <#field_types as #path::query::WorldQuery>::Fetch<'__w>,)*
- #(#ignored_field_idents: #ignored_field_types,)*
- }
-
- // SAFETY: `update_component_access` and `update_archetype_component_access` are called on every field
- unsafe impl #user_impl_generics #path::query::WorldQuery
- for #struct_name #user_ty_generics #user_where_clauses {
-
- type Item<'__w> = #item_struct_name #user_ty_generics_with_world;
- type Fetch<'__w> = #fetch_struct_name #user_ty_generics_with_world;
- type ReadOnly = #read_only_struct_name #user_ty_generics;
- type State = #state_struct_name #user_ty_generics;
-
- fn shrink<'__wlong: '__wshort, '__wshort>(
- item: <#struct_name #user_ty_generics as #path::query::WorldQuery>::Item<'__wlong>
- ) -> <#struct_name #user_ty_generics as #path::query::WorldQuery>::Item<'__wshort> {
- #item_struct_name {
- #(
- #field_idents: <#field_types>::shrink(item.#field_idents),
- )*
- #(
- #ignored_field_idents: item.#ignored_field_idents,
- )*
- }
- }
-
- unsafe fn init_fetch<'__w>(
- _world: &'__w #path::world::World,
- state: &Self::State,
- _last_change_tick: u32,
- _change_tick: u32
- ) -> <Self as #path::query::WorldQuery>::Fetch<'__w> {
- #fetch_struct_name {
- #(#field_idents:
- <#field_types>::init_fetch(
- _world,
- &state.#field_idents,
- _last_change_tick,
- _change_tick
- ),
- )*
- #(#ignored_field_idents: Default::default(),)*
- }
- }
-
- unsafe fn clone_fetch<'__w>(
- _fetch: &<Self as #path::query::WorldQuery>::Fetch<'__w>
- ) -> <Self as #path::query::WorldQuery>::Fetch<'__w> {
- #fetch_struct_name {
- #(
- #field_idents: <#field_types>::clone_fetch(& _fetch. #field_idents),
- )*
- #(
- #ignored_field_idents: Default::default(),
- )*
- }
- }
-
- const IS_DENSE: bool = true #(&& <#field_types>::IS_DENSE)*;
-
- const IS_ARCHETYPAL: bool = true #(&& <#field_types>::IS_ARCHETYPAL)*;
-
- /// SAFETY: we call `set_archetype` for each member that implements `Fetch`
- #[inline]
- unsafe fn set_archetype<'__w>(
- _fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
- _state: &Self::State,
- _archetype: &'__w #path::archetype::Archetype,
- _table: &'__w #path::storage::Table
- ) {
- #(<#field_types>::set_archetype(&mut _fetch.#field_idents, &_state.#field_idents, _archetype, _table);)*
- }
-
- /// SAFETY: we call `set_table` for each member that implements `Fetch`
- #[inline]
- unsafe fn set_table<'__w>(
- _fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
- _state: &Self::State,
- _table: &'__w #path::storage::Table
- ) {
- #(<#field_types>::set_table(&mut _fetch.#field_idents, &_state.#field_idents, _table);)*
- }
-
- /// SAFETY: we call `fetch` for each member that implements `Fetch`.
- #[inline(always)]
- unsafe fn fetch<'__w>(
- _fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
- _entity: Entity,
- _table_row: usize
- ) -> <Self as #path::query::WorldQuery>::Item<'__w> {
- Self::Item {
- #(#field_idents: <#field_types>::fetch(&mut _fetch.#field_idents, _entity, _table_row),)*
- #(#ignored_field_idents: Default::default(),)*
- }
- }
-
- #[allow(unused_variables)]
- #[inline(always)]
- unsafe fn filter_fetch<'__w>(
- _fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
- _entity: Entity,
- _table_row: usize
- ) -> bool {
- true #(&& <#field_types>::filter_fetch(&mut _fetch.#field_idents, _entity, _table_row))*
- }
-
- fn update_component_access(state: &Self::State, _access: &mut #path::query::FilteredAccess<#path::component::ComponentId>) {
- #( <#field_types>::update_component_access(&state.#field_idents, _access); )*
- }
-
- fn update_archetype_component_access(
- state: &Self::State,
- _archetype: &#path::archetype::Archetype,
- _access: &mut #path::query::Access<#path::archetype::ArchetypeComponentId>
- ) {
- #(
- <#field_types>::update_archetype_component_access(&state.#field_idents, _archetype, _access);
- )*
- }
-
- fn init_state(world: &mut #path::world::World) -> #state_struct_name #user_ty_generics {
- #state_struct_name {
- #(#field_idents: <#field_types>::init_state(world),)*
- #(#ignored_field_idents: Default::default(),)*
- }
- }
-
- fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(#path::component::ComponentId) -> bool) -> bool {
- true #(&& <#field_types>::matches_component_set(&state.#field_idents, _set_contains_id))*
- }
- }
- }
- };
-
- let mutable_impl = impl_fetch(false);
- let readonly_impl = if fetch_struct_attributes.is_mutable {
- let world_query_impl = impl_fetch(true);
- quote! {
- #[doc(hidden)]
- #[doc = "Automatically generated internal [`WorldQuery`] type for [`"]
- #[doc = stringify!(#struct_name)]
- #[doc = "`], used for read-only access."]
- #[automatically_derived]
- #visibility struct #read_only_struct_name #user_impl_generics #user_where_clauses {
- #( #field_idents: #read_only_field_types, )*
- #(#(#ignored_field_attrs)* #ignored_field_visibilities #ignored_field_idents: #ignored_field_types,)*
- }
-
- #world_query_impl
- }
- } else {
- quote! {}
- };
-
- let read_only_asserts = if fetch_struct_attributes.is_mutable {
- quote! {
- // Double-check that the data fetched by `<_ as WorldQuery>::ReadOnly` is read-only.
- // This is technically unnecessary as `<_ as WorldQuery>::ReadOnly: ReadOnlyWorldQuery`
- // but to protect against future mistakes we assert the assoc type implements `ReadOnlyWorldQuery` anyway
- #( assert_readonly::<#read_only_field_types>(); )*
- }
- } else {
- quote! {
- // Statically checks that the safety guarantee of `ReadOnlyWorldQuery` for `$fetch_struct_name` actually holds true.
- // We need this to make sure that we don't compile `ReadOnlyWorldQuery` if our struct contains nested `WorldQuery`
- // members that don't implement it. I.e.:
- // ```
- // #[derive(WorldQuery)]
- // pub struct Foo { a: &'static mut MyComponent }
- // ```
- #( assert_readonly::<#field_types>(); )*
- }
- };
-
- TokenStream::from(quote! {
- #mutable_impl
-
- #readonly_impl
-
- #[doc(hidden)]
- #[doc = "Automatically generated internal [`WorldQuery`] state type for [`"]
- #[doc = stringify!(#struct_name)]
- #[doc = "`], used for caching."]
- #[automatically_derived]
- #visibility struct #state_struct_name #user_impl_generics #user_where_clauses {
- #(#field_idents: <#field_types as #path::query::WorldQuery>::State,)*
- #(#ignored_field_idents: #ignored_field_types,)*
- }
-
- /// SAFETY: we assert fields are readonly below
- unsafe impl #user_impl_generics #path::query::ReadOnlyWorldQuery
- for #read_only_struct_name #user_ty_generics #user_where_clauses {}
-
- #[allow(dead_code)]
- const _: () = {
- fn assert_readonly<T>()
- where
- T: #path::query::ReadOnlyWorldQuery,
- {
- }
-
- // We generate a readonly assertion for every struct member.
- fn assert_all #user_impl_generics_with_world () #user_where_clauses_with_world {
- #read_only_asserts
- }
- };
-
- // The original struct will most likely be left unused. As we don't want our users having
- // to specify `#[allow(dead_code)]` for their custom queries, we are using this cursed
- // workaround.
- #[allow(dead_code)]
- const _: () = {
- fn dead_code_workaround #user_impl_generics (
- q: #struct_name #user_ty_generics,
- q2: #read_only_struct_name #user_ty_generics
- ) #user_where_clauses {
- #(q.#field_idents;)*
- #(q.#ignored_field_idents;)*
- #(q2.#field_idents;)*
- #(q2.#ignored_field_idents;)*
-
- }
- };
- })
-}
-
-struct WorldQueryFieldInfo {
- /// Has `#[fetch(ignore)]` or `#[filter_fetch(ignore)]` attribute.
- is_ignored: bool,
- /// All field attributes except for `world_query` ones.
- attrs: Vec<Attribute>,
-}
-
-fn read_world_query_field_info(field: &Field) -> WorldQueryFieldInfo {
- let is_ignored = field
- .attrs
- .iter()
- .find(|attr| {
- attr.path
- .get_ident()
- .map_or(false, |ident| ident == WORLD_QUERY_ATTRIBUTE_NAME)
- })
- .map_or(false, |attr| {
- let mut is_ignored = false;
- attr.parse_args_with(|input: ParseStream| {
- if input
- .parse::<Option<field_attr_keywords::ignore>>()?
- .is_some()
- {
- is_ignored = true;
- }
- Ok(())
- })
- .unwrap_or_else(|_| panic!("Invalid `{WORLD_QUERY_ATTRIBUTE_NAME}` attribute format"));
-
- is_ignored
- });
-
- let attrs = field
- .attrs
- .iter()
- .filter(|attr| {
- attr.path
- .get_ident()
- .map_or(true, |ident| ident != WORLD_QUERY_ATTRIBUTE_NAME)
- })
- .cloned()
- .collect();
-
- WorldQueryFieldInfo { is_ignored, attrs }
-}
diff --git a/azalea-ecs/azalea-ecs-macros/src/lib.rs b/azalea-ecs/azalea-ecs-macros/src/lib.rs
deleted file mode 100755
index 9d4e9b2d..00000000
--- a/azalea-ecs/azalea-ecs-macros/src/lib.rs
+++ /dev/null
@@ -1,525 +0,0 @@
-//! A fork of bevy_ecs_macros that uses azalea_ecs instead of bevy_ecs.
-
-extern crate proc_macro;
-
-mod component;
-mod fetch;
-pub(crate) mod utils;
-
-use crate::fetch::derive_world_query_impl;
-use proc_macro::TokenStream;
-use proc_macro2::Span;
-use quote::{format_ident, quote};
-use syn::{
- parse::{Parse, ParseStream},
- parse_macro_input,
- punctuated::Punctuated,
- spanned::Spanned,
- token::Comma,
- DeriveInput, Field, GenericParam, Ident, Index, LitInt, Meta, MetaList, NestedMeta, Result,
- Token, TypeParam,
-};
-use utils::{derive_label, get_named_struct_fields, BevyManifest};
-
-struct AllTuples {
- macro_ident: Ident,
- start: usize,
- end: usize,
- idents: Vec<Ident>,
-}
-
-impl Parse for AllTuples {
- fn parse(input: ParseStream) -> Result<Self> {
- let macro_ident = input.parse::<Ident>()?;
- input.parse::<Comma>()?;
- let start = input.parse::<LitInt>()?.base10_parse()?;
- input.parse::<Comma>()?;
- let end = input.parse::<LitInt>()?.base10_parse()?;
- input.parse::<Comma>()?;
- let mut idents = vec![input.parse::<Ident>()?];
- while input.parse::<Comma>().is_ok() {
- idents.push(input.parse::<Ident>()?);
- }
-
- Ok(AllTuples {
- macro_ident,
- start,
- end,
- idents,
- })
- }
-}
-
-#[proc_macro]
-pub fn all_tuples(input: TokenStream) -> TokenStream {
- let input = parse_macro_input!(input as AllTuples);
- let len = input.end - input.start;
- let mut ident_tuples = Vec::with_capacity(len);
- for i in input.start..=input.end {
- let idents = input
- .idents
- .iter()
- .map(|ident| format_ident!("{}{}", ident, i));
- if input.idents.len() < 2 {
- ident_tuples.push(quote! {
- #(#idents)*
- });
- } else {
- ident_tuples.push(quote! {
- (#(#idents),*)
- });
- }
- }
-
- let macro_ident = &input.macro_ident;
- let invocations = (input.start..=input.end).map(|i| {
- let ident_tuples = &ident_tuples[..i];
- quote! {
- #macro_ident!(#(#ident_tuples),*);
- }
- });
- TokenStream::from(quote! {
- #(
- #invocations
- )*
- })
-}
-
-enum BundleFieldKind {
- Component,
- Ignore,
-}
-
-const BUNDLE_ATTRIBUTE_NAME: &str = "bundle";
-const BUNDLE_ATTRIBUTE_IGNORE_NAME: &str = "ignore";
-
-#[proc_macro_derive(Bundle, attributes(bundle))]
-pub fn derive_bundle(input: TokenStream) -> TokenStream {
- let ast = parse_macro_input!(input as DeriveInput);
- let ecs_path = azalea_ecs_path();
-
- let named_fields = match get_named_struct_fields(&ast.data) {
- Ok(fields) => &fields.named,
- Err(e) => return e.into_compile_error().into(),
- };
-
- let mut field_kind = Vec::with_capacity(named_fields.len());
-
- 'field_loop: for field in named_fields.iter() {
- for attr in &field.attrs {
- if attr.path.is_ident(BUNDLE_ATTRIBUTE_NAME) {
- if let Ok(Meta::List(MetaList { nested, .. })) = attr.parse_meta() {
- if let Some(&NestedMeta::Meta(Meta::Path(ref path))) = nested.first() {
- if path.is_ident(BUNDLE_ATTRIBUTE_IGNORE_NAME) {
- field_kind.push(BundleFieldKind::Ignore);
- continue 'field_loop;
- }
-
- return syn::Error::new(
- path.span(),
- format!(
- "Invalid bundle attribute. Use `{BUNDLE_ATTRIBUTE_IGNORE_NAME}`"
- ),
- )
- .into_compile_error()
- .into();
- }
-
- return syn::Error::new(attr.span(), format!("Invalid bundle attribute. Use `#[{BUNDLE_ATTRIBUTE_NAME}({BUNDLE_ATTRIBUTE_IGNORE_NAME})]`")).into_compile_error().into();
- }
- }
- }
-
- field_kind.push(BundleFieldKind::Component);
- }
-
- let field = named_fields
- .iter()
- .map(|field| field.ident.as_ref().unwrap())
- .collect::<Vec<_>>();
- let field_type = named_fields
- .iter()
- .map(|field| &field.ty)
- .collect::<Vec<_>>();
-
- let mut field_component_ids = Vec::new();
- let mut field_get_components = Vec::new();
- let mut field_from_components = Vec::new();
- for ((field_type, field_kind), field) in
- field_type.iter().zip(field_kind.iter()).zip(field.iter())
- {
- match field_kind {
- BundleFieldKind::Component => {
- field_component_ids.push(quote! {
- <#field_type as #ecs_path::bundle::_BevyBundle>::component_ids(components, storages, &mut *ids);
- });
- field_get_components.push(quote! {
- self.#field.get_components(&mut *func);
- });
- field_from_components.push(quote! {
- #field: <#field_type as #ecs_path::bundle::_BevyBundle>::from_components(ctx, &mut *func),
- });
- }
-
- BundleFieldKind::Ignore => {
- field_from_components.push(quote! {
- #field: ::std::default::Default::default(),
- });
- }
- }
- }
- let generics = ast.generics;
- let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
- let struct_name = &ast.ident;
-
- TokenStream::from(quote! {
- /// SAFETY: ComponentId is returned in field-definition-order. [from_components] and [get_components] use field-definition-order
- unsafe impl #impl_generics #ecs_path::bundle::_BevyBundle for #struct_name #ty_generics #where_clause {
- fn component_ids(
- components: &mut #ecs_path::component::Components,
- storages: &mut #ecs_path::storage::Storages,
- ids: &mut impl FnMut(#ecs_path::component::ComponentId)
- ){
- #(#field_component_ids)*
- }
-
- #[allow(unused_variables, non_snake_case)]
- unsafe fn from_components<__T, __F>(ctx: &mut __T, func: &mut __F) -> Self
- where
- __F: FnMut(&mut __T) -> #ecs_path::ptr::OwningPtr<'_>
- {
- Self {
- #(#field_from_components)*
- }
- }
-
- #[allow(unused_variables)]
- fn get_components(self, func: &mut impl FnMut(#ecs_path::ptr::OwningPtr<'_>)) {
- #(#field_get_components)*
- }
- }
- })
-}
-
-fn get_idents(fmt_string: fn(usize) -> String, count: usize) -> Vec<Ident> {
- (0..count)
- .map(|i| Ident::new(&fmt_string(i), Span::call_site()))
- .collect::<Vec<Ident>>()
-}
-
-#[proc_macro]
-pub fn impl_param_set(_input: TokenStream) -> TokenStream {
- let mut tokens = TokenStream::new();
- let max_params = 8;
- let params = get_idents(|i| format!("P{i}"), max_params);
- let params_fetch = get_idents(|i| format!("PF{i}"), max_params);
- let metas = get_idents(|i| format!("m{i}"), max_params);
- let mut param_fn_muts = Vec::new();
- for (i, param) in params.iter().enumerate() {
- let fn_name = Ident::new(&format!("p{i}"), Span::call_site());
- let index = Index::from(i);
- param_fn_muts.push(quote! {
- pub fn #fn_name<'a>(&'a mut self) -> <#param::Fetch as SystemParamFetch<'a, 'a>>::Item {
- // SAFETY: systems run without conflicts with other systems.
- // Conflicting params in ParamSet are not accessible at the same time
- // ParamSets are guaranteed to not conflict with other SystemParams
- unsafe {
- <#param::Fetch as SystemParamFetch<'a, 'a>>::get_param(&mut self.param_states.#index, &self.system_meta, self.world, self.change_tick)
- }
- }
- });
- }
-
- for param_count in 1..=max_params {
- let param = &params[0..param_count];
- let param_fetch = &params_fetch[0..param_count];
- let meta = &metas[0..param_count];
- let param_fn_mut = &param_fn_muts[0..param_count];
- tokens.extend(TokenStream::from(quote! {
- impl<'w, 's, #(#param: SystemParam,)*> SystemParam for ParamSet<'w, 's, (#(#param,)*)>
- {
- type Fetch = ParamSetState<(#(#param::Fetch,)*)>;
- }
-
- // SAFETY: All parameters are constrained to ReadOnlyFetch, so World is only read
-
- unsafe impl<#(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> ReadOnlySystemParamFetch for ParamSetState<(#(#param_fetch,)*)>
- where #(#param_fetch: ReadOnlySystemParamFetch,)*
- { }
-
- // SAFETY: Relevant parameter ComponentId and ArchetypeComponentId access is applied to SystemMeta. If any ParamState conflicts
- // with any prior access, a panic will occur.
-
- unsafe impl<#(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> SystemParamState for ParamSetState<(#(#param_fetch,)*)>
- {
- fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
- #(
- // Pretend to add each param to the system alone, see if it conflicts
- let mut #meta = system_meta.clone();
- #meta.component_access_set.clear();
- #meta.archetype_component_access.clear();
- #param_fetch::init(world, &mut #meta);
- let #param = #param_fetch::init(world, &mut system_meta.clone());
- )*
- #(
- system_meta
- .component_access_set
- .extend(#meta.component_access_set);
- system_meta
- .archetype_component_access
- .extend(&#meta.archetype_component_access);
- )*
- ParamSetState((#(#param,)*))
- }
-
- fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) {
- let (#(#param,)*) = &mut self.0;
- #(
- #param.new_archetype(archetype, system_meta);
- )*
- }
-
- fn apply(&mut self, world: &mut World) {
- self.0.apply(world)
- }
- }
-
-
-
- impl<'w, 's, #(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> SystemParamFetch<'w, 's> for ParamSetState<(#(#param_fetch,)*)>
- {
- type Item = ParamSet<'w, 's, (#(<#param_fetch as SystemParamFetch<'w, 's>>::Item,)*)>;
-
- #[inline]
- unsafe fn get_param(
- state: &'s mut Self,
- system_meta: &SystemMeta,
- world: &'w World,
- change_tick: u32,
- ) -> Self::Item {
- ParamSet {
- param_states: &mut state.0,
- system_meta: system_meta.clone(),
- world,
- change_tick,
- }
- }
- }
-
- impl<'w, 's, #(#param: SystemParam,)*> ParamSet<'w, 's, (#(#param,)*)>
- {
-
- #(#param_fn_mut)*
- }
- }));
- }
-
- tokens
-}
-
-#[derive(Default)]
-struct SystemParamFieldAttributes {
- pub ignore: bool,
-}
-
-static SYSTEM_PARAM_ATTRIBUTE_NAME: &str = "system_param";
-
-/// Implement `SystemParam` to use a struct as a parameter in a system
-#[proc_macro_derive(SystemParam, attributes(system_param))]
-pub fn derive_system_param(input: TokenStream) -> TokenStream {
- let ast = parse_macro_input!(input as DeriveInput);
- let fields = match get_named_struct_fields(&ast.data) {
- Ok(fields) => &fields.named,
- Err(e) => return e.into_compile_error().into(),
- };
- let path = azalea_ecs_path();
-
- let field_attributes = fields
- .iter()
- .map(|field| {
- (
- field,
- field
- .attrs
- .iter()
- .find(|a| *a.path.get_ident().as_ref().unwrap() == SYSTEM_PARAM_ATTRIBUTE_NAME)
- .map_or_else(SystemParamFieldAttributes::default, |a| {
- syn::custom_keyword!(ignore);
- let mut attributes = SystemParamFieldAttributes::default();
- a.parse_args_with(|input: ParseStream| {
- if input.parse::<Option<ignore>>()?.is_some() {
- attributes.ignore = true;
- }
- Ok(())
- })
- .expect("Invalid 'system_param' attribute format.");
-
- attributes
- }),
- )
- })
- .collect::<Vec<(&Field, SystemParamFieldAttributes)>>();
- let mut fields = Vec::new();
- let mut field_indices = Vec::new();
- let mut field_types = Vec::new();
- let mut ignored_fields = Vec::new();
- let mut ignored_field_types = Vec::new();
- for (i, (field, attrs)) in field_attributes.iter().enumerate() {
- if attrs.ignore {
- ignored_fields.push(field.ident.as_ref().unwrap());
- ignored_field_types.push(&field.ty);
- } else {
- fields.push(field.ident.as_ref().unwrap());
- field_types.push(&field.ty);
- field_indices.push(Index::from(i));
- }
- }
-
- let generics = ast.generics;
- let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
-
- let lifetimeless_generics: Vec<_> = generics
- .params
- .iter()
- .filter(|g| matches!(g, GenericParam::Type(_)))
- .collect();
-
- let mut punctuated_generics = Punctuated::<_, Token![,]>::new();
- punctuated_generics.extend(lifetimeless_generics.iter().map(|g| match g {
- GenericParam::Type(g) => GenericParam::Type(TypeParam {
- default: None,
- ..g.clone()
- }),
- _ => unreachable!(),
- }));
-
- let mut punctuated_generic_idents = Punctuated::<_, Token![,]>::new();
- punctuated_generic_idents.extend(lifetimeless_generics.iter().map(|g| match g {
- GenericParam::Type(g) => &g.ident,
- _ => unreachable!(),
- }));
-
- let struct_name = &ast.ident;
- let fetch_struct_visibility = &ast.vis;
-
- TokenStream::from(quote! {
- // We define the FetchState struct in an anonymous scope to avoid polluting the user namespace.
- // The struct can still be accessed via SystemParam::Fetch, e.g. EventReaderState can be accessed via
- // <EventReader<'static, 'static, T> as SystemParam>::Fetch
- const _: () = {
- impl #impl_generics #path::system::SystemParam for #struct_name #ty_generics #where_clause {
- type Fetch = FetchState <(#(<#field_types as #path::system::SystemParam>::Fetch,)*), #punctuated_generic_idents>;
- }
-
- #[doc(hidden)]
- #fetch_struct_visibility struct FetchState <TSystemParamState, #punctuated_generic_idents> {
- state: TSystemParamState,
- marker: std::marker::PhantomData<fn()->(#punctuated_generic_idents)>
- }
-
- unsafe impl<TSystemParamState: #path::system::SystemParamState, #punctuated_generics> #path::system::SystemParamState for FetchState <TSystemParamState, #punctuated_generic_idents> #where_clause {
- fn init(world: &mut #path::world::World, system_meta: &mut #path::system::SystemMeta) -> Self {
- Self {
- state: TSystemParamState::init(world, system_meta),
- marker: std::marker::PhantomData,
- }
- }
-
- fn new_archetype(&mut self, archetype: &#path::archetype::Archetype, system_meta: &mut #path::system::SystemMeta) {
- self.state.new_archetype(archetype, system_meta)
- }
-
- fn apply(&mut self, world: &mut #path::world::World) {
- self.state.apply(world)
- }
- }
-
- impl #impl_generics #path::system::SystemParamFetch<'w, 's> for FetchState <(#(<#field_types as #path::system::SystemParam>::Fetch,)*), #punctuated_generic_idents> #where_clause {
- type Item = #struct_name #ty_generics;
- unsafe fn get_param(
- state: &'s mut Self,
- system_meta: &#path::system::SystemMeta,
- world: &'w #path::world::World,
- change_tick: u32,
- ) -> Self::Item {
- #struct_name {
- #(#fields: <<#field_types as #path::system::SystemParam>::Fetch as #path::system::SystemParamFetch>::get_param(&mut state.state.#field_indices, system_meta, world, change_tick),)*
- #(#ignored_fields: <#ignored_field_types>::default(),)*
- }
- }
- }
-
- // Safety: The `ParamState` is `ReadOnlySystemParamFetch`, so this can only read from the `World`
- unsafe impl<TSystemParamState: #path::system::SystemParamState + #path::system::ReadOnlySystemParamFetch, #punctuated_generics> #path::system::ReadOnlySystemParamFetch for FetchState <TSystemParamState, #punctuated_generic_idents> #where_clause {}
- };
- })
-}
-
-/// Implement `WorldQuery` to use a struct as a parameter in a query
-#[proc_macro_derive(WorldQuery, attributes(world_query))]
-pub fn derive_world_query(input: TokenStream) -> TokenStream {
- let ast = parse_macro_input!(input as DeriveInput);
- derive_world_query_impl(ast)
-}
-
-/// Generates an impl of the `SystemLabel` trait.
-///
-/// This works only for unit structs, or enums with only unit variants.
-/// You may force a struct or variant to behave as if it were fieldless with
-/// `#[system_label(ignore_fields)]`.
-#[proc_macro_derive(SystemLabel, attributes(system_label))]
-pub fn derive_system_label(input: TokenStream) -> TokenStream {
- let input = parse_macro_input!(input as DeriveInput);
- let mut trait_path = azalea_ecs_path();
- trait_path.segments.push(format_ident!("schedule").into());
- trait_path
- .segments
- .push(format_ident!("SystemLabel").into());
- derive_label(input, &trait_path, "system_label")
-}
-
-/// Generates an impl of the `StageLabel` trait.
-///
-/// This works only for unit structs, or enums with only unit variants.
-/// You may force a struct or variant to behave as if it were fieldless with
-/// `#[stage_label(ignore_fields)]`.
-#[proc_macro_derive(StageLabel, attributes(stage_label))]
-pub fn derive_stage_label(input: TokenStream) -> TokenStream {
- let input = parse_macro_input!(input as DeriveInput);
- let mut trait_path = azalea_ecs_path();
- trait_path.segments.push(format_ident!("schedule").into());
- trait_path
- .segments
- .push(format_ident!("_BevyStageLabel").into());
- derive_label(input, &trait_path, "stage_label")
-}
-
-/// Generates an impl of the `RunCriteriaLabel` trait.
-///
-/// This works only for unit structs, or enums with only unit variants.
-/// You may force a struct or variant to behave as if it were fieldless with
-/// `#[run_criteria_label(ignore_fields)]`.
-#[proc_macro_derive(RunCriteriaLabel, attributes(run_criteria_label))]
-pub fn derive_run_criteria_label(input: TokenStream) -> TokenStream {
- let input = parse_macro_input!(input as DeriveInput);
- let mut trait_path = azalea_ecs_path();
- trait_path.segments.push(format_ident!("schedule").into());
- trait_path
- .segments
- .push(format_ident!("RunCriteriaLabel").into());
- derive_label(input, &trait_path, "run_criteria_label")
-}
-
-pub(crate) fn azalea_ecs_path() -> syn::Path {
- BevyManifest::default().get_path("azalea_ecs")
-}
-
-#[proc_macro_derive(Resource)]
-pub fn derive_resource(input: TokenStream) -> TokenStream {
- component::derive_resource(input)
-}
-
-#[proc_macro_derive(Component, attributes(component))]
-pub fn derive_component(input: TokenStream) -> TokenStream {
- component::derive_component(input)
-}
diff --git a/azalea-ecs/azalea-ecs-macros/src/utils/attrs.rs b/azalea-ecs/azalea-ecs-macros/src/utils/attrs.rs
deleted file mode 100644
index 05f0712a..00000000
--- a/azalea-ecs/azalea-ecs-macros/src/utils/attrs.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-#![allow(dead_code)]
-
-use syn::DeriveInput;
-
-use super::symbol::Symbol;
-
-pub fn parse_attrs(ast: &DeriveInput, attr_name: Symbol) -> syn::Result<Vec<syn::NestedMeta>> {
- let mut list = Vec::new();
- for attr in ast.attrs.iter().filter(|a| a.path == attr_name) {
- match attr.parse_meta()? {
- syn::Meta::List(meta) => list.extend(meta.nested.into_iter()),
- other => {
- return Err(syn::Error::new_spanned(
- other,
- format!("expected #[{attr_name}(...)]"),
- ))
- }
- }
- }
- Ok(list)
-}
-
-pub fn get_lit_str(attr_name: Symbol, lit: &syn::Lit) -> syn::Result<&syn::LitStr> {
- if let syn::Lit::Str(lit) = lit {
- Ok(lit)
- } else {
- Err(syn::Error::new_spanned(
- lit,
- format!("expected {attr_name} attribute to be a string: `{attr_name} = \"...\"`"),
- ))
- }
-}
-
-pub fn get_lit_bool(attr_name: Symbol, lit: &syn::Lit) -> syn::Result<bool> {
- if let syn::Lit::Bool(lit) = lit {
- Ok(lit.value())
- } else {
- Err(syn::Error::new_spanned(
- lit,
- format!(
- "expected {attr_name} attribute to be a bool value, `true` or `false`: `{attr_name} = ...`"
- ),
- ))
- }
-}
diff --git a/azalea-ecs/azalea-ecs-macros/src/utils/mod.rs b/azalea-ecs/azalea-ecs-macros/src/utils/mod.rs
deleted file mode 100644
index c79e3efe..00000000
--- a/azalea-ecs/azalea-ecs-macros/src/utils/mod.rs
+++ /dev/null
@@ -1,227 +0,0 @@
-#![allow(dead_code)]
-
-extern crate proc_macro;
-
-mod attrs;
-mod shape;
-mod symbol;
-
-pub use attrs::*;
-pub use shape::*;
-pub use symbol::*;
-
-use proc_macro::TokenStream;
-use quote::{quote, quote_spanned};
-use std::{env, path::PathBuf};
-use syn::spanned::Spanned;
-use toml::{map::Map, Value};
-
-pub struct BevyManifest {
- manifest: Map<String, Value>,
-}
-
-impl Default for BevyManifest {
- fn default() -> Self {
- Self {
- manifest: env::var_os("CARGO_MANIFEST_DIR")
- .map(PathBuf::from)
- .map(|mut path| {
- path.push("Cargo.toml");
- let manifest = std::fs::read_to_string(path).unwrap();
- toml::from_str(&manifest).unwrap()
- })
- .unwrap(),
- }
- }
-}
-
-impl BevyManifest {
- pub fn maybe_get_path(&self, name: &str) -> Option<syn::Path> {
- const AZALEA: &str = "azalea";
- const AZALEA_ECS: &str = "azalea_ecs";
- const BEVY_ECS: &str = "bevy_ecs";
- const BEVY: &str = "bevy";
-
- fn dep_package(dep: &Value) -> Option<&str> {
- if dep.as_str().is_some() {
- None
- } else {
- dep.as_table()
- .unwrap()
- .get("package")
- .map(|name| name.as_str().unwrap())
- }
- }
-
- let find_in_deps = |deps: &Map<String, Value>| -> Option<syn::Path> {
- let package = if let Some(dep) = deps.get(name) {
- return Some(Self::parse_str(dep_package(dep).unwrap_or(name)));
- } else if let Some(dep) = deps.get(AZALEA) {
- dep_package(dep).unwrap_or(AZALEA)
- } else if let Some(dep) = deps.get(AZALEA_ECS) {
- dep_package(dep).unwrap_or(AZALEA_ECS)
- } else if let Some(dep) = deps.get(BEVY_ECS) {
- dep_package(dep).unwrap_or(BEVY_ECS)
- } else if let Some(dep) = deps.get(BEVY) {
- dep_package(dep).unwrap_or(BEVY)
- } else {
- return None;
- };
-
- let mut path = Self::parse_str::<syn::Path>(package);
- if let Some(module) = name.strip_prefix("azalea_") {
- path.segments.push(Self::parse_str(module));
- }
- Some(path)
- };
-
- let deps = self
- .manifest
- .get("dependencies")
- .map(|deps| deps.as_table().unwrap());
- let deps_dev = self
- .manifest
- .get("dev-dependencies")
- .map(|deps| deps.as_table().unwrap());
-
- deps.and_then(find_in_deps)
- .or_else(|| deps_dev.and_then(find_in_deps))
- }
-
- /// Returns the path for the crate with the given name.
- ///
- /// This is a convenience method for constructing a [manifest] and
- /// calling the [`get_path`] method.
- ///
- /// This method should only be used where you just need the path and can't
- /// cache the [manifest]. If caching is possible, it's recommended to create
- /// the [manifest] yourself and use the [`get_path`] method.
- ///
- /// [`get_path`]: Self::get_path
- /// [manifest]: Self
- pub fn get_path_direct(name: &str) -> syn::Path {
- Self::default().get_path(name)
- }
-
- pub fn get_path(&self, name: &str) -> syn::Path {
- self.maybe_get_path(name)
- .unwrap_or_else(|| Self::parse_str(name))
- }
-
- pub fn parse_str<T: syn::parse::Parse>(path: &str) -> T {
- syn::parse(path.parse::<TokenStream>().unwrap()).unwrap()
- }
-}
-
-/// Derive a label trait
-///
-/// # Args
-///
-/// - `input`: The [`syn::DeriveInput`] for struct that is deriving the label
-/// trait
-/// - `trait_path`: The path [`syn::Path`] to the label trait
-pub fn derive_label(
- input: syn::DeriveInput,
- trait_path: &syn::Path,
- attr_name: &str,
-) -> TokenStream {
- // return true if the variant specified is an `ignore_fields` attribute
- fn is_ignore(attr: &syn::Attribute, attr_name: &str) -> bool {
- if attr.path.get_ident().as_ref().unwrap() != &attr_name {
- return false;
- }
-
- syn::custom_keyword!(ignore_fields);
- attr.parse_args_with(|input: syn::parse::ParseStream| {
- let ignore = input.parse::<Option<ignore_fields>>()?.is_some();
- Ok(ignore)
- })
- .unwrap()
- }
-
- let ident = input.ident.clone();
-
- let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
- let mut where_clause = where_clause.cloned().unwrap_or_else(|| syn::WhereClause {
- where_token: Default::default(),
- predicates: Default::default(),
- });
- where_clause
- .predicates
- .push(syn::parse2(quote! { Self: 'static }).unwrap());
-
- let as_str = match input.data {
- syn::Data::Struct(d) => {
- // see if the user tried to ignore fields incorrectly
- if let Some(attr) = d
- .fields
- .iter()
- .flat_map(|f| &f.attrs)
- .find(|a| is_ignore(a, attr_name))
- {
- let err_msg = format!("`#[{attr_name}(ignore_fields)]` cannot be applied to fields individually: add it to the struct declaration");
- return quote_spanned! {
- attr.span() => compile_error!(#err_msg);
- }
- .into();
- }
- // Structs must either be fieldless, or explicitly ignore the fields.
- let ignore_fields = input.attrs.iter().any(|a| is_ignore(a, attr_name));
- if matches!(d.fields, syn::Fields::Unit) || ignore_fields {
- let lit = ident.to_string();
- quote! { #lit }
- } else {
- let err_msg = format!("Labels cannot contain data, unless explicitly ignored with `#[{attr_name}(ignore_fields)]`");
- return quote_spanned! {
- d.fields.span() => compile_error!(#err_msg);
- }
- .into();
- }
- }
- syn::Data::Enum(d) => {
- // check if the user put #[label(ignore_fields)] in the wrong place
- if let Some(attr) = input.attrs.iter().find(|a| is_ignore(a, attr_name)) {
- let err_msg = format!("`#[{attr_name}(ignore_fields)]` can only be applied to enum variants or struct declarations");
- return quote_spanned! {
- attr.span() => compile_error!(#err_msg);
- }
- .into();
- }
- let arms = d.variants.iter().map(|v| {
- // Variants must either be fieldless, or explicitly ignore the fields.
- let ignore_fields = v.attrs.iter().any(|a| is_ignore(a, attr_name));
- if matches!(v.fields, syn::Fields::Unit) | ignore_fields {
- let mut path = syn::Path::from(ident.clone());
- path.segments.push(v.ident.clone().into());
- let lit = format!("{ident}::{}", v.ident.clone());
- quote! { #path { .. } => #lit }
- } else {
- let err_msg = format!("Label variants cannot contain data, unless explicitly ignored with `#[{attr_name}(ignore_fields)]`");
- quote_spanned! {
- v.fields.span() => _ => { compile_error!(#err_msg); }
- }
- }
- });
- quote! {
- match self {
- #(#arms),*
- }
- }
- }
- syn::Data::Union(_) => {
- return quote_spanned! {
- input.span() => compile_error!("Unions cannot be used as labels.");
- }
- .into();
- }
- };
-
- (quote! {
- impl #impl_generics #trait_path for #ident #ty_generics #where_clause {
- fn as_str(&self) -> &'static str {
- #as_str
- }
- }
- })
- .into()
-}
diff --git a/azalea-ecs/azalea-ecs-macros/src/utils/shape.rs b/azalea-ecs/azalea-ecs-macros/src/utils/shape.rs
deleted file mode 100644
index 98230749..00000000
--- a/azalea-ecs/azalea-ecs-macros/src/utils/shape.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-use proc_macro::Span;
-use syn::{Data, DataStruct, Error, Fields, FieldsNamed};
-
-/// Get the fields of a data structure if that structure is a struct with named
-/// fields; otherwise, return a compile error that points to the site of the
-/// macro invocation.
-pub fn get_named_struct_fields(data: &syn::Data) -> syn::Result<&FieldsNamed> {
- match data {
- Data::Struct(DataStruct {
- fields: Fields::Named(fields),
- ..
- }) => Ok(fields),
- _ => Err(Error::new(
- // This deliberately points to the call site rather than the structure
- // body; marking the entire body as the source of the error makes it
- // impossible to figure out which `derive` has a problem.
- Span::call_site().into(),
- "Only structs with named fields are supported",
- )),
- }
-}
diff --git a/azalea-ecs/azalea-ecs-macros/src/utils/symbol.rs b/azalea-ecs/azalea-ecs-macros/src/utils/symbol.rs
deleted file mode 100644
index dc639f4d..00000000
--- a/azalea-ecs/azalea-ecs-macros/src/utils/symbol.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-use std::fmt::{self, Display};
-use syn::{Ident, Path};
-
-#[derive(Copy, Clone)]
-pub struct Symbol(pub &'static str);
-
-impl PartialEq<Symbol> for Ident {
- fn eq(&self, word: &Symbol) -> bool {
- self == word.0
- }
-}
-
-impl<'a> PartialEq<Symbol> for &'a Ident {
- fn eq(&self, word: &Symbol) -> bool {
- *self == word.0
- }
-}
-
-impl PartialEq<Symbol> for Path {
- fn eq(&self, word: &Symbol) -> bool {
- self.is_ident(word.0)
- }
-}
-
-impl<'a> PartialEq<Symbol> for &'a Path {
- fn eq(&self, word: &Symbol) -> bool {
- self.is_ident(word.0)
- }
-}
-
-impl Display for Symbol {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str(self.0)
- }
-}
diff --git a/azalea-ecs/src/lib.rs b/azalea-ecs/src/lib.rs
deleted file mode 100644
index bc374e45..00000000
--- a/azalea-ecs/src/lib.rs
+++ /dev/null
@@ -1,157 +0,0 @@
-#![feature(trait_alias)]
-
-//! Re-export important parts of [`bevy_ecs`] and [`bevy_app`] and make them
-//! more compatible with Azalea.
-//!
-//! This is completely compatible with `bevy_ecs`, so it won't cause issues if
-//! you use plugins meant for Bevy.
-//!
-//! Changes:
-//! - Add [`TickPlugin`], [`TickStage`] and [`AppTickExt`] (which adds
-//! `app.add_tick_system` and `app.add_tick_system_set`).
-//! - Change the macros to use azalea/azalea_ecs instead of bevy/bevy_ecs
-//! - Rename `world::World` to [`ecs::Ecs`]
-//! - Re-export `bevy_app` in the [`app`] module.
-//!
-//! [`bevy_ecs`]: https://docs.rs/bevy_ecs
-//! [`bevy_app`]: https://docs.rs/bevy_app
-
-use std::time::{Duration, Instant};
-
-pub mod ecs {
- pub use bevy_ecs::world::World as Ecs;
- pub use bevy_ecs::world::{EntityMut, EntityRef, Mut};
-}
-pub mod component {
- pub use azalea_ecs_macros::Component;
- pub use bevy_ecs::component::{ComponentId, ComponentStorage, Components, TableStorage};
-
- // we do this because re-exporting Component would re-export the macro as well,
- // which is bad (since we have our own Component macro)
- // instead, we have to do this so Component is a trait alias and the original
- // impl-able trait is still available as _BevyComponent
- pub trait Component = bevy_ecs::component::Component;
- pub use bevy_ecs::component::Component as _BevyComponent;
-}
-pub mod bundle {
- pub use azalea_ecs_macros::Bundle;
- pub trait Bundle = bevy_ecs::bundle::Bundle;
- pub use bevy_ecs::bundle::Bundle as _BevyBundle;
-}
-pub mod system {
- pub use azalea_ecs_macros::Resource;
- pub use bevy_ecs::system::{
- Command, Commands, EntityCommands, Query, Res, ResMut, SystemState,
- };
- pub trait Resource = bevy_ecs::system::Resource;
- pub use bevy_ecs::system::Resource as _BevyResource;
-}
-pub mod schedule {
- pub use azalea_ecs_macros::StageLabel;
- pub use bevy_ecs::schedule::{
- IntoRunCriteria, IntoSystemDescriptor, ReportExecutionOrderAmbiguities, Schedule, Stage,
- SystemSet, SystemStage,
- };
- pub trait StageLabel = bevy_ecs::schedule::StageLabel;
- pub use bevy_ecs::schedule::StageLabel as _BevyStageLabel;
-}
-pub use bevy_app as app;
-pub use bevy_ecs::{entity, event, ptr, query, storage};
-
-use app::{App, CoreStage, Plugin};
-use bevy_ecs::schedule::*;
-use ecs::Ecs;
-
-pub struct TickPlugin {
- /// How often a tick should happen. 50 milliseconds by default. Set to 0 to
- /// tick every update.
- pub tick_interval: Duration,
-}
-impl Plugin for TickPlugin {
- fn build(&self, app: &mut App) {
- app.add_stage_before(
- CoreStage::Update,
- TickLabel,
- TickStage {
- interval: self.tick_interval,
- next_tick: Instant::now(),
- stage: Box::new(SystemStage::parallel()),
- },
- );
- }
-}
-impl Default for TickPlugin {
- fn default() -> Self {
- Self {
- tick_interval: Duration::from_millis(50),
- }
- }
-}
-
-#[derive(StageLabel)]
-struct TickLabel;
-
-/// A [`Stage`] that runs every 50 milliseconds.
-pub struct TickStage {
- pub interval: Duration,
- pub next_tick: Instant,
- stage: Box<dyn Stage>,
-}
-
-impl Stage for TickStage {
- fn run(&mut self, ecs: &mut Ecs) {
- // if the interval is 0, that means it runs every tick
- if self.interval.is_zero() {
- self.stage.run(ecs);
- return;
- }
- // keep calling run until it's caught up
- // TODO: Minecraft bursts up to 10 ticks and then skips, we should too (but
- // check the source so we do it right)
- while Instant::now() > self.next_tick {
- self.next_tick += self.interval;
- self.stage.run(ecs);
- }
- }
-}
-
-pub trait AppTickExt {
- fn add_tick_system_set(&mut self, system_set: SystemSet) -> &mut App;
- fn add_tick_system<Params>(&mut self, system: impl IntoSystemDescriptor<Params>) -> &mut App;
-}
-
-impl AppTickExt for App {
- /// Adds a set of ECS systems that will run every 50 milliseconds.
- ///
- /// Note that you should NOT have `EventReader`s in tick systems, as this
- /// will make them sometimes be missed.
- fn add_tick_system_set(&mut self, system_set: SystemSet) -> &mut App {
- let tick_stage = self
- .schedule
- .get_stage_mut::<TickStage>(TickLabel)
- .expect("Tick Stage not found");
- let stage = tick_stage
- .stage
- .downcast_mut::<SystemStage>()
- .expect("Fixed Timestep sub-stage is not a SystemStage");
- stage.add_system_set(system_set);
- self
- }
-
- /// Adds a new ECS system that will run every 50 milliseconds.
- ///
- /// Note that you should NOT have `EventReader`s in tick systems, as this
- /// will make them sometimes be missed.
- fn add_tick_system<Params>(&mut self, system: impl IntoSystemDescriptor<Params>) -> &mut App {
- let tick_stage = self
- .schedule
- .get_stage_mut::<TickStage>(TickLabel)
- .expect("Tick Stage not found");
- let stage = tick_stage
- .stage
- .downcast_mut::<SystemStage>()
- .expect("Fixed Timestep sub-stage is not a SystemStage");
- stage.add_system(system);
- self
- }
-}