]> git.proxmox.com Git - rustc.git/blame - vendor/cxxbridge-macro/src/derive.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / vendor / cxxbridge-macro / src / derive.rs
CommitLineData
49aad941
FG
1use crate::syntax::{derive, Enum, Struct, Trait};
2use proc_macro2::{Ident, Span, TokenStream};
3use quote::{quote, quote_spanned, ToTokens};
4
5pub use crate::syntax::derive::*;
6
7pub fn expand_struct(strct: &Struct, actual_derives: &mut Option<TokenStream>) -> TokenStream {
8 let mut expanded = TokenStream::new();
9 let mut traits = Vec::new();
10
11 for derive in &strct.derives {
12 let span = derive.span;
13 match derive.what {
14 Trait::Copy => expanded.extend(struct_copy(strct, span)),
15 Trait::Clone => expanded.extend(struct_clone(strct, span)),
16 Trait::Debug => expanded.extend(struct_debug(strct, span)),
17 Trait::Default => expanded.extend(struct_default(strct, span)),
18 Trait::Eq => traits.push(quote_spanned!(span=> ::cxx::core::cmp::Eq)),
19 Trait::ExternType => unreachable!(),
20 Trait::Hash => traits.push(quote_spanned!(span=> ::cxx::core::hash::Hash)),
21 Trait::Ord => expanded.extend(struct_ord(strct, span)),
22 Trait::PartialEq => traits.push(quote_spanned!(span=> ::cxx::core::cmp::PartialEq)),
23 Trait::PartialOrd => expanded.extend(struct_partial_ord(strct, span)),
24 Trait::Serialize => traits.push(quote_spanned!(span=> ::serde::Serialize)),
25 Trait::Deserialize => traits.push(quote_spanned!(span=> ::serde::Deserialize)),
26 }
27 }
28
29 if traits.is_empty() {
30 *actual_derives = None;
31 } else {
32 *actual_derives = Some(quote!(#[derive(#(#traits),*)]));
33 }
34
35 expanded
36}
37
38pub fn expand_enum(enm: &Enum, actual_derives: &mut Option<TokenStream>) -> TokenStream {
39 let mut expanded = TokenStream::new();
40 let mut traits = Vec::new();
41 let mut has_copy = false;
42 let mut has_clone = false;
43 let mut has_eq = false;
44 let mut has_partial_eq = false;
45
46 for derive in &enm.derives {
47 let span = derive.span;
48 match derive.what {
49 Trait::Copy => {
50 expanded.extend(enum_copy(enm, span));
51 has_copy = true;
52 }
53 Trait::Clone => {
54 expanded.extend(enum_clone(enm, span));
55 has_clone = true;
56 }
57 Trait::Debug => expanded.extend(enum_debug(enm, span)),
58 Trait::Default => unreachable!(),
59 Trait::Eq => {
60 traits.push(quote_spanned!(span=> ::cxx::core::cmp::Eq));
61 has_eq = true;
62 }
63 Trait::ExternType => unreachable!(),
64 Trait::Hash => traits.push(quote_spanned!(span=> ::cxx::core::hash::Hash)),
65 Trait::Ord => expanded.extend(enum_ord(enm, span)),
66 Trait::PartialEq => {
67 traits.push(quote_spanned!(span=> ::cxx::core::cmp::PartialEq));
68 has_partial_eq = true;
69 }
70 Trait::PartialOrd => expanded.extend(enum_partial_ord(enm, span)),
71 Trait::Serialize => traits.push(quote_spanned!(span=> ::serde::Serialize)),
72 Trait::Deserialize => traits.push(quote_spanned!(span=> ::serde::Deserialize)),
73 }
74 }
75
76 let span = enm.name.rust.span();
77 if !has_copy {
78 expanded.extend(enum_copy(enm, span));
79 }
80 if !has_clone {
81 expanded.extend(enum_clone(enm, span));
82 }
83 if !has_eq {
84 // Required to be derived in order for the enum's "variants" to be
85 // usable in patterns.
86 traits.push(quote!(::cxx::core::cmp::Eq));
87 }
88 if !has_partial_eq {
89 traits.push(quote!(::cxx::core::cmp::PartialEq));
90 }
91
92 *actual_derives = Some(quote!(#[derive(#(#traits),*)]));
93
94 expanded
95}
96
97fn struct_copy(strct: &Struct, span: Span) -> TokenStream {
98 let ident = &strct.name.rust;
99 let generics = &strct.generics;
100
101 quote_spanned! {span=>
102 impl #generics ::cxx::core::marker::Copy for #ident #generics {}
103 }
104}
105
106fn struct_clone(strct: &Struct, span: Span) -> TokenStream {
107 let ident = &strct.name.rust;
108 let generics = &strct.generics;
109
110 let body = if derive::contains(&strct.derives, Trait::Copy) {
111 quote!(*self)
112 } else {
113 let fields = strct.fields.iter().map(|field| &field.name.rust);
114 let values = strct.fields.iter().map(|field| {
115 let ident = &field.name.rust;
116 let ty = field.ty.to_token_stream();
117 let span = ty.into_iter().last().unwrap().span();
118 quote_spanned!(span=> &self.#ident)
119 });
120 quote_spanned!(span=> #ident {
121 #(#fields: ::cxx::core::clone::Clone::clone(#values),)*
122 })
123 };
124
125 quote_spanned! {span=>
126 #[allow(clippy::expl_impl_clone_on_copy)]
127 impl #generics ::cxx::core::clone::Clone for #ident #generics {
128 fn clone(&self) -> Self {
129 #body
130 }
131 }
132 }
133}
134
135fn struct_debug(strct: &Struct, span: Span) -> TokenStream {
136 let ident = &strct.name.rust;
137 let generics = &strct.generics;
138 let struct_name = ident.to_string();
139 let fields = strct.fields.iter().map(|field| &field.name.rust);
140 let field_names = fields.clone().map(Ident::to_string);
141
142 quote_spanned! {span=>
143 impl #generics ::cxx::core::fmt::Debug for #ident #generics {
144 fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
145 formatter.debug_struct(#struct_name)
146 #(.field(#field_names, &self.#fields))*
147 .finish()
148 }
149 }
150 }
151}
152
153fn struct_default(strct: &Struct, span: Span) -> TokenStream {
154 let ident = &strct.name.rust;
155 let generics = &strct.generics;
156 let fields = strct.fields.iter().map(|field| &field.name.rust);
157
158 quote_spanned! {span=>
159 #[allow(clippy::derivable_impls)] // different spans than the derived impl
160 impl #generics ::cxx::core::default::Default for #ident #generics {
161 fn default() -> Self {
162 #ident {
163 #(
164 #fields: ::cxx::core::default::Default::default(),
165 )*
166 }
167 }
168 }
169 }
170}
171
172fn struct_ord(strct: &Struct, span: Span) -> TokenStream {
173 let ident = &strct.name.rust;
174 let generics = &strct.generics;
175 let fields = strct.fields.iter().map(|field| &field.name.rust);
176
177 quote_spanned! {span=>
178 impl #generics ::cxx::core::cmp::Ord for #ident #generics {
179 fn cmp(&self, other: &Self) -> ::cxx::core::cmp::Ordering {
180 #(
181 match ::cxx::core::cmp::Ord::cmp(&self.#fields, &other.#fields) {
182 ::cxx::core::cmp::Ordering::Equal => {}
183 ordering => return ordering,
184 }
185 )*
186 ::cxx::core::cmp::Ordering::Equal
187 }
188 }
189 }
190}
191
192fn struct_partial_ord(strct: &Struct, span: Span) -> TokenStream {
193 let ident = &strct.name.rust;
194 let generics = &strct.generics;
195
196 let body = if derive::contains(&strct.derives, Trait::Ord) {
197 quote! {
198 ::cxx::core::option::Option::Some(::cxx::core::cmp::Ord::cmp(self, other))
199 }
200 } else {
201 let fields = strct.fields.iter().map(|field| &field.name.rust);
202 quote! {
203 #(
204 match ::cxx::core::cmp::PartialOrd::partial_cmp(&self.#fields, &other.#fields) {
205 ::cxx::core::option::Option::Some(::cxx::core::cmp::Ordering::Equal) => {}
206 ordering => return ordering,
207 }
208 )*
209 ::cxx::core::option::Option::Some(::cxx::core::cmp::Ordering::Equal)
210 }
211 };
212
213 quote_spanned! {span=>
214 impl #generics ::cxx::core::cmp::PartialOrd for #ident #generics {
215 fn partial_cmp(&self, other: &Self) -> ::cxx::core::option::Option<::cxx::core::cmp::Ordering> {
216 #body
217 }
218 }
219 }
220}
221
222fn enum_copy(enm: &Enum, span: Span) -> TokenStream {
223 let ident = &enm.name.rust;
224
225 quote_spanned! {span=>
226 impl ::cxx::core::marker::Copy for #ident {}
227 }
228}
229
230fn enum_clone(enm: &Enum, span: Span) -> TokenStream {
231 let ident = &enm.name.rust;
232
233 quote_spanned! {span=>
234 #[allow(clippy::expl_impl_clone_on_copy)]
235 impl ::cxx::core::clone::Clone for #ident {
236 fn clone(&self) -> Self {
237 *self
238 }
239 }
240 }
241}
242
243fn enum_debug(enm: &Enum, span: Span) -> TokenStream {
244 let ident = &enm.name.rust;
245 let variants = enm.variants.iter().map(|variant| {
246 let variant = &variant.name.rust;
247 let name = variant.to_string();
248 quote_spanned! {span=>
249 #ident::#variant => formatter.write_str(#name),
250 }
251 });
252 let fallback = format!("{}({{}})", ident);
253
254 quote_spanned! {span=>
255 impl ::cxx::core::fmt::Debug for #ident {
256 fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
257 match *self {
258 #(#variants)*
259 _ => ::cxx::core::write!(formatter, #fallback, self.repr),
260 }
261 }
262 }
263 }
264}
265
266fn enum_ord(enm: &Enum, span: Span) -> TokenStream {
267 let ident = &enm.name.rust;
268
269 quote_spanned! {span=>
270 impl ::cxx::core::cmp::Ord for #ident {
271 fn cmp(&self, other: &Self) -> ::cxx::core::cmp::Ordering {
272 ::cxx::core::cmp::Ord::cmp(&self.repr, &other.repr)
273 }
274 }
275 }
276}
277
278fn enum_partial_ord(enm: &Enum, span: Span) -> TokenStream {
279 let ident = &enm.name.rust;
280
281 quote_spanned! {span=>
282 impl ::cxx::core::cmp::PartialOrd for #ident {
283 fn partial_cmp(&self, other: &Self) -> ::cxx::core::option::Option<::cxx::core::cmp::Ordering> {
284 ::cxx::core::cmp::PartialOrd::partial_cmp(&self.repr, &other.repr)
285 }
286 }
287 }
288}