(input: DeriveInput)
| 16 | } |
| 17 | |
| 18 | pub fn derive(input: DeriveInput) -> Result<TokenStream> { |
| 19 | if let Data::Struct(ref s) = input.data |
| 20 | && matches!(s.fields, Fields::Unit) |
| 21 | { |
| 22 | return Err(Error::new(input.ident.span(), "Cannot derive SemanticEq on this struct")); |
| 23 | } |
| 24 | if matches!(input.data, Data::Union(_)) { |
| 25 | return Err(Error::new(input.ident.span(), "Cannot derive SemanticEq on a Union")); |
| 26 | } |
| 27 | |
| 28 | let s_a = structure_with_prefix(&input, "a")?; |
| 29 | let s_b = structure_with_prefix(&input, "b")?; |
| 30 | |
| 31 | let mut wc = WhereCollector::new(); |
| 32 | for variant in s_a.variants() { |
| 33 | for bi in variant.bindings() { |
| 34 | wc.add(&bi.ast().ty); |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | let ident = &input.ident; |
| 39 | let (impl_generics, type_generics, _) = input.generics.split_for_impl(); |
| 40 | |
| 41 | let body = if matches!(input.data, Data::Struct(_)) { |
| 42 | let steps: Vec<TokenStream> = s_a.variants()[0] |
| 43 | .bindings() |
| 44 | .iter() |
| 45 | .zip(s_b.variants()[0].bindings().iter()) |
| 46 | .map(|(a, b)| { |
| 47 | let a_name = &a.binding; |
| 48 | let b_name = &b.binding; |
| 49 | quote! { #a_name.semantic_eq(&#b_name) } |
| 50 | }) |
| 51 | .collect(); |
| 52 | let a_pat = s_a.variants()[0].pat(); |
| 53 | let b_pat = s_b.variants()[0].pat(); |
| 54 | let body = steps.into_iter().reduce(|acc, item| quote! { #acc && #item }).unwrap_or_default(); |
| 55 | quote! { |
| 56 | let #a_pat = self; |
| 57 | let #b_pat = other; |
| 58 | #body |
| 59 | } |
| 60 | } else { |
| 61 | let arms: TokenStream = s_a |
| 62 | .variants() |
| 63 | .iter() |
| 64 | .zip(s_b.variants().iter()) |
| 65 | .map(|(va, vb)| { |
| 66 | let a_pat = va.pat(); |
| 67 | let b_pat = vb.pat(); |
| 68 | let steps: Vec<TokenStream> = va |
| 69 | .bindings() |
| 70 | .iter() |
| 71 | .zip(vb.bindings().iter()) |
| 72 | .map(|(a, b)| { |
| 73 | let a_name = &a.binding; |
| 74 | let b_name = &b.binding; |
| 75 | quote! { #a_name.semantic_eq(&#b_name) } |
nothing calls this directly
no test coverage detected