Skip to main content

zyn_core/ext/
data.rs

1//! Extension trait for `syn::Data` inspection.
2//!
3//! [`DataExt`] adds variant predicates and conversions to `syn::Data`.
4//!
5//! # Examples
6//!
7//! ```ignore
8//! use zyn::ext::DataExt;
9//!
10//! if data.is_struct() {
11//!     let s = data.as_struct().unwrap();
12//!     // s.fields ...
13//! }
14//! ```
15
16use syn::Data;
17
18/// Extension methods for `syn::Data`.
19///
20/// Provides variant predicates (`is_struct`, `is_enum`, `is_union`)
21/// and conversions (`as_struct`, `as_enum`, `as_union`).
22///
23/// # Examples
24///
25/// ```ignore
26/// use zyn::ext::DataExt;
27///
28/// assert!(data.is_enum());
29/// let e = data.as_enum().unwrap();
30/// // e.variants ...
31/// ```
32pub trait DataExt {
33    /// Returns `true` if this is `Data::Struct`.
34    fn is_struct(&self) -> bool;
35    /// Returns `true` if this is `Data::Enum`.
36    fn is_enum(&self) -> bool;
37    /// Returns `true` if this is `Data::Union`.
38    fn is_union(&self) -> bool;
39    /// Returns the inner `syn::DataStruct` if this is a struct.
40    fn as_struct(&self) -> Option<&syn::DataStruct>;
41    /// Returns the inner `syn::DataEnum` if this is an enum.
42    fn as_enum(&self) -> Option<&syn::DataEnum>;
43    /// Returns the inner `syn::DataUnion` if this is a union.
44    fn as_union(&self) -> Option<&syn::DataUnion>;
45}
46
47impl DataExt for Data {
48    fn is_struct(&self) -> bool {
49        matches!(self, Self::Struct(_))
50    }
51
52    fn is_enum(&self) -> bool {
53        matches!(self, Self::Enum(_))
54    }
55
56    fn is_union(&self) -> bool {
57        matches!(self, Self::Union(_))
58    }
59
60    fn as_struct(&self) -> Option<&syn::DataStruct> {
61        match self {
62            Self::Struct(s) => Some(s),
63            _ => None,
64        }
65    }
66
67    fn as_enum(&self) -> Option<&syn::DataEnum> {
68        match self {
69            Self::Enum(e) => Some(e),
70            _ => None,
71        }
72    }
73
74    fn as_union(&self) -> Option<&syn::DataUnion> {
75        match self {
76            Self::Union(u) => Some(u),
77            _ => None,
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    fn data_from(input: &str) -> Data {
87        let di: syn::DeriveInput = syn::parse_str(input).unwrap();
88        di.data
89    }
90
91    mod predicates {
92        use super::*;
93
94        #[test]
95        fn struct_variant() {
96            let data = data_from("struct Foo { x: i32 }");
97            assert!(data.is_struct());
98            assert!(!data.is_enum());
99            assert!(!data.is_union());
100        }
101
102        #[test]
103        fn enum_variant() {
104            let data = data_from("enum Foo { A, B }");
105            assert!(!data.is_struct());
106            assert!(data.is_enum());
107            assert!(!data.is_union());
108        }
109
110        #[test]
111        fn union_variant() {
112            let data = data_from("union Foo { x: i32, y: u32 }");
113            assert!(!data.is_struct());
114            assert!(!data.is_enum());
115            assert!(data.is_union());
116        }
117    }
118
119    mod conversions {
120        use super::*;
121
122        #[test]
123        fn as_struct_some() {
124            let data = data_from("struct Foo { x: i32 }");
125            assert!(data.as_struct().is_some());
126        }
127
128        #[test]
129        fn as_struct_none() {
130            let data = data_from("enum Foo { A }");
131            assert!(data.as_struct().is_none());
132        }
133
134        #[test]
135        fn as_enum_some() {
136            let data = data_from("enum Foo { A, B }");
137            assert!(data.as_enum().is_some());
138        }
139
140        #[test]
141        fn as_enum_none() {
142            let data = data_from("struct Foo;");
143            assert!(data.as_enum().is_none());
144        }
145
146        #[test]
147        fn as_union_some() {
148            let data = data_from("union Foo { x: i32, y: u32 }");
149            assert!(data.as_union().is_some());
150        }
151
152        #[test]
153        fn as_union_none() {
154            let data = data_from("struct Foo;");
155            assert!(data.as_union().is_none());
156        }
157    }
158}