1use super::{ImplArgs, ImplTrait, Result};
9use crate::{IdentFormatter, SimplePath};
10use proc_macro2::TokenStream as Toks;
11use quote::{quote, ToTokens, TokenStreamExt};
12use syn::{Fields, Index, ItemEnum, ItemStruct, Member, Token};
13
14pub struct ImplClone;
16impl ImplTrait for ImplClone {
17 fn path(&self) -> SimplePath {
18 SimplePath::new(&["", "core", "clone", "Clone"])
19 }
20
21 fn support_ignore(&self) -> bool {
22 true
23 }
24
25 fn enum_items(&self, item: &ItemEnum, args: &ImplArgs) -> Result<(Toks, Toks)> {
26 let mut idfmt = IdentFormatter::new();
27 let name = &item.ident;
28 let mut variants = Toks::new();
29 for v in item.variants.iter() {
30 for attr in &v.attrs {
31 if attr.path().get_ident().is_some_and(|path| path == "cfg") {
32 attr.to_tokens(&mut variants);
33 }
34 }
35
36 let ident = &v.ident;
37 let tag = quote! { #name :: #ident };
38 variants.append_all(match v.fields {
39 Fields::Named(ref fields) => {
40 let mut idents = Toks::new();
41 let mut toks = Toks::new();
42 for field in fields.named.iter() {
43 for attr in &field.attrs {
44 if attr.path().get_ident().is_some_and(|path| path == "cfg") {
45 attr.to_tokens(&mut idents);
46 attr.to_tokens(&mut toks);
47 }
48 }
49
50 let ident = field.ident.as_ref().unwrap();
51 idents.append_all(quote! { ref #ident, });
52 toks.append_all(if args.ignore_named(ident) {
53 quote! { #ident: Default::default(), }
54 } else {
55 quote! { #ident: ::core::clone::Clone::clone(#ident), }
56 });
57 }
58 quote! { #tag { #idents } => #tag { #toks }, }
59 }
60 Fields::Unnamed(ref fields) => {
61 let mut bindings = Toks::new();
62 let mut toks = Toks::new();
63 for (i, field) in fields.unnamed.iter().enumerate() {
64 let ident = idfmt.make_call_site(format_args!("_{i}"));
65
66 for attr in &field.attrs {
67 if attr.path().get_ident().is_some_and(|path| path == "cfg") {
68 attr.to_tokens(&mut bindings);
69 attr.to_tokens(&mut toks);
70 }
71 }
72
73 bindings.append_all(quote! { ref #ident, });
74 toks.append_all(quote! { ::core::clone::Clone::clone(#ident), });
75 }
76 quote! { #tag ( #bindings ) => #tag ( #toks ), }
77 }
78 Fields::Unit => quote! { #tag => #tag, },
79 });
80 }
81 let method = quote! {
82 fn clone(&self) -> Self {
83 match *self {
84 #variants
85 }
86 }
87 };
88 Ok((quote! { ::core::clone::Clone }, method))
89 }
90
91 fn struct_items(&self, item: &ItemStruct, args: &ImplArgs) -> Result<(Toks, Toks)> {
92 let type_ident = &item.ident;
93 let inner = match &item.fields {
94 Fields::Named(fields) => {
95 let mut toks = Toks::new();
96 for field in fields.named.iter() {
97 for attr in &field.attrs {
98 if attr.path().get_ident().is_some_and(|path| path == "cfg") {
99 attr.to_tokens(&mut toks);
100 }
101 }
102
103 let ident = field.ident.as_ref().unwrap();
104 toks.append_all(if args.ignore_named(ident) {
105 quote! { #ident: Default::default(), }
106 } else {
107 quote! { #ident: ::core::clone::Clone::clone(&self.#ident), }
108 });
109 }
110 quote! { #type_ident { #toks } }
111 }
112 Fields::Unnamed(fields) => {
113 let mut toks = Toks::new();
114 for (i, field) in fields.unnamed.iter().enumerate() {
115 for attr in &field.attrs {
116 if attr.path().get_ident().is_some_and(|path| path == "cfg") {
117 attr.to_tokens(&mut toks);
118 }
119 }
120
121 let index = Index::from(i);
122 toks.append_all(if args.ignore_unnamed(&index) {
123 quote! { Default::default(), }
124 } else {
125 quote! { ::core::clone::Clone::clone(&self.#index), }
126 });
127 }
128 quote! { #type_ident ( #toks ) }
129 }
130 Fields::Unit => quote! { #type_ident },
131 };
132 let method = quote! {
133 fn clone(&self) -> Self {
134 #inner
135 }
136 };
137 Ok((quote! { ::core::clone::Clone }, method))
138 }
139}
140
141pub struct ImplCopy;
143impl ImplTrait for ImplCopy {
144 fn path(&self) -> SimplePath {
145 SimplePath::new(&["", "core", "marker", "Copy"])
146 }
147
148 fn allow_ignore_with(&self) -> Option<SimplePath> {
149 Some(SimplePath::new(&["", "core", "clone", "Clone"]))
150 }
151
152 fn enum_items(&self, _: &ItemEnum, _: &ImplArgs) -> Result<(Toks, Toks)> {
153 Ok((quote! { ::core::marker::Copy }, quote! {}))
154 }
155
156 fn struct_items(&self, _: &ItemStruct, _: &ImplArgs) -> Result<(Toks, Toks)> {
157 Ok((quote! { ::core::marker::Copy }, quote! {}))
158 }
159}
160
161pub struct ImplDebug;
163impl ImplTrait for ImplDebug {
164 fn path(&self) -> SimplePath {
165 SimplePath::new(&["", "core", "fmt", "Debug"])
166 }
167
168 fn support_ignore(&self) -> bool {
169 true
170 }
171
172 fn enum_items(&self, item: &ItemEnum, args: &ImplArgs) -> Result<(Toks, Toks)> {
173 let mut idfmt = IdentFormatter::new();
174 let name = &item.ident;
175 let type_name = item.ident.to_string();
176 let mut variants = Toks::new();
177 for v in item.variants.iter() {
178 let ident = &v.ident;
179 let var_name = ident.to_string();
180 let tag = quote! { #name :: #ident };
181 variants.append_all(match v.fields {
182 Fields::Named(ref fields) => {
183 let mut idents = Toks::new();
184 let mut stmts = quote! { let mut debug = f.debug_struct(#var_name); };
185 for field in fields.named.iter() {
186 for attr in &field.attrs {
187 if attr.path().get_ident().is_some_and(|path| path == "cfg") {
188 attr.to_tokens(&mut idents);
189 attr.to_tokens(&mut stmts);
190 }
191 }
192
193 let ident = field.ident.as_ref().unwrap();
194 idents.append_all(quote! { ref #ident, });
195 if !args.ignore_named(ident) {
196 let name = ident.to_string();
197 stmts.append_all(quote! { { debug.field(#name, #ident); } });
198 }
199 }
200 stmts.append_all(quote! { debug.finish() });
201
202 quote! { #tag { #idents } => { #stmts }, }
203 }
204 Fields::Unnamed(ref fields) => {
205 let mut bindings = Toks::new();
206 let mut stmts = quote! { let mut debug = f.debug_tuple(#var_name); };
207 for (i, field) in fields.unnamed.iter().enumerate() {
208 for attr in &field.attrs {
209 if attr.path().get_ident().is_some_and(|path| path == "cfg") {
210 attr.to_tokens(&mut bindings);
211 attr.to_tokens(&mut stmts);
212 }
213 }
214
215 let ident = idfmt.make_call_site(format_args!("_{i}"));
216 bindings.append_all(quote! { ref #ident, });
217 stmts.append_all(quote! { { debug.field(#ident); } });
218 }
219 quote! {
220 #tag ( #bindings ) => { #stmts; debug.finish() },
221 }
222 }
223 Fields::Unit => quote! { #tag => f.write_str(#var_name), },
224 })
225 }
226
227 let method = quote! {
229 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
230 write!(f, "{}::", #type_name)?;
231 match *self {
232 #variants
233 }
234 }
235 };
236 Ok((quote! { ::core::fmt::Debug }, method))
237 }
238
239 fn struct_items(&self, item: &ItemStruct, args: &ImplArgs) -> Result<(Toks, Toks)> {
240 let type_name = item.ident.to_string();
241 let inner = match &item.fields {
242 Fields::Named(fields) => {
243 let mut stmts = quote! { let mut debug = f.debug_struct(#type_name); };
244 let mut no_skips = true;
245 for field in fields.named.iter() {
246 for attr in &field.attrs {
247 if attr.path().get_ident().is_some_and(|path| path == "cfg") {
248 attr.to_tokens(&mut stmts);
249 }
250 }
251
252 let ident = field.ident.as_ref().unwrap();
253 if !args.ignore_named(ident) {
254 let name = ident.to_string();
255 stmts.append_all(quote! { { debug.field(#name, &self.#ident); } });
256 } else {
257 no_skips = false;
258 }
259 }
260 if no_skips {
261 quote! { #stmts; debug.finish() }
262 } else {
263 quote! { #stmts; debug.finish_non_exhaustive() }
264 }
265 }
266 Fields::Unnamed(fields) => {
267 let mut stmts = quote! { let mut debug = f.debug_tuple(#type_name); };
268 for (i, field) in fields.unnamed.iter().enumerate() {
269 for attr in &field.attrs {
270 if attr.path().get_ident().is_some_and(|path| path == "cfg") {
271 attr.to_tokens(&mut stmts);
272 }
273 }
274
275 let index = Index::from(i);
276 if !args.ignore_unnamed(&index) {
277 stmts.append_all(quote! { { debug.field(&self.#index); } });
278 } else {
279 stmts.append_all(quote! { { debug.field(&format_args!("_")); } });
280 }
281 }
282 quote! { #stmts; debug.finish() }
283 }
284 Fields::Unit => quote! { f.write_str(#type_name) },
285 };
286
287 let method = quote! {
288 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
289 #inner
290 }
291 };
292 Ok((quote! { ::core::fmt::Debug }, method))
293 }
294}
295
296pub struct ImplDefault;
298impl ImplTrait for ImplDefault {
299 fn path(&self) -> SimplePath {
300 SimplePath::new(&["", "core", "default", "Default"])
301 }
302
303 fn struct_items(&self, item: &ItemStruct, _: &ImplArgs) -> Result<(Toks, Toks)> {
304 let type_ident = &item.ident;
305 let inner = match &item.fields {
306 Fields::Named(fields) => {
307 let mut toks = Toks::new();
308 for field in fields.named.iter() {
309 for attr in &field.attrs {
310 if attr.path().get_ident().is_some_and(|path| path == "cfg") {
311 attr.to_tokens(&mut toks);
312 }
313 }
314
315 let ident = field.ident.as_ref().unwrap();
316 toks.append_all(quote! { #ident: Default::default(), });
317 }
318 quote! { #type_ident { #toks } }
319 }
320 Fields::Unnamed(fields) => {
321 let mut toks = Toks::new();
322 for field in fields.unnamed.iter() {
323 for attr in &field.attrs {
324 if attr.path().get_ident().is_some_and(|path| path == "cfg") {
325 attr.to_tokens(&mut toks);
326 }
327 }
328
329 toks.append_all(quote! { Default::default(), });
330 }
331 quote! { #type_ident(#toks) }
332 }
333 Fields::Unit => quote! { #type_ident },
334 };
335
336 let method = quote! {
337 fn default() -> Self {
338 #inner
339 }
340 };
341 Ok((quote! { ::core::default::Default }, method))
342 }
343}
344
345pub struct ImplPartialEq;
349impl ImplTrait for ImplPartialEq {
350 fn path(&self) -> SimplePath {
351 SimplePath::new(&["", "core", "cmp", "PartialEq"])
352 }
353
354 fn support_ignore(&self) -> bool {
355 true
356 }
357
358 fn enum_items(&self, item: &ItemEnum, _: &ImplArgs) -> Result<(Toks, Toks)> {
359 let mut idfmt = IdentFormatter::new();
360 let name = &item.ident;
361 let mut variants = Toks::new();
362 for v in item.variants.iter() {
363 let ident = &v.ident;
364 let tag = quote! { #name :: #ident };
365 variants.append_all(match v.fields {
366 Fields::Named(ref fields) => {
367 let mut l_args = quote! {};
368 let mut r_args = quote! {};
369 let mut cond = quote! {};
370 for (i, field) in fields.named.iter().enumerate() {
371 let ident = field.ident.as_ref().unwrap();
372 let li = idfmt.make_call_site(format_args!("__l{i}"));
373 let ri = idfmt.make_call_site(format_args!("__r{i}"));
374 l_args.append_all(quote! { #ident: #li, });
375 r_args.append_all(quote! { #ident: #ri, });
376 if !cond.is_empty() {
377 cond.append_all(quote! { && });
378 }
379 cond.append_all(quote! { #li == #ri });
380 }
381
382 quote! { (#tag { #l_args }, #tag { #r_args }) => #cond, }
383 }
384 Fields::Unnamed(ref fields) => {
385 let len = fields.unnamed.len();
386 let mut l_args = quote! {};
387 let mut r_args = quote! {};
388 let mut cond = quote! {};
389 for i in 0..len {
390 let li = idfmt.make_call_site(format_args!("__l{i}"));
391 let ri = idfmt.make_call_site(format_args!("__r{i}"));
392 l_args.append_all(quote! { #li, });
393 r_args.append_all(quote! { #ri, });
394 if !cond.is_empty() {
395 cond.append_all(quote! { && });
396 }
397 cond.append_all(quote! { #li == #ri });
398 }
399
400 quote! { (#tag ( #l_args ), #tag ( #r_args )) => #cond, }
401 }
402 Fields::Unit => quote! { (#tag, #tag) => true, },
403 });
404 }
405 variants.append_all(quote! { (_, _) => false, });
406
407 let method = quote! {
408 #[inline]
409 fn eq(&self, other: &Self) -> bool {
410 match (self, other) {
411 #variants
412 }
413 }
414 };
415 Ok((quote! { ::core::cmp::PartialEq }, method))
416 }
417
418 fn struct_items(&self, item: &ItemStruct, args: &ImplArgs) -> Result<(Toks, Toks)> {
419 let mut toks = Toks::new();
420 let mut require_sep = false;
421 args.for_fields(&item.fields, |member: Member, _| {
422 if require_sep {
423 <Token![&&]>::default().to_tokens(&mut toks);
424 }
425 toks.append_all(quote! { self.#member == other.#member });
426 require_sep = true;
427 });
428 if toks.is_empty() {
429 toks = quote! { true };
430 }
431
432 let method = quote! {
433 #[inline]
434 fn eq(&self, other: &Self) -> bool {
435 #toks
436 }
437 };
438 Ok((quote! { ::core::cmp::PartialEq }, method))
439 }
440}
441
442pub struct ImplEq;
444impl ImplTrait for ImplEq {
445 fn path(&self) -> SimplePath {
446 SimplePath::new(&["", "core", "cmp", "Eq"])
447 }
448
449 fn allow_ignore_with(&self) -> Option<SimplePath> {
450 Some(SimplePath::new(&["", "core", "cmp", "PartialEq"]))
451 }
452
453 fn enum_items(&self, _: &ItemEnum, _: &ImplArgs) -> Result<(Toks, Toks)> {
454 Ok((quote! { ::core::cmp::Eq }, quote! {}))
455 }
456
457 fn struct_items(&self, _: &ItemStruct, _: &ImplArgs) -> Result<(Toks, Toks)> {
458 Ok((quote! { ::core::cmp::Eq }, quote! {}))
459 }
460}
461
462pub struct ImplPartialOrd;
466impl ImplTrait for ImplPartialOrd {
467 fn path(&self) -> SimplePath {
468 SimplePath::new(&["", "core", "cmp", "PartialOrd"])
469 }
470
471 fn support_ignore(&self) -> bool {
472 true
473 }
474
475 fn struct_items(&self, item: &ItemStruct, args: &ImplArgs) -> Result<(Toks, Toks)> {
476 let mut toks = Toks::new();
477 args.for_fields_iter(item.fields.iter().enumerate().rev(), |member: Member, _| {
478 let cmp =
479 quote! { ::core::cmp::PartialOrd::partial_cmp(&self.#member, &other.#member) };
480 if toks.is_empty() {
481 toks = cmp;
482 } else {
483 toks = quote! {
484 match #cmp {
485 ::core::option::Option::Some(::core::cmp::Ordering::Equal) => #toks,
486 cmp => cmp,
487 }
488 }
489 }
490 });
491 if toks.is_empty() {
492 toks = quote! { ::core::option::Option::Some(::core::cmp::Ordering::Equal) };
493 }
494
495 let method = quote! {
496 #[inline]
497 fn partial_cmp(&self, other: &Self) -> ::core::option::Option<::core::cmp::Ordering> {
498 #toks
499 }
500 };
501 Ok((quote! { ::core::cmp::PartialOrd }, method))
502 }
503}
504
505pub struct ImplOrd;
507impl ImplTrait for ImplOrd {
508 fn path(&self) -> SimplePath {
509 SimplePath::new(&["", "core", "cmp", "Ord"])
510 }
511
512 fn support_ignore(&self) -> bool {
513 true
514 }
515
516 fn struct_items(&self, item: &ItemStruct, args: &ImplArgs) -> Result<(Toks, Toks)> {
517 let mut toks = Toks::new();
518 args.for_fields_iter(item.fields.iter().enumerate().rev(), |member: Member, _| {
519 let cmp = quote! { ::core::cmp::Ord::cmp(&self.#member, &other.#member) };
520 if toks.is_empty() {
521 toks = cmp;
522 } else {
523 toks = quote! {
524 match #cmp {
525 ::core::cmp::Ordering::Equal => #toks,
526 cmp => cmp,
527 }
528 }
529 }
530 });
531 if toks.is_empty() {
532 toks = quote! { ::core::cmp::Ordering::Equal };
533 }
534
535 let method = quote! {
536 #[inline]
537 fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
538 #toks
539 }
540 };
541 Ok((quote! { ::core::cmp::Ord }, method))
542 }
543}
544
545pub struct ImplHash;
547impl ImplTrait for ImplHash {
548 fn path(&self) -> SimplePath {
549 SimplePath::new(&["", "core", "hash", "Hash"])
550 }
551
552 fn support_ignore(&self) -> bool {
553 true
554 }
555
556 fn enum_items(&self, item: &ItemEnum, _: &ImplArgs) -> Result<(Toks, Toks)> {
557 let mut idfmt = IdentFormatter::new();
558 let name = &item.ident;
559 let mut variants = Toks::new();
560 for v in item.variants.iter() {
561 let ident = &v.ident;
562 variants.append_all(quote! { #name :: #ident });
563 variants.append_all(match v.fields {
564 Fields::Named(ref fields) => {
565 let idents = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
566 let hashes = fields.named.iter().map(|f| {
567 let ident = f.ident.as_ref().unwrap();
568 quote! { ::core::hash::Hash::hash(&#ident, state); }
569 });
570 quote! { { #(ref #idents),* } => { #(#hashes);* } }
571 }
572 Fields::Unnamed(ref fields) => {
573 let len = fields.unnamed.len();
574 let mut bindings = Vec::with_capacity(len);
575 let mut hashes = quote! {};
576 for i in 0..len {
577 let ident = idfmt.make_call_site(format_args!("_{i}"));
578 bindings.push(quote! { ref #ident });
579 hashes.append_all(quote! {
580 ::core::hash::Hash::hash(#ident, state);
581 });
582 }
583 quote! { ( #(#bindings),* ) => { #hashes } }
584 }
585 Fields::Unit => quote! { => (), },
586 });
587 }
588 let method = quote! {
589 fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
590 match *self {
591 #variants
592 }
593 }
594 };
595 Ok((quote! { ::core::hash::Hash }, method))
596 }
597
598 fn struct_items(&self, item: &ItemStruct, args: &ImplArgs) -> Result<(Toks, Toks)> {
599 let mut toks = Toks::new();
600 args.for_fields_iter(item.fields.iter().enumerate().rev(), |member: Member, _| {
601 toks.append_all(quote! { ::core::hash::Hash::hash(&self.#member, state); });
602 });
603
604 let method = quote! {
605 #[inline]
606 fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
607 #toks
608 }
609 };
610 Ok((quote! { ::core::hash::Hash }, method))
611 }
612}