specs_visitor_derive/
lib.rs

1//! Procedural macros for deriving specs entity visitors.
2//!
3//! These visitors can be used to implement generic transformations of ECS graphs that compile down
4//! to very effective code.
5//!
6//! See the [`specs-visitor`](https://crates.io/crates/specs-visitor) crate for API documentation
7//! for the actual types derived by this crate.
8#![deny(nonstandard_style, warnings, unused)]
9#![deny(
10    missing_debug_implementations,
11    missing_copy_implementations,
12    trivial_casts,
13    trivial_numeric_casts,
14    unstable_features,
15    unused_import_braces,
16    unused_qualifications
17)]
18#![cfg_attr(feature = "cargo-clippy", deny(clippy::all, clippy::pedantic))]
19#![recursion_limit = "128"]
20
21#[macro_use]
22extern crate synstructure;
23#[macro_use]
24extern crate quote;
25
26fn visit_entities_derive(mut s: synstructure::Structure) -> proc_macro2::TokenStream {
27    let accept_body = s.each(|bi| {
28        quote! {
29            ::specs_visitor::VisitEntities::accept(#bi, visitor);
30        }
31    });
32
33    s.add_bounds(synstructure::AddBounds::Generics);
34
35    s.gen_impl(quote! {
36        gen impl ::specs_visitor::VisitEntities for @Self {
37            fn accept<V>(&self, visitor: &V)
38            where
39                V: ::specs_visitor::EntityVisitor,
40            {
41                match *self {
42                    #accept_body
43                }
44            }
45        }
46    })
47}
48
49fn visit_entities_mut_derive(mut s: synstructure::Structure) -> proc_macro2::TokenStream {
50    s.bind_with(|_| synstructure::BindStyle::RefMut);
51
52    let accept_mut_body = s.each(|bi| {
53        quote! {
54            ::specs_visitor::VisitEntitiesMut::accept_mut(#bi, visitor);
55        }
56    });
57
58    s.add_bounds(synstructure::AddBounds::Generics);
59
60    s.gen_impl(quote! {
61        gen impl ::specs_visitor::VisitEntitiesMut for @Self {
62            fn accept_mut<V>(&mut self, visitor: &V)
63            where
64                V: ::specs_visitor::EntityVisitorMut,
65            {
66                match *self {
67                    #accept_mut_body
68                }
69            }
70        }
71    })
72}
73
74decl_derive!([VisitEntities] => visit_entities_derive);
75decl_derive!([VisitEntitiesMut] => visit_entities_mut_derive);
76
77#[cfg(test)]
78mod test {
79    use specs;
80
81    use super::visit_entities_derive;
82    use super::visit_entities_mut_derive;
83
84    #[test]
85    fn simple() {
86        test_derive! {
87            visit_entities_derive {
88                struct Foo {
89                    entity: specs::Entity,
90                }
91            }
92            expands to {
93                #[allow(non_upper_case_globals)]
94                const _DERIVE_specs_visitor_VisitEntities_FOR_Foo: () = {
95                    impl ::specs_visitor::VisitEntities for Foo {
96                        fn accept<V>(&self, visitor: &V)
97                        where
98                            V: ::specs_visitor::EntityVisitor,
99                        {
100                            match *self {
101                                Foo {
102                                    entity: ref __binding_0,
103                                } => {{
104                                    ::specs_visitor::VisitEntities::accept(__binding_0, visitor);
105                                }}
106                            }
107                        }
108                    }
109                };
110            }
111        }
112    }
113
114    #[test]
115    fn simple_mut() {
116        test_derive! {
117            visit_entities_mut_derive {
118                struct Foo {
119                    entity: specs::Entity,
120                }
121            }
122            expands to {
123                #[allow(non_upper_case_globals)]
124                const _DERIVE_specs_visitor_VisitEntitiesMut_FOR_Foo: () = {
125                    impl ::specs_visitor::VisitEntitiesMut for Foo {
126                        fn accept_mut<V>(&mut self, visitor: &V)
127                        where
128                            V: ::specs_visitor::EntityVisitorMut,
129                        {
130                            match *self {
131                                Foo {
132                                    entity: ref mut __binding_0,
133                                } => {{
134                                    ::specs_visitor::VisitEntitiesMut::accept_mut(__binding_0, visitor);
135                                }}
136                            }
137                        }
138                    }
139                };
140            }
141        }
142    }
143
144    #[test]
145    fn generic() {
146        test_derive! {
147            visit_entities_derive {
148                struct Foo<T> {
149                    entity_stuff: T,
150                }
151            }
152            expands to {
153                #[allow(non_upper_case_globals)]
154                const _DERIVE_specs_visitor_VisitEntities_FOR_Foo: () = {
155                    impl<T> ::specs_visitor::VisitEntities for Foo<T>
156                        where
157                            T: ::specs_visitor::VisitEntities
158                    {
159                        fn accept<V>(&self, visitor: &V)
160                        where
161                            V: ::specs_visitor::EntityVisitor,
162                        {
163                            match *self {
164                                Foo {
165                                    entity_stuff: ref __binding_0,
166                                } => {{
167                                    ::specs_visitor::VisitEntities::accept(__binding_0, visitor);
168                                }}
169                            }
170                        }
171                    }
172                };
173            }
174        }
175    }
176
177    #[test]
178    fn generic_mut() {
179        test_derive! {
180            visit_entities_mut_derive {
181                struct Foo<T> {
182                    entity_stuff: T,
183                }
184            }
185            expands to {
186                #[allow(non_upper_case_globals)]
187                const _DERIVE_specs_visitor_VisitEntitiesMut_FOR_Foo: () = {
188                    impl<T> ::specs_visitor::VisitEntitiesMut for Foo<T>
189                        where
190                            T: ::specs_visitor::VisitEntitiesMut
191                    {
192                        fn accept_mut<V>(&mut self, visitor: &V)
193                        where
194                            V: ::specs_visitor::EntityVisitorMut,
195                        {
196                            match *self {
197                                Foo {
198                                    entity_stuff: ref mut __binding_0,
199                                } => {{
200                                    ::specs_visitor::VisitEntitiesMut::accept_mut(__binding_0, visitor);
201                                }}
202                            }
203                        }
204                    }
205                };
206            }
207        }
208    }
209}