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. |
24 | pub fn preserve_str_literal(meta: &Meta) -> crate::Result<Expr> { |
25 | match meta { |
26 | Meta::Path(_) => Err(Error::unsupported_format("path" ).with_span(node:meta)), |
27 | Meta::List(_) => Err(Error::unsupported_format("list" ).with_span(node:meta)), |
28 | Meta::NameValue(nv: &MetaNameValue) => 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. |
34 | pub fn parse_str_literal(meta: &Meta) -> crate::Result<Expr> { |
35 | match meta { |
36 | Meta::Path(_) => Err(Error::unsupported_format("path" ).with_span(node:meta)), |
37 | Meta::List(_) => Err(Error::unsupported_format("list" ).with_span(node:meta)), |
38 | Meta::NameValue(nv: &MetaNameValue) => { |
39 | if let Expr::Lit(expr_lit: &ExprLit) = &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 ] |
64 | fn preserve_str() { |
65 | assert_eq!( |
66 | preserve_str_literal(&meta!("World" )).unwrap(), |
67 | parse_quote!("World" ) |
68 | ); |
69 | } |
70 | |
71 | #[test ] |
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 ] |
80 | fn parse_ident() { |
81 | assert_eq!( |
82 | parse_str_literal(&meta!("world" )).unwrap(), |
83 | parse_quote!(world) |
84 | ) |
85 | } |
86 | } |
87 | |