Skip to main content

zyn_core/extract/
data.rs

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