darling_core/util/
preserved_str_expr.rs

1use crate::{FromMeta, Result};
2use syn::Expr;
3
4/// A wrapper around [`Expr`] that preserves the original expression
5/// without evaluating it.
6///
7/// For compatibility reasons, `darling` evaluates the expression inside string
8/// literals, which might be undesirable. In many cases,
9/// [`darling::util::parse_expr::preserve_str_literal`] can be used. However,
10/// when using [`Expr`] inside a container (such as a
11/// [`HashMap`](std::collections::HashMap)), it is not possible to use it.
12///
13/// This wrapper preserves the original expression without evaluating it.
14///
15/// # Example
16///
17/// ```ignore
18/// #[derive(FromMeta)]
19/// #[darling(attributes(demo))]
20/// struct Demo {
21///     option: Option<HashMap<syn::Ident, PreservedStrExpr>>,
22/// }
23/// ```
24#[repr(transparent)]
25#[derive(Debug, Clone, Eq, PartialEq, Hash)]
26pub struct PreservedStrExpr(pub Expr);
27
28impl FromMeta for PreservedStrExpr {
29    fn from_expr(expr: &Expr) -> Result<Self> {
30        Ok(Self(expr.clone()))
31    }
32}
33
34impl From<Expr> for PreservedStrExpr {
35    fn from(value: Expr) -> Self {
36        Self(value)
37    }
38}
39
40impl From<PreservedStrExpr> for Expr {
41    fn from(value: PreservedStrExpr) -> Self {
42        value.0
43    }
44}
45
46impl quote::ToTokens for PreservedStrExpr {
47    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
48        self.0.to_tokens(tokens);
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55    use syn::{parse_quote, Meta, MetaNameValue};
56
57    #[test]
58    fn preserved_str_expr_from_meta() {
59        let name_value: MetaNameValue = parse_quote!(test = "Hello, world!");
60        let preserved = PreservedStrExpr::from_meta(&Meta::NameValue(name_value)).unwrap();
61
62        assert_eq!(preserved.0, parse_quote!("Hello, world!"));
63    }
64}