ouroboros_macro/generate/
derives.rs
1use crate::info_structures::{Derive, StructInfo};
2use proc_macro2::TokenStream;
3use quote::quote;
4use syn::{Error, GenericParam, TypeParamBound};
5
6fn add_trait_bound(param: &GenericParam, bound: &TypeParamBound) -> GenericParam {
7 let mut new = param.clone();
8
9 if let GenericParam::Type(t) = &mut new {
10 t.bounds.push(bound.clone())
11 }
12
13 new
14}
15
16fn impl_trait(info: &StructInfo, trait_name: TypeParamBound, body: TokenStream) -> TokenStream {
17 let generic_params = info.generic_params();
18 let generic_params = generic_params
19 .into_iter()
20 .map(|i| add_trait_bound(i, &trait_name))
21 .collect::<Vec<_>>();
22 let generic_args = info.generic_arguments();
23 let generic_where = &info.generics.where_clause;
24 let struct_name = &info.ident;
25 quote! {
26 impl <#(#generic_params),*> #trait_name for #struct_name <#(#generic_args),*> #generic_where {
27 #body
28 }
29 }
30}
31
32fn impl_debug(info: &StructInfo) -> Result<TokenStream, Error> {
33 let fields = info
34 .fields
35 .iter()
36 .filter(|field| !field.is_mutably_borrowed())
37 .map(|field| {
38 let name = &field.name;
39 quote! {
40 field(stringify!(#name), &safe_self.#name)
41 }
42 })
43 .collect::<Vec<_>>();
44 let trait_name = syn::parse_quote! { ::core::fmt::Debug };
45 let struct_name = &info.ident;
46 let body = quote! {
47 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
48 self.with(|safe_self| {
49 f.debug_struct(stringify!(#struct_name))
50 #(.#fields)*
51 .finish()
52 })
53 }
54 };
55 Ok(impl_trait(info, trait_name, body))
56}
57
58fn impl_partial_eq(info: &StructInfo) -> Result<TokenStream, Error> {
59 let fields = info
60 .fields
61 .iter()
62 .filter(|field| !field.is_mutably_borrowed())
63 .map(|field| {
64 let name = &field.name;
65 quote! {
66 &*safe_self.#name == &*safe_other.#name
67 }
68 })
69 .collect::<Vec<_>>();
70 let trait_name = syn::parse_quote! { ::core::cmp::PartialEq };
71 let body = quote! {
72 fn eq(&self, other: &Self) -> bool {
73 self.with(|safe_self| {
74 other.with(|safe_other| {
75 #(#fields)&&*
76 })
77 })
78 }
79 };
80 Ok(impl_trait(info, trait_name, body))
81}
82
83fn impl_eq(info: &StructInfo) -> Result<TokenStream, Error> {
84 let trait_name = syn::parse_quote! { ::core::cmp::Eq };
85 let body = quote! {};
86 Ok(impl_trait(info, trait_name, body))
87}
88
89pub fn create_derives(info: &StructInfo) -> Result<TokenStream, Error> {
90 let mut impls = Vec::new();
91 for derive in &info.derives {
92 match derive {
93 Derive::Debug => impls.push(impl_debug(info)?),
94 Derive::PartialEq => impls.push(impl_partial_eq(info)?),
95 Derive::Eq => impls.push(impl_eq(info)?),
96 }
97 }
98 Ok(quote! { #(#impls)* })
99}