From 85d264c3e21e9df9a82985d8fbf7961899547c93 Mon Sep 17 00:00:00 2001 From: Dmitry Stepanov Date: Tue, 9 Jan 2024 12:31:22 +0300 Subject: [PATCH] proc-macro for TypeUuidProvider - allows to add `#[type_uuid(id = "15a8ecd6-a09f-4c5d-b9f9-b7f0e8a44ac9")]` attribute to types that `#[derive(TypeUuidProvider)]` --- fyrox-core-derive/src/lib.rs | 10 +++++ fyrox-core-derive/src/uuid.rs | 28 ++++++++++++ fyrox-core-derive/tests/it/main.rs | 1 + fyrox-core-derive/tests/it/uuid.rs | 12 ++++++ fyrox-core/src/lib.rs | 66 ++-------------------------- fyrox-core/src/type_traits.rs | 69 ++++++++++++++++++++++++++++++ 6 files changed, 123 insertions(+), 63 deletions(-) create mode 100644 fyrox-core-derive/src/uuid.rs create mode 100644 fyrox-core-derive/tests/it/uuid.rs create mode 100644 fyrox-core/src/type_traits.rs diff --git a/fyrox-core-derive/src/lib.rs b/fyrox-core-derive/src/lib.rs index 069c8409b..39654930b 100644 --- a/fyrox-core-derive/src/lib.rs +++ b/fyrox-core-derive/src/lib.rs @@ -1,4 +1,5 @@ mod reflect; +mod uuid; mod visit; use darling::FromDeriveInput; @@ -43,3 +44,12 @@ pub fn impl_reflect(input: TokenStream) -> TokenStream { TokenStream::from(reflect_impl) } + +/// Implements `TypeUuidProvider` trait +/// +/// User has to import `TypeUuidProvider` trait to use this macro. +#[proc_macro_derive(TypeUuidProvider, attributes(type_uuid))] +pub fn type_uuid(input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + TokenStream::from(uuid::impl_type_uuid_provider(ast)) +} diff --git a/fyrox-core-derive/src/uuid.rs b/fyrox-core-derive/src/uuid.rs new file mode 100644 index 000000000..e14a7f2ec --- /dev/null +++ b/fyrox-core-derive/src/uuid.rs @@ -0,0 +1,28 @@ +use darling::*; +use proc_macro2::TokenStream as TokenStream2; +use quote::*; +use syn::*; + +#[derive(FromDeriveInput)] +#[darling(attributes(type_uuid), supports(struct_any, enum_any))] +pub struct TypeArgs { + pub ident: Ident, + pub generics: Generics, + pub id: String, +} + +pub fn impl_type_uuid_provider(ast: DeriveInput) -> TokenStream2 { + let ty_args = TypeArgs::from_derive_input(&ast).unwrap(); + let ty_ident = &ty_args.ident; + let id = &ty_args.id; + + let (impl_generics, ty_generics, where_clause) = ty_args.generics.split_for_impl(); + + quote! { + impl #impl_generics TypeUuidProvider for #ty_ident #ty_generics #where_clause { + fn type_uuid() -> Uuid { + uuid!(#id) + } + } + } +} diff --git a/fyrox-core-derive/tests/it/main.rs b/fyrox-core-derive/tests/it/main.rs index 547afb7ef..21762ffc5 100644 --- a/fyrox-core-derive/tests/it/main.rs +++ b/fyrox-core-derive/tests/it/main.rs @@ -6,4 +6,5 @@ // trace_macros!(true); pub mod reflect; +pub mod uuid; pub mod visit; diff --git a/fyrox-core-derive/tests/it/uuid.rs b/fyrox-core-derive/tests/it/uuid.rs new file mode 100644 index 000000000..24fa6e7ad --- /dev/null +++ b/fyrox-core-derive/tests/it/uuid.rs @@ -0,0 +1,12 @@ +use fyrox_core::type_traits::prelude::*; +use std::marker::PhantomData; + +#[derive(TypeUuidProvider)] +#[type_uuid(id = "5fb10a22-4ea9-4a13-a58c-82f2734aefd8")] +struct Foo {} + +#[derive(TypeUuidProvider)] +#[type_uuid(id = "5fb10a22-4ea9-4a13-a58c-82f2734aefd9")] +struct Bar { + phantom: PhantomData, +} diff --git a/fyrox-core/src/lib.rs b/fyrox-core/src/lib.rs index 6642bbc4b..0c6d2b1d6 100644 --- a/fyrox-core/src/lib.rs +++ b/fyrox-core/src/lib.rs @@ -45,6 +45,7 @@ pub mod reflect; pub mod sparse; pub mod sstorage; pub mod task; +pub mod type_traits; pub mod variable; pub mod visitor; pub mod watcher; @@ -58,7 +59,6 @@ pub use notify; pub use js_sys; use std::iter::FromIterator; use std::marker::PhantomData; -use uuid::Uuid; #[cfg(target_arch = "wasm32")] pub use wasm_bindgen; #[cfg(target_arch = "wasm32")] @@ -66,6 +66,8 @@ pub use wasm_bindgen_futures; #[cfg(target_arch = "wasm32")] pub use web_sys; +pub use type_traits::prelude::*; + /// Defines as_(variant), as_mut_(variant) and is_(variant) methods. #[macro_export] macro_rules! define_is_as { @@ -298,68 +300,6 @@ pub fn make_relative_path>(path: P) -> Result Uuid; -} - -#[macro_export] -macro_rules! uuid_provider { - ($type:ident $(<$($generics:tt),*>)? = $uuid:expr) => { - impl$(<$($generics),*>)? $crate::TypeUuidProvider for $type $(<$($generics),*>)? { - fn type_uuid() -> $crate::uuid::Uuid { - $crate::uuid::uuid!($uuid) - } - } - }; -} - -#[macro_export] -macro_rules! stub_uuid_provider { - ($type:ty) => { - impl $crate::TypeUuidProvider for $type { - fn type_uuid() -> $crate::uuid::Uuid { - unimplemented!() - } - } - }; -} - -uuid_provider!(u8 = "7a8c337c-0219-466b-92b5-81460fa9c836"); -uuid_provider!(i8 = "3036f00e-5986-4ac3-8763-19e51d0889d7"); -uuid_provider!(u16 = "c662169d-cc3b-453c-bdf3-e0104ac3b966"); -uuid_provider!(i16 = "abce35a9-5e7b-4f7e-a729-2620a9806a6b"); -uuid_provider!(u32 = "8c4d2541-76a5-4dd8-9eb1-10222d2d6912"); -uuid_provider!(i32 = "7413ddd4-71ce-484d-a808-4f3479f5712d"); -uuid_provider!(u64 = "d1a45bd5-5066-4b28-b103-95c59c230e77"); -uuid_provider!(i64 = "35b89368-805f-486d-b3b1-fd3e86b5d645"); -uuid_provider!(f32 = "479e29c6-85fd-4bb8-b311-7b98793b8bf6"); -uuid_provider!(f64 = "dac09d54-d069-47f4-aa0e-aa0057cc2b52"); -uuid_provider!(usize = "620e24e3-fb51-48c6-a885-91d65135c5c9"); -uuid_provider!(isize = "0a06591a-1c66-4299-ba6f-2b205b795575"); -uuid_provider!(bool = "3b104074-9d39-4a2b-b974-da8cc1759fe8"); - -impl TypeUuidProvider for Option { - fn type_uuid() -> Uuid { - combine_uuids( - uuid::uuid!("ffe06d3b-0d07-42cd-886b-5248f6ca7f7d"), - T::type_uuid(), - ) - } -} - -#[inline] -pub fn combine_uuids(a: Uuid, b: Uuid) -> Uuid { - let mut combined_bytes = a.into_bytes(); - - for (src, dest) in b.into_bytes().into_iter().zip(combined_bytes.iter_mut()) { - *dest ^= src; - } - - Uuid::from_bytes(combined_bytes) -} - /// "Transmutes" array of any sized type to a slice of bytes. pub fn array_as_u8_slice(v: &[T]) -> &'_ [u8] { // SAFETY: It is safe to reinterpret data to read it. diff --git a/fyrox-core/src/type_traits.rs b/fyrox-core/src/type_traits.rs new file mode 100644 index 000000000..60fa978be --- /dev/null +++ b/fyrox-core/src/type_traits.rs @@ -0,0 +1,69 @@ +pub use fyrox_core_derive::TypeUuidProvider; +use uuid::Uuid; + +pub mod prelude { + pub use super::{combine_uuids, TypeUuidProvider}; + pub use uuid::{uuid, Uuid}; +} + +/// A trait for an entity that has unique type identifier. +pub trait TypeUuidProvider: Sized { + /// Return type UUID. + fn type_uuid() -> Uuid; +} + +#[macro_export] +macro_rules! uuid_provider { + ($type:ident $(<$($generics:tt),*>)? = $uuid:expr) => { + impl$(<$($generics),*>)? $crate::type_traits::TypeUuidProvider for $type $(<$($generics),*>)? { + fn type_uuid() -> $crate::uuid::Uuid { + $crate::uuid::uuid!($uuid) + } + } + }; +} + +#[macro_export] +macro_rules! stub_uuid_provider { + ($type:ty) => { + impl $crate::TypeUuidProvider for $type { + fn type_uuid() -> $crate::uuid::Uuid { + unimplemented!() + } + } + }; +} + +uuid_provider!(u8 = "7a8c337c-0219-466b-92b5-81460fa9c836"); +uuid_provider!(i8 = "3036f00e-5986-4ac3-8763-19e51d0889d7"); +uuid_provider!(u16 = "c662169d-cc3b-453c-bdf3-e0104ac3b966"); +uuid_provider!(i16 = "abce35a9-5e7b-4f7e-a729-2620a9806a6b"); +uuid_provider!(u32 = "8c4d2541-76a5-4dd8-9eb1-10222d2d6912"); +uuid_provider!(i32 = "7413ddd4-71ce-484d-a808-4f3479f5712d"); +uuid_provider!(u64 = "d1a45bd5-5066-4b28-b103-95c59c230e77"); +uuid_provider!(i64 = "35b89368-805f-486d-b3b1-fd3e86b5d645"); +uuid_provider!(f32 = "479e29c6-85fd-4bb8-b311-7b98793b8bf6"); +uuid_provider!(f64 = "dac09d54-d069-47f4-aa0e-aa0057cc2b52"); +uuid_provider!(usize = "620e24e3-fb51-48c6-a885-91d65135c5c9"); +uuid_provider!(isize = "0a06591a-1c66-4299-ba6f-2b205b795575"); +uuid_provider!(bool = "3b104074-9d39-4a2b-b974-da8cc1759fe8"); + +impl TypeUuidProvider for Option { + fn type_uuid() -> Uuid { + combine_uuids( + uuid::uuid!("ffe06d3b-0d07-42cd-886b-5248f6ca7f7d"), + T::type_uuid(), + ) + } +} + +#[inline] +pub fn combine_uuids(a: Uuid, b: Uuid) -> Uuid { + let mut combined_bytes = a.into_bytes(); + + for (src, dest) in b.into_bytes().into_iter().zip(combined_bytes.iter_mut()) { + *dest ^= src; + } + + Uuid::from_bytes(combined_bytes) +}