1 use std::{fmt, iter::FromIterator}; 2 3 use crate::ast; 4 5 /// Get the "shape" of a fields container, such as a struct or variant. 6 pub trait AsShape { 7 /// Get the "shape" of a fields container. as_shape(&self) -> Shape8 fn as_shape(&self) -> Shape; 9 } 10 11 impl<T> AsShape for ast::Fields<T> { as_shape(&self) -> Shape12 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 22 impl AsShape for syn::Fields { as_shape(&self) -> Shape23 fn as_shape(&self) -> Shape { 24 match self { 25 syn::Fields::Named(fields) => fields.as_shape(), 26 syn::Fields::Unnamed(fields) => fields.as_shape(), 27 syn::Fields::Unit => Shape::Unit, 28 } 29 } 30 } 31 32 impl AsShape for syn::FieldsNamed { as_shape(&self) -> Shape33 fn as_shape(&self) -> Shape { 34 Shape::Named 35 } 36 } 37 38 impl AsShape for syn::FieldsUnnamed { as_shape(&self) -> Shape39 fn as_shape(&self) -> Shape { 40 if self.unnamed.len() == 1 { 41 Shape::Newtype 42 } else { 43 Shape::Tuple 44 } 45 } 46 } 47 48 impl AsShape for syn::DataStruct { as_shape(&self) -> Shape49 fn as_shape(&self) -> Shape { 50 self.fields.as_shape() 51 } 52 } 53 54 impl AsShape for syn::Variant { as_shape(&self) -> Shape55 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)] 62 pub 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 73 impl Shape { description(&self) -> &'static str74 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 84 impl fmt::Display for Shape { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 86 write!(f, "{}", self.description()) 87 } 88 } 89 90 impl AsShape for Shape { as_shape(&self) -> Shape91 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)] 108 pub struct ShapeSet { 109 newtype: bool, 110 named: bool, 111 tuple: bool, 112 unit: bool, 113 } 114 115 impl 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 /// ``` new(items: impl IntoIterator<Item = Shape>) -> Self124 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 /// ``` insert_all(&mut self)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 insert(&mut self, shape: 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. is_empty(&self) -> bool157 pub fn is_empty(&self) -> bool { 158 !self.named && !self.newtype && !self.tuple && !self.unit 159 } 160 contains_shape(&self, shape: Shape) -> bool161 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. contains(&self, fields: &impl AsShape) -> bool171 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. check(&self, fields: &impl AsShape) -> crate::Result<()>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 to_vec(&self) -> Vec<Shape>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 213 impl fmt::Display for ShapeSet { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 215 let shapes = 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 227 impl FromIterator<Shape> for ShapeSet { from_iter<T: IntoIterator<Item = Shape>>(iter: T) -> Self228 fn from_iter<T: IntoIterator<Item = Shape>>(iter: T) -> Self { 229 let mut output = ShapeSet::default(); 230 for shape in iter.into_iter() { 231 output.insert(shape); 232 } 233 234 output 235 } 236 } 237 238 #[cfg(test)] 239 mod tests { 240 use syn::parse_quote; 241 242 use super::*; 243 244 #[test] any_accepts_anything()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] tuple_accepts_newtype()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] newtype_rejects_tuple()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