1 use proc_macro2::TokenStream; 2 use quote::ToTokens; 3 use syn::token; 4 5 pub 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 13 macro_rules! quote_expr { 14 ($($tt:tt)*) => { 15 $crate::fragment::Fragment::Expr(quote!($($tt)*)) 16 } 17 } 18 19 macro_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. 27 pub struct Expr(pub Fragment); 28 impl ToTokens for Expr { to_tokens(&self, out: &mut TokenStream)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. 40 pub struct Stmts(pub Fragment); 41 impl ToTokens for Stmts { to_tokens(&self, out: &mut TokenStream)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. 52 pub struct Match(pub Fragment); 53 impl ToTokens for Match { to_tokens(&self, out: &mut TokenStream)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 67 impl AsRef<TokenStream> for Fragment { as_ref(&self) -> &TokenStream68 fn as_ref(&self) -> &TokenStream { 69 match self { 70 Fragment::Expr(expr) => expr, 71 Fragment::Block(block) => block, 72 } 73 } 74 } 75