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: &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.
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: &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.
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: &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
67impl 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