1use proc_macro2::TokenStream; 2use quote::ToTokens; 3use syn::{token, Token}; 4 5pub enum Fragment { 6 /// Tokens that can be used as an expression. 7 Expr(TokenStream), 8 /// Tokens that can be used inside a block. The surrounding curly braces are 9 /// not part of these tokens. 10 Block(TokenStream), 11} 12 13macro_rules! quote_expr { 14 ($($tt:tt)*) => { 15 $crate::fragment::Fragment::Expr(quote!($($tt)*)) 16 } 17} 18 19macro_rules! quote_block { 20 ($($tt:tt)*) => { 21 $crate::fragment::Fragment::Block(quote!($($tt)*)) 22 } 23} 24 25/// Interpolate a fragment in place of an expression. This involves surrounding 26/// Block fragments in curly braces. 27pub struct Expr(pub Fragment); 28impl ToTokens for Expr { 29 fn to_tokens(&self, out: &mut TokenStream) { 30 match &self.0 { 31 Fragment::Expr(expr) => expr.to_tokens(out), 32 Fragment::Block(block) => { 33 token::Brace::default().surround(out, |out| block.to_tokens(out)); 34 } 35 } 36 } 37} 38 39/// Interpolate a fragment as the statements of a block. 40pub struct Stmts(pub Fragment); 41impl ToTokens for Stmts { 42 fn to_tokens(&self, out: &mut TokenStream) { 43 match &self.0 { 44 Fragment::Expr(expr) => expr.to_tokens(out), 45 Fragment::Block(block) => block.to_tokens(out), 46 } 47 } 48} 49 50/// Interpolate a fragment as the value part of a `match` expression. This 51/// involves putting a comma after expressions and curly braces around blocks. 52pub struct Match(pub Fragment); 53impl ToTokens for Match { 54 fn to_tokens(&self, out: &mut TokenStream) { 55 match &self.0 { 56 Fragment::Expr(expr) => { 57 expr.to_tokens(out); 58 <Token![,]>::default().to_tokens(out); 59 } 60 Fragment::Block(block) => { 61 token::Brace::default().surround(out, |out| block.to_tokens(out)); 62 } 63 } 64 } 65} 66 67impl AsRef<TokenStream> for Fragment { 68 fn as_ref(&self) -> &TokenStream { 69 match self { 70 Fragment::Expr(expr) => expr, 71 Fragment::Block(block) => block, 72 } 73 } 74} 75