auto_default/lib.rs
1#, "?style=flat-square&logo=rust)](https://crates.io/crates/", env!("CARGO_PKG_NAME"), ")")]
2#, "?style=flat-square&logo=docs.rs)](https://docs.rs/", env!("CARGO_PKG_NAME"), ")")]
3#"]
4//! 
5#, ")](https://github.com/nik-rev/", env!("CARGO_PKG_NAME"), ")")]
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
86use std::iter::Peekable;
87
88use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
89
90/// Adds a default field value of `Default::default()` to fields that don't have one
91///
92/// # Example
93///
94/// Turns this:
95///
96/// ```rust
97/// # #![feature(default_field_values)]
98/// # #![feature(const_trait_impl)]
99/// # #![feature(const_default)]
100/// #[auto_default]
101/// struct User {
102/// age: u8,
103/// is_admin: bool = false
104/// }
105/// # use auto_default::auto_default;
106/// ```
107///
108/// Into this:
109///
110/// ```rust
111/// # #![feature(default_field_values)]
112/// # #![feature(const_trait_impl)]
113/// # #![feature(const_default)]
114/// struct User {
115/// age: u8 = Default::default(),
116/// is_admin: bool = false
117/// }
118/// ```
119///
120/// This macro applies to `struct`s with named fields, and enums.
121///
122/// # Do not add `= Default::default()` field value to select fields
123///
124/// If you do not want a specific field to have a default, you can opt-out
125/// with `#[auto_default(skip)]`:
126///
127/// ```rust
128/// # #![feature(default_field_values)]
129/// # #![feature(const_trait_impl)]
130/// # #![feature(const_default)]
131/// #[auto_default]
132/// struct User {
133/// #[auto_default(skip)]
134/// age: u8,
135/// is_admin: bool
136/// }
137/// # use auto_default::auto_default;
138/// ```
139///
140/// The above is transformed into this:
141///
142/// ```rust
143/// # #![feature(default_field_values)]
144/// # #![feature(const_trait_impl)]
145/// # #![feature(const_default)]
146/// struct User {
147/// age: u8,
148/// is_admin: bool = Default::default()
149/// }
150/// ```
151#[proc_macro_attribute]
152pub fn auto_default(args: TokenStream, input: TokenStream) -> TokenStream {
153 let mut compile_errors = TokenStream::new();
154
155 if !args.is_empty() {
156 compile_errors.extend(create_compile_error!(
157 args.into_iter().next(),
158 "no arguments expected",
159 ));
160 }
161
162 // Input supplied by the user. All tokens from here will
163 // get sent back to `output`
164 let mut source = input.into_iter().peekable();
165
166 // We collect all tokens into here and then return this
167 let mut sink = TokenStream::new();
168
169 stream_attrs(
170 &mut source,
171 &mut sink,
172 &mut compile_errors,
173 // no skip allowed on the container, would make no sense
174 // (just don't use the `#[auto_default]` at all at that point!)
175 IsSkipAllowed(false),
176 );
177 stream_vis(&mut source, &mut sink);
178
179 // pub(in crate) struct Foo
180 // ^^^^^^
181 let item_kind = match source.next() {
182 Some(TokenTree::Ident(kw)) if kw.to_string() == "struct" => {
183 sink.extend([kw]);
184 ItemKind::Struct
185 }
186 Some(TokenTree::Ident(kw)) if kw.to_string() == "enum" => {
187 sink.extend([kw]);
188 ItemKind::Enum
189 }
190 tt => {
191 compile_errors.extend(create_compile_error!(
192 tt,
193 "expected a `struct` or an `enum`"
194 ));
195 return compile_errors;
196 }
197 };
198
199 // struct Foo
200 // ^^^
201 let item_ident_span = stream_ident(&mut source, &mut sink)
202 .expect("`struct` or `enum` keyword is always followed by an identifier");
203
204 // Generics
205 //
206 // struct Foo<Bar, Baz: Trait> where Baz: Quux { ... }
207 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
208 let source_item_fields = loop {
209 match source.next() {
210 // Fields of the struct
211 Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => break group,
212 // This token is part of the generics of the struct
213 Some(tt) => sink.extend([tt]),
214 // reached end of input
215 None => {
216 // note: if enum, this is unreachable because `enum Foo` is invalid (requires `{}`),
217 // whilst `struct Foo;` is completely valid
218 compile_errors.extend(CompileError::new(
219 item_ident_span,
220 "expected struct with named fields",
221 ));
222 return compile_errors;
223 }
224 }
225 };
226
227 match item_kind {
228 ItemKind::Struct => {
229 sink.extend([add_default_field_values(
230 source_item_fields,
231 &mut compile_errors,
232 // none of the fields are considered to be skipped initially
233 IsSkip(false),
234 )]);
235 }
236 ItemKind::Enum => {
237 let mut source_variants = source_item_fields.stream().into_iter().peekable();
238 let mut sink_variants = TokenStream::new();
239
240 loop {
241 // if this variant is marked #[auto_default(skip)]
242 let is_skip = stream_attrs(
243 &mut source_variants,
244 &mut sink_variants,
245 &mut compile_errors,
246 // can skip the variant, which removes auto-default for all
247 // fields
248 IsSkipAllowed(true),
249 );
250
251 // variants technically can have visibility, at least on a syntactic level
252 //
253 // pub Variant { }
254 // ^^^
255 stream_vis(&mut source_variants, &mut sink_variants);
256
257 // Variant { }
258 // ^^^^^^^
259 let Some(variant_ident_span) =
260 stream_ident(&mut source_variants, &mut sink_variants)
261 else {
262 // that means we have an enum with no variants, e.g.:
263 //
264 // enum Never {}
265 //
266 // When we parse the variants, there won't be an identifier
267 break;
268 };
269
270 // only variants with named fields can be marked `#[auto_default(skip)]`
271 let mut disallow_skip = || {
272 if is_skip.0 {
273 compile_errors.extend(CompileError::new(
274 variant_ident_span,
275 concat!(
276 "`#[auto_default(skip)]` is",
277 " only allowed on variants with named fields"
278 ),
279 ));
280 }
281 };
282
283 match source_variants.peek() {
284 // Enum variant with named fields. Add default field values.
285 Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => {
286 let Some(TokenTree::Group(named_variant_fields)) = source_variants.next()
287 else {
288 unreachable!()
289 };
290 sink_variants.extend([add_default_field_values(
291 named_variant_fields,
292 &mut compile_errors,
293 is_skip,
294 )]);
295
296 stream_enum_variant_discriminant_and_comma(
297 &mut source_variants,
298 &mut sink_variants,
299 );
300 }
301 // Enum variant with unnamed fields.
302 Some(TokenTree::Group(group))
303 if group.delimiter() == Delimiter::Parenthesis =>
304 {
305 disallow_skip();
306 let Some(TokenTree::Group(unnamed_variant_fields)) = source_variants.next()
307 else {
308 unreachable!()
309 };
310 sink_variants.extend([unnamed_variant_fields]);
311
312 stream_enum_variant_discriminant_and_comma(
313 &mut source_variants,
314 &mut sink_variants,
315 );
316 }
317 // This was a unit variant. Next variant may exist,
318 // if it does it is parsed on next iteration
319 Some(TokenTree::Punct(punct))
320 if punct.as_char() == ',' || punct.as_char() == '=' =>
321 {
322 disallow_skip();
323 stream_enum_variant_discriminant_and_comma(
324 &mut source_variants,
325 &mut sink_variants,
326 );
327 }
328 // Unit variant, with no comma at the end. This is the last variant
329 None => {
330 disallow_skip();
331 break;
332 }
333 Some(_) => unreachable!(),
334 }
335 }
336
337 let mut sink_variants = Group::new(source_item_fields.delimiter(), sink_variants);
338 sink_variants.set_span(source_item_fields.span());
339 sink.extend([sink_variants]);
340 }
341 }
342
343 sink.extend(compile_errors);
344
345 sink
346}
347
348struct IsSkip(bool);
349struct IsSkipAllowed(bool);
350
351/// Streams enum variant discriminant + comma at the end from `source` into `sink`
352///
353/// enum Example {
354/// Three,
355/// ^
356/// Two(u32) = 2,
357/// ^^^^^
358/// Four { hello: u32 } = 4,
359/// ^^^^^
360/// }
361fn stream_enum_variant_discriminant_and_comma(source: &mut Source, sink: &mut Sink) {
362 match source.next() {
363 // No discriminant, there may be another variant after this
364 Some(TokenTree::Punct(punct)) if punct.as_char() == ',' => {
365 sink.extend([punct]);
366 }
367 // No discriminant, this is the final enum variant
368 None => {}
369 // Enum variant has a discriminant
370 Some(TokenTree::Punct(punct)) if punct.as_char() == '=' => {
371 sink.extend([punct]);
372
373 // Stream discriminant expression from `source` into `sink`
374 loop {
375 match source.next() {
376 // End of discriminant, there may be a variant after this
377 Some(TokenTree::Punct(punct)) if punct.as_char() == ',' => {
378 sink.extend([punct]);
379 break;
380 }
381 // This token is part of the variant's expression
382 Some(tt) => {
383 sink.extend([tt]);
384 }
385 // End of discriminant, this is the last variant
386 None => break,
387 }
388 }
389 }
390 Some(_) => unreachable!(),
391 }
392}
393
394type Source = Peekable<proc_macro::token_stream::IntoIter>;
395type Sink = TokenStream;
396
397/// Streams the identifier from `input` into `output`, returning its span, if the identifier exists
398fn stream_ident(source: &mut Source, sink: &mut Sink) -> Option<Span> {
399 let ident = source.next()?;
400 let span = ident.span();
401 sink.extend([ident]);
402 Some(span)
403}
404
405// Parses attributes
406//
407// #[attr] #[attr] pub field: Type
408// #[attr] #[attr] struct Foo
409// #[attr] #[attr] enum Foo
410//
411// Returns `true` if `#[auto_default(skip)]` was encountered
412fn stream_attrs(
413 source: &mut Source,
414 sink: &mut Sink,
415 errors: &mut TokenStream,
416 is_skip_allowed: IsSkipAllowed,
417) -> IsSkip {
418 let mut is_skip = None;
419
420 let is_skip = loop {
421 if !matches!(source.peek(), Some(TokenTree::Punct(hash)) if *hash == '#') {
422 break is_skip;
423 };
424
425 // #[some_attr]
426 // ^
427 let pound = source.next();
428
429 // #[some_attr]
430 // ^^^^^^^^^^^
431 let Some(TokenTree::Group(attr)) = source.next() else {
432 unreachable!()
433 };
434
435 // #[some_attr = hello]
436 // ^^^^^^^^^^^^^^^^^
437 let mut attr_tokens = attr.stream().into_iter().peekable();
438
439 // Check if this attribute is `#[auto_default(skip)]`
440 if let Some(skip_span) = is_skip_attribute(&mut attr_tokens, errors) {
441 if is_skip.is_some() {
442 // Disallow 2 attributes on a single field:
443 //
444 // #[auto_default(skip)]
445 // #[auto_default(skip)]
446 errors.extend(CompileError::new(
447 skip_span,
448 "duplicate `#[auto_default(skip)]`",
449 ));
450 } else {
451 is_skip = Some(skip_span);
452 }
453 continue;
454 }
455
456 // #[attr]
457 // ^
458 sink.extend(pound);
459
460 // Re-construct the `[..]` for the attribute
461 //
462 // #[attr]
463 // ^^^^^^
464 let mut group = Group::new(attr.delimiter(), attr_tokens.collect());
465 group.set_span(attr.span());
466
467 // #[attr]
468 // ^^^^^^
469 sink.extend([group]);
470 };
471
472 if let Some(skip_span) = is_skip
473 && !is_skip_allowed.0
474 {
475 errors.extend(CompileError::new(
476 skip_span,
477 "`#[auto_default(skip)]` is not allowed on container",
478 ));
479 }
480
481 IsSkip(is_skip.is_some())
482}
483
484/// if `source` is exactly `auto_default(skip)`, returns `Some(span)`
485/// with `span` being the `Span` of the `skip` identifier
486fn is_skip_attribute(source: &mut Source, errors: &mut TokenStream) -> Option<Span> {
487 let Some(TokenTree::Ident(ident)) = source.peek() else {
488 return None;
489 };
490
491 if ident.to_string() != "auto_default" {
492 return None;
493 };
494
495 // #[auto_default(skip)]
496 // ^^^^^^^^^^^^
497 let ident = source.next().unwrap();
498
499 // We know it is `#[auto_default ???]`, we need to validate that `???`
500 // is exactly `(skip)` now
501
502 // #[auto_default(skip)]
503 // ^^^^^^^^^^^^
504 let auto_default_span = ident.span();
505
506 // #[auto_default(skip)]
507 // ^^^^^^
508 let group = match source.next() {
509 Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Parenthesis => group,
510 Some(tt) => {
511 errors.extend(CompileError::new(tt.span(), "expected `(skip)`"));
512 return None;
513 }
514 None => {
515 errors.extend(CompileError::new(
516 auto_default_span,
517 "expected `(skip)` after this",
518 ));
519 return None;
520 }
521 };
522
523 // #[auto_default(skip)]
524 // ^^^^
525 let mut inside = group.stream().into_iter();
526
527 // #[auto_default(skip)]
528 // ^^^^
529 let ident_skip = match inside.next() {
530 Some(TokenTree::Ident(ident)) => ident,
531 Some(tt) => {
532 errors.extend(CompileError::new(tt.span(), "expected `skip`"));
533 return None;
534 }
535 None => {
536 errors.extend(CompileError::new(
537 group.span(),
538 "expected `(skip)`, found `()`",
539 ));
540 return None;
541 }
542 };
543
544 if ident_skip.to_string() != "skip" {
545 errors.extend(CompileError::new(ident_skip.span(), "expected `skip`"));
546 return None;
547 }
548
549 // Validate that there's nothing after `skip`
550 //
551 // #[auto_default(skip )]
552 // ^^^^
553 if let Some(tt) = inside.next() {
554 errors.extend(CompileError::new(tt.span(), "unexpected token"));
555 return None;
556 }
557
558 Some(ident_skip.span())
559}
560
561fn stream_vis(source: &mut Source, sink: &mut Sink) {
562 // Remove visibility if it is present
563 //
564 // pub(in crate) struct
565 // ^^^^^^^^^^^^^
566 if let Some(TokenTree::Ident(vis)) = source.peek()
567 && vis.to_string() == "pub"
568 {
569 // pub(in crate) struct
570 // ^^^
571 sink.extend(source.next());
572
573 if let Some(TokenTree::Group(group)) = source.peek()
574 && let Delimiter::Parenthesis = group.delimiter()
575 {
576 // pub(in crate) struct
577 // ^^^^^^^^^^
578 sink.extend(source.next());
579 }
580 };
581}
582
583#[derive(PartialEq)]
584enum ItemKind {
585 Struct,
586 Enum,
587}
588
589/// `fields` is [`StructFields`] in the grammar.
590///
591/// It is the curly braces, and everything within, for a struct with named fields,
592/// or an enum variant with named fields.
593///
594/// These fields are transformed by adding `= Default::default()` to every
595/// field that doesn't already have a default value.
596///
597/// If a field is marked with `#[auto_default(skip)]`, no default value will be
598/// added
599///
600/// [`StructFields`]: https://doc.rust-lang.org/reference/items/structs.html#grammar-StructFields
601fn add_default_field_values(
602 fields: Group,
603 compile_errors: &mut TokenStream,
604 is_skip_variant: IsSkip,
605) -> Group {
606 // All the tokens corresponding to the struct's field, passed by the user
607 // These tokens will eventually all be sent to `output_fields`,
608 // plus a few extra for any `Default::default()` that we output
609 let mut input_fields = fields.stream().into_iter().peekable();
610
611 // The tokens corresponding to the fields of the output struct
612 let mut output_fields = TokenStream::new();
613
614 // Parses all fields.
615 // Each iteration parses a single field
616 'parse_field: loop {
617 let is_skip_field = stream_attrs(
618 &mut input_fields,
619 &mut output_fields,
620 compile_errors,
621 IsSkipAllowed(true),
622 );
623 let is_skip = is_skip_field.0 || is_skip_variant.0;
624 stream_vis(&mut input_fields, &mut output_fields);
625 let Some(field_ident_span) = stream_ident(&mut input_fields, &mut output_fields) else {
626 // No fields. e.g.: `struct Struct {}`
627 break;
628 };
629
630 // field: Type
631 // ^
632 output_fields.extend(input_fields.next());
633
634 // Everything after the `:` in the field
635 //
636 // Involves:
637 //
638 // - Adding default value of `= Default::default()` if one is not present
639 // - Continue to next iteration of the loop
640 loop {
641 match input_fields.peek() {
642 // This field has a custom default field value
643 //
644 // field: Type = default
645 // ^
646 Some(TokenTree::Punct(p)) if p.as_char() == '=' => {
647 if is_skip {
648 compile_errors.extend(CompileError::new(
649 field_ident_span,
650 concat!(
651 "this field is marked `#[auto_default(skip)]`,",
652 " which does nothing since this field has a",
653 " default value: `= ...`\n",
654 "the attribute `#[auto_default(skip)]` can be removed"
655 ),
656 ));
657 }
658
659 loop {
660 match input_fields.next() {
661 Some(TokenTree::Punct(p)) if p == ',' => {
662 output_fields.extend([p]);
663 // Comma after field. Field is finished.
664 continue 'parse_field;
665 }
666 Some(tt) => output_fields.extend([tt]),
667 // End of input. Field is finished. This is the last field
668 None => break 'parse_field,
669 }
670 }
671 }
672 // Reached end of field, has comma at the end, no custom default value
673 //
674 // field: Type,
675 // ^
676 Some(TokenTree::Punct(p)) if p.as_char() == ',' => {
677 // Insert default value before the comma
678 //
679 // field: Type = Default::default(),
680 // ^^^^^^^^^^^^^^^^^^^^
681 if !is_skip {
682 output_fields.extend(default(field_ident_span));
683 }
684 // field: Type = Default::default(),
685 // ^
686 output_fields.extend(input_fields.next());
687 // Next iteration handles the next field
688 continue 'parse_field;
689 }
690 // This token is part of the field's type
691 //
692 // field: some::Type
693 // ^^^^
694 Some(_) => output_fields.extend(input_fields.next()),
695 // Reached end of input, and it has no comma.
696 // This is the last field.
697 //
698 // struct Foo {
699 // field: Type
700 // ^
701 // }
702 None => {
703 if !is_skip {
704 output_fields.extend(default(field_ident_span));
705 }
706 // No more fields
707 break 'parse_field;
708 }
709 }
710 }
711 }
712 let mut g = Group::new(Delimiter::Brace, output_fields);
713 g.set_span(fields.span());
714 g
715}
716
717// = ::core::default::Default::default()
718fn default(span: Span) -> [TokenTree; 14] {
719 [
720 TokenTree::Punct(Punct::new('=', Spacing::Alone)),
721 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
722 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
723 TokenTree::Ident(Ident::new("core", span)),
724 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
725 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
726 TokenTree::Ident(Ident::new("default", span)),
727 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
728 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
729 TokenTree::Ident(Ident::new("Default", span)),
730 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
731 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
732 TokenTree::Ident(Ident::new("default", span)),
733 TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())).with_span(span),
734 ]
735}
736
737macro_rules! create_compile_error {
738 ($spanned:expr, $($tt:tt)*) => {{
739 let span = if let Some(spanned) = $spanned {
740 spanned.span()
741 } else {
742 Span::call_site()
743 };
744 CompileError::new(span, format!($($tt)*))
745 }};
746}
747use create_compile_error;
748
749/// `.into_iter()` generates `compile_error!($message)` at `$span`
750struct CompileError {
751 /// Where the compile error is generates
752 pub span: Span,
753 /// Message of the compile error
754 pub message: String,
755}
756
757impl CompileError {
758 /// Create a new compile error
759 pub fn new(span: Span, message: impl AsRef<str>) -> Self {
760 Self {
761 span,
762 message: message.as_ref().to_string(),
763 }
764 }
765}
766
767impl IntoIterator for CompileError {
768 type Item = TokenTree;
769 type IntoIter = std::array::IntoIter<Self::Item, 8>;
770
771 fn into_iter(self) -> Self::IntoIter {
772 [
773 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(self.span),
774 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(self.span),
775 TokenTree::Ident(Ident::new("core", self.span)),
776 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(self.span),
777 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(self.span),
778 TokenTree::Ident(Ident::new("compile_error", self.span)),
779 TokenTree::Punct(Punct::new('!', Spacing::Alone)).with_span(self.span),
780 TokenTree::Group(Group::new(Delimiter::Brace, {
781 TokenStream::from(
782 TokenTree::Literal(Literal::string(&self.message)).with_span(self.span),
783 )
784 }))
785 .with_span(self.span),
786 ]
787 .into_iter()
788 }
789}
790
791trait TokenTreeExt {
792 /// Set span of `TokenTree` without needing to create a new binding
793 fn with_span(self, span: Span) -> TokenTree;
794}
795
796impl TokenTreeExt for TokenTree {
797 fn with_span(mut self, span: Span) -> TokenTree {
798 self.set_span(span);
799 self
800 }
801}