1 use std::{slice, vec}; 2 3 use proc_macro2::{Span, TokenStream}; 4 use quote::ToTokens; 5 use syn::spanned::Spanned; 6 7 use usage::{ 8 self, IdentRefSet, IdentSet, LifetimeRefSet, LifetimeSet, UsesLifetimes, UsesTypeParams, 9 }; 10 use {Error, FromField, FromVariant, Result}; 11 12 /// A struct or enum body. 13 /// 14 /// `V` is the type which receives any encountered variants, and `F` receives struct fields. 15 #[derive(Debug, Clone, PartialEq, Eq)] 16 pub enum Data<V, F> { 17 Enum(Vec<V>), 18 Struct(Fields<F>), 19 } 20 21 impl<V, F> Data<V, F> { 22 /// Creates an empty body of the same shape as the passed-in body. 23 /// 24 /// # Panics 25 /// This function will panic if passed `syn::Data::Union`. empty_from(src: &syn::Data) -> Self26 pub fn empty_from(src: &syn::Data) -> Self { 27 match *src { 28 syn::Data::Enum(_) => Data::Enum(vec![]), 29 syn::Data::Struct(ref vd) => Data::Struct(Fields::empty_from(&vd.fields)), 30 syn::Data::Union(_) => panic!("Unions are not supported"), 31 } 32 } 33 34 /// Creates an empty body of the same shape as the passed-in body. 35 /// 36 /// `darling` does not support unions; calling this function with a union body will return an error. try_empty_from(src: &syn::Data) -> Result<Self>37 pub fn try_empty_from(src: &syn::Data) -> Result<Self> { 38 match *src { 39 syn::Data::Enum(_) => Ok(Data::Enum(vec![])), 40 syn::Data::Struct(ref vd) => Ok(Data::Struct(Fields::empty_from(&vd.fields))), 41 // This deliberately doesn't set a span on the error message, as the error is most useful if 42 // applied to the call site of the offending macro. Given that the message is very generic, 43 // putting it on the union keyword ends up being confusing. 44 syn::Data::Union(_) => Err(Error::custom("Unions are not supported")), 45 } 46 } 47 48 /// Creates a new `Data<&'a V, &'a F>` instance from `Data<V, F>`. as_ref<'a>(&'a self) -> Data<&'a V, &'a F>49 pub fn as_ref<'a>(&'a self) -> Data<&'a V, &'a F> { 50 match *self { 51 Data::Enum(ref variants) => Data::Enum(variants.iter().collect()), 52 Data::Struct(ref data) => Data::Struct(data.as_ref()), 53 } 54 } 55 56 /// Applies a function `V -> U` on enum variants, if this is an enum. map_enum_variants<T, U>(self, map: T) -> Data<U, F> where T: FnMut(V) -> U,57 pub fn map_enum_variants<T, U>(self, map: T) -> Data<U, F> 58 where 59 T: FnMut(V) -> U, 60 { 61 match self { 62 Data::Enum(v) => Data::Enum(v.into_iter().map(map).collect()), 63 Data::Struct(f) => Data::Struct(f), 64 } 65 } 66 67 /// Applies a function `F -> U` on struct fields, if this is a struct. map_struct_fields<T, U>(self, map: T) -> Data<V, U> where T: FnMut(F) -> U,68 pub fn map_struct_fields<T, U>(self, map: T) -> Data<V, U> 69 where 70 T: FnMut(F) -> U, 71 { 72 match self { 73 Data::Enum(v) => Data::Enum(v), 74 Data::Struct(f) => Data::Struct(f.map(map)), 75 } 76 } 77 78 /// Applies a function to the `Fields` if this is a struct. map_struct<T, U>(self, mut map: T) -> Data<V, U> where T: FnMut(Fields<F>) -> Fields<U>,79 pub fn map_struct<T, U>(self, mut map: T) -> Data<V, U> 80 where 81 T: FnMut(Fields<F>) -> Fields<U>, 82 { 83 match self { 84 Data::Enum(v) => Data::Enum(v), 85 Data::Struct(f) => Data::Struct(map(f)), 86 } 87 } 88 89 /// Consumes the `Data`, returning `Fields<F>` if it was a struct. take_struct(self) -> Option<Fields<F>>90 pub fn take_struct(self) -> Option<Fields<F>> { 91 match self { 92 Data::Enum(_) => None, 93 Data::Struct(f) => Some(f), 94 } 95 } 96 97 /// Consumes the `Data`, returning `Vec<V>` if it was an enum. take_enum(self) -> Option<Vec<V>>98 pub fn take_enum(self) -> Option<Vec<V>> { 99 match self { 100 Data::Enum(v) => Some(v), 101 Data::Struct(_) => None, 102 } 103 } 104 105 /// Returns `true` if this instance is `Data::Enum`. is_enum(&self) -> bool106 pub fn is_enum(&self) -> bool { 107 match *self { 108 Data::Enum(_) => true, 109 Data::Struct(_) => false, 110 } 111 } 112 113 /// Returns `true` if this instance is `Data::Struct`. is_struct(&self) -> bool114 pub fn is_struct(&self) -> bool { 115 !self.is_enum() 116 } 117 } 118 119 impl<V: FromVariant, F: FromField> Data<V, F> { 120 /// Attempt to convert from a `syn::Data` instance. try_from(body: &syn::Data) -> Result<Self>121 pub fn try_from(body: &syn::Data) -> Result<Self> { 122 match *body { 123 syn::Data::Enum(ref data) => { 124 let mut items = Vec::with_capacity(data.variants.len()); 125 let mut errors = Vec::new(); 126 for v_result in data.variants.iter().map(FromVariant::from_variant) { 127 match v_result { 128 Ok(val) => items.push(val), 129 Err(err) => errors.push(err), 130 } 131 } 132 133 if !errors.is_empty() { 134 Err(Error::multiple(errors)) 135 } else { 136 Ok(Data::Enum(items)) 137 } 138 } 139 syn::Data::Struct(ref data) => Ok(Data::Struct(Fields::try_from(&data.fields)?)), 140 // This deliberately doesn't set a span on the error message, as the error is most useful if 141 // applied to the call site of the offending macro. Given that the message is very generic, 142 // putting it on the union keyword ends up being confusing. 143 syn::Data::Union(_) => Err(Error::custom("Unions are not supported")), 144 } 145 } 146 } 147 148 impl<V: UsesTypeParams, F: UsesTypeParams> UsesTypeParams for Data<V, F> { uses_type_params<'a>( &self, options: &usage::Options, type_set: &'a IdentSet, ) -> IdentRefSet<'a>149 fn uses_type_params<'a>( 150 &self, 151 options: &usage::Options, 152 type_set: &'a IdentSet, 153 ) -> IdentRefSet<'a> { 154 match *self { 155 Data::Struct(ref v) => v.uses_type_params(options, type_set), 156 Data::Enum(ref v) => v.uses_type_params(options, type_set), 157 } 158 } 159 } 160 161 impl<V: UsesLifetimes, F: UsesLifetimes> UsesLifetimes for Data<V, F> { uses_lifetimes<'a>( &self, options: &usage::Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>162 fn uses_lifetimes<'a>( 163 &self, 164 options: &usage::Options, 165 lifetimes: &'a LifetimeSet, 166 ) -> LifetimeRefSet<'a> { 167 match *self { 168 Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes), 169 Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes), 170 } 171 } 172 } 173 174 /// Equivalent to `syn::Fields`, but replaces the AST element with a generic. 175 #[derive(Debug, Clone)] 176 pub struct Fields<T> { 177 pub style: Style, 178 pub fields: Vec<T>, 179 span: Option<Span>, 180 __nonexhaustive: (), 181 } 182 183 impl<T> Fields<T> { 184 /// Creates a new [`Fields`] struct. new(style: Style, fields: Vec<T>) -> Self185 pub fn new(style: Style, fields: Vec<T>) -> Self { 186 Self { 187 style, 188 fields, 189 span: None, 190 __nonexhaustive: (), 191 } 192 } 193 194 /// Adds a [`Span`] to [`Fields`]. with_span(mut self, span: Span) -> Self195 pub fn with_span(mut self, span: Span) -> Self { 196 if self.span.is_none() { 197 self.span = Some(span); 198 } 199 self 200 } 201 empty_from(vd: &syn::Fields) -> Self202 pub fn empty_from(vd: &syn::Fields) -> Self { 203 Self::new(vd.into(), Vec::new()) 204 } 205 206 /// Splits the `Fields` into its style and fields for further processing. 207 /// Returns an empty `Vec` for `Unit` data. split(self) -> (Style, Vec<T>)208 pub fn split(self) -> (Style, Vec<T>) { 209 (self.style, self.fields) 210 } 211 212 /// Returns true if this variant's data makes it a newtype. is_newtype(&self) -> bool213 pub fn is_newtype(&self) -> bool { 214 self.style == Style::Tuple && self.len() == 1 215 } 216 is_unit(&self) -> bool217 pub fn is_unit(&self) -> bool { 218 self.style.is_unit() 219 } 220 is_tuple(&self) -> bool221 pub fn is_tuple(&self) -> bool { 222 self.style.is_tuple() 223 } 224 is_struct(&self) -> bool225 pub fn is_struct(&self) -> bool { 226 self.style.is_struct() 227 } 228 as_ref<'a>(&'a self) -> Fields<&'a T>229 pub fn as_ref<'a>(&'a self) -> Fields<&'a T> { 230 Fields { 231 style: self.style, 232 fields: self.fields.iter().collect(), 233 span: self.span, 234 __nonexhaustive: (), 235 } 236 } 237 map<F, U>(self, map: F) -> Fields<U> where F: FnMut(T) -> U,238 pub fn map<F, U>(self, map: F) -> Fields<U> 239 where 240 F: FnMut(T) -> U, 241 { 242 Fields { 243 style: self.style, 244 fields: self.fields.into_iter().map(map).collect(), 245 span: self.span, 246 __nonexhaustive: (), 247 } 248 } 249 iter(&self) -> slice::Iter<T>250 pub fn iter(&self) -> slice::Iter<T> { 251 self.fields.iter() 252 } 253 254 /// Returns the number of fields in the structure. len(&self) -> usize255 pub fn len(&self) -> usize { 256 self.fields.len() 257 } 258 259 /// Returns `true` if the `Fields` contains no fields. is_empty(&self) -> bool260 pub fn is_empty(&self) -> bool { 261 self.fields.is_empty() 262 } 263 } 264 265 impl<F: FromField> Fields<F> { try_from(fields: &syn::Fields) -> Result<Self>266 pub fn try_from(fields: &syn::Fields) -> Result<Self> { 267 let (items, errors) = { 268 match &fields { 269 syn::Fields::Named(fields) => { 270 let mut items = Vec::with_capacity(fields.named.len()); 271 let mut errors = Vec::new(); 272 273 for field in &fields.named { 274 match FromField::from_field(field) { 275 Ok(val) => items.push(val), 276 Err(err) => errors.push({ 277 if let Some(ident) = &field.ident { 278 err.at(ident) 279 } else { 280 err 281 } 282 }), 283 } 284 } 285 286 (items, errors) 287 } 288 syn::Fields::Unnamed(fields) => { 289 let mut items = Vec::with_capacity(fields.unnamed.len()); 290 let mut errors = Vec::new(); 291 292 for field in &fields.unnamed { 293 match FromField::from_field(field) { 294 Ok(val) => items.push(val), 295 Err(err) => errors.push({ 296 if let Some(ident) = &field.ident { 297 err.at(ident) 298 } else { 299 err 300 } 301 }), 302 } 303 } 304 305 (items, errors) 306 } 307 syn::Fields::Unit => (vec![], vec![]), 308 } 309 }; 310 311 if !errors.is_empty() { 312 Err(Error::multiple(errors)) 313 } else { 314 Ok(Self::new(fields.into(), items).with_span(fields.span())) 315 } 316 } 317 } 318 319 impl<T: ToTokens> ToTokens for Fields<T> { to_tokens(&self, tokens: &mut TokenStream)320 fn to_tokens(&self, tokens: &mut TokenStream) { 321 let fields = &self.fields; 322 // An unknown Span should be `Span::call_site()`; 323 // https://docs.rs/syn/1.0.12/syn/spanned/trait.Spanned.html#tymethod.span 324 let span = self.span.unwrap_or_else(Span::call_site); 325 326 match self.style { 327 Style::Struct => { 328 let trailing_comma = { 329 if fields.is_empty() { 330 quote!() 331 } else { 332 quote!(,) 333 } 334 }; 335 336 tokens.extend(quote_spanned![span => { #(#fields),* #trailing_comma }]); 337 } 338 Style::Tuple => { 339 tokens.extend(quote_spanned![span => ( #(#fields),* )]); 340 } 341 Style::Unit => {} 342 } 343 } 344 } 345 346 impl<T: PartialEq> PartialEq for Fields<T> { eq(&self, other: &Self) -> bool347 fn eq(&self, other: &Self) -> bool { 348 self.style == other.style && self.fields == other.fields 349 } 350 } 351 352 impl<T: Eq> Eq for Fields<T> {} 353 354 impl<T> IntoIterator for Fields<T> { 355 type Item = T; 356 type IntoIter = vec::IntoIter<T>; 357 into_iter(self) -> Self::IntoIter358 fn into_iter(self) -> Self::IntoIter { 359 self.fields.into_iter() 360 } 361 } 362 363 impl<T> From<Style> for Fields<T> { from(style: Style) -> Self364 fn from(style: Style) -> Self { 365 Self::new(style, Vec::new()) 366 } 367 } 368 369 impl<T, U: Into<Vec<T>>> From<(Style, U)> for Fields<T> { from((style, fields): (Style, U)) -> Self370 fn from((style, fields): (Style, U)) -> Self { 371 style.with_fields(fields) 372 } 373 } 374 375 impl<T: UsesTypeParams> UsesTypeParams for Fields<T> { uses_type_params<'a>( &self, options: &usage::Options, type_set: &'a IdentSet, ) -> IdentRefSet<'a>376 fn uses_type_params<'a>( 377 &self, 378 options: &usage::Options, 379 type_set: &'a IdentSet, 380 ) -> IdentRefSet<'a> { 381 self.fields.uses_type_params(options, type_set) 382 } 383 } 384 385 impl<T: UsesLifetimes> UsesLifetimes for Fields<T> { uses_lifetimes<'a>( &self, options: &usage::Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>386 fn uses_lifetimes<'a>( 387 &self, 388 options: &usage::Options, 389 lifetimes: &'a LifetimeSet, 390 ) -> LifetimeRefSet<'a> { 391 self.fields.uses_lifetimes(options, lifetimes) 392 } 393 } 394 395 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 396 pub enum Style { 397 Tuple, 398 Struct, 399 Unit, 400 } 401 402 impl Style { is_unit(self) -> bool403 pub fn is_unit(self) -> bool { 404 self == Style::Unit 405 } 406 is_tuple(self) -> bool407 pub fn is_tuple(self) -> bool { 408 self == Style::Tuple 409 } 410 is_struct(self) -> bool411 pub fn is_struct(self) -> bool { 412 self == Style::Struct 413 } 414 415 /// Creates a new `Fields` of the specified style with the passed-in fields. with_fields<T, U: Into<Vec<T>>>(self, fields: U) -> Fields<T>416 fn with_fields<T, U: Into<Vec<T>>>(self, fields: U) -> Fields<T> { 417 Fields::new(self, fields.into()) 418 } 419 } 420 421 impl From<syn::Fields> for Style { from(vd: syn::Fields) -> Self422 fn from(vd: syn::Fields) -> Self { 423 (&vd).into() 424 } 425 } 426 427 impl<'a> From<&'a syn::Fields> for Style { from(vd: &syn::Fields) -> Self428 fn from(vd: &syn::Fields) -> Self { 429 match *vd { 430 syn::Fields::Named(_) => Style::Struct, 431 syn::Fields::Unnamed(_) => Style::Tuple, 432 syn::Fields::Unit => Style::Unit, 433 } 434 } 435 } 436 437 #[cfg(test)] 438 mod tests { 439 use super::*; 440 441 // it is not possible to directly convert a TokenStream into syn::Fields, so you have 442 // to convert the TokenStream into DeriveInput first and then pass the syn::Fields to 443 // Fields::try_from. token_stream_to_fields(input: TokenStream) -> Fields<syn::Field>444 fn token_stream_to_fields(input: TokenStream) -> Fields<syn::Field> { 445 Fields::try_from(&{ 446 if let syn::Data::Struct(s) = 447 syn::parse2::<syn::DeriveInput>(input.clone()).unwrap().data 448 { 449 s.fields 450 } else { 451 panic!(); 452 } 453 }) 454 .unwrap() 455 } 456 457 #[test] test_style_eq()458 fn test_style_eq() { 459 // `Fields` implements `Eq` manually, so it has to be ensured, that all fields of `Fields` 460 // implement `Eq`, this test would fail, if someone accidentally removed the Eq 461 // implementation from `Style`. 462 struct _AssertEq 463 where 464 Style: Eq; 465 } 466 467 #[test] test_fields_to_tokens_struct()468 fn test_fields_to_tokens_struct() { 469 let reference = quote!( 470 { 471 executable: String, 472 args: Vec<String>, 473 env: Vec<String>, 474 index: usize, 475 optional: Option<String>, 476 current_dir: String, 477 } 478 ); 479 let input = quote!( 480 struct ExampleTest #reference 481 ); 482 483 let fields = token_stream_to_fields(input); 484 485 let mut result = quote!(); 486 fields.to_tokens(&mut result); 487 assert_eq!(result.to_string(), reference.to_string()); 488 } 489 490 #[test] test_fields_to_tokens_tuple()491 fn test_fields_to_tokens_tuple() { 492 let reference = quote!((u64, usize, &'a T)); 493 let input = quote!( 494 struct ExampleTest #reference; 495 ); 496 497 let fields = token_stream_to_fields(input); 498 499 let mut result = quote!(); 500 fields.to_tokens(&mut result); 501 assert_eq!(result.to_string(), reference.to_string()); 502 } 503 } 504