1 use crate::attr::Attribute; 2 use crate::expr::{Expr, Index, Member}; 3 use crate::ident::Ident; 4 use crate::punctuated::{self, Punctuated}; 5 use crate::restriction::{FieldMutability, Visibility}; 6 use crate::token; 7 use crate::ty::Type; 8 9 ast_struct! { 10 /// An enum variant. 11 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 12 pub struct Variant { 13 pub attrs: Vec<Attribute>, 14 15 /// Name of the variant. 16 pub ident: Ident, 17 18 /// Content stored in the variant. 19 pub fields: Fields, 20 21 /// Explicit discriminant: `Variant = 1` 22 pub discriminant: Option<(Token![=], Expr)>, 23 } 24 } 25 26 ast_enum_of_structs! { 27 /// Data stored within an enum variant or struct. 28 /// 29 /// # Syntax tree enum 30 /// 31 /// This type is a [syntax tree enum]. 32 /// 33 /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums 34 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 35 pub enum Fields { 36 /// Named fields of a struct or struct variant such as `Point { x: f64, 37 /// y: f64 }`. 38 Named(FieldsNamed), 39 40 /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`. 41 Unnamed(FieldsUnnamed), 42 43 /// Unit struct or unit variant such as `None`. 44 Unit, 45 } 46 } 47 48 ast_struct! { 49 /// Named fields of a struct or struct variant such as `Point { x: f64, 50 /// y: f64 }`. 51 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 52 pub struct FieldsNamed { 53 pub brace_token: token::Brace, 54 pub named: Punctuated<Field, Token![,]>, 55 } 56 } 57 58 ast_struct! { 59 /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`. 60 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 61 pub struct FieldsUnnamed { 62 pub paren_token: token::Paren, 63 pub unnamed: Punctuated<Field, Token![,]>, 64 } 65 } 66 67 impl Fields { 68 /// Get an iterator over the borrowed [`Field`] items in this object. This 69 /// iterator can be used to iterate over a named or unnamed struct or 70 /// variant's fields uniformly. iter(&self) -> punctuated::Iter<Field>71 pub fn iter(&self) -> punctuated::Iter<Field> { 72 match self { 73 Fields::Unit => crate::punctuated::empty_punctuated_iter(), 74 Fields::Named(f) => f.named.iter(), 75 Fields::Unnamed(f) => f.unnamed.iter(), 76 } 77 } 78 79 /// Get an iterator over the mutably borrowed [`Field`] items in this 80 /// object. This iterator can be used to iterate over a named or unnamed 81 /// struct or variant's fields uniformly. iter_mut(&mut self) -> punctuated::IterMut<Field>82 pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> { 83 match self { 84 Fields::Unit => crate::punctuated::empty_punctuated_iter_mut(), 85 Fields::Named(f) => f.named.iter_mut(), 86 Fields::Unnamed(f) => f.unnamed.iter_mut(), 87 } 88 } 89 90 /// Returns the number of fields. len(&self) -> usize91 pub fn len(&self) -> usize { 92 match self { 93 Fields::Unit => 0, 94 Fields::Named(f) => f.named.len(), 95 Fields::Unnamed(f) => f.unnamed.len(), 96 } 97 } 98 99 /// Returns `true` if there are zero fields. is_empty(&self) -> bool100 pub fn is_empty(&self) -> bool { 101 match self { 102 Fields::Unit => true, 103 Fields::Named(f) => f.named.is_empty(), 104 Fields::Unnamed(f) => f.unnamed.is_empty(), 105 } 106 } 107 108 return_impl_trait! { 109 /// Get an iterator over the fields of a struct or variant as [`Member`]s. 110 /// This iterator can be used to iterate over a named or unnamed struct or 111 /// variant's fields uniformly. 112 /// 113 /// # Example 114 /// 115 /// The following is a simplistic [`Clone`] derive for structs. (A more 116 /// complete implementation would additionally want to infer trait bounds on 117 /// the generic type parameters.) 118 /// 119 /// ``` 120 /// # use quote::quote; 121 /// # 122 /// fn derive_clone(input: &syn::ItemStruct) -> proc_macro2::TokenStream { 123 /// let ident = &input.ident; 124 /// let members = input.fields.members(); 125 /// let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); 126 /// quote! { 127 /// impl #impl_generics Clone for #ident #ty_generics #where_clause { 128 /// fn clone(&self) -> Self { 129 /// Self { 130 /// #(#members: self.#members.clone()),* 131 /// } 132 /// } 133 /// } 134 /// } 135 /// } 136 /// ``` 137 /// 138 /// For structs with named fields, it produces an expression like `Self { a: 139 /// self.a.clone() }`. For structs with unnamed fields, `Self { 0: 140 /// self.0.clone() }`. And for unit structs, `Self {}`. 141 pub fn members(&self) -> impl Iterator<Item = Member> + Clone + '_ [Members] { 142 Members { 143 fields: self.iter(), 144 index: 0, 145 } 146 } 147 } 148 } 149 150 impl IntoIterator for Fields { 151 type Item = Field; 152 type IntoIter = punctuated::IntoIter<Field>; 153 into_iter(self) -> Self::IntoIter154 fn into_iter(self) -> Self::IntoIter { 155 match self { 156 Fields::Unit => Punctuated::<Field, ()>::new().into_iter(), 157 Fields::Named(f) => f.named.into_iter(), 158 Fields::Unnamed(f) => f.unnamed.into_iter(), 159 } 160 } 161 } 162 163 impl<'a> IntoIterator for &'a Fields { 164 type Item = &'a Field; 165 type IntoIter = punctuated::Iter<'a, Field>; 166 into_iter(self) -> Self::IntoIter167 fn into_iter(self) -> Self::IntoIter { 168 self.iter() 169 } 170 } 171 172 impl<'a> IntoIterator for &'a mut Fields { 173 type Item = &'a mut Field; 174 type IntoIter = punctuated::IterMut<'a, Field>; 175 into_iter(self) -> Self::IntoIter176 fn into_iter(self) -> Self::IntoIter { 177 self.iter_mut() 178 } 179 } 180 181 ast_struct! { 182 /// A field of a struct or enum variant. 183 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] 184 pub struct Field { 185 pub attrs: Vec<Attribute>, 186 187 pub vis: Visibility, 188 189 pub mutability: FieldMutability, 190 191 /// Name of the field, if any. 192 /// 193 /// Fields of tuple structs have no names. 194 pub ident: Option<Ident>, 195 196 pub colon_token: Option<Token![:]>, 197 198 pub ty: Type, 199 } 200 } 201 202 pub struct Members<'a> { 203 fields: punctuated::Iter<'a, Field>, 204 index: u32, 205 } 206 207 impl<'a> Iterator for Members<'a> { 208 type Item = Member; 209 next(&mut self) -> Option<Self::Item>210 fn next(&mut self) -> Option<Self::Item> { 211 let field = self.fields.next()?; 212 let member = match &field.ident { 213 Some(ident) => Member::Named(ident.clone()), 214 None => { 215 #[cfg(all(feature = "parsing", feature = "printing"))] 216 let span = crate::spanned::Spanned::span(&field.ty); 217 #[cfg(not(all(feature = "parsing", feature = "printing")))] 218 let span = proc_macro2::Span::call_site(); 219 Member::Unnamed(Index { 220 index: self.index, 221 span, 222 }) 223 } 224 }; 225 self.index += 1; 226 Some(member) 227 } 228 } 229 230 impl<'a> Clone for Members<'a> { clone(&self) -> Self231 fn clone(&self) -> Self { 232 Members { 233 fields: self.fields.clone(), 234 index: self.index, 235 } 236 } 237 } 238 239 #[cfg(feature = "parsing")] 240 pub(crate) mod parsing { 241 use crate::attr::Attribute; 242 use crate::data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant}; 243 use crate::error::Result; 244 use crate::expr::Expr; 245 use crate::ext::IdentExt as _; 246 use crate::ident::Ident; 247 #[cfg(not(feature = "full"))] 248 use crate::parse::discouraged::Speculative as _; 249 use crate::parse::{Parse, ParseStream}; 250 use crate::restriction::{FieldMutability, Visibility}; 251 #[cfg(not(feature = "full"))] 252 use crate::scan_expr::scan_expr; 253 use crate::token; 254 use crate::ty::Type; 255 use crate::verbatim; 256 257 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] 258 impl Parse for Variant { parse(input: ParseStream) -> Result<Self>259 fn parse(input: ParseStream) -> Result<Self> { 260 let attrs = input.call(Attribute::parse_outer)?; 261 let _visibility: Visibility = input.parse()?; 262 let ident: Ident = input.parse()?; 263 let fields = if input.peek(token::Brace) { 264 Fields::Named(input.parse()?) 265 } else if input.peek(token::Paren) { 266 Fields::Unnamed(input.parse()?) 267 } else { 268 Fields::Unit 269 }; 270 let discriminant = if input.peek(Token![=]) { 271 let eq_token: Token![=] = input.parse()?; 272 #[cfg(feature = "full")] 273 let discriminant: Expr = input.parse()?; 274 #[cfg(not(feature = "full"))] 275 let discriminant = { 276 let begin = input.fork(); 277 let ahead = input.fork(); 278 let mut discriminant: Result<Expr> = ahead.parse(); 279 if discriminant.is_ok() { 280 input.advance_to(&ahead); 281 } else if scan_expr(input).is_ok() { 282 discriminant = Ok(Expr::Verbatim(verbatim::between(&begin, input))); 283 } 284 discriminant? 285 }; 286 Some((eq_token, discriminant)) 287 } else { 288 None 289 }; 290 Ok(Variant { 291 attrs, 292 ident, 293 fields, 294 discriminant, 295 }) 296 } 297 } 298 299 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] 300 impl Parse for FieldsNamed { parse(input: ParseStream) -> Result<Self>301 fn parse(input: ParseStream) -> Result<Self> { 302 let content; 303 Ok(FieldsNamed { 304 brace_token: braced!(content in input), 305 named: content.parse_terminated(Field::parse_named, Token![,])?, 306 }) 307 } 308 } 309 310 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] 311 impl Parse for FieldsUnnamed { parse(input: ParseStream) -> Result<Self>312 fn parse(input: ParseStream) -> Result<Self> { 313 let content; 314 Ok(FieldsUnnamed { 315 paren_token: parenthesized!(content in input), 316 unnamed: content.parse_terminated(Field::parse_unnamed, Token![,])?, 317 }) 318 } 319 } 320 321 impl Field { 322 /// Parses a named (braced struct) field. 323 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] parse_named(input: ParseStream) -> Result<Self>324 pub fn parse_named(input: ParseStream) -> Result<Self> { 325 let attrs = input.call(Attribute::parse_outer)?; 326 let vis: Visibility = input.parse()?; 327 328 let unnamed_field = cfg!(feature = "full") && input.peek(Token![_]); 329 let ident = if unnamed_field { 330 input.call(Ident::parse_any) 331 } else { 332 input.parse() 333 }?; 334 335 let colon_token: Token![:] = input.parse()?; 336 337 let ty: Type = if unnamed_field 338 && (input.peek(Token![struct]) 339 || input.peek(Token![union]) && input.peek2(token::Brace)) 340 { 341 let begin = input.fork(); 342 input.call(Ident::parse_any)?; 343 input.parse::<FieldsNamed>()?; 344 Type::Verbatim(verbatim::between(&begin, input)) 345 } else { 346 input.parse()? 347 }; 348 349 Ok(Field { 350 attrs, 351 vis, 352 mutability: FieldMutability::None, 353 ident: Some(ident), 354 colon_token: Some(colon_token), 355 ty, 356 }) 357 } 358 359 /// Parses an unnamed (tuple struct) field. 360 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] parse_unnamed(input: ParseStream) -> Result<Self>361 pub fn parse_unnamed(input: ParseStream) -> Result<Self> { 362 Ok(Field { 363 attrs: input.call(Attribute::parse_outer)?, 364 vis: input.parse()?, 365 mutability: FieldMutability::None, 366 ident: None, 367 colon_token: None, 368 ty: input.parse()?, 369 }) 370 } 371 } 372 } 373 374 #[cfg(feature = "printing")] 375 mod printing { 376 use crate::data::{Field, FieldsNamed, FieldsUnnamed, Variant}; 377 use crate::print::TokensOrDefault; 378 use proc_macro2::TokenStream; 379 use quote::{ToTokens, TokenStreamExt}; 380 381 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 382 impl ToTokens for Variant { to_tokens(&self, tokens: &mut TokenStream)383 fn to_tokens(&self, tokens: &mut TokenStream) { 384 tokens.append_all(&self.attrs); 385 self.ident.to_tokens(tokens); 386 self.fields.to_tokens(tokens); 387 if let Some((eq_token, disc)) = &self.discriminant { 388 eq_token.to_tokens(tokens); 389 disc.to_tokens(tokens); 390 } 391 } 392 } 393 394 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 395 impl ToTokens for FieldsNamed { to_tokens(&self, tokens: &mut TokenStream)396 fn to_tokens(&self, tokens: &mut TokenStream) { 397 self.brace_token.surround(tokens, |tokens| { 398 self.named.to_tokens(tokens); 399 }); 400 } 401 } 402 403 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 404 impl ToTokens for FieldsUnnamed { to_tokens(&self, tokens: &mut TokenStream)405 fn to_tokens(&self, tokens: &mut TokenStream) { 406 self.paren_token.surround(tokens, |tokens| { 407 self.unnamed.to_tokens(tokens); 408 }); 409 } 410 } 411 412 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 413 impl ToTokens for Field { to_tokens(&self, tokens: &mut TokenStream)414 fn to_tokens(&self, tokens: &mut TokenStream) { 415 tokens.append_all(&self.attrs); 416 self.vis.to_tokens(tokens); 417 if let Some(ident) = &self.ident { 418 ident.to_tokens(tokens); 419 TokensOrDefault(&self.colon_token).to_tokens(tokens); 420 } 421 self.ty.to_tokens(tokens); 422 } 423 } 424 } 425