1use std::{fmt, iter::FromIterator};
2
3use crate::ast;
4
5/// Get the "shape" of a fields container, such as a struct or variant.
6pub trait AsShape {
7 /// Get the "shape" of a fields container.
8 fn as_shape(&self) -> Shape;
9}
10
11impl<T> AsShape for ast::Fields<T> {
12 fn as_shape(&self) -> Shape {
13 match self.style {
14 ast::Style::Tuple if self.fields.len() == 1 => Shape::Newtype,
15 ast::Style::Tuple => Shape::Tuple,
16 ast::Style::Struct => Shape::Named,
17 ast::Style::Unit => Shape::Unit,
18 }
19 }
20}
21
22impl AsShape for syn::Fields {
23 fn as_shape(&self) -> Shape {
24 match self {
25 syn::Fields::Named(fields: &FieldsNamed) => fields.as_shape(),
26 syn::Fields::Unnamed(fields: &FieldsUnnamed) => fields.as_shape(),
27 syn::Fields::Unit => Shape::Unit,
28 }
29 }
30}
31
32impl AsShape for syn::FieldsNamed {
33 fn as_shape(&self) -> Shape {
34 Shape::Named
35 }
36}
37
38impl AsShape for syn::FieldsUnnamed {
39 fn as_shape(&self) -> Shape {
40 if self.unnamed.len() == 1 {
41 Shape::Newtype
42 } else {
43 Shape::Tuple
44 }
45 }
46}
47
48impl AsShape for syn::DataStruct {
49 fn as_shape(&self) -> Shape {
50 self.fields.as_shape()
51 }
52}
53
54impl AsShape for syn::Variant {
55 fn as_shape(&self) -> Shape {
56 self.fields.as_shape()
57 }
58}
59
60/// Description of how fields in a struct or variant are syntactically laid out.
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum Shape {
63 /// A set of named fields, e.g. `{ field: String }`.
64 Named,
65 /// A list of unnamed fields, e.g. `(String, u64)`.
66 Tuple,
67 /// No fields, e.g. `struct Example;`
68 Unit,
69 /// A special case of [`Tuple`](Shape#variant.Tuple) with exactly one field, e.g. `(String)`.
70 Newtype,
71}
72
73impl Shape {
74 pub fn description(&self) -> &'static str {
75 match self {
76 Shape::Named => "named fields",
77 Shape::Tuple => "unnamed fields",
78 Shape::Unit => "no fields",
79 Shape::Newtype => "one unnamed field",
80 }
81 }
82}
83
84impl fmt::Display for Shape {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 write!(f, "{}", self.description())
87 }
88}
89
90impl AsShape for Shape {
91 fn as_shape(&self) -> Shape {
92 *self
93 }
94}
95
96/// A set of [`Shape`] values, which correctly handles the relationship between
97/// [newtype](Shape#variant.Newtype) and [tuple](Shape#variant.Tuple) shapes.
98///
99/// # Example
100/// ```rust
101/// # use darling_core::util::{Shape, ShapeSet};
102/// let shape_set = ShapeSet::new(vec![Shape::Tuple]);
103///
104/// // This is correct, because all newtypes are single-field tuples.
105/// assert!(shape_set.contains(&Shape::Newtype));
106/// ```
107#[derive(Debug, Clone, Default)]
108pub struct ShapeSet {
109 newtype: bool,
110 named: bool,
111 tuple: bool,
112 unit: bool,
113}
114
115impl ShapeSet {
116 /// Create a new `ShapeSet` which includes the specified items.
117 ///
118 /// # Exampe
119 /// ```rust
120 /// # use darling_core::util::{Shape, ShapeSet};
121 /// let shape_set = ShapeSet::new(vec![Shape::Named, Shape::Newtype]);
122 /// assert!(shape_set.contains(&Shape::Newtype));
123 /// ```
124 pub fn new(items: impl IntoIterator<Item = Shape>) -> Self {
125 items.into_iter().collect()
126 }
127
128 /// Insert all possible shapes into the set.
129 ///
130 /// This is equivalent to calling [`insert`](ShapeSet#method.insert) with every value of [`Shape`].
131 ///
132 /// # Example
133 /// ```rust
134 /// # use darling_core::util::{Shape, ShapeSet};
135 /// let mut shape_set = ShapeSet::default();
136 /// shape_set.insert_all();
137 /// assert!(shape_set.contains(&Shape::Named));
138 /// ```
139 pub fn insert_all(&mut self) {
140 self.insert(Shape::Named);
141 self.insert(Shape::Newtype);
142 self.insert(Shape::Tuple);
143 self.insert(Shape::Unit);
144 }
145
146 /// Insert a shape into the set, so that the set will match that shape
147 pub fn insert(&mut self, shape: Shape) {
148 match shape {
149 Shape::Named => self.named = true,
150 Shape::Tuple => self.tuple = true,
151 Shape::Unit => self.unit = true,
152 Shape::Newtype => self.newtype = true,
153 }
154 }
155
156 /// Whether this set is empty.
157 pub fn is_empty(&self) -> bool {
158 !self.named && !self.newtype && !self.tuple && !self.unit
159 }
160
161 fn contains_shape(&self, shape: Shape) -> bool {
162 match shape {
163 Shape::Named => self.named,
164 Shape::Tuple => self.tuple,
165 Shape::Unit => self.unit,
166 Shape::Newtype => self.newtype || self.tuple,
167 }
168 }
169
170 /// Check if a fields container's shape is in this set.
171 pub fn contains(&self, fields: &impl AsShape) -> bool {
172 self.contains_shape(fields.as_shape())
173 }
174
175 /// Check if a field container's shape is in this set of shapes, and produce
176 /// an [`Error`](crate::Error) if it does not.
177 pub fn check(&self, fields: &impl AsShape) -> crate::Result<()> {
178 let shape = fields.as_shape();
179
180 if self.contains_shape(shape) {
181 Ok(())
182 } else {
183 Err(crate::Error::unsupported_shape_with_expected(
184 shape.description(),
185 self,
186 ))
187 }
188 }
189
190 fn to_vec(&self) -> Vec<Shape> {
191 let mut shapes = Vec::with_capacity(3);
192
193 if self.named {
194 shapes.push(Shape::Named);
195 }
196
197 if self.tuple || self.newtype {
198 shapes.push(if self.tuple {
199 Shape::Tuple
200 } else {
201 Shape::Newtype
202 });
203 }
204
205 if self.unit {
206 shapes.push(Shape::Unit)
207 }
208
209 shapes
210 }
211}
212
213impl fmt::Display for ShapeSet {
214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215 let shapes: Vec = self.to_vec();
216
217 match shapes.len() {
218 0 => write!(f, "nothing"),
219 1 => write!(f, "{}", shapes[0]),
220 2 => write!(f, "{} or {}", shapes[0], shapes[1]),
221 3 => write!(f, "{}, {}, or {}", shapes[0], shapes[1], shapes[2]),
222 _ => unreachable!(),
223 }
224 }
225}
226
227impl FromIterator<Shape> for ShapeSet {
228 fn from_iter<T: IntoIterator<Item = Shape>>(iter: T) -> Self {
229 let mut output: ShapeSet = ShapeSet::default();
230 for shape: Shape in iter.into_iter() {
231 output.insert(shape);
232 }
233
234 output
235 }
236}
237
238#[cfg(test)]
239mod tests {
240 use syn::parse_quote;
241
242 use super::*;
243
244 #[test]
245 fn any_accepts_anything() {
246 let mut filter = ShapeSet::default();
247 filter.insert_all();
248 let unit_struct: syn::DeriveInput = syn::parse_quote! {
249 struct Example;
250 };
251 if let syn::Data::Struct(data) = unit_struct.data {
252 assert!(filter.contains(&data));
253 } else {
254 panic!("Struct not parsed as struct");
255 };
256 }
257
258 #[test]
259 fn tuple_accepts_newtype() {
260 let filter = ShapeSet::new(vec![Shape::Tuple]);
261 let newtype_struct: syn::DeriveInput = parse_quote! {
262 struct Example(String);
263 };
264
265 if let syn::Data::Struct(data) = newtype_struct.data {
266 assert!(filter.contains(&data));
267 } else {
268 panic!("Struct not parsed as struct");
269 };
270 }
271
272 #[test]
273 fn newtype_rejects_tuple() {
274 let filter = ShapeSet::new(vec![Shape::Newtype]);
275 let tuple_struct: syn::DeriveInput = parse_quote! {
276 struct Example(String, u64);
277 };
278
279 if let syn::Data::Struct(data) = tuple_struct.data {
280 assert!(!filter.contains(&data));
281 } else {
282 panic!("Struct not parsed as struct");
283 };
284 }
285}
286