derivable_object_pool_macros/
lib.rs

1//! # Derivable Object Pool Macro
2//!
3//! Internal crate for [derivable-object-pool](https://crates.io/crates/derivable-object-pool)
4//! crate. That provides a derive macro for [`ObjectPool`] trait.
5//!
6//! [`ObjectPool`]: trait.ObjectPool.html
7use proc_macro::TokenStream;
8use syn::DeriveInput;
9
10fn impl_object_pool_derive_macro(ast: DeriveInput) -> TokenStream {
11    let ident = ast.ident;
12    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
13    let ident_capital = ident.to_string().to_ascii_uppercase();
14    let pool = quote::format_ident!("{ident_capital}_OBJECT_POOL");
15
16    let attrs = ast.attrs;
17
18    let generator = {
19        // Find attribute generator
20        let attr = attrs.iter().find(|attr| attr.path().is_ident("generator"));
21        match attr {
22            Some(attr) => {
23                let generator = attr.parse_args::<syn::Expr>().unwrap();
24                quote::quote! { #generator }
25            }
26            None => quote::quote! { #ident::default },
27        }
28    };
29
30    quote::quote! {
31        static #pool: Pool<#ident> = Pool::new(#generator);
32
33        impl #impl_generics ObjectPool for #ident #ty_generics #where_clause {
34            #[inline]
35            fn pool<'a>() -> &'a Pool<Self> {
36                &#pool
37            }
38        }
39    }
40    .into()
41}
42
43/// Derive macro for [`ObjectPool`] trait implementation.
44/// Optionally, you can specify a generator function for the pool. If not
45/// specified, the trait will try to use [`Default`] trait implementation.
46///
47/// Internally, the macro will generate a static variable with the name of
48/// `#[ident]_OBJECT_POOL` (where `#[ident]` is the name of the type in
49/// uppercase) and implement the [ObjectPool] trait for the type.
50///
51/// # Example
52///
53/// ```rust
54/// use derivable_object_pool::prelude::*;
55///
56/// #[derive(ObjectPool)]
57/// #[generator(Test2::new_item)]
58/// struct Test2(u32);
59///
60/// impl Test2 {
61///     fn new_item() -> Self {
62///         Test2(10)
63///     }
64/// }
65///
66/// fn main() {
67///     let mut item = Test2::new();
68///     item.0 = 20;
69///     assert_eq!(item.0, 20);
70///     drop(item);
71///     assert_eq!(Test2::pool().len(), 1);
72/// }
73/// ```
74///
75/// Generated extra code for the derive macro:
76///
77/// ```rust
78///# use derivable_object_pool::prelude::*;
79///#
80///# struct Test2(u32);
81///#
82///# impl Test2 {
83///#     fn new_item() -> Self {
84///#         Test2(10)
85///#     }
86///# }
87///#
88/// static TEST2_OBJECT_POOL: Pool<Test2> = Pool::new(Test2::new_item);
89///
90/// impl ObjectPool for Test2 {
91///     #[inline]
92///     fn pool<'a>() -> &'a Pool<Self> {
93///         &TEST2_OBJECT_POOL
94///     }
95/// }
96///#
97///# fn main() {
98///#     let mut item = Test2::new();
99///#     item.0 = 20;
100///#     assert_eq!(item.0, 20);
101///#     drop(item);
102///#     assert_eq!(Test2::pool().len(), 1);
103///# }
104/// ```
105///
106/// # Attributes
107///
108/// ## generator
109///
110/// Specify a generator function for the pool. If not specified, the trait will
111/// try to use [`Default`] trait implementation.
112///
113///
114/// [`ObjectPool`]: trait.ObjectPool.html
115/// [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html
116#[proc_macro_derive(ObjectPool, attributes(generator))]
117pub fn object_pool_derive_macro(tokens: TokenStream) -> TokenStream {
118    let ast: DeriveInput = syn::parse(tokens).unwrap();
119
120    impl_object_pool_derive_macro(ast)
121}