1 use crate::attr::Attribute; 2 use crate::expr::Expr; 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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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(doc_cfg, 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 109 impl IntoIterator for Fields { 110 type Item = Field; 111 type IntoIter = punctuated::IntoIter<Field>; 112 into_iter(self) -> Self::IntoIter113 fn into_iter(self) -> Self::IntoIter { 114 match self { 115 Fields::Unit => Punctuated::<Field, ()>::new().into_iter(), 116 Fields::Named(f) => f.named.into_iter(), 117 Fields::Unnamed(f) => f.unnamed.into_iter(), 118 } 119 } 120 } 121 122 impl<'a> IntoIterator for &'a Fields { 123 type Item = &'a Field; 124 type IntoIter = punctuated::Iter<'a, Field>; 125 into_iter(self) -> Self::IntoIter126 fn into_iter(self) -> Self::IntoIter { 127 self.iter() 128 } 129 } 130 131 impl<'a> IntoIterator for &'a mut Fields { 132 type Item = &'a mut Field; 133 type IntoIter = punctuated::IterMut<'a, Field>; 134 into_iter(self) -> Self::IntoIter135 fn into_iter(self) -> Self::IntoIter { 136 self.iter_mut() 137 } 138 } 139 140 ast_struct! { 141 /// A field of a struct or enum variant. 142 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 143 pub struct Field { 144 pub attrs: Vec<Attribute>, 145 146 pub vis: Visibility, 147 148 pub mutability: FieldMutability, 149 150 /// Name of the field, if any. 151 /// 152 /// Fields of tuple structs have no names. 153 pub ident: Option<Ident>, 154 155 pub colon_token: Option<Token![:]>, 156 157 pub ty: Type, 158 } 159 } 160 161 #[cfg(feature = "parsing")] 162 pub(crate) mod parsing { 163 use crate::attr::Attribute; 164 use crate::data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant}; 165 use crate::error::Result; 166 use crate::expr::Expr; 167 use crate::ext::IdentExt as _; 168 use crate::ident::Ident; 169 #[cfg(not(feature = "full"))] 170 use crate::parse::discouraged::Speculative as _; 171 use crate::parse::{Parse, ParseStream}; 172 use crate::restriction::{FieldMutability, Visibility}; 173 use crate::token; 174 use crate::ty::Type; 175 use crate::verbatim; 176 177 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 178 impl Parse for Variant { parse(input: ParseStream) -> Result<Self>179 fn parse(input: ParseStream) -> Result<Self> { 180 let attrs = input.call(Attribute::parse_outer)?; 181 let _visibility: Visibility = input.parse()?; 182 let ident: Ident = input.parse()?; 183 let fields = if input.peek(token::Brace) { 184 Fields::Named(input.parse()?) 185 } else if input.peek(token::Paren) { 186 Fields::Unnamed(input.parse()?) 187 } else { 188 Fields::Unit 189 }; 190 let discriminant = if input.peek(Token![=]) { 191 let eq_token: Token![=] = input.parse()?; 192 #[cfg(feature = "full")] 193 let discriminant: Expr = input.parse()?; 194 #[cfg(not(feature = "full"))] 195 let discriminant = { 196 let begin = input.fork(); 197 let ahead = input.fork(); 198 let mut discriminant: Result<Expr> = ahead.parse(); 199 if discriminant.is_ok() { 200 input.advance_to(&ahead); 201 } else if scan_lenient_discriminant(input).is_ok() { 202 discriminant = Ok(Expr::Verbatim(verbatim::between(&begin, input))); 203 } 204 discriminant? 205 }; 206 Some((eq_token, discriminant)) 207 } else { 208 None 209 }; 210 Ok(Variant { 211 attrs, 212 ident, 213 fields, 214 discriminant, 215 }) 216 } 217 } 218 219 #[cfg(not(feature = "full"))] scan_lenient_discriminant(input: ParseStream) -> Result<()>220 pub(crate) fn scan_lenient_discriminant(input: ParseStream) -> Result<()> { 221 use crate::expr::Member; 222 use crate::lifetime::Lifetime; 223 use crate::lit::Lit; 224 use crate::lit::LitFloat; 225 use crate::op::{BinOp, UnOp}; 226 use crate::path::{self, AngleBracketedGenericArguments}; 227 use proc_macro2::Delimiter::{self, Brace, Bracket, Parenthesis}; 228 229 let consume = |delimiter: Delimiter| { 230 Result::unwrap(input.step(|cursor| match cursor.group(delimiter) { 231 Some((_inside, _span, rest)) => Ok((true, rest)), 232 None => Ok((false, *cursor)), 233 })) 234 }; 235 236 macro_rules! consume { 237 [$token:tt] => { 238 input.parse::<Option<Token![$token]>>().unwrap().is_some() 239 }; 240 } 241 242 let mut initial = true; 243 let mut depth = 0usize; 244 loop { 245 if initial { 246 if consume![&] { 247 input.parse::<Option<Token![mut]>>()?; 248 } else if consume![if] || consume![match] || consume![while] { 249 depth += 1; 250 } else if input.parse::<Option<Lit>>()?.is_some() 251 || (consume(Brace) || consume(Bracket) || consume(Parenthesis)) 252 || (consume![async] || consume![const] || consume![loop] || consume![unsafe]) 253 && (consume(Brace) || break) 254 { 255 initial = false; 256 } else if consume![let] { 257 while !consume![=] { 258 if !((consume![|] || consume![ref] || consume![mut] || consume![@]) 259 || (consume![!] || input.parse::<Option<Lit>>()?.is_some()) 260 || (consume![..=] || consume![..] || consume![&] || consume![_]) 261 || (consume(Brace) || consume(Bracket) || consume(Parenthesis))) 262 { 263 path::parsing::qpath(input, true)?; 264 } 265 } 266 } else if input.parse::<Option<Lifetime>>()?.is_some() && !consume![:] { 267 break; 268 } else if input.parse::<UnOp>().is_err() { 269 path::parsing::qpath(input, true)?; 270 initial = consume![!] || depth == 0 && input.peek(token::Brace); 271 } 272 } else if input.is_empty() || input.peek(Token![,]) { 273 return Ok(()); 274 } else if depth > 0 && consume(Brace) { 275 if consume![else] && !consume(Brace) { 276 initial = consume![if] || break; 277 } else { 278 depth -= 1; 279 } 280 } else if input.parse::<BinOp>().is_ok() || (consume![..] | consume![=]) { 281 initial = true; 282 } else if consume![.] { 283 if input.parse::<Option<LitFloat>>()?.is_none() 284 && (input.parse::<Member>()?.is_named() && consume![::]) 285 { 286 AngleBracketedGenericArguments::do_parse(None, input)?; 287 } 288 } else if consume![as] { 289 input.parse::<Type>()?; 290 } else if !(consume(Brace) || consume(Bracket) || consume(Parenthesis)) { 291 break; 292 } 293 } 294 295 Err(input.error("unsupported expression")) 296 } 297 298 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 299 impl Parse for FieldsNamed { parse(input: ParseStream) -> Result<Self>300 fn parse(input: ParseStream) -> Result<Self> { 301 let content; 302 Ok(FieldsNamed { 303 brace_token: braced!(content in input), 304 named: content.parse_terminated(Field::parse_named, Token![,])?, 305 }) 306 } 307 } 308 309 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 310 impl Parse for FieldsUnnamed { parse(input: ParseStream) -> Result<Self>311 fn parse(input: ParseStream) -> Result<Self> { 312 let content; 313 Ok(FieldsUnnamed { 314 paren_token: parenthesized!(content in input), 315 unnamed: content.parse_terminated(Field::parse_unnamed, Token![,])?, 316 }) 317 } 318 } 319 320 impl Field { 321 /// Parses a named (braced struct) field. 322 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_named(input: ParseStream) -> Result<Self>323 pub fn parse_named(input: ParseStream) -> Result<Self> { 324 let attrs = input.call(Attribute::parse_outer)?; 325 let vis: Visibility = input.parse()?; 326 327 let unnamed_field = cfg!(feature = "full") && input.peek(Token![_]); 328 let ident = if unnamed_field { 329 input.call(Ident::parse_any) 330 } else { 331 input.parse() 332 }?; 333 334 let colon_token: Token![:] = input.parse()?; 335 336 let ty: Type = if unnamed_field 337 && (input.peek(Token![struct]) 338 || input.peek(Token![union]) && input.peek2(token::Brace)) 339 { 340 let begin = input.fork(); 341 input.call(Ident::parse_any)?; 342 input.parse::<FieldsNamed>()?; 343 Type::Verbatim(verbatim::between(&begin, input)) 344 } else { 345 input.parse()? 346 }; 347 348 Ok(Field { 349 attrs, 350 vis, 351 mutability: FieldMutability::None, 352 ident: Some(ident), 353 colon_token: Some(colon_token), 354 ty, 355 }) 356 } 357 358 /// Parses an unnamed (tuple struct) field. 359 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_unnamed(input: ParseStream) -> Result<Self>360 pub fn parse_unnamed(input: ParseStream) -> Result<Self> { 361 Ok(Field { 362 attrs: input.call(Attribute::parse_outer)?, 363 vis: input.parse()?, 364 mutability: FieldMutability::None, 365 ident: None, 366 colon_token: None, 367 ty: input.parse()?, 368 }) 369 } 370 } 371 } 372 373 #[cfg(feature = "printing")] 374 mod printing { 375 use crate::data::{Field, FieldsNamed, FieldsUnnamed, Variant}; 376 use crate::print::TokensOrDefault; 377 use proc_macro2::TokenStream; 378 use quote::{ToTokens, TokenStreamExt}; 379 380 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 381 impl ToTokens for Variant { to_tokens(&self, tokens: &mut TokenStream)382 fn to_tokens(&self, tokens: &mut TokenStream) { 383 tokens.append_all(&self.attrs); 384 self.ident.to_tokens(tokens); 385 self.fields.to_tokens(tokens); 386 if let Some((eq_token, disc)) = &self.discriminant { 387 eq_token.to_tokens(tokens); 388 disc.to_tokens(tokens); 389 } 390 } 391 } 392 393 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 394 impl ToTokens for FieldsNamed { to_tokens(&self, tokens: &mut TokenStream)395 fn to_tokens(&self, tokens: &mut TokenStream) { 396 self.brace_token.surround(tokens, |tokens| { 397 self.named.to_tokens(tokens); 398 }); 399 } 400 } 401 402 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 403 impl ToTokens for FieldsUnnamed { to_tokens(&self, tokens: &mut TokenStream)404 fn to_tokens(&self, tokens: &mut TokenStream) { 405 self.paren_token.surround(tokens, |tokens| { 406 self.unnamed.to_tokens(tokens); 407 }); 408 } 409 } 410 411 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 412 impl ToTokens for Field { to_tokens(&self, tokens: &mut TokenStream)413 fn to_tokens(&self, tokens: &mut TokenStream) { 414 tokens.append_all(&self.attrs); 415 self.vis.to_tokens(tokens); 416 if let Some(ident) = &self.ident { 417 ident.to_tokens(tokens); 418 TokensOrDefault(&self.colon_token).to_tokens(tokens); 419 } 420 self.ty.to_tokens(tokens); 421 } 422 } 423 } 424