Skip to main content

zyn_core/extract/
data.rs

1use proc_macro2::Span;
2use syn::spanned::Spanned;
3
4use crate::diagnostic::Diagnostics;
5use crate::types::Input;
6
7use super::FromInput;
8
9/// Converts `syn::Data` into a specific data representation.
10///
11/// Implementations exist for `syn::Data` (any kind), `syn::DataStruct`,
12/// `syn::DataEnum`, and `syn::DataUnion`.
13pub trait FromData: Sized {
14    fn from_data(data: syn::Data) -> crate::Result<Self>;
15}
16
17impl FromData for syn::Data {
18    fn from_data(data: syn::Data) -> crate::Result<Self> {
19        Ok(data)
20    }
21}
22
23impl FromData for syn::DataStruct {
24    fn from_data(data: syn::Data) -> crate::Result<Self> {
25        match data {
26            syn::Data::Struct(s) => Ok(s),
27            _ => Err(Diagnostics::error(
28                Span::call_site(),
29                "expected struct data",
30            )),
31        }
32    }
33}
34
35impl FromData for syn::DataEnum {
36    fn from_data(data: syn::Data) -> crate::Result<Self> {
37        match data {
38            syn::Data::Enum(e) => Ok(e),
39            _ => Err(Diagnostics::error(Span::call_site(), "expected enum data")),
40        }
41    }
42}
43
44impl FromData for syn::DataUnion {
45    fn from_data(data: syn::Data) -> crate::Result<Self> {
46        match data {
47            syn::Data::Union(u) => Ok(u),
48            _ => Err(Diagnostics::error(Span::call_site(), "expected union data")),
49        }
50    }
51}
52
53/// Element extractor that pulls the `syn::Data` from a derive input.
54///
55/// Defaults to `syn::Data` (accepts any kind). Parameterize with
56/// `syn::DataStruct`, `syn::DataEnum`, or `syn::DataUnion` to restrict
57/// and validate. Access the inner value via `Deref` or the `inner()` method.
58///
59/// ```ignore
60/// #[zyn::element]
61/// fn my_element(#[zyn(input)] data: zyn::Data<syn::DataStruct>) -> proc_macro2::TokenStream {
62///     // data.fields — accessed via Deref to syn::DataStruct
63/// }
64/// ```
65pub struct Data<T: FromData = syn::Data>(T);
66
67impl<T: FromData> Data<T> {
68    pub fn inner(self) -> T {
69        self.0
70    }
71}
72
73impl<T: FromData> std::ops::Deref for Data<T> {
74    type Target = T;
75
76    fn deref(&self) -> &Self::Target {
77        &self.0
78    }
79}
80
81impl<T: FromData> std::ops::DerefMut for Data<T> {
82    fn deref_mut(&mut self) -> &mut Self::Target {
83        &mut self.0
84    }
85}
86
87impl<T: FromData> FromInput for Data<T> {
88    fn from_input(input: &Input) -> crate::Result<Self> {
89        match input {
90            Input::Derive(d) => T::from_data(d.data.clone()).map(Data),
91            _ => Err(Diagnostics::error(
92                input.span(),
93                "Data extractor requires derive input",
94            )),
95        }
96    }
97}