1#![forbid(unsafe_code, unused_crate_dependencies)]
2#![deny(clippy::all)]
3
4#[cfg(test)]
7use infinitree as _;
8#[cfg(test)]
9use serde as _;
10
11use proc_macro::TokenStream;
12use syn::{parse_macro_input, DeriveInput};
13
14mod derive_index;
15
16#[proc_macro_derive(Index, attributes(infinitree))]
49pub fn derive_index_macro(input: TokenStream) -> TokenStream {
50 let input = parse_macro_input!(input as DeriveInput);
51 derive_index::expand(derive_index::crate_name_token(), input)
52 .unwrap_or_else(syn::Error::into_compile_error)
53 .into()
54}
55
56#[cfg(test)]
57mod tests {
58 #[test]
59 fn test_macro() {
60 use quote::quote;
61 use syn::parse_quote;
62
63 let input = parse_quote! {
64 #[derive(Default, Index)]
65 pub struct TestStruct<T> {
66 unattributed: ChunkIndex,
68
69 #[infinitree(name = "renamed_chunks")]
72 chunks: ChunkIndex,
73
74 #[infinitree(skip)]
76 _unreferenced: ChunkIndex,
77
78 #[infinitree(strategy = "infinitree::fields::SparseField")]
80 strategizing: ChunkIndex,
81
82 #[infinitree(skip)]
83 _ph: PhantomData<T>
84 }
85 };
86
87 let result = super::derive_index::expand(quote::quote!(::infinitree), input).unwrap();
88
89 #[rustfmt::skip]
90 let expected = quote! {
91 #[automatically_derived]
92 impl<T> TestStruct<T> {
93 #[inline]
94 pub fn unattributed(&'_ self) -> ::infinitree::fields::Intent<Box<::infinitree::fields::LocalField<ChunkIndex>>> {
95 use ::infinitree::fields::{Intent, strategy::Strategy};
96 Intent::new(
97 "unattributed",
98 Box::new(::infinitree::fields::LocalField::for_field(
99 &self.unattributed,
100 )),
101 )
102 }
103 #[inline]
104 pub fn renamed_chunks(&'_ self) -> ::infinitree::fields::Intent<Box<::infinitree::fields::LocalField<ChunkIndex>>> {
105 use ::infinitree::fields::{Intent, strategy::Strategy};
106 Intent::new(
107 "renamed_chunks",
108 Box::new(::infinitree::fields::LocalField::for_field(
109 &self.chunks,
110 )),
111 )
112 }
113 #[inline]
114 pub fn strategizing(&'_ self) -> ::infinitree::fields::Intent<Box<infinitree::fields::SparseField<ChunkIndex>>> {
115 use ::infinitree::fields::{Intent, strategy::Strategy};
116 Intent::new(
117 "strategizing",
118 Box::new(infinitree::fields::SparseField::for_field(
119 &self.strategizing,
120 )),
121 )
122 }
123 pub fn fields(&self) -> Vec<String> {
124 vec!["unattributed".into(),
125 "renamed_chunks".into(),
126 "strategizing".into(),
127 ]
128 }
129 }
130 impl<T> ::infinitree::Index for TestStruct<T> {
131 fn store_all(&'_ self) -> ::infinitree::anyhow::Result<Vec<::infinitree::fields::Intent<Box<dyn ::infinitree::fields::Store>>>> {
132 Ok(vec![
133 self.unattributed().into(),
134 self.renamed_chunks().into(),
135 self.strategizing().into(),
136 ])
137 }
138 fn load_all(&'_ self) -> ::infinitree::anyhow::Result<Vec<::infinitree::fields::Intent<Box<dyn ::infinitree::fields::Load>>>> {
139 Ok(vec![
140 self.unattributed().into(),
141 self.renamed_chunks().into(),
142 self.strategizing().into(),
143 ])
144 }
145 }
146 };
147
148 assert_eq!(result.to_string(), expected.to_string());
149 }
150}