darling_core/util/
callable.rs

1use quote::ToTokens;
2
3use 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)]
16pub struct Callable {
17    /// The callable
18    call: syn::Expr,
19}
20
21impl AsRef<syn::Expr> for Callable {
22    fn as_ref(&self) -> &syn::Expr {
23        &self.call
24    }
25}
26
27impl From<syn::ExprPath> for Callable {
28    fn from(value: syn::ExprPath) -> Self {
29        Self {
30            call: syn::Expr::Path(value),
31        }
32    }
33}
34
35impl From<syn::ExprClosure> for Callable {
36    fn from(value: syn::ExprClosure) -> Self {
37        Self {
38            call: syn::Expr::Closure(value),
39        }
40    }
41}
42
43impl From<Callable> for syn::Expr {
44    fn from(value: Callable) -> Self {
45        value.call
46    }
47}
48
49impl 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
58impl ToTokens for Callable {
59    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
60        self.call.to_tokens(tokens);
61    }
62}