### Implementing ToTokens for a Custom Struct Source: https://docs.rs/quote/1.0.47/quote/trait.ToTokens.html Example implementation of ToTokens for a Path struct, demonstrating how to append tokens to a TokenStream. ```rust use proc_macro2::{TokenTree, Spacing, Span, Punct, TokenStream}; use quote::{TokenStreamExt, ToTokens}; pub struct Path { pub global: bool, pub segments: Vec, } impl ToTokens for Path { fn to_tokens(&self, tokens: &mut TokenStream) { for (i, segment) in self.segments.iter().enumerate() { if i > 0 || self.global { // Double colon `::` tokens.append(Punct::new(':', Spacing::Joint)); tokens.append(Punct::new(':', Spacing::Alone)); } segment.to_tokens(tokens); } } } ``` -------------------------------- ### Punctuation Helper Invocations Source: https://docs.rs/quote/1.0.47/src/quote/runtime.rs.html Examples of using the push_punct macro to define specific punctuation appending functions. ```rust push_punct!(push_add push_add_spanned '+'); ``` ```rust push_punct!(push_add_eq push_add_eq_spanned '+' '='); ``` ```rust push_punct!(push_and push_and_spanned '&'); ``` ```rust push_punct!(push_and_and push_and_and_spanned '&' '&'); ``` -------------------------------- ### Composing identifiers Source: https://docs.rs/quote/1.0.47/quote/macro.format_ident.html Examples of composing raw and non-raw identifiers using the macro. ```rust let my_ident = format_ident!("My{}", "Ident"); assert_eq!(my_ident, "MyIdent"); let raw = format_ident!("r#Raw"); assert_eq!(raw, "r#Raw"); let my_ident_raw = format_ident!("{}Is{}", my_ident, raw); assert_eq!(my_ident_raw, "MyIdentIsRaw"); ``` -------------------------------- ### Example compiler error output Source: https://docs.rs/quote/1.0.47/quote/macro.quote_spanned.html Shows how the compiler reports an error when a trait bound assertion fails using a spanned quote. ```text error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied --> src/main.rs:10:21 | 10 | static ref PTR: *const () = &(); | ^^^^^^^^^ `*const ()` cannot be shared between threads safely ``` -------------------------------- ### Integer formatting Source: https://docs.rs/quote/1.0.47/quote/macro.format_ident.html Demonstrates using different integer formatting options within the macro. ```rust let num: u32 = 10; let decimal = format_ident!("Id_{}", num); assert_eq!(decimal, "Id_10"); let octal = format_ident!("Id_{:o}", num); assert_eq!(octal, "Id_12"); let binary = format_ident!("Id_{:b}", num); assert_eq!(binary, "Id_1010"); let lower_hex = format_ident!("Id_{:x}", num); assert_eq!(lower_hex, "Id_a"); let upper_hex = format_ident!("Id_{:X}", num); assert_eq!(upper_hex, "Id_A"); ``` -------------------------------- ### Append tokens using append_all Source: https://docs.rs/quote/1.0.47/quote/trait.TokenStreamExt.html Demonstrates implementing ToTokens for a custom struct and using append_all to append multiple tokens to the TokenStream. ```rust struct X; impl ToTokens for X { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append_all(&[true, false]); } } let tokens = quote!(#X); assert_eq!(tokens.to_string(), "true false"); ``` -------------------------------- ### Constructing Identifiers Source: https://docs.rs/quote/1.0.47/quote/macro.quote.html Techniques for creating new identifiers, such as prepending an underscore, using format_ident! or syn::Ident. ```rust // incorrect quote! { let mut _#ident = 0; } ``` ```rust let varname = format_ident!("_{}", ident); quote! { let mut #varname = 0; } ``` ```rust let concatenated = format!("_{}", ident); let varname = syn::Ident::new(&concatenated, ident.span()); quote! { let mut #varname = 0; } ``` -------------------------------- ### Procedural Macro Implementation Source: https://docs.rs/quote/1.0.47/src/quote/lib.rs.html Basic structure for a procedural macro using the quote! macro to generate implementation code. ```rust #[cfg(any())] extern crate proc_macro; # extern crate proc_macro2; # #[cfg(any())] use proc_macro::TokenStream; # use proc_macro2::TokenStream; use quote::quote; # const IGNORE_TOKENS: &'static str = stringify! { #[proc_macro_derive(HeapSize)] # }; pub fn derive_heap_size(input: TokenStream) -> TokenStream { // Parse the input and figure out what implementation to generate... # const IGNORE_TOKENS: &'static str = stringify! { let name = /* ... */; let expr = /* ... */; # }; # # let name = 0; # let expr = 0; let expanded = quote! { // The generated impl. impl heapsize::HeapSize for #name { fn heap_size_of_children(&self) -> usize { #expr } } }; // Hand the output tokens back to the compiler. TokenStream::from(expanded) } ``` -------------------------------- ### Implement ToTokens for Token Types Source: https://docs.rs/quote/1.0.47/src/quote/to_tokens.rs.html Implementations for proc-macro token types. ```rust impl ToTokens for Group { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(self.clone()); } } ``` ```rust impl ToTokens for Ident { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(self.clone()); } } ``` ```rust impl ToTokens for Punct { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(self.clone()); } } ``` ```rust impl ToTokens for Literal { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(self.clone()); } } ``` ```rust impl ToTokens for TokenTree { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(self.clone()); } } ``` -------------------------------- ### Making Method Calls Source: https://docs.rs/quote/1.0.47/quote/macro.quote.html Invoking methods on types from macro input, using universal function call syntax to handle complex types like Vec. ```rust // incorrect quote! { let value = #field_type::new(); } ``` ```rust quote! { let value = <#field_type>::new(); } ``` ```rust quote! { let value = <#field_type as core::default::Default>::default(); } ``` -------------------------------- ### Implement ToTokens for C-Strings Source: https://docs.rs/quote/1.0.47/src/quote/to_tokens.rs.html Implementations for CStr and CString types. ```rust impl ToTokens for CStr { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(Literal::c_string(self)); } } ``` ```rust impl ToTokens for CString { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(Literal::c_string(self)); } } ``` -------------------------------- ### Implement ToTokens for TokenStream Source: https://docs.rs/quote/1.0.47/src/quote/to_tokens.rs.html Implementation for TokenStream, including into_token_stream. ```rust impl ToTokens for TokenStream { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.extend(iter::once(self.clone())); } fn into_token_stream(self) -> TokenStream { self } } ``` -------------------------------- ### Add quote dependency Source: https://docs.rs/quote/1.0.47/quote/index.html Include the quote crate in your Cargo.toml file. ```toml [dependencies] quote = "1.0" ``` -------------------------------- ### Token Iteration Macros Source: https://docs.rs/quote/1.0.47/src/quote/lib.rs.html Macros for iterating over token streams with context, used internally for interpolation. ```rust #[macro_export] #[doc(hidden)] macro_rules! quote_each_token { ($tokens:ident $($tts:tt)*) => { $crate::quote_tokens_with_context!{$tokens (@ @ @ @ @ @ $($tts)*) (@ @ @ @ @ $($tts)* @) (@ @ @ @ $($tts)* @ @) (@ @ @ $(($tts))* @ @ @) (@ @ $($tts)* @ @ @ @) (@ $($tts)* @ @ @ @ @) ($($tts)* @ @ @ @ @ @) } }; } ``` ```rust #[macro_export] #[doc(hidden)] macro_rules! quote_each_token_spanned { ($tokens:ident $span:ident $($tts:tt)*) => { $crate::quote_tokens_with_context_spanned!{$tokens $span (@ @ @ @ @ @ $($tts)*) (@ @ @ @ @ $($tts)* @) (@ @ @ @ $($tts)* @ @) (@ @ @ $(($tts))* @ @ @) (@ @ $($tts)* @ @ @ @) (@ $($tts)* @ @ @ @ @) ($($tts)* @ @ @ @ @ @) } }; } ``` -------------------------------- ### Using quote_spanned! for Token Generation Source: https://docs.rs/quote/1.0.47/src/quote/lib.rs.html Demonstrates how to use quote_spanned! with both single-line and multi-line syntax. ```rust // On one line, use parentheses. let tokens = quote_spanned!(span=> Box::into_raw(Box::new(#init))); // On multiple lines, place the span at the top and use braces. let tokens = quote_spanned! {span=> Box::into_raw(Box::new(#init)) }; ``` -------------------------------- ### Procedural Macro Structure Source: https://docs.rs/quote/1.0.47/quote/macro.quote.html Basic structure for a procedural macro using the quote crate to generate code. ```rust extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; #[proc_macro_derive(HeapSize)] pub fn derive_heap_size(input: TokenStream) -> TokenStream { // Parse the input and figure out what implementation to generate... let name = /* ... */; let expr = /* ... */; let expanded = quote! { // The generated impl. impl heapsize::HeapSize for #name { fn heap_size_of_children(&self) -> usize { #expr } } }; // Hand the output tokens back to the compiler. TokenStream::from(expanded) } ``` -------------------------------- ### Implement RepAsIteratorExt for Collections Source: https://docs.rs/quote/1.0.47/src/quote/runtime.rs.html Implementations of RepAsIteratorExt for standard collection types to support iteration within quote interpolations. ```rust impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec { type Iter = slice::Iter<'q, T>; fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator) { (self.iter(), HasIterator::) } } ``` ```rust impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet { type Iter = btree_set::Iter<'q, T>; fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator) { (self.iter(), HasIterator::) } } ``` -------------------------------- ### Implement IdentFragment for Ident Source: https://docs.rs/quote/1.0.47/src/quote/ident_fragment.rs.html Implementation for proc_macro2::Ident that strips the 'r#' prefix during formatting. ```rust impl IdentFragment for Ident { fn span(&self) -> Option { Some(self.span()) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let id = self.to_string(); if let Some(id) = id.strip_prefix("r#") { fmt::Display::fmt(id, f) } else { fmt::Display::fmt(&id[..], f) } } } ``` -------------------------------- ### quote! Source: https://docs.rs/quote/1.0.47/index.html The primary macro for quasi-quoting. It allows writing code-like syntax that is treated as data, enabling interpolation of runtime variables using the #var syntax. ```APIDOC ## quote! ### Description Produces a stream of tokens from the provided Rust-like syntax. It supports interpolation of variables using the # syntax. ### Usage ```rust let tokens = quote! { struct MyStruct { field: #field_type, } }; ``` ``` -------------------------------- ### Implement ToTokens for Primitive Types Source: https://docs.rs/quote/1.0.47/src/quote/to_tokens.rs.html Implementations for char and bool types. ```rust impl ToTokens for char { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(Literal::character(*self)); } } ``` ```rust impl ToTokens for bool { fn to_tokens(&self, tokens: &mut TokenStream) { let word = if *self { "true" } else { "false" }; tokens.append(Ident::new(word, Span::call_site())); } } ``` -------------------------------- ### Token Contextual Expansion Logic Source: https://docs.rs/quote/1.0.47/src/quote/lib.rs.html Core logic for handling token expansion, including repetition patterns with and without separators. ```rust #[macro_export] #[doc(hidden)] macro_rules! quote_token_with_context { ($tokens:ident $b3:tt $b2:tt $b1:tt @ $a1:tt $a2:tt $a3:tt) => {}; ($tokens:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) * $a3:tt) => {{ use $crate::__private::ext::*; let has_iter = $crate::__private::HasIterator::; $crate::pounded_var_names!{quote_bind_into_iter!(has_iter) () $($inner)*} <_ as $crate::__private::CheckHasIterator>::check(has_iter); while true { $crate::pounded_var_names!{quote_bind_next_or_break!() () $($inner)*} $crate::quote_each_token!{$tokens $($inner)*} } }}; ($tokens:ident $b3:tt $b2:tt # (( $($inner:tt)* )) * $a2:tt $a3:tt) => {}; ($tokens:ident $b3:tt # ( $($inner:tt)* ) (*) $a1:tt $a2:tt $a3:tt) => {}; ($tokens:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) $sep:tt *) => {{ use $crate::__private::ext::*; let mut _first = true; let has_iter = $crate::__private::HasIterator::; $crate::pounded_var_names!{quote_bind_into_iter!(has_iter) () $($inner)*} <_ as $crate::__private::CheckHasIterator>::check(has_iter); while true { $crate::pounded_var_names!{quote_bind_next_or_break!() () $($inner)*} if !_first { $crate::quote_token!{$sep $tokens} } _first = false; $crate::quote_each_token!{$tokens $($inner)*} } }}; ($tokens:ident $b3:tt $b2:tt # (( $($inner:tt)* )) $sep:tt * $a3:tt) => {}; ($tokens:ident $b3:tt # ( $($inner:tt)* ) ($sep:tt) * $a2:tt $a3:tt) => {}; } ``` -------------------------------- ### Internal Token Parsing Macro Source: https://docs.rs/quote/1.0.47/src/quote/lib.rs.html A helper macro for parsing tokens into the internal stream. ```rust ($other:tt $tokens:ident) => { $crate::__private::parse( &mut $tokens, $crate::__private::stringify!($other), ); }; } ``` -------------------------------- ### Macro definition Source: https://docs.rs/quote/1.0.47/quote/macro.format_ident.html The signature of the format_ident macro. ```rust macro_rules! format_ident { ($fmt:expr) => { ... }; ($fmt:expr, $($rest:tt)*) => { ... }; } ``` -------------------------------- ### IdentFragmentAdapter Struct Source: https://docs.rs/quote/1.0.47/src/quote/runtime.rs.html Adapter for IdentFragment to fmt::Display, used by format_ident!. ```rust #[derive(#[automatically_derived] impl ::core::marker::Copy for IdentFragmentAdapter { }Copy, #[automatically_derived] impl ::core::clone::Clone for IdentFragmentAdapter { #[inline] fn clone(&self) -> IdentFragmentAdapter { IdentFragmentAdapter(::core::clone::Clone::clone(&self.0)) } }Clone)] #[doc(hidden)] pub struct IdentFragmentAdapter(pub T); ``` -------------------------------- ### Implement IdentFragment for References Source: https://docs.rs/quote/1.0.47/src/quote/ident_fragment.rs.html Implementations for shared and mutable references to types that already implement IdentFragment. ```rust impl IdentFragment for &T { fn span(&self) -> Option { ::span(*self) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { IdentFragment::fmt(*self, f) } } impl IdentFragment for &mut T { fn span(&self) -> Option { ::span(*self) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { IdentFragment::fmt(*self, f) } } ``` -------------------------------- ### Implement ToTokens for Numeric Types Source: https://docs.rs/quote/1.0.47/src/quote/to_tokens.rs.html Implementations for integer and floating-point types using suffixed literals. ```rust impl ToTokens for isize { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(Literal::isize_suffixed(*self)); } } ``` ```rust impl ToTokens for u8 { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(Literal::u8_suffixed(*self)); } } ``` ```rust impl ToTokens for u16 { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(Literal::u16_suffixed(*self)); } } ``` ```rust impl ToTokens for u32 { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(Literal::u32_suffixed(*self)); } } ``` ```rust impl ToTokens for u64 { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(Literal::u64_suffixed(*self)); } } ``` ```rust impl ToTokens for u128 { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(Literal::u128_suffixed(*self)); } } ``` ```rust impl ToTokens for usize { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(Literal::usize_suffixed(*self)); } } ``` ```rust impl ToTokens for f32 { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(Literal::f32_suffixed(*self)); } } ``` ```rust impl ToTokens for f64 { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(Literal::f64_suffixed(*self)); } } ``` -------------------------------- ### Manage Token Spans Source: https://docs.rs/quote/1.0.47/src/quote/runtime.rs.html Utilities for wrapping and unwrapping spans, including joining logic for DelimSpan. ```rust impl GetSpan { #[inline] pub fn __into_span(self) -> Span { ((self.0).0).0 } } ``` ```rust impl GetSpanInner { #[inline] pub fn __into_span(&self) -> Span { (self.0).0.join() } } ``` -------------------------------- ### Implement IdentFragment for Primitive Types Source: https://docs.rs/quote/1.0.47/src/quote/ident_fragment.rs.html Implementations for common primitive types using the ident_fragment_display macro. ```rust impl IdentFragment for char { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } }ident_fragment_display!(bool, str, String, char); impl IdentFragment for usize { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } }ident_fragment_display!(u8, u16, u32, u64, u128, usize); ``` -------------------------------- ### Use quote! macro for code generation Source: https://docs.rs/quote/1.0.47/quote/index.html Interpolate runtime variables into tokens using the #var syntax within the quote! macro. ```rust let tokens = quote! { struct SerializeWith #generics #where_clause { value: &'a #field_ty, phantom: core::marker::PhantomData<#item_ty>, } impl #generics serde::Serialize for SerializeWith #generics #where_clause { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { #path(self.value, serializer) } } SerializeWith { value: #value, phantom: core::marker::PhantomData::<#item_ty>, } }; ``` -------------------------------- ### Spanned Token Generation Macros Source: https://docs.rs/quote/1.0.47/src/quote/lib.rs.html A collection of macro rules for pushing specific tokens with span metadata into a token stream. ```rust #[macro_export] #[doc(hidden)] macro_rules! quote_token_spanned { ($ident:ident $tokens:ident $span:ident) => { $crate::__private::push_ident_spanned( &mut $tokens, $span, $crate::__private::stringify!($ident), ); }; (:: $tokens:ident $span:ident) => { $crate::__private::push_colon2_spanned(&mut $tokens, $span); }; (( $($inner:tt)* ) $tokens:ident $span:ident) => { $crate::__private::push_group_spanned( &mut $tokens, $span, $crate::__private::Delimiter::Parenthesis, { $crate::quote_spanned_with_expanded_span!{$span $($inner)*} }, ); }; ([ $($inner:tt)* ] $tokens:ident $span:ident) => { $crate::__private::push_group_spanned( &mut $tokens, $span, $crate::__private::Delimiter::Bracket, { $crate::quote_spanned_with_expanded_span!{$span $($inner)*} }, ); }; ({ $($inner:tt)* } $tokens:ident $span:ident) => { $crate::__private::push_group_spanned( &mut $tokens, $span, $crate::__private::Delimiter::Brace, { $crate::quote_spanned_with_expanded_span!{$span $($inner)*} }, ); }; (# $tokens:ident $span:ident) => { $crate::__private::push_pound_spanned(&mut $tokens, $span); }; (, $tokens:ident $span:ident) => { $crate::__private::push_comma_spanned(&mut $tokens, $span); }; (. $tokens:ident $span:ident) => { $crate::__private::push_dot_spanned(&mut $tokens, $span); }; (; $tokens:ident $span:ident) => { $crate::__private::push_semi_spanned(&mut $tokens, $span); }; (: $tokens:ident $span:ident) => { $crate::__private::push_colon_spanned(&mut $tokens, $span); }; (+ $tokens:ident $span:ident) => { $crate::__private::push_add_spanned(&mut $tokens, $span); }; (+= $tokens:ident $span:ident) => { $crate::__private::push_add_eq_spanned(&mut $tokens, $span); }; (& $tokens:ident $span:ident) => { $crate::__private::push_and_spanned(&mut $tokens, $span); }; (&& $tokens:ident $span:ident) => { $crate::__private::push_and_and_spanned(&mut $tokens, $span); }; (&= $tokens:ident $span:ident) => { $crate::__private::push_and_eq_spanned(&mut $tokens, $span); }; (@ $tokens:ident $span:ident) => { $crate::__private::push_at_spanned(&mut $tokens, $span); }; (! $tokens:ident $span:ident) => { $crate::__private::push_bang_spanned(&mut $tokens, $span); }; (^ $tokens:ident $span:ident) => { $crate::__private::push_caret_spanned(&mut $tokens, $span); }; (^= $tokens:ident $span:ident) => { $crate::__private::push_caret_eq_spanned(&mut $tokens, $span); }; (/ $tokens:ident $span:ident) => { $crate::__private::push_div_spanned(&mut $tokens, $span); }; (/= $tokens:ident $span:ident) => { $crate::__private::push_div_eq_spanned(&mut $tokens, $span); }; (.. $tokens:ident $span:ident) => { $crate::__private::push_dot2_spanned(&mut $tokens, $span); }; (... $tokens:ident $span:ident) => { $crate::__private::push_dot3_spanned(&mut $tokens, $span); }; (..= $tokens:ident $span:ident) => { $crate::__private::push_dot_dot_eq_spanned(&mut $tokens, $span); }; (= $tokens:ident $span:ident) => { $crate::__private::push_eq_spanned(&mut $tokens, $span); }; (== $tokens:ident $span:ident) => { $crate::__private::push_eq_eq_spanned(&mut $tokens, $span); }; (>= $tokens:ident $span:ident) => { $crate::__private::push_ge_spanned(&mut $tokens, $span); }; (> $tokens:ident $span:ident) => { $crate::__private::push_gt_spanned(&mut $tokens, $span); }; (<= $tokens:ident $span:ident) => { $crate::__private::push_le_spanned(&mut $tokens, $span); }; } ``` -------------------------------- ### Token Pushing Macro Source: https://docs.rs/quote/1.0.47/src/quote/lib.rs.html Macro for pushing individual tokens into the token stream, ordered by frequency for performance. ```rust macro_rules! quote_token { ($ident:ident $tokens:ident) => { $crate::__private::push_ident( &mut $tokens, $crate::__private::stringify!($ident), ); }; (:: $tokens:ident) => { $crate::__private::push_colon2(&mut $tokens); }; (( $($inner:tt)* ) $tokens:ident) => { $crate::__private::push_group( &mut $tokens, $crate::__private::Delimiter::Parenthesis, $crate::quote!($($inner)*), ); }; ([ $($inner:tt)* ] $tokens:ident) => { $crate::__private::push_group( &mut $tokens, $crate::__private::Delimiter::Bracket, $crate::quote!($($inner)*), ); }; ({ $($inner:tt)* } $tokens:ident) => { ``` -------------------------------- ### Constructing identifiers Source: https://docs.rs/quote/1.0.47/src/quote/lib.rs.html Use format_ident! to safely concatenate identifiers, avoiding the pitfalls of simple token interpolation. ```rust # use proc_macro2::{self as syn, Span}; # use quote::quote; # # let ident = syn::Ident::new("i", Span::call_site()); # // incorrect quote! { let mut _#ident = 0; } ``` ```rust # use proc_macro2::{Ident, Span}; # use quote::{format_ident, quote}; # # let ident = Ident::new("i", Span::call_site()); # let varname = format_ident!("_{}", ident); quote! { let mut #varname = 0; } ``` ```rust # use proc_macro2::{self as syn, Span}; # use quote::quote; # # let ident = syn::Ident::new("i", Span::call_site()); # let concatenated = format!("_{}", ident); let varname = syn::Ident::new(&concatenated, ident.span()); quote! { let mut #varname = 0; } ``` -------------------------------- ### Append QUESTION punctuation Source: https://docs.rs/quote/1.0.47/src/quote/runtime.rs.html Functions to append the '?' character to a TokenStream. ```rust #[doc(hidden)] pub fn push_question(tokens: &mut TokenStream) { tokens.append(Punct::new('?', Spacing::Alone)); } #[doc(hidden)] pub fn push_question_spanned(tokens: &mut TokenStream, span: Span) { let mut punct = Punct::new('?', Spacing::Alone); punct.set_span(span); tokens.append(punct); }push_punct!(push_question push_question_spanned '?'); ``` -------------------------------- ### Append OR operator punctuation Source: https://docs.rs/quote/1.0.47/src/quote/runtime.rs.html Functions to append the '|' character to a TokenStream. ```rust pub fn push_or_spanned(tokens: &mut TokenStream, span: Span) { let mut punct = Punct::new('|', Spacing::Alone); punct.set_span(span); tokens.append(punct); }push_punct!(push_or push_or_spanned '|'); ``` -------------------------------- ### Macro Pattern Matching for format_ident_impl Source: https://docs.rs/quote/1.0.47/src/quote/format.rs.html Handles identifier formatting by matching spans and arguments, utilizing IdentFragmentAdapter for span resolution. ```rust 160 ([$span:expr, $($fmt:tt)*] $arg:expr) => { 161 $crate::format_ident_impl!([$span, $($fmt)*] $arg,) 162 }; 163 ([$span:expr, $($fmt:tt)*] $arg:expr, $($rest:tt)*) => { 164 match $crate::__private::IdentFragmentAdapter(&$arg) { 165 arg => $crate::format_ident_impl!([$span.or(arg.span()), $($fmt)*, arg] $($rest)*), 166 } 167 }; 168} ``` -------------------------------- ### Append dot-dot-dot Source: https://docs.rs/quote/1.0.47/src/quote/runtime.rs.html Appends three dots to the TokenStream. ```rust tokens.append(Punct::new('.', Spacing::Joint)); tokens.append(Punct::new('.', Spacing::Joint)); tokens.append(Punct::new('.', Spacing::Alone)); } #[doc(hidden)] pub fn push_dot3_spanned(tokens: &mut TokenStream, span: Span) { let mut punct = Punct::new('.', Spacing::Joint); punct.set_span(span); tokens.append(punct); let mut punct = Punct::new('.', Spacing::Joint); punct.set_span(span); tokens.append(punct); let mut punct = Punct::new('.', Spacing::Alone); punct.set_span(span); tokens.append(punct); }push_punct!(push_dot3 push_dot3_spanned '.' '.' '.'); ``` -------------------------------- ### Inheriting Span in format_ident! Source: https://docs.rs/quote/1.0.47/src/quote/format.rs.html Demonstrates how the span of an identifier argument is inherited by the resulting identifier. ```rust # use quote::format_ident; # let ident = format_ident!("Ident"); // If `ident` is an Ident, the span of `my_ident` will be inherited from it. let my_ident = format_ident!("My{}{}", ident, "IsCool"); assert_eq!(my_ident, "MyIdentIsCool"); ``` -------------------------------- ### Repetition Patterns Source: https://docs.rs/quote/1.0.47/quote/macro.quote.html Common patterns for repeating tokens within the quote macro. ```rust #(#var)* ``` ```rust #(#var),* ``` ```rust #( struct #var; )* ``` ```rust #( #k => println!("{}", #v), )* ``` -------------------------------- ### quote! Source: https://docs.rs/quote/1.0.47/quote/macro.quote.html The quote macro performs variable interpolation against the input and produces a proc_macro2::TokenStream. It supports variable interpolation using #var and repetition using #(...)* syntax. ```APIDOC ## macro_rules! quote ### Description Performs variable interpolation against the input and produces it as `proc_macro2::TokenStream`. This is the primary tool for generating code within procedural macros. ### Syntax ```rust quote!($($tt:tt)*) ``` ### Interpolation - **#var**: Interpolates a variable currently in scope. The type must implement the `ToTokens` trait. - **#(...)***: Repeats the body for each element in an interpolated collection (Vec, slice, BTreeSet, or Iterator). - **Separators**: Use characters before the asterisk (e.g., `#(#var),*`) to define separators between repeated elements. ### Usage Note To return tokens to the compiler in a procedural macro, use `.into()` on the result to convert the `proc_macro2::TokenStream` to `proc_macro::TokenStream`. ``` -------------------------------- ### Punctuation Generation Macro Source: https://docs.rs/quote/1.0.47/src/quote/runtime.rs.html A macro to generate functions for appending specific punctuation marks to a TokenStream, supporting both spanned and non-spanned versions. ```rust macro_rules! push_punct { ($name:ident $spanned:ident $char1:tt) => { #[doc(hidden)] pub fn $name(tokens: &mut TokenStream) { tokens.append(Punct::new($char1, Spacing::Alone)); } #[doc(hidden)] pub fn $spanned(tokens: &mut TokenStream, span: Span) { let mut punct = Punct::new($char1, Spacing::Alone); punct.set_span(span); tokens.append(punct); } }; ($name:ident $spanned:ident $char1:tt $char2:tt) => { #[doc(hidden)] pub fn $name(tokens: &mut TokenStream) { tokens.append(Punct::new($char1, Spacing::Joint)); tokens.append(Punct::new($char2, Spacing::Alone)); } #[doc(hidden)] pub fn $spanned(tokens: &mut TokenStream, span: Span) { let mut punct = Punct::new($char1, Spacing::Joint); punct.set_span(span); tokens.append(punct); let mut punct = Punct::new($char2, Spacing::Alone); punct.set_span(span); tokens.append(punct); } }; ($name:ident $spanned:ident $char1:tt $char2:tt $char3:tt) => { #[doc(hidden)] pub fn $name(tokens: &mut TokenStream) { tokens.append(Punct::new($char1, Spacing::Joint)); tokens.append(Punct::new($char2, Spacing::Joint)); tokens.append(Punct::new($char3, Spacing::Alone)); } #[doc(hidden)] pub fn $spanned(tokens: &mut TokenStream, span: Span) { let mut punct = Punct::new($char1, Spacing::Joint); punct.set_span(span); tokens.append(punct); let mut punct = Punct::new($char2, Spacing::Joint); punct.set_span(span); tokens.append(punct); let mut punct = Punct::new($char3, Spacing::Alone); punct.set_span(span); tokens.append(punct); } }; } ``` -------------------------------- ### format_ident! Source: https://docs.rs/quote/1.0.47/index.html A formatting macro specifically designed for constructing Ident (identifier) types. ```APIDOC ## format_ident! ### Description Constructs an Ident by formatting arguments, similar to how format! works for strings. ``` -------------------------------- ### Combining Quoted Fragments Source: https://docs.rs/quote/1.0.47/quote/macro.quote.html Interpolate tokens produced by multiple quote! invocations into a final TokenStream. ```rust let type_definition = quote! {...}; let methods = quote! {...}; let tokens = quote! { #type_definition #methods }; ``` -------------------------------- ### Append SHL punctuation Source: https://docs.rs/quote/1.0.47/src/quote/runtime.rs.html Functions to append the '<<' sequence to a TokenStream. ```rust #[doc(hidden)] pub fn push_shl(tokens: &mut TokenStream) { tokens.append(Punct::new('<', Spacing::Joint)); tokens.append(Punct::new('<', Spacing::Alone)); } #[doc(hidden)] pub fn push_shl_spanned(tokens: &mut TokenStream, span: Span) { ``` -------------------------------- ### format_ident! Macro Definition Source: https://docs.rs/quote/1.0.47/src/quote/format.rs.html The implementation of the format_ident! macro. ```rust #[macro_export] macro_rules! format_ident { ($fmt:expr) => { $crate::format_ident_impl!([ $crate::__private::Option::None, $fmt ]) }; ($fmt:expr, $($rest:tt)*) => { $crate::format_ident_impl!([ $crate::__private::Option::None, $fmt ] $($rest)*) }; } ``` -------------------------------- ### Internal Token Interpolation Macros Source: https://docs.rs/quote/1.0.47/src/quote/lib.rs.html Macros for handling token interpolation and repetition logic, including non-repetition and ordinary token processing. ```rust ($tokens:ident # ( $($inner:tt)* ) * (*) $a1:tt $a2:tt $a3:tt) => { // https://github.com/dtolnay/quote/issues/130 $crate::quote_token!{* $tokens} }; // ... and one step later. ($tokens:ident # ( $($inner:tt)* ) $sep:tt (*) $a1:tt $a2:tt $a3:tt) => {}; // A non-repetition interpolation. ($tokens:ident $b3:tt $b2:tt $b1:tt (#) $var:ident $a2:tt $a3:tt) => { $crate::ToTokens::to_tokens(&$var, &mut $tokens); }; // ... and one step later. ($tokens:ident $b3:tt $b2:tt # ($var:ident) $a1:tt $a2:tt $a3:tt) => {}; // An ordinary token, not part of any interpolation. ($tokens:ident $b3:tt $b2:tt $b1:tt ($curr:tt) $a1:tt $a2:tt $a3:tt) => { $crate::quote_token!{$curr $tokens} }; } ``` -------------------------------- ### Construct Identifiers Source: https://docs.rs/quote/1.0.47/src/quote/runtime.rs.html Helper functions for creating identifiers, including support for raw identifiers (r#). ```rust pub fn mk_ident(id: &str, span: Option) -> Ident { let span = span.unwrap_or_else(Span::call_site); ident_maybe_raw(id, span) } fn ident_maybe_raw(id: &str, span: Span) -> Ident { if let Some(id) = id.strip_prefix("r#") { Ident::new_raw(id, span) } else { Ident::new(id, span) } } ``` -------------------------------- ### format_ident_impl! Macro Definition Source: https://docs.rs/quote/1.0.47/src/quote/format.rs.html The internal implementation logic for the format_ident! macro. ```rust #[macro_export] #[doc(hidden)] macro_rules! format_ident_impl { // Final state ([$span:expr, $($fmt:tt)*]) => { $crate::__private::mk_ident( &$crate::__private::format!($($fmt)*), $span, ) }; // Span argument ([$old:expr, $($fmt:tt)*] span = $span:expr) => { $crate::format_ident_impl!([$old, $($fmt)*] span = $span,) }; ([$old:expr, $($fmt:tt)*] span = $span:expr, $($rest:tt)*) => { $crate::format_ident_impl!([ $crate::__private::Option::Some::<$crate::__private::Span>($span), $($fmt)* ] $($rest)*) }; // Named argument ([$span:expr, $($fmt:tt)*] $name:ident = $arg:expr) => { $crate::format_ident_impl!([$span, $($fmt)*] $name = $arg,) }; ([$span:expr, $($fmt:tt)*] $name:ident = $arg:expr, $($rest:tt)*) => { match $crate::__private::IdentFragmentAdapter(&$arg) { arg => $crate::format_ident_impl!([$span.or(arg.span()), $($fmt)*, $name = arg] $($rest)*), } }; // Positional argument ``` -------------------------------- ### Append At Punctuation Source: https://docs.rs/quote/1.0.47/src/quote/runtime.rs.html Appends '@' to the token stream, with an optional spanned version. ```rust #[doc(hidden)] pub fn push_at(tokens: &mut TokenStream) { tokens.append(Punct::new('@', Spacing::Alone)); } #[doc(hidden)] pub fn push_at_spanned(tokens: &mut TokenStream, span: Span) { let mut punct = Punct::new('@', Spacing::Alone); punct.set_span(span); tokens.append(punct); }push_punct!(push_at push_at_spanned '@'); ``` -------------------------------- ### Macro Token Pushing Rules Source: https://docs.rs/quote/1.0.47/src/quote/lib.rs.html These macro rules handle the conversion of various Rust tokens into their spanned counterparts within a token stream. They are intended for internal use within the crate's procedural macro infrastructure. ```rust (< $tokens:ident $span:ident) => { $crate::__private::push_lt_spanned(&mut $tokens, $span); }; (*= $tokens:ident $span:ident) => { $crate::__private::push_mul_eq_spanned(&mut $tokens, $span); }; (!= $tokens:ident $span:ident) => { $crate::__private::push_ne_spanned(&mut $tokens, $span); }; (| $tokens:ident $span:ident) => { $crate::__private::push_or_spanned(&mut $tokens, $span); }; (|= $tokens:ident $span:ident) => { $crate::__private::push_or_eq_spanned(&mut $tokens, $span); }; (|| $tokens:ident $span:ident) => { $crate::__private::push_or_or_spanned(&mut $tokens, $span); }; (? $tokens:ident $span:ident) => { $crate::__private::push_question_spanned(&mut $tokens, $span); }; (-> $tokens:ident $span:ident) => { $crate::__private::push_rarrow_spanned(&mut $tokens, $span); }; (<- $tokens:ident $span:ident) => { $crate::__private::push_larrow_spanned(&mut $tokens, $span); }; (% $tokens:ident $span:ident) => { $crate::__private::push_rem_spanned(&mut $tokens, $span); }; (%= $tokens:ident $span:ident) => { $crate::__private::push_rem_eq_spanned(&mut $tokens, $span); }; (=> $tokens:ident $span:ident) => { $crate::__private::push_fat_arrow_spanned(&mut $tokens, $span); }; (<< $tokens:ident $span:ident) => { $crate::__private::push_shl_spanned(&mut $tokens, $span); }; (<<= $tokens:ident $span:ident) => { $crate::__private::push_shl_eq_spanned(&mut $tokens, $span); }; (>> $tokens:ident $span:ident) => { $crate::__private::push_shr_spanned(&mut $tokens, $span); }; (>>= $tokens:ident $span:ident) => { $crate::__private::push_shr_eq_spanned(&mut $tokens, $span); }; (* $tokens:ident $span:ident) => { $crate::__private::push_star_spanned(&mut $tokens, $span); }; (- $tokens:ident $span:ident) => { $crate::__private::push_sub_spanned(&mut $tokens, $span); }; (-= $tokens:ident $span:ident) => { $crate::__private::push_sub_eq_spanned(&mut $tokens, $span); }; ($lifetime:lifetime $tokens:ident $span:ident) => { $crate::__private::push_lifetime_spanned( &mut $tokens, $span, $crate::__private::stringify!($lifetime), ); }; (_ $tokens:ident $span:ident) => { $crate::__private::push_underscore_spanned(&mut $tokens, $span); }; ($other:tt $tokens:ident $span:ident) => { $crate::__private::parse_spanned( &mut $tokens, $span, $crate::__private::stringify!($other), ); }; ``` -------------------------------- ### Append Comma Punctuation Source: https://docs.rs/quote/1.0.47/src/quote/runtime.rs.html Appends ',' to the token stream, with an optional spanned version. ```rust #[doc(hidden)] pub fn push_comma(tokens: &mut TokenStream) { tokens.append(Punct::new(',', Spacing::Alone)); } #[doc(hidden)] pub fn push_comma_spanned(tokens: &mut TokenStream, span: Span) { let mut punct = Punct::new(',', Spacing::Alone); punct.set_span(span); tokens.append(punct); }push_punct!(push_comma push_comma_spanned ','); ``` -------------------------------- ### Push Underscore Identifier Source: https://docs.rs/quote/1.0.47/src/quote/runtime.rs.html Appends an underscore identifier (_) to a TokenStream. ```rust #[doc(hidden)] pub fn push_underscore(tokens: &mut TokenStream) { push_underscore_spanned(tokens, Span::call_site()); } #[doc(hidden)] pub fn push_underscore_spanned(tokens: &mut TokenStream, span: Span) { tokens.append(Ident::new("_", span)); } ``` -------------------------------- ### Implement IdentFragment for Cow Source: https://docs.rs/quote/1.0.47/src/quote/ident_fragment.rs.html Implementation for Cow smart pointers where the inner type implements IdentFragment and ToOwned. ```rust impl IdentFragment for Cow<'_, T> where T: IdentFragment + ToOwned + ?Sized, { fn span(&self) -> Option { T::span(self) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { T::fmt(self, f) } } ``` -------------------------------- ### Use quote_spanned with different formatting Source: https://docs.rs/quote/1.0.47/quote/macro.quote_spanned.html Demonstrates using parentheses for single-line expressions and braces for multi-line expressions. ```rust let span = /* ... */; // On one line, use parentheses. let tokens = quote_spanned!(span=> Box::into_raw(Box::new(#init))); // On multiple lines, place the span at the top and use braces. let tokens = quote_spanned! {span=> Box::into_raw(Box::new(#init)) }; ```