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}
63