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}