Skip to main content

auto_default/
lib.rs

1#![doc = concat!("[![crates.io](https://img.shields.io/crates/v/", env!("CARGO_PKG_NAME"), "?style=flat-square&logo=rust)](https://crates.io/crates/", env!("CARGO_PKG_NAME"), ")")]
2#![doc = concat!("[![docs.rs](https://img.shields.io/docsrs/", env!("CARGO_PKG_NAME"), "?style=flat-square&logo=docs.rs)](https://docs.rs/", env!("CARGO_PKG_NAME"), ")")]
3#![doc = "![license](https://img.shields.io/badge/license-Apache--2.0_OR_MIT-blue?style=flat-square)"]
4//! ![msrv](https://img.shields.io/badge/msrv-nightly-blue?style=flat-square&logo=rust)
5//! [![github](https://img.shields.io/github/stars/nik-rev/auto-default)](https://github.com/nik-rev/auto-default)
6//!
7//! This crate provides an attribute macro `#[auto_default]`, which adds a default field value of
8//! `Default::default()` to fields that do not have one.
9//!
10//! ```toml
11#![doc = concat!(env!("CARGO_PKG_NAME"), " = ", "\"", env!("CARGO_PKG_VERSION_MAJOR"), ".", env!("CARGO_PKG_VERSION_MINOR"), "\"")]
12//! ```
13//!
14//! Note: `auto-default` has *zero* dependencies. Not even `syn`! The compile times are very fast.
15//!
16//! # Showcase
17//!
18//! Rust's [default field values](https://github.com/rust-lang/rust/issues/132162) allow
19//! the shorthand `Struct { field, .. }` instead of the lengthy `Struct { field, ..Default::default() }`
20//!
21//! For `..` instead of `..Default::default()` to work,
22//! your `Struct` needs **all** fields to have a default value.
23//!
24//! This often means `= Default::default()` boilerplate on every field, because it is
25//! very common to want field defaults to be the value of their `Default` implementation
26//!
27//! ## Before
28//!
29//! ```rust
30//! # #![feature(default_field_values)]
31//! # #![feature(const_trait_impl)]
32//! # #![feature(const_default)]
33//! # #![feature(derive_const)]
34//! # use auto_default::auto_default;
35//! # #[derive_const(Default)]
36//! # struct Rect { value: f32 }
37//! # #[derive_const(Default)]
38//! # struct Size { value: f32 }
39//! # #[derive_const(Default)]
40//! # struct Point { value: f32 }
41//! #[derive(Default)]
42//! pub struct Layout {
43//!     order: u32 = Default::default(),
44//!     location: Point = Default::default(),
45//!     size: Size = Default::default(),
46//!     content_size: Size = Default::default(),
47//!     scrollbar_size: Size = Default::default(),
48//!     border: Rect = Default::default(),
49//!     padding: Rect = Default::default(),
50//!     margin: Rect = Default::default(),
51//! }
52//! ```
53//!
54//! ## With `#[auto_default]`
55//!
56//! ```rust
57//! # #![feature(default_field_values)]
58//! # #![feature(const_trait_impl)]
59//! # #![feature(const_default)]
60//! # #![feature(derive_const)]
61//! # use auto_default::auto_default;
62//! # #[derive_const(Default)]
63//! # struct Rect { value: f32 }
64//! # #[derive_const(Default)]
65//! # struct Size { value: f32 }
66//! # #[derive_const(Default)]
67//! # struct Point { value: f32 }
68//! #[auto_default]
69//! #[derive(Default)]
70//! pub struct Layout {
71//!     order: u32,
72//!     location: Point,
73//!     size: Size,
74//!     content_size: Size,
75//!     scrollbar_size: Size,
76//!     border: Rect,
77//!     padding: Rect,
78//!     margin: Rect,
79//! }
80//! ```
81//!
82//! You can apply the [`#[auto_default]`](macro@auto_default) macro to `struct`s with named fields, and `enum`s.
83//!
84//! If any field or variant has the `#[auto_default(skip)]` attribute, a default field value of `Default::default()`
85//! will **not** be added
86//!
87//! # Global Import
88//!
89//! This will make `#[auto_default]` globally accessible in your entire crate, without needing to import it:
90//!
91//! ```
92//! #[macro_use(auto_default)]
93//! extern crate auto_default;
94//! ```
95use std::iter::Peekable;
96
97use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
98
99/// Adds a default field value of `Default::default()` to fields that don't have one
100///
101/// # Example
102///
103/// Turns this:
104///
105/// ```rust
106/// # #![feature(default_field_values)]
107/// # #![feature(const_trait_impl)]
108/// # #![feature(const_default)]
109/// #[auto_default]
110/// struct User {
111///     age: u8,
112///     is_admin: bool = false
113/// }
114/// # use auto_default::auto_default;
115/// ```
116///
117/// Into this:
118///
119/// ```rust
120/// # #![feature(default_field_values)]
121/// # #![feature(const_trait_impl)]
122/// # #![feature(const_default)]
123/// struct User {
124///     age: u8 = Default::default(),
125///     is_admin: bool = false
126/// }
127/// ```
128///
129/// This macro applies to `struct`s with named fields, and enums.
130///
131/// # Do not add `= Default::default()` field value to select fields
132///
133/// If you do not want a specific field to have a default, you can opt-out
134/// with `#[auto_default(skip)]`:
135///
136/// ```rust
137/// # #![feature(default_field_values)]
138/// # #![feature(const_trait_impl)]
139/// # #![feature(const_default)]
140/// #[auto_default]
141/// struct User {
142///     #[auto_default(skip)]
143///     age: u8,
144///     is_admin: bool
145/// }
146/// # use auto_default::auto_default;
147/// ```
148///
149/// The above is transformed into this:
150///
151/// ```rust
152/// # #![feature(default_field_values)]
153/// # #![feature(const_trait_impl)]
154/// # #![feature(const_default)]
155/// struct User {
156///     age: u8,
157///     is_admin: bool = Default::default()
158/// }
159/// ```
160#[proc_macro_attribute]
161pub fn auto_default(args: TokenStream, input: TokenStream) -> TokenStream {
162    let mut compile_errors = TokenStream::new();
163
164    if !args.is_empty() {
165        compile_errors.extend(create_compile_error!(
166            args.into_iter().next(),
167            "no arguments expected",
168        ));
169    }
170
171    // Input supplied by the user. All tokens from here will
172    // get sent back to `output`
173    let mut source = input.into_iter().peekable();
174
175    // We collect all tokens into here and then return this
176    let mut sink = TokenStream::new();
177
178    // #[derive(Foo)]
179    // pub(in crate) struct Foo
180    stream_attrs(
181        &mut source,
182        &mut sink,
183        &mut compile_errors,
184        // no skip allowed on the container, would make no sense
185        // (just don't use the `#[auto_default]` at all at that point!)
186        IsSkipAllowed(false),
187    );
188
189    // pub(in crate) struct Foo
190    // ^^^^^^^^^^^^^
191    stream_vis(&mut source, &mut sink);
192
193    // pub(in crate) struct Foo
194    //               ^^^^^^
195    let item_kind = match source.next() {
196        Some(TokenTree::Ident(kw)) if kw.to_string() == "struct" => {
197            sink.extend([kw]);
198            ItemKind::Struct
199        }
200        Some(TokenTree::Ident(kw)) if kw.to_string() == "enum" => {
201            sink.extend([kw]);
202            ItemKind::Enum
203        }
204        tt => {
205            compile_errors.extend(create_compile_error!(
206                tt,
207                "expected a `struct` or an `enum`"
208            ));
209            return compile_errors;
210        }
211    };
212
213    // struct Foo
214    //        ^^^
215    let item_ident_span = stream_ident(&mut source, &mut sink)
216        .expect("`struct` or `enum` keyword is always followed by an identifier");
217
218    // Generics
219    //
220    // struct Foo<Bar, Baz: Trait> where Baz: Quux { ... }
221    //           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
222    let source_item_fields = loop {
223        match source.next() {
224            // Fields of the struct
225            Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => break group,
226            // This token is part of the generics of the struct
227            Some(tt) => sink.extend([tt]),
228            // reached end of input
229            None => {
230                // note: if enum, this is unreachable because `enum Foo` is invalid (requires `{}`),
231                // whilst `struct Foo;` is completely valid
232                compile_errors.extend(CompileError::new(
233                    item_ident_span,
234                    "expected struct with named fields",
235                ));
236                return compile_errors;
237            }
238        }
239    };
240
241    match item_kind {
242        ItemKind::Struct => {
243            sink.extend([add_default_field_values(
244                source_item_fields,
245                &mut compile_errors,
246                // none of the fields are considered to be skipped initially
247                IsSkip(false),
248            )]);
249        }
250        ItemKind::Enum => {
251            let mut source_variants = source_item_fields.stream().into_iter().peekable();
252            let mut sink_variants = TokenStream::new();
253
254            loop {
255                // if this variant is marked #[auto_default(skip)]
256                let is_skip = stream_attrs(
257                    &mut source_variants,
258                    &mut sink_variants,
259                    &mut compile_errors,
260                    // can skip the variant, which removes auto-default for all
261                    // fields
262                    IsSkipAllowed(true),
263                );
264
265                // variants technically can have visibility, at least on a syntactic level
266                //
267                // pub Variant {  }
268                // ^^^
269                stream_vis(&mut source_variants, &mut sink_variants);
270
271                // Variant {  }
272                // ^^^^^^^
273                let Some(variant_ident_span) =
274                    stream_ident(&mut source_variants, &mut sink_variants)
275                else {
276                    // that means we have an enum with no variants, e.g.:
277                    //
278                    // enum Never {}
279                    //
280                    // When we parse the variants, there won't be an identifier
281                    break;
282                };
283
284                // only variants with named fields can be marked `#[auto_default(skip)]`
285                let mut disallow_skip = || {
286                    if is_skip.0 {
287                        compile_errors.extend(CompileError::new(
288                            variant_ident_span,
289                            concat!(
290                                "`#[auto_default(skip)]` is",
291                                " only allowed on variants with named fields"
292                            ),
293                        ));
294                    }
295                };
296
297                match source_variants.peek() {
298                    // Enum variant with named fields. Add default field values.
299                    Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => {
300                        let Some(TokenTree::Group(named_variant_fields)) = source_variants.next()
301                        else {
302                            unreachable!()
303                        };
304                        sink_variants.extend([add_default_field_values(
305                            named_variant_fields,
306                            &mut compile_errors,
307                            is_skip,
308                        )]);
309
310                        stream_enum_variant_discriminant_and_comma(
311                            &mut source_variants,
312                            &mut sink_variants,
313                        );
314                    }
315                    // Enum variant with unnamed fields.
316                    Some(TokenTree::Group(group))
317                        if group.delimiter() == Delimiter::Parenthesis =>
318                    {
319                        disallow_skip();
320                        let Some(TokenTree::Group(unnamed_variant_fields)) = source_variants.next()
321                        else {
322                            unreachable!()
323                        };
324                        sink_variants.extend([unnamed_variant_fields]);
325
326                        stream_enum_variant_discriminant_and_comma(
327                            &mut source_variants,
328                            &mut sink_variants,
329                        );
330                    }
331                    // This was a unit variant. Next variant may exist,
332                    // if it does it is parsed on next iteration
333                    Some(TokenTree::Punct(punct))
334                        if punct.as_char() == ',' || punct.as_char() == '=' =>
335                    {
336                        disallow_skip();
337                        stream_enum_variant_discriminant_and_comma(
338                            &mut source_variants,
339                            &mut sink_variants,
340                        );
341                    }
342                    // Unit variant, with no comma at the end. This is the last variant
343                    None => {
344                        disallow_skip();
345                        break;
346                    }
347                    Some(_) => unreachable!(),
348                }
349            }
350
351            let mut sink_variants = Group::new(source_item_fields.delimiter(), sink_variants);
352            sink_variants.set_span(source_item_fields.span());
353            sink.extend([sink_variants]);
354        }
355    }
356
357    sink.extend(compile_errors);
358
359    sink
360}
361
362struct IsSkip(bool);
363struct IsSkipAllowed(bool);
364
365/// Streams enum variant discriminant + comma at the end from `source` into `sink`
366///
367/// enum Example {
368///     Three,
369///          ^
370///     Two(u32) = 2,
371///             ^^^^^
372///     Four { hello: u32 } = 4,
373///                        ^^^^^
374/// }
375fn stream_enum_variant_discriminant_and_comma(source: &mut Source, sink: &mut Sink) {
376    match source.next() {
377        // No discriminant, there may be another variant after this
378        Some(TokenTree::Punct(punct)) if punct.as_char() == ',' => {
379            sink.extend([punct]);
380        }
381        // No discriminant, this is the final enum variant
382        None => {}
383        // Enum variant has a discriminant
384        Some(TokenTree::Punct(punct)) if punct.as_char() == '=' => {
385            sink.extend([punct]);
386
387            // Stream discriminant expression from `source` into `sink`
388            loop {
389                match source.next() {
390                    // End of discriminant, there may be a variant after this
391                    Some(TokenTree::Punct(punct)) if punct.as_char() == ',' => {
392                        sink.extend([punct]);
393                        break;
394                    }
395                    // This token is part of the variant's expression
396                    Some(tt) => {
397                        sink.extend([tt]);
398                    }
399                    // End of discriminant, this is the last variant
400                    None => break,
401                }
402            }
403        }
404        Some(_) => unreachable!(),
405    }
406}
407
408type Source = Peekable<proc_macro::token_stream::IntoIter>;
409type Sink = TokenStream;
410
411/// Streams the identifier from `input` into `output`, returning its span, if the identifier exists
412fn stream_ident(source: &mut Source, sink: &mut Sink) -> Option<Span> {
413    let ident = source.next()?;
414    let span = ident.span();
415    sink.extend([ident]);
416    Some(span)
417}
418
419// Parses attributes
420//
421// #[attr] #[attr] pub field: Type
422// #[attr] #[attr] struct Foo
423// #[attr] #[attr] enum Foo
424//
425// Returns `true` if `#[auto_default(skip)]` was encountered
426fn stream_attrs(
427    source: &mut Source,
428    sink: &mut Sink,
429    errors: &mut TokenStream,
430    is_skip_allowed: IsSkipAllowed,
431) -> IsSkip {
432    let mut is_skip = None;
433
434    let is_skip = loop {
435        if !matches!(source.peek(), Some(TokenTree::Punct(hash)) if *hash == '#') {
436            break is_skip;
437        };
438
439        // #[some_attr]
440        // ^
441        let pound = source.next();
442
443        // #[some_attr]
444        //  ^^^^^^^^^^^
445        let Some(TokenTree::Group(attr)) = source.next() else {
446            unreachable!()
447        };
448
449        // #[some_attr = hello]
450        //   ^^^^^^^^^^^^^^^^^
451        let mut attr_tokens = attr.stream().into_iter().peekable();
452
453        // Check if this attribute is `#[auto_default(skip)]`
454        if let Some(skip_span) = is_skip_attribute(&mut attr_tokens, errors) {
455            if is_skip.is_some() {
456                // Disallow 2 attributes on a single field:
457                //
458                // #[auto_default(skip)]
459                // #[auto_default(skip)]
460                errors.extend(CompileError::new(
461                    skip_span,
462                    "duplicate `#[auto_default(skip)]`",
463                ));
464            } else {
465                is_skip = Some(skip_span);
466            }
467            continue;
468        }
469
470        // #[attr]
471        // ^
472        sink.extend(pound);
473
474        // Re-construct the `[..]` for the attribute
475        //
476        // #[attr]
477        //  ^^^^^^
478        let mut group = Group::new(attr.delimiter(), attr_tokens.collect());
479        group.set_span(attr.span());
480
481        // #[attr]
482        //  ^^^^^^
483        sink.extend([group]);
484    };
485
486    if let Some(skip_span) = is_skip
487        && !is_skip_allowed.0
488    {
489        errors.extend(CompileError::new(
490            skip_span,
491            "`#[auto_default(skip)]` is not allowed on container",
492        ));
493    }
494
495    IsSkip(is_skip.is_some())
496}
497
498/// if `source` is exactly `auto_default(skip)`, returns `Some(span)`
499/// with `span` being the `Span` of the `skip` identifier
500fn is_skip_attribute(source: &mut Source, errors: &mut TokenStream) -> Option<Span> {
501    let Some(TokenTree::Ident(ident)) = source.peek() else {
502        return None;
503    };
504
505    if ident.to_string() != "auto_default" {
506        return None;
507    };
508
509    // #[auto_default(skip)]
510    //   ^^^^^^^^^^^^
511    let ident = source.next().unwrap();
512
513    // We know it is `#[auto_default ???]`, we need to validate that `???`
514    // is exactly `(skip)` now
515
516    // #[auto_default(skip)]
517    //   ^^^^^^^^^^^^
518    let auto_default_span = ident.span();
519
520    // #[auto_default(skip)]
521    //               ^^^^^^
522    let group = match source.next() {
523        Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Parenthesis => group,
524        Some(tt) => {
525            errors.extend(CompileError::new(tt.span(), "expected `(skip)`"));
526            return None;
527        }
528        None => {
529            errors.extend(CompileError::new(
530                auto_default_span,
531                "expected `(skip)` after this",
532            ));
533            return None;
534        }
535    };
536
537    // #[auto_default(skip)]
538    //                ^^^^
539    let mut inside = group.stream().into_iter();
540
541    // #[auto_default(skip)]
542    //                ^^^^
543    let ident_skip = match inside.next() {
544        Some(TokenTree::Ident(ident)) => ident,
545        Some(tt) => {
546            errors.extend(CompileError::new(tt.span(), "expected `skip`"));
547            return None;
548        }
549        None => {
550            errors.extend(CompileError::new(
551                group.span(),
552                "expected `(skip)`, found `()`",
553            ));
554            return None;
555        }
556    };
557
558    if ident_skip.to_string() != "skip" {
559        errors.extend(CompileError::new(ident_skip.span(), "expected `skip`"));
560        return None;
561    }
562
563    // Validate that there's nothing after `skip`
564    //
565    // #[auto_default(skip    )]
566    //                    ^^^^
567    if let Some(tt) = inside.next() {
568        errors.extend(CompileError::new(tt.span(), "unexpected token"));
569        return None;
570    }
571
572    Some(ident_skip.span())
573}
574
575fn stream_vis(source: &mut Source, sink: &mut Sink) {
576    // Remove visibility if it is present
577    //
578    // pub(in crate) struct
579    // ^^^^^^^^^^^^^
580    if let Some(TokenTree::Ident(vis)) = source.peek()
581        && vis.to_string() == "pub"
582    {
583        // pub(in crate) struct
584        // ^^^
585        sink.extend(source.next());
586
587        if let Some(TokenTree::Group(group)) = source.peek()
588            && let Delimiter::Parenthesis = group.delimiter()
589        {
590            // pub(in crate) struct
591            //    ^^^^^^^^^^
592            sink.extend(source.next());
593        }
594    };
595}
596
597#[derive(PartialEq)]
598enum ItemKind {
599    Struct,
600    Enum,
601}
602
603/// `fields` is [`StructFields`] in the grammar.
604///
605/// It is the curly braces, and everything within, for a struct with named fields,
606/// or an enum variant with named fields.
607///
608/// These fields are transformed by adding `= Default::default()` to every
609/// field that doesn't already have a default value.
610///
611/// If a field is marked with `#[auto_default(skip)]`, no default value will be
612/// added
613///
614/// [`StructFields`]: https://doc.rust-lang.org/reference/items/structs.html#grammar-StructFields
615fn add_default_field_values(
616    fields: Group,
617    compile_errors: &mut TokenStream,
618    is_skip_variant: IsSkip,
619) -> Group {
620    // All the tokens corresponding to the struct's field, passed by the user
621    // These tokens will eventually all be sent to `output_fields`,
622    // plus a few extra for any `Default::default()` that we output
623    let mut input_fields = fields.stream().into_iter().peekable();
624
625    // The tokens corresponding to the fields of the output struct
626    let mut output_fields = TokenStream::new();
627
628    // Parses all fields.
629    // Each iteration parses a single field
630    'parse_field: loop {
631        // #[serde(rename = "x")] pub field: Type
632        // ^^^^^^^^^^^^^^^^^^^^^^
633        let is_skip_field = stream_attrs(
634            &mut input_fields,
635            &mut output_fields,
636            compile_errors,
637            IsSkipAllowed(true),
638        );
639        let is_skip = is_skip_field.0 || is_skip_variant.0;
640
641        // pub field: Type
642        // ^^^
643        stream_vis(&mut input_fields, &mut output_fields);
644
645        // pub field: Type
646        //     ^^^^^
647        let Some(field_ident_span) = stream_ident(&mut input_fields, &mut output_fields) else {
648            // No fields. e.g.: `struct Struct {}`
649            break;
650        };
651
652        // field: Type
653        //      ^
654        output_fields.extend(input_fields.next());
655
656        // Everything after the `:` in the field
657        //
658        // Involves:
659        //
660        // - Adding default value of `= Default::default()` if one is not present
661        // - Continue to next iteration of the loop
662        loop {
663            match input_fields.peek() {
664                // This field has a custom default field value
665                //
666                // field: Type = default
667                //             ^
668                Some(TokenTree::Punct(p)) if p.as_char() == '=' => {
669                    if is_skip {
670                        compile_errors.extend(CompileError::new(
671                            field_ident_span,
672                            concat!(
673                                "this field is marked `#[auto_default(skip)]`,",
674                                " which does nothing since this field has a",
675                                " default value: `= ...`\n",
676                                "the attribute `#[auto_default(skip)]` can be removed"
677                            ),
678                        ));
679                    }
680
681                    loop {
682                        match input_fields.next() {
683                            Some(TokenTree::Punct(p)) if p == ',' => {
684                                output_fields.extend([p]);
685                                // Comma after field. Field is finished.
686                                continue 'parse_field;
687                            }
688                            Some(tt) => output_fields.extend([tt]),
689                            // End of input. Field is finished. This is the last field
690                            None => break 'parse_field,
691                        }
692                    }
693                }
694                // Reached end of field, has comma at the end, no custom default value
695                //
696                // field: Type,
697                //            ^
698                //
699                // OR, this comma is part of the field's type:
700                //
701                // field: HashMap<u8, u8>,
702                //                  ^
703                Some(TokenTree::Punct(p)) if p.as_char() == ',' => {
704                    let comma = input_fields.next().expect("match on `Some`");
705
706                    /// What does this comma represent?
707                    #[derive(Debug)]
708                    enum CommaStatus {
709                        /// End of field
710                        EndOfField0,
711                        /// End of field, with 2 tokens to insert after end of the field
712                        EndOfField1(TokenTree),
713                        /// Part of type
714                        PartOfType0,
715                        /// Part of type, with 1 token to insert after the comma
716                        PartOfType1(TokenTree),
717                    }
718
719                    // When we encounter a COMMA token while parsing
720                    let comma_status = match input_fields.peek() {
721                        // pub field: Type
722                        // ^^^
723                        Some(TokenTree::Ident(ident)) if ident.to_string() == "pub" => {
724                            // this `comma` is end of the field
725                            //
726                            //     field: HashMap<u8, u8>,
727                            //                           ^ `comma`
728                            // pub next_field: Type
729                            // ^^^ `ident`
730                            CommaStatus::EndOfField0
731                        }
732
733                        // #[foo(bar)] pub field: Type
734                        // ^
735                        Some(TokenTree::Punct(punct)) if *punct == '#' => {
736                            // this `comma` is end of the field
737                            //
738                            //             field: HashMap<u8, u8>,
739                            //                                   ^ this
740                            // #[foo(bar)] next_field: HashMap<u8, u8>,
741                            CommaStatus::EndOfField0
742                        }
743
744                        // field: Type
745                        // ^^^^^
746                        Some(TokenTree::Ident(_)) => {
747                            let field_or_ty_ident = input_fields.next().expect("match on `Some`");
748
749                            match input_fields.peek() {
750                                // field: Type
751                                //      ^
752                                Some(TokenTree::Punct(punct)) if *punct == ':' => {
753                                    let field_ident = field_or_ty_ident;
754
755                                    CommaStatus::EndOfField1(field_ident)
756                                }
757                                // This identifier is part of the type
758                                //
759                                // field: HashMap<u8, u8>,
760                                //                    ^^
761                                _ => {
762                                    let ty_ident = field_or_ty_ident;
763                                    CommaStatus::PartOfType1(ty_ident)
764                                }
765                            }
766                        }
767
768                        // This comma is part of a type, NOT end of field!
769                        //
770                        // pub field: HashMap<String, String>
771                        //                          ^
772                        Some(_) => CommaStatus::PartOfType0,
773
774                        // Reached end of input. This comma is end of the field
775                        //
776                        // field: Type,
777                        //            ^
778                        None => CommaStatus::EndOfField0,
779                    };
780
781                    let insert_extra_token = match comma_status {
782                        CommaStatus::EndOfField0 => None,
783                        CommaStatus::EndOfField1(token_tree) => Some(token_tree),
784                        CommaStatus::PartOfType0 => {
785                            output_fields.extend([comma]);
786                            continue;
787                        }
788                        CommaStatus::PartOfType1(token_tree) => {
789                            output_fields.extend([comma]);
790                            output_fields.extend([token_tree]);
791                            continue;
792                        }
793                    };
794
795                    // Now that we're here, we can be 100% sure that the `comma` we have
796                    // is at the END of the field
797
798                    // Insert default value before the comma
799                    //
800                    // field: Type = Default::default(),
801                    //             ^^^^^^^^^^^^^^^^^^^^
802                    if !is_skip {
803                        output_fields.extend(default(field_ident_span));
804                    }
805
806                    // field: Type = Default::default(),
807                    //                                 ^
808                    output_fields.extend([comma]);
809
810                    if let Some(token_tree) = insert_extra_token {
811                        // Insert the extra token which we needed to take when figuring out if this
812                        // comma is part of the type, or end of the field
813
814                        output_fields.extend([token_tree]);
815                    }
816
817                    // Next iteration handles the next field
818                    continue 'parse_field;
819                }
820                // This token is part of the field's type
821                //
822                // field: some::Type
823                //              ^^^^
824                Some(_) => output_fields.extend(input_fields.next()),
825                // Reached end of input, and it has no comma.
826                // This is the last field.
827                //
828                // struct Foo {
829                //     field: Type
830                //                ^
831                // }
832                None => {
833                    if !is_skip {
834                        output_fields.extend(default(field_ident_span));
835                    }
836                    // No more fields
837                    break 'parse_field;
838                }
839            }
840        }
841    }
842    let mut g = Group::new(Delimiter::Brace, output_fields);
843    g.set_span(fields.span());
844    g
845}
846
847// = ::core::default::Default::default()
848fn default(span: Span) -> [TokenTree; 14] {
849    [
850        TokenTree::Punct(Punct::new('=', Spacing::Alone)),
851        TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
852        TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
853        TokenTree::Ident(Ident::new("core", span)),
854        TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
855        TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
856        TokenTree::Ident(Ident::new("default", span)),
857        TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
858        TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
859        TokenTree::Ident(Ident::new("Default", span)),
860        TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
861        TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
862        TokenTree::Ident(Ident::new("default", span)),
863        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())).with_span(span),
864    ]
865}
866
867macro_rules! create_compile_error {
868    ($spanned:expr, $($tt:tt)*) => {{
869        let span = if let Some(spanned) = $spanned {
870            spanned.span()
871        } else {
872            Span::call_site()
873        };
874        CompileError::new(span, format!($($tt)*))
875    }};
876}
877use create_compile_error;
878
879/// `.into_iter()` generates `compile_error!($message)` at `$span`
880struct CompileError {
881    /// Where the compile error is generates
882    pub span: Span,
883    /// Message of the compile error
884    pub message: String,
885}
886
887impl CompileError {
888    /// Create a new compile error
889    pub fn new(span: Span, message: impl AsRef<str>) -> Self {
890        Self {
891            span,
892            message: message.as_ref().to_string(),
893        }
894    }
895}
896
897impl IntoIterator for CompileError {
898    type Item = TokenTree;
899    type IntoIter = std::array::IntoIter<Self::Item, 8>;
900
901    fn into_iter(self) -> Self::IntoIter {
902        [
903            TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(self.span),
904            TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(self.span),
905            TokenTree::Ident(Ident::new("core", self.span)),
906            TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(self.span),
907            TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(self.span),
908            TokenTree::Ident(Ident::new("compile_error", self.span)),
909            TokenTree::Punct(Punct::new('!', Spacing::Alone)).with_span(self.span),
910            TokenTree::Group(Group::new(Delimiter::Brace, {
911                TokenStream::from(
912                    TokenTree::Literal(Literal::string(&self.message)).with_span(self.span),
913                )
914            }))
915            .with_span(self.span),
916        ]
917        .into_iter()
918    }
919}
920
921trait TokenTreeExt {
922    /// Set span of `TokenTree` without needing to create a new binding
923    fn with_span(self, span: Span) -> TokenTree;
924}
925
926impl TokenTreeExt for TokenTree {
927    fn with_span(mut self, span: Span) -> TokenTree {
928        self.set_span(span);
929        self
930    }
931}