1 | use proc_macro2::TokenStream; |
2 | use quote::ToTokens; |
3 | use syn::{token, 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 { |
29 | fn to_tokens(&self, out: &mut TokenStream) { |
30 | match &self.0 { |
31 | Fragment::Expr(expr: &TokenStream) => expr.to_tokens(out), |
32 | Fragment::Block(block: &TokenStream) => { |
33 | token::Brace::default().surround(tokens:out, |out: &mut TokenStream| 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 { |
42 | fn to_tokens(&self, out: &mut TokenStream) { |
43 | match &self.0 { |
44 | Fragment::Expr(expr: &TokenStream) => expr.to_tokens(out), |
45 | Fragment::Block(block: &TokenStream) => 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 { |
54 | fn to_tokens(&self, out: &mut TokenStream) { |
55 | match &self.0 { |
56 | Fragment::Expr(expr: &TokenStream) => { |
57 | expr.to_tokens(out); |
58 | <Token![,]>::default().to_tokens(out); |
59 | } |
60 | Fragment::Block(block: &TokenStream) => { |
61 | token::Brace::default().surround(tokens:out, |out: &mut TokenStream| block.to_tokens(out)); |
62 | } |
63 | } |
64 | } |
65 | } |
66 | |
67 | impl AsRef<TokenStream> for Fragment { |
68 | fn as_ref(&self) -> &TokenStream { |
69 | match self { |
70 | Fragment::Expr(expr: &TokenStream) => expr, |
71 | Fragment::Block(block: &TokenStream) => block, |
72 | } |
73 | } |
74 | } |
75 | |