• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Functions to use with `#[darling(with = "...")]` that control how quoted values
2 //! in [`Meta`] instances are parsed into [`Expr`] fields.
3 //!
4 //! Version 1 of syn did not permit expressions on the right-hand side of the `=` in a
5 //! [`MetaNameValue`](syn::MetaNameValue), so darling accepted string literals and then
6 //! parsed their contents as expressions.
7 //! Passing a string literal in this version would have required the use of a raw string
8 //! to add quotation marks inside the literal.
9 //!
10 //! Version 2 of syn removes the requirement that the right-hand side be a literal.
11 //! For most types, such as [`Path`](syn::Path), the [`FromMeta`] impl can accept the
12 //! version without quotation marks without causing ambiguity; a path cannot start and
13 //! end with quotation marks, so removal is automatic.
14 //!
15 //! [`Expr`] is the one type where this ambiguity is new and unavoidable. To address this,
16 //! this module provides different functions for different expected behaviors.
17 
18 use syn::{Expr, Meta};
19 
20 use crate::{Error, FromMeta};
21 
22 /// Parse a [`Meta`] to an [`Expr`]; if the value is a string literal, the emitted
23 /// expression will be a string literal.
preserve_str_literal(meta: &Meta) -> crate::Result<Expr>24 pub fn preserve_str_literal(meta: &Meta) -> crate::Result<Expr> {
25     match meta {
26         Meta::Path(_) => Err(Error::unsupported_format("path").with_span(meta)),
27         Meta::List(_) => Err(Error::unsupported_format("list").with_span(meta)),
28         Meta::NameValue(nv) => Ok(nv.value.clone()),
29     }
30 }
31 
32 /// Parse a [`Meta`] to an [`Expr`]; if the value is a string literal, the string's
33 /// contents will be parsed as an expression and emitted.
parse_str_literal(meta: &Meta) -> crate::Result<Expr>34 pub fn parse_str_literal(meta: &Meta) -> crate::Result<Expr> {
35     match meta {
36         Meta::Path(_) => Err(Error::unsupported_format("path").with_span(meta)),
37         Meta::List(_) => Err(Error::unsupported_format("list").with_span(meta)),
38         Meta::NameValue(nv) => {
39             if let Expr::Lit(expr_lit) = &nv.value {
40                 Expr::from_value(&expr_lit.lit)
41             } else {
42                 Ok(nv.value.clone())
43             }
44         }
45     }
46 }
47 
48 #[cfg(test)]
49 mod tests {
50     use syn::parse_quote;
51 
52     use super::*;
53 
54     macro_rules! meta {
55         ($body:expr) => {
56             {
57                 let attr: ::syn::Attribute = ::syn::parse_quote!(#[ignore = $body]);
58                 attr.meta
59             }
60         };
61     }
62 
63     #[test]
preserve_str()64     fn preserve_str() {
65         assert_eq!(
66             preserve_str_literal(&meta!("World")).unwrap(),
67             parse_quote!("World")
68         );
69     }
70 
71     #[test]
preserve_binary_exp()72     fn preserve_binary_exp() {
73         assert_eq!(
74             preserve_str_literal(&meta!("World" + 5)).unwrap(),
75             parse_quote!("World" + 5)
76         )
77     }
78 
79     #[test]
parse_ident()80     fn parse_ident() {
81         assert_eq!(
82             parse_str_literal(&meta!("world")).unwrap(),
83             parse_quote!(world)
84         )
85     }
86 }
87