1use proc_macro2::TokenStream as TokenStream2;
2use quote::ToTokens;
3use std::hash;
4use syn::{parse::Parse, spanned::Spanned, token::Brace, Expr};
5
6#[derive(Clone, Debug)]
11pub struct PartialExpr {
12 pub brace: Option<Brace>,
13 pub expr: TokenStream2,
14}
15
16impl Parse for PartialExpr {
17 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
18 if !input.peek(syn::token::Brace) {
20 let expr = input.parse::<syn::Expr>()?;
21 return Ok(Self {
22 brace: None,
23 expr: expr.to_token_stream(),
24 });
25 }
26
27 let content;
28 let brace = Some(syn::braced!(content in input));
29 let expr: TokenStream2 = content.parse()?;
30
31 Ok(Self { brace, expr })
32 }
33}
34
35impl ToTokens for PartialExpr {
36 fn to_tokens(&self, tokens: &mut TokenStream2) {
37 match &self.brace {
38 Some(brace) => brace.surround(tokens, |tokens| self.expr.to_tokens(tokens)),
39 _ => self.expr.to_tokens(tokens),
40 }
41 }
42}
43
44impl PartialExpr {
45 pub fn as_expr(&self) -> syn::Result<syn::Expr> {
46 if let Some(brace) = &self.brace {
49 let mut tokens = TokenStream2::new();
50 let f = |tokens: &mut TokenStream2| self.expr.to_tokens(tokens);
51 brace.surround(&mut tokens, f);
52 return syn::parse2(tokens);
53 }
54
55 let expr = self.expr.clone();
56 syn::parse2(expr.to_token_stream())
57 }
58
59 pub fn from_expr(expr: &Expr) -> Self {
60 Self {
61 brace: None,
62 expr: expr.to_token_stream(),
63 }
64 }
65 pub fn span(&self) -> proc_macro2::Span {
66 if let Some(brace) = &self.brace {
67 brace.span.span()
68 } else {
69 self.expr.span()
70 }
71 }
72}
73
74impl PartialEq for PartialExpr {
75 fn eq(&self, other: &Self) -> bool {
76 self.expr.to_string() == other.expr.to_string()
77 }
78}
79
80impl Eq for PartialExpr {}
81
82impl hash::Hash for PartialExpr {
83 fn hash<H: hash::Hasher>(&self, state: &mut H) {
84 self.expr.to_string().hash(state);
85 }
86}