diff --git a/.changes/refactor-type-dependencies.md b/.changes/refactor-type-dependencies.md new file mode 100644 index 0000000..dae3e0f --- /dev/null +++ b/.changes/refactor-type-dependencies.md @@ -0,0 +1,6 @@ +--- +"qubit-macros": minor:refactor +"qubit": minor:refactor +--- + +refactor `TypeDependencies` trait into `ExportType` trait diff --git a/crates/qubit-macros/src/handler/mod.rs b/crates/qubit-macros/src/handler/mod.rs index 0327a5d..f92708e 100644 --- a/crates/qubit-macros/src/handler/mod.rs +++ b/crates/qubit-macros/src/handler/mod.rs @@ -282,12 +282,12 @@ impl From for TokenStream { #register_impl } - fn add_dependencies(dependencies: &mut std::collections::BTreeMap) { + fn export_types(registry: &mut std::collections::BTreeMap) { // Add dependencies for the parameters - #(<#param_tys as qubit::TypeDependencies>::get_deps(dependencies);)* + #(<#param_tys as qubit::ExportType>::export(registry);)* // Add dependencies for the return type - <#return_type as qubit::TypeDependencies>::get_deps(dependencies); + <#return_type as qubit::ExportType>::export(registry); } } }.into() diff --git a/crates/qubit-macros/src/lib.rs b/crates/qubit-macros/src/lib.rs index 257405c..c735d0e 100644 --- a/crates/qubit-macros/src/lib.rs +++ b/crates/qubit-macros/src/lib.rs @@ -10,10 +10,10 @@ pub fn handler( macros::handler(attr, input) } -/// Derive [`qubit::TypeDependencies`] implementation for the attached struct. Will check to see if +/// Derive [`qubit::ExportType`] implementation for the attached struct. Will check to see if /// the struct has been added before, and if not it will add it's own inline definition, and /// recurse to add the types of any nested types. -#[proc_macro_derive(TypeDependencies)] -pub fn derive_type_dependencies(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - macros::derive_type_dependencies(input) +#[proc_macro_derive(ExportType)] +pub fn derive_export_type(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + macros::derive_export_type(input) } diff --git a/crates/qubit-macros/src/macros/derive_type_dependencies.rs b/crates/qubit-macros/src/macros/derive_export_type.rs similarity index 51% rename from crates/qubit-macros/src/macros/derive_type_dependencies.rs rename to crates/qubit-macros/src/macros/derive_export_type.rs index ef54f0a..c8b9ae1 100644 --- a/crates/qubit-macros/src/macros/derive_type_dependencies.rs +++ b/crates/qubit-macros/src/macros/derive_export_type.rs @@ -1,7 +1,7 @@ use quote::quote; use syn::Item; -pub fn derive_type_dependencies(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +pub fn derive_export_type(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let s = syn::parse::(input).unwrap(); let (target_struct, fields) = match s { @@ -13,18 +13,18 @@ pub fn derive_type_dependencies(input: proc_macro::TokenStream) -> proc_macro::T }; quote! { - impl qubit::TypeDependencies for #target_struct { - fn get_deps(dependencies: &mut std::collections::BTreeMap) { + impl qubit::ExportType for #target_struct { + fn export(registry: &mut std::collections::BTreeMap) { // Short circuit if this type has already been added - if dependencies.contains_key(&::name()) { + if registry.contains_key(&::name()) { return; } // Insert this type - dependencies.insert(::name(), ::inline()); + registry.insert(::name(), ::inline()); // Insert field types - #(<#fields as qubit::TypeDependencies>::get_deps(dependencies);)* + #(<#fields as qubit::ExportType>::export(registry);)* } } } diff --git a/crates/qubit-macros/src/macros/mod.rs b/crates/qubit-macros/src/macros/mod.rs index 807b5fb..e219bb4 100644 --- a/crates/qubit-macros/src/macros/mod.rs +++ b/crates/qubit-macros/src/macros/mod.rs @@ -1,5 +1,5 @@ -mod derive_type_dependencies; +mod derive_export_type; mod handler; -pub use derive_type_dependencies::derive_type_dependencies; +pub use derive_export_type::derive_export_type; pub use handler::handler; diff --git a/examples/counter/src/main.rs b/examples/counter/src/main.rs index a6b64cb..d8cc968 100644 --- a/examples/counter/src/main.rs +++ b/examples/counter/src/main.rs @@ -13,7 +13,7 @@ use qubit::*; use axum::routing::get; use serde::{Deserialize, Serialize}; -#[derive(ts_rs::TS, Clone, Serialize, Deserialize, Debug, TypeDependencies)] +#[derive(ts_rs::TS, Clone, Serialize, Deserialize, Debug, ExportType)] pub struct Metadata { param_a: String, param_b: u32, @@ -22,7 +22,7 @@ pub struct Metadata { more_metadata: Option>, } -#[derive(ts_rs::TS, Clone, Serialize, Deserialize, Debug, TypeDependencies)] +#[derive(ts_rs::TS, Clone, Serialize, Deserialize, Debug, ExportType)] pub struct User { name: String, email: String, @@ -31,7 +31,7 @@ pub struct User { metadata: Metadata, } -#[derive(ts_rs::TS, Clone, Serialize, Deserialize, Debug, TypeDependencies)] +#[derive(ts_rs::TS, Clone, Serialize, Deserialize, Debug, ExportType)] pub struct Test { a: usize, b: bool, diff --git a/src/builder/handler.rs b/src/builder/handler.rs index efaea7b..0610081 100644 --- a/src/builder/handler.rs +++ b/src/builder/handler.rs @@ -32,8 +32,8 @@ pub trait Handler { /// Get the type of this handler, to generate the client. fn get_type() -> HandlerType; - /// Get any dependencies required to use this [`HandlerType`] in the client. - fn add_dependencies(dependencies: &mut BTreeMap); + /// Export any types required to use this [`HandlerType`] in the client. + fn export_types(registry: &mut BTreeMap); } /// Wrapper struct to assist with erasure of concrete [`Handler`] type. Contains function pointers @@ -51,7 +51,7 @@ pub(crate) struct HandlerCallbacks { /// Function pointer to the implementation that will add any type dependencies for the handler /// to the provided collection. - pub add_dependencies: fn(&mut BTreeMap), + pub export_types: fn(&mut BTreeMap), } impl HandlerCallbacks @@ -65,7 +65,7 @@ where Self { register: H::register, get_type: H::get_type, - add_dependencies: H::add_dependencies, + export_types: H::export_types, } } } diff --git a/src/builder/ty/dependencies.rs b/src/builder/ty/dependencies.rs deleted file mode 100644 index e125e42..0000000 --- a/src/builder/ty/dependencies.rs +++ /dev/null @@ -1,82 +0,0 @@ -use std::collections::{BTreeMap, HashMap}; - -// TODO: Document this better -/// Since macros cannot lookup other items in the source code, any user types must 'register' -/// themselves into a central repository so that their types can be collated, ensuring that they're -/// only inserted into the generated types once. -pub trait TypeDependencies { - #[allow(unused_variables)] - fn get_deps(dependencies: &mut BTreeMap) {} -} - -macro_rules! impl_type_dependencies { - ($($t:ident<$($generic:ident),*>),*) => { - $(impl<$($generic),*> TypeDependencies for $t<$($generic),*> - where $($generic: ts_rs::TS + crate::TypeDependencies),* - { - fn get_deps(dependencies: &mut BTreeMap) { - $(impl_type_dependencies!(generic: $generic, dependencies);)* - } - })* - }; - - ($($t:ty),*) => { - $(impl TypeDependencies for $t {})* - }; - - (tuple: $t:ident) => { - impl<$t> TypeDependencies for ($t,) - where $t: ts_rs::TS + crate::TypeDependencies, - { - fn get_deps(dependencies: &mut BTreeMap) { - impl_type_dependencies!(generic: $t, dependencies); - } - } - }; - - (tuple: $t:ident $(, $t_other:ident)*) => { - impl<$t, $($t_other),*> TypeDependencies for ($t, $($t_other),*) - where $t: ts_rs::TS + crate::TypeDependencies, - $($t_other: ts_rs::TS + crate::TypeDependencies),* - { - fn get_deps(dependencies: &mut BTreeMap) { - impl_type_dependencies!(generic: $t, dependencies); - $(impl_type_dependencies!(generic: $t_other, dependencies);)* - } - } - - impl_type_dependencies!(tuple: $($t_other),*); - }; - - (generic: $generic:ident, $dependencies:ident) => { - <$generic as TypeDependencies>::get_deps($dependencies) - }; -} - -impl_type_dependencies!( - u8, - u16, - u32, - u64, - u128, - usize, - i8, - i16, - i32, - i64, - i128, - isize, - String, - &'static str, - bool, - char, - () -); -impl_type_dependencies!( - Vec, - Box, - Option, - Result, - HashMap -); -impl_type_dependencies!(tuple: T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); diff --git a/src/builder/ty/export_type.rs b/src/builder/ty/export_type.rs new file mode 100644 index 0000000..33d77b2 --- /dev/null +++ b/src/builder/ty/export_type.rs @@ -0,0 +1,83 @@ +use std::collections::{BTreeMap, HashMap}; + +use ts_rs::TS; + +/// Since macros cannot lookup other items in the source code, any user types must 'register' +/// themselves into a central repository so that their types can be collated, ensuring that they're +/// only inserted into the generated types once. +pub trait ExportType: TS { + #[allow(unused_variables)] + fn export(registry: &mut BTreeMap) {} +} + +macro_rules! impl_export_type { + ($($t:ident<$($generic:ident),*>),*) => { + $(impl<$($generic),*> ExportType for $t<$($generic),*> + where $($generic: ts_rs::TS + crate::ExportType),* + { + fn export(register: &mut BTreeMap) { + $(impl_export_type!(generic: $generic, register);)* + } + })* + }; + + ($($t:ty),*) => { + $(impl ExportType for $t {})* + }; + + (tuple: $t:ident) => { + impl<$t> ExportType for ($t,) + where $t: ts_rs::TS + crate::ExportType, + { + fn export(register: &mut BTreeMap) { + impl_export_type!(generic: $t, register); + } + } + }; + + (tuple: $t:ident $(, $t_other:ident)*) => { + impl<$t, $($t_other),*> ExportType for ($t, $($t_other),*) + where $t: ts_rs::TS + crate::ExportType, + $($t_other: ts_rs::TS + crate::ExportType),* + { + fn export(register: &mut BTreeMap) { + impl_export_type!(generic: $t, register); + $(impl_export_type!(generic: $t_other, register);)* + } + } + + impl_export_type!(tuple: $($t_other),*); + }; + + (generic: $generic:ident, $register:ident) => { + <$generic as ExportType>::export($register) + }; +} + +impl_export_type!( + u8, + u16, + u32, + u64, + u128, + usize, + i8, + i16, + i32, + i64, + i128, + isize, + String, + &'static str, + bool, + char, + () +); +impl_export_type!( + Vec, + Box, + Option, + Result, + HashMap +); +impl_export_type!(tuple: T0, T1, T2, T3, T4, T5, T6, T7, T8, T9); diff --git a/src/builder/ty/mod.rs b/src/builder/ty/mod.rs index 480f4b3..0a120eb 100644 --- a/src/builder/ty/mod.rs +++ b/src/builder/ty/mod.rs @@ -1,9 +1,9 @@ //! Type generation specific functionality. There is no real need for this to be directly used, //! [`qubit_macros::handler`] should handle it all. -mod dependencies; +mod export_type; -pub use dependencies::*; +pub use export_type::*; /// Components used to construct the client type for this handler. #[derive(Debug)] diff --git a/src/server/router.rs b/src/server/router.rs index 099683b..352de78 100644 --- a/src/server/router.rs +++ b/src/server/router.rs @@ -123,7 +123,7 @@ where // Add all handler dependencies self.handlers .iter() - .for_each(|handler| (handler.add_dependencies)(dependencies)); + .for_each(|handler| (handler.export_types)(dependencies)); // Add dependencies for nested routers self.nested_routers