serde_derive/
fragment.rs

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}