3.6 KiB
Rust Quasi-Quoting
Quasi-quoting without a Syntex dependency, intended for use with Macros 1.1.
[dependencies]
quote = "0.3"
#[macro_use]
extern crate quote;
What is quasi-quoting?
Quasi-quoting is a way of writing code and treating it as data, similar to writing code inside of a double-quoted string literal except more friendly to your text editor or IDE. It does not get in the way of syntax highlighting, brace matching, indentation, or autocompletion, all of which you would lose by writing code inside of double quotes.
Check out my meetup talk on the topic to learn more about the use case. Start the video at 3:00.
This crate is motivated by the Macros 1.1 use case, but is a general-purpose Rust quasi-quoting library and is not specific to procedural macros.
Syntax
The quote crate provides a quote!
macro within which you can write Rust code
that gets packaged into a quote::Tokens
and can be treated as data. You should
think of quote::Tokens
as representing a fragment of Rust source code. Call
to_string()
or as_str()
on a Tokens to get back the fragment of source code
as a string.
Within the quote!
macro, interpolation is done with #var
. Any type
implementing the quote::ToTokens
trait can be interpolated. This includes most
Rust primitive types as well as most of the syntax tree types from
syn
.
let tokens = quote! {
struct SerializeWith #generics #where_clause {
value: &'a #field_ty,
phantom: ::std::marker::PhantomData<#item_ty>,
}
impl #generics serde::Serialize for SerializeWith #generics #where_clause {
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
where S: serde::Serializer
{
#path(self.value, s)
}
}
SerializeWith {
value: #value,
phantom: ::std::marker::PhantomData::<#item_ty>,
}
};
Repetition is done using #(...)*
or #(...),*
very similar to macro_rules!
:
#(#var)*
- no separators#(#var),*
- the character before the asterisk is used as a separator#( struct #var; )*
- the repetition can contain other things#( #k => println!("{}", #v), )*
- even multiple interpolations
Tokens can be interpolated into other quotes:
let t = quote! { /* ... */ };
return quote! { /* ... */ #t /* ... */ };
The quote!
macro relies on deep recursion so some large invocations may fail
with "recursion limit reached" when you compile. If it fails, bump up the
recursion limit by adding #![recursion_limit = "128"]
to your crate. An even
higher limit may be necessary for especially large invocations. You don't need
this unless the compiler tells you that you need it.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.