| 1 | use quote::ToTokens; |
| 2 | |
| 3 | use crate::{Error, FromMeta, Result}; |
| 4 | |
| 5 | /// Either a path or a closure. |
| 6 | /// |
| 7 | /// This type is useful for options that historically took a path, |
| 8 | /// e.g. `#[darling(with = ...)]` or `#[serde(skip_serializing_if = ...)]` |
| 9 | /// and now want to also allow using a closure to avoid needing a separate |
| 10 | /// function declaration. |
| 11 | /// |
| 12 | /// In `darling`, this value is wrapped in [`core::convert::identity`] before usage; |
| 13 | /// this allows treatment of the closure and path cases as equivalent, and prevents |
| 14 | /// a closure from accessing locals in the generated code. |
| 15 | #[derive (Debug, Clone)] |
| 16 | pub struct Callable { |
| 17 | /// The callable |
| 18 | call: syn::Expr, |
| 19 | } |
| 20 | |
| 21 | impl AsRef<syn::Expr> for Callable { |
| 22 | fn as_ref(&self) -> &syn::Expr { |
| 23 | &self.call |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | impl From<syn::ExprPath> for Callable { |
| 28 | fn from(value: syn::ExprPath) -> Self { |
| 29 | Self { |
| 30 | call: syn::Expr::Path(value), |
| 31 | } |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | impl From<syn::ExprClosure> for Callable { |
| 36 | fn from(value: syn::ExprClosure) -> Self { |
| 37 | Self { |
| 38 | call: syn::Expr::Closure(value), |
| 39 | } |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | impl From<Callable> for syn::Expr { |
| 44 | fn from(value: Callable) -> Self { |
| 45 | value.call |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | impl FromMeta for Callable { |
| 50 | fn from_expr(expr: &syn::Expr) -> Result<Self> { |
| 51 | match expr { |
| 52 | syn::Expr::Path(_) | syn::Expr::Closure(_) => Ok(Self { call: expr.clone() }), |
| 53 | _ => Err(Error::unexpected_expr_type(expr)), |
| 54 | } |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | impl ToTokens for Callable { |
| 59 | fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
| 60 | self.call.to_tokens(tokens); |
| 61 | } |
| 62 | } |
| 63 | |