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