Skip to main content

thiserror_impl/
attr.rs

1use proc_macro2::{Delimiter, Group, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
2use quote::{format_ident, quote, quote_spanned, ToTokens};
3use std::collections::BTreeSet as Set;
4use syn::parse::discouraged::Speculative;
5use syn::parse::{End, ParseStream};
6use syn::{
7    braced, bracketed, parenthesized, token, Attribute, Error, ExprPath, Ident, Index, LitFloat,
8    LitInt, LitStr, Meta, Result, Token,
9};
10
11pub struct Attrs<'a> {
12    pub display: Option<Display<'a>>,
13    pub source: Option<Source<'a>>,
14    pub backtrace: Option<&'a Attribute>,
15    pub from: Option<From<'a>>,
16    pub transparent: Option<Transparent<'a>>,
17    pub fmt: Option<Fmt<'a>>,
18}
19
20#[derive(#[automatically_derived]
impl<'a> ::core::clone::Clone for Display<'a> {
    #[inline]
    fn clone(&self) -> Self {
        Self {
            original: ::core::clone::Clone::clone(&self.original),
            fmt: ::core::clone::Clone::clone(&self.fmt),
            args: ::core::clone::Clone::clone(&self.args),
            requires_fmt_machinery: ::core::clone::Clone::clone(&self.requires_fmt_machinery),
            has_bonus_display: ::core::clone::Clone::clone(&self.has_bonus_display),
            infinite_recursive: ::core::clone::Clone::clone(&self.infinite_recursive),
            implied_bounds: ::core::clone::Clone::clone(&self.implied_bounds),
            bindings: ::core::clone::Clone::clone(&self.bindings),
        }
    }
}Clone)]
21pub struct Display<'a> {
22    pub original: &'a Attribute,
23    pub fmt: LitStr,
24    pub args: TokenStream,
25    pub requires_fmt_machinery: bool,
26    pub has_bonus_display: bool,
27    pub infinite_recursive: bool,
28    pub implied_bounds: Set<(usize, Trait)>,
29    pub bindings: Vec<(Ident, TokenStream)>,
30}
31
32#[derive(#[automatically_derived]
impl<'a> ::core::marker::Copy for Source<'a> { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl<'a> ::core::clone::TrivialClone for Source<'a> { }
#[automatically_derived]
impl<'a> ::core::clone::Clone for Source<'a> {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<&'a Attribute>;
        let _: ::core::clone::AssertParamIsClone<Span>;
        *self
    }
}Clone)]
33pub struct Source<'a> {
34    pub original: &'a Attribute,
35    pub span: Span,
36}
37
38#[derive(#[automatically_derived]
impl<'a> ::core::marker::Copy for From<'a> { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl<'a> ::core::clone::TrivialClone for From<'a> { }
#[automatically_derived]
impl<'a> ::core::clone::Clone for From<'a> {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<&'a Attribute>;
        let _: ::core::clone::AssertParamIsClone<Span>;
        *self
    }
}Clone)]
39pub struct From<'a> {
40    pub original: &'a Attribute,
41    pub span: Span,
42}
43
44#[derive(#[automatically_derived]
impl<'a> ::core::marker::Copy for Transparent<'a> { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl<'a> ::core::clone::TrivialClone for Transparent<'a> { }
#[automatically_derived]
impl<'a> ::core::clone::Clone for Transparent<'a> {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<&'a Attribute>;
        let _: ::core::clone::AssertParamIsClone<Span>;
        *self
    }
}Clone)]
45pub struct Transparent<'a> {
46    pub original: &'a Attribute,
47    pub span: Span,
48}
49
50#[derive(#[automatically_derived]
impl<'a> ::core::clone::Clone for Fmt<'a> {
    #[inline]
    fn clone(&self) -> Self {
        Self {
            original: ::core::clone::Clone::clone(&self.original),
            path: ::core::clone::Clone::clone(&self.path),
        }
    }
}Clone)]
51pub struct Fmt<'a> {
52    pub original: &'a Attribute,
53    pub path: ExprPath,
54}
55
56#[derive(#[automatically_derived]
impl ::core::marker::Copy for Trait { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Trait { }
#[automatically_derived]
impl ::core::clone::Clone for Trait {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::Eq for Trait { }Eq, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for Trait { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Trait {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Ord for Trait {
    #[inline]
    fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr)
    }
}Ord, #[automatically_derived]
impl ::core::cmp::PartialOrd for Trait {
    #[inline]
    fn partial_cmp(&self, other: &Self)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
    }
}PartialOrd, #[automatically_derived]
impl ::core::fmt::Debug for Trait {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                Trait::Debug => "Debug",
                Trait::Display => "Display",
                Trait::Octal => "Octal",
                Trait::LowerHex => "LowerHex",
                Trait::UpperHex => "UpperHex",
                Trait::Pointer => "Pointer",
                Trait::Binary => "Binary",
                Trait::LowerExp => "LowerExp",
                Trait::UpperExp => "UpperExp",
            })
    }
}Debug)]
57pub enum Trait {
58    Debug,
59    Display,
60    Octal,
61    LowerHex,
62    UpperHex,
63    Pointer,
64    Binary,
65    LowerExp,
66    UpperExp,
67}
68
69pub fn get(input: &[Attribute]) -> Result<Attrs> {
70    let mut attrs = Attrs {
71        display: None,
72        source: None,
73        backtrace: None,
74        from: None,
75        transparent: None,
76        fmt: None,
77    };
78
79    for attr in input {
80        if attr.path().is_ident("error") {
81            parse_error_attribute(&mut attrs, attr)?;
82        } else if attr.path().is_ident("source") {
83            attr.meta.require_path_only()?;
84            if attrs.source.is_some() {
85                return Err(Error::new_spanned(attr, "duplicate #[source] attribute"));
86            }
87            let span = (attr.pound_token.span)
88                .join(attr.bracket_token.span.join())
89                .unwrap_or(attr.path().get_ident().unwrap().span());
90            attrs.source = Some(Source {
91                original: attr,
92                span,
93            });
94        } else if attr.path().is_ident("backtrace") {
95            attr.meta.require_path_only()?;
96            if attrs.backtrace.is_some() {
97                return Err(Error::new_spanned(attr, "duplicate #[backtrace] attribute"));
98            }
99            attrs.backtrace = Some(attr);
100        } else if attr.path().is_ident("from") {
101            match attr.meta {
102                Meta::Path(_) => {}
103                Meta::List(_) | Meta::NameValue(_) => {
104                    // Assume this is meant for derive_more crate or something.
105                    continue;
106                }
107            }
108            if attrs.from.is_some() {
109                return Err(Error::new_spanned(attr, "duplicate #[from] attribute"));
110            }
111            let span = (attr.pound_token.span)
112                .join(attr.bracket_token.span.join())
113                .unwrap_or(attr.path().get_ident().unwrap().span());
114            attrs.from = Some(From {
115                original: attr,
116                span,
117            });
118        }
119    }
120
121    Ok(attrs)
122}
123
124fn parse_error_attribute<'a>(attrs: &mut Attrs<'a>, attr: &'a Attribute) -> Result<()> {
125    mod kw {
126        #[allow(non_camel_case_types)]
pub struct transparent {
    #[allow(dead_code)]
    pub span: ::syn::__private::Span,
}
#[doc(hidden)]
#[allow(dead_code, non_snake_case)]
pub fn transparent<__S: ::syn::__private::IntoSpans<::syn::__private::Span>>(span:
        __S) -> transparent {
    transparent { span: ::syn::__private::IntoSpans::into_spans(span) }
}
const _: () =
    {
        impl ::syn::__private::Default for transparent {
            fn default() -> Self {
                transparent { span: ::syn::__private::Span::call_site() }
            }
        }
        impl ::syn::__private::CustomToken for transparent {
            fn peek(cursor: ::syn::buffer::Cursor) -> ::syn::__private::bool {
                if let ::syn::__private::Some((ident, _rest)) = cursor.ident()
                    {
                    ident == "transparent"
                } else { false }
            }
            fn display() -> &'static ::syn::__private::str { "`transparent`" }
        }
        impl ::syn::parse::Parse for transparent {
            fn parse(input: ::syn::parse::ParseStream)
                -> ::syn::parse::Result<transparent> {
                input.step(|cursor|
                        {
                            if let ::syn::__private::Some((ident, rest)) =
                                    cursor.ident() {
                                if ident == "transparent" {
                                    return ::syn::__private::Ok((transparent {
                                                    span: ident.span(),
                                                }, rest));
                                }
                            }
                            ::syn::__private::Err(cursor.error("expected `transparent`"))
                        })
            }
        }
        impl ::syn::__private::ToTokens for transparent {
            fn to_tokens(&self, tokens: &mut ::syn::__private::TokenStream2) {
                let ident = ::syn::Ident::new("transparent", self.span);
                ::syn::__private::TokenStreamExt::append(tokens, ident);
            }
        }
        impl ::syn::__private::Copy for transparent {}
        #[allow(clippy :: expl_impl_clone_on_copy)]
        impl ::syn::__private::Clone for transparent {
            fn clone(&self) -> Self { *self }
        }
        ;
    };syn::custom_keyword!(transparent);
127        #[allow(non_camel_case_types)]
pub struct fmt {
    #[allow(dead_code)]
    pub span: ::syn::__private::Span,
}
#[doc(hidden)]
#[allow(dead_code, non_snake_case)]
pub fn fmt<__S: ::syn::__private::IntoSpans<::syn::__private::Span>>(span:
        __S) -> fmt {
    fmt { span: ::syn::__private::IntoSpans::into_spans(span) }
}
const _: () =
    {
        impl ::syn::__private::Default for fmt {
            fn default() -> Self {
                fmt { span: ::syn::__private::Span::call_site() }
            }
        }
        impl ::syn::__private::CustomToken for fmt {
            fn peek(cursor: ::syn::buffer::Cursor) -> ::syn::__private::bool {
                if let ::syn::__private::Some((ident, _rest)) = cursor.ident()
                    {
                    ident == "fmt"
                } else { false }
            }
            fn display() -> &'static ::syn::__private::str { "`fmt`" }
        }
        impl ::syn::parse::Parse for fmt {
            fn parse(input: ::syn::parse::ParseStream)
                -> ::syn::parse::Result<fmt> {
                input.step(|cursor|
                        {
                            if let ::syn::__private::Some((ident, rest)) =
                                    cursor.ident() {
                                if ident == "fmt" {
                                    return ::syn::__private::Ok((fmt { span: ident.span() },
                                                rest));
                                }
                            }
                            ::syn::__private::Err(cursor.error("expected `fmt`"))
                        })
            }
        }
        impl ::syn::__private::ToTokens for fmt {
            fn to_tokens(&self, tokens: &mut ::syn::__private::TokenStream2) {
                let ident = ::syn::Ident::new("fmt", self.span);
                ::syn::__private::TokenStreamExt::append(tokens, ident);
            }
        }
        impl ::syn::__private::Copy for fmt {}
        #[allow(clippy :: expl_impl_clone_on_copy)]
        impl ::syn::__private::Clone for fmt {
            fn clone(&self) -> Self { *self }
        }
        ;
    };syn::custom_keyword!(fmt);
128    }
129
130    attr.parse_args_with(|input: ParseStream| {
131        let lookahead = input.lookahead1();
132        let fmt = if lookahead.peek(LitStr) {
133            input.parse::<LitStr>()?
134        } else if lookahead.peek(kw::transparent) {
135            let kw: kw::transparent = input.parse()?;
136            if attrs.transparent.is_some() {
137                return Err(Error::new_spanned(
138                    attr,
139                    "duplicate #[error(transparent)] attribute",
140                ));
141            }
142            attrs.transparent = Some(Transparent {
143                original: attr,
144                span: kw.span,
145            });
146            return Ok(());
147        } else if lookahead.peek(kw::fmt) {
148            input.parse::<kw::fmt>()?;
149            input.parse::<::syn::token::EqToken![=]>()?;
150            let path: ExprPath = input.parse()?;
151            if attrs.fmt.is_some() {
152                return Err(Error::new_spanned(
153                    attr,
154                    "duplicate #[error(fmt = ...)] attribute",
155                ));
156            }
157            attrs.fmt = Some(Fmt {
158                original: attr,
159                path,
160            });
161            return Ok(());
162        } else {
163            return Err(lookahead.error());
164        };
165
166        let args = if input.is_empty() || input.peek(::syn::token::CommaToken![,]) && input.peek2(End) {
167            input.parse::<Option<::syn::token::CommaToken![,]>>()?;
168            TokenStream::new()
169        } else {
170            parse_token_expr(input, false)?
171        };
172
173        let requires_fmt_machinery = !args.is_empty();
174
175        let display = Display {
176            original: attr,
177            fmt,
178            args,
179            requires_fmt_machinery,
180            has_bonus_display: false,
181            infinite_recursive: false,
182            implied_bounds: Set::new(),
183            bindings: Vec::new(),
184        };
185        if attrs.display.is_some() {
186            return Err(Error::new_spanned(
187                attr,
188                "only one #[error(...)] attribute is allowed",
189            ));
190        }
191        attrs.display = Some(display);
192        Ok(())
193    })
194}
195
196fn parse_token_expr(input: ParseStream, mut begin_expr: bool) -> Result<TokenStream> {
197    let mut tokens = Vec::new();
198    let mut turbofish = 0usize;
199    while !input.is_empty() {
200        if input.peek(token::Group) {
201            let group: TokenTree = input.parse()?;
202            tokens.push(group);
203            begin_expr = false;
204            continue;
205        }
206
207        if begin_expr && input.peek(::syn::token::DotToken![.]) {
208            if input.peek2(Ident) {
209                input.parse::<::syn::token::DotToken![.]>()?;
210                begin_expr = false;
211                continue;
212            } else if input.peek2(LitInt) {
213                input.parse::<::syn::token::DotToken![.]>()?;
214                let int: Index = input.parse()?;
215                tokens.push({
216                    let ident = match ::quote::__private::IdentFragmentAdapter(&int.index) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("_{0}", arg))
                    }),
            ::quote::__private::Option::Some::<::quote::__private::Span>(int.span)),
}format_ident!("_{}", int.index, span = int.span);
217                    TokenTree::Ident(ident)
218                });
219                begin_expr = false;
220                continue;
221            } else if input.peek2(LitFloat) {
222                let ahead = input.fork();
223                ahead.parse::<::syn::token::DotToken![.]>()?;
224                let float: LitFloat = ahead.parse()?;
225                let repr = float.to_string();
226                let mut indices = repr.split('.').map(syn::parse_str::<Index>);
227                if let (Some(Ok(first)), Some(Ok(second)), None) =
228                    (indices.next(), indices.next(), indices.next())
229                {
230                    input.advance_to(&ahead);
231                    tokens.push({
232                        let ident = match ::quote::__private::IdentFragmentAdapter(&first) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("_{0}", arg))
                    }),
            ::quote::__private::Option::Some::<::quote::__private::Span>(float.span())),
}format_ident!("_{}", first, span = float.span());
233                        TokenTree::Ident(ident)
234                    });
235                    tokens.push({
236                        let mut punct = Punct::new('.', Spacing::Alone);
237                        punct.set_span(float.span());
238                        TokenTree::Punct(punct)
239                    });
240                    tokens.push({
241                        let mut literal = Literal::u32_unsuffixed(second.index);
242                        literal.set_span(float.span());
243                        TokenTree::Literal(literal)
244                    });
245                    begin_expr = false;
246                    continue;
247                }
248            }
249        }
250
251        let closes_turbofish = if input.peek(::syn::token::LtToken![<]) {
252            if turbofish > 0 || follows_path_sep(&tokens) {
253                turbofish += 1;
254            }
255            false
256        } else if turbofish > 0 && input.peek(::syn::token::GtToken![>]) && !follows_hyphen(&tokens) {
257            turbofish -= 1;
258            true
259        } else {
260            false
261        };
262
263        begin_expr = input.peek(::syn::token::BreakToken![break])
264            || input.peek(::syn::token::ContinueToken![continue])
265            || input.peek(::syn::token::IfToken![if])
266            || input.peek(::syn::token::InToken![in])
267            || input.peek(::syn::token::MatchToken![match])
268            || input.peek(::syn::token::MutToken![mut])
269            || input.peek(::syn::token::ReturnToken![return])
270            || input.peek(::syn::token::WhileToken![while])
271            || input.peek(::syn::token::PlusToken![+])
272            || input.peek(::syn::token::AndToken![&])
273            || input.peek(::syn::token::NotToken![!])
274            || input.peek(::syn::token::CaretToken![^])
275            || input.peek(::syn::token::CommaToken![,])
276            || input.peek(::syn::token::SlashToken![/])
277            || input.peek(::syn::token::EqToken![=])
278            || input.peek(::syn::token::GtToken![>]) && !closes_turbofish
279            || input.peek(::syn::token::LtToken![<])
280            || input.peek(::syn::token::OrToken![|])
281            || input.peek(::syn::token::PercentToken![%])
282            || input.peek(::syn::token::SemiToken![;])
283            || input.peek(::syn::token::StarToken![*])
284            || input.peek(::syn::token::MinusToken![-]);
285
286        let token: TokenTree = if input.peek(token::Paren) {
287            let content;
288            let delimiter = match ::syn::__private::parse_parens(&input) {
    ::syn::__private::Ok(parens) => {
        content = parens.content;
        _ = content;
        parens.token
    }
    ::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
}parenthesized!(content in input);
289            let nested = parse_token_expr(&content, true)?;
290            let mut group = Group::new(Delimiter::Parenthesis, nested);
291            group.set_span(delimiter.span.join());
292            TokenTree::Group(group)
293        } else if input.peek(token::Brace) {
294            let content;
295            let delimiter = match ::syn::__private::parse_braces(&input) {
    ::syn::__private::Ok(braces) => {
        content = braces.content;
        _ = content;
        braces.token
    }
    ::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
}braced!(content in input);
296            let nested = parse_token_expr(&content, true)?;
297            let mut group = Group::new(Delimiter::Brace, nested);
298            group.set_span(delimiter.span.join());
299            TokenTree::Group(group)
300        } else if input.peek(token::Bracket) {
301            let content;
302            let delimiter = match ::syn::__private::parse_brackets(&input) {
    ::syn::__private::Ok(brackets) => {
        content = brackets.content;
        _ = content;
        brackets.token
    }
    ::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
}bracketed!(content in input);
303            let nested = parse_token_expr(&content, true)?;
304            let mut group = Group::new(Delimiter::Bracket, nested);
305            group.set_span(delimiter.span.join());
306            TokenTree::Group(group)
307        } else {
308            input.parse()?
309        };
310        tokens.push(token);
311    }
312    Ok(TokenStream::from_iter(tokens))
313}
314
315fn follows_path_sep(tokens: &[TokenTree]) -> bool {
316    #[allow(non_exhaustive_omitted_patterns)] match tokens.last_chunk() {
    Some([TokenTree::Punct(p), TokenTree::Punct(q)]) if
        p.spacing() == Spacing::Joint && p.as_char() == ':' &&
            q.as_char() == ':' => true,
    _ => false,
}matches!(
317        tokens.last_chunk(),
318        Some([TokenTree::Punct(p), TokenTree::Punct(q)])
319            if p.spacing() == Spacing::Joint
320                && p.as_char() == ':'
321                && q.as_char() == ':',
322    )
323}
324
325fn follows_hyphen(tokens: &[TokenTree]) -> bool {
326    #[allow(non_exhaustive_omitted_patterns)] match tokens.last() {
    Some(TokenTree::Punct(p)) if
        p.spacing() == Spacing::Joint && p.as_char() == '-' => true,
    _ => false,
}matches!(
327        tokens.last(),
328        Some(TokenTree::Punct(p))
329            if p.spacing() == Spacing::Joint && p.as_char() == '-',
330    )
331}
332
333impl ToTokens for Display<'_> {
334    fn to_tokens(&self, tokens: &mut TokenStream) {
335        if self.infinite_recursive {
336            let span = self.fmt.span();
337            tokens.extend({
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_pound_spanned(&mut _s, _span);
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident_spanned(&mut _s, _span, "warn");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident_spanned(&mut _s, _span,
                        "unconditional_recursion");
                    _s
                });
            _s
        });
    ::quote::__private::push_ident_spanned(&mut _s, _span, "fn");
    ::quote::__private::push_ident_spanned(&mut _s, _span, "_fmt");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        { ::quote::__private::TokenStream::new() });
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident_spanned(&mut _s, _span, "_fmt");
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                { ::quote::__private::TokenStream::new() });
            _s
        });
    _s
}quote_spanned! {span=>
338                #[warn(unconditional_recursion)]
339                fn _fmt() { _fmt() }
340            });
341        }
342
343        let fmt = &self.fmt;
344        let args = &self.args;
345
346        // Currently `write!(f, "text")` produces less efficient code than
347        // `f.write_str("text")`. We recognize the case when the format string
348        // has no braces and no interpolated values, and generate simpler code.
349        let write = if self.requires_fmt_machinery {
350            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "write");
    ::quote::__private::push_bang(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "__formatter");
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&fmt, &mut _s);
            ::quote::ToTokens::to_tokens(&args, &mut _s);
            _s
        });
    _s
}quote! {
351                ::core::write!(__formatter, #fmt #args)
352            }
353        } else {
354            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "__formatter");
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "write_str");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&fmt, &mut _s);
            _s
        });
    _s
}quote! {
355                __formatter.write_str(#fmt)
356            }
357        };
358
359        tokens.extend(if self.bindings.is_empty() {
360            write
361        } else {
362            let locals = self.bindings.iter().map(|(local, _value)| local);
363            let values = self.bindings.iter().map(|(_local, value)| value);
364            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "match");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            {
                use ::quote::__private::ext::*;
                let has_iter = ::quote::__private::HasIterator::<false>;
                #[allow(unused_mut)]
                let (mut values, i) = values.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let values =
                        match values.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    ::quote::ToTokens::to_tokens(&values, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                }
            }
            _s
        });
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    {
                        use ::quote::__private::ext::*;
                        let has_iter = ::quote::__private::HasIterator::<false>;
                        #[allow(unused_mut)]
                        let (mut locals, i) = locals.quote_into_iter();
                        let has_iter = has_iter | i;
                        <_ as
                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                        while true {
                            let locals =
                                match locals.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            ::quote::ToTokens::to_tokens(&locals, &mut _s);
                            ::quote::__private::push_comma(&mut _s);
                        }
                    }
                    _s
                });
            ::quote::__private::push_fat_arrow(&mut _s);
            ::quote::ToTokens::to_tokens(&write, &mut _s);
            _s
        });
    _s
}quote! {
365                match (#(#values,)*) {
366                    (#(#locals,)*) => #write
367                }
368            }
369        });
370    }
371}
372
373impl ToTokens for Trait {
374    fn to_tokens(&self, tokens: &mut TokenStream) {
375        let trait_name = match self {
376            Trait::Debug => "Debug",
377            Trait::Display => "Display",
378            Trait::Octal => "Octal",
379            Trait::LowerHex => "LowerHex",
380            Trait::UpperHex => "UpperHex",
381            Trait::Pointer => "Pointer",
382            Trait::Binary => "Binary",
383            Trait::LowerExp => "LowerExp",
384            Trait::UpperExp => "UpperExp",
385        };
386        let ident = Ident::new(trait_name, Span::call_site());
387        tokens.extend({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "fmt");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    _s
}quote!(::core::fmt::#ident));
388    }
389}