(input: DeriveInput)
| 174 | } |
| 175 | |
| 176 | pub fn derive(input: DeriveInput) -> Result<TokenStream> { |
| 177 | if matches!(input.data, Data::Union(_)) { |
| 178 | return Err(Error::new(input.ident.span(), "Cannot derive Visitable on a Union")); |
| 179 | } |
| 180 | if let Data::Struct(ref s) = input.data |
| 181 | && matches!(s.fields, Fields::Unit) |
| 182 | { |
| 183 | return Err(Error::new(input.ident.span(), "Cannot derive Visitable on this struct")); |
| 184 | } |
| 185 | |
| 186 | let style: VisitStyle = VisitStyle::from(input.attrs.as_slice()); |
| 187 | let is_queryable = style.visit_self(); |
| 188 | let ident = &input.ident; |
| 189 | let (impl_generics, type_generics, _) = input.generics.split_for_impl(); |
| 190 | |
| 191 | let (visit_mut, exit_mut) = if style.visit_self() { |
| 192 | let visit_method = format_ident!("visit_{}", ident.to_string().to_snake_case()); |
| 193 | let exit_method = format_ident!("exit_{}", ident.to_string().to_snake_case()); |
| 194 | (quote! { v.#visit_method(self); }, quote! { v.#exit_method(self); }) |
| 195 | } else { |
| 196 | (quote! {}, quote! {}) |
| 197 | }; |
| 198 | |
| 199 | let (visit_feature, exit_feature) = if has_feature_metadata(&input.attrs) { |
| 200 | (quote! { v.visit_feature(self); }, quote! { v.exit_feature(self); }) |
| 201 | } else { |
| 202 | (quote! {}, quote! {}) |
| 203 | }; |
| 204 | |
| 205 | let mut s = Structure::try_new(&input)?; |
| 206 | s.add_bounds(AddBounds::None); |
| 207 | |
| 208 | let mut wc = WhereCollector::new(); |
| 209 | |
| 210 | let (body_mut, body) = if style.visit_children() { |
| 211 | let accept_mut = format_ident!("accept_mut"); |
| 212 | let accept = format_ident!("accept"); |
| 213 | let b_mut = make_body(&s, &accept_mut, &mut wc, false); |
| 214 | let b = make_body(&s, &accept, &mut wc, true); |
| 215 | (b_mut, b) |
| 216 | } else { |
| 217 | (quote! {}, quote! { <visit_flow::VisitFlow as visit_flow::VisitFlowExt>::DESCEND }) |
| 218 | }; |
| 219 | |
| 220 | let accept_body = if is_queryable { |
| 221 | let node_var = quote! { __node }; |
| 222 | let children_block = if style.visit_self() { |
| 223 | let visit_method = format_ident!("visit_{}", ident.to_string().to_snake_case()); |
| 224 | let exit_method = format_ident!("exit_{}", ident.to_string().to_snake_case()); |
| 225 | quote! { |
| 226 | if let visit_flow::VisitAction::Descend = visit_flow::try_visit!(v.#visit_method(self)) { |
| 227 | visit_flow::try_visit!({ #body }); |
| 228 | } |
| 229 | visit_flow::try_visit!(v.#exit_method(self)); |
| 230 | } |
| 231 | } else { |
| 232 | quote! { visit_flow::try_visit!({ #body }); } |
| 233 | }; |
nothing calls this directly
no test coverage detected