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