1 use super::*; 2 use crate::punctuated::Punctuated; 3 4 ast_struct! { 5 /// An enum variant. 6 /// 7 /// *This type is available only if Syn is built with the `"derive"` or `"full"` 8 /// feature.* 9 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 10 pub struct Variant { 11 /// Attributes tagged on the variant. 12 pub attrs: Vec<Attribute>, 13 14 /// Name of the variant. 15 pub ident: Ident, 16 17 /// Content stored in the variant. 18 pub fields: Fields, 19 20 /// Explicit discriminant: `Variant = 1` 21 pub discriminant: Option<(Token![=], Expr)>, 22 } 23 } 24 25 ast_enum_of_structs! { 26 /// Data stored within an enum variant or struct. 27 /// 28 /// *This type is available only if Syn is built with the `"derive"` or `"full"` 29 /// feature.* 30 /// 31 /// # Syntax tree enum 32 /// 33 /// This type is a [syntax tree enum]. 34 /// 35 /// [syntax tree enum]: Expr#syntax-tree-enums 36 #[cfg_attr(doc_cfg, 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 /// 54 /// *This type is available only if Syn is built with the `"derive"` or 55 /// `"full"` feature.* 56 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 57 pub struct FieldsNamed { 58 pub brace_token: token::Brace, 59 pub named: Punctuated<Field, Token![,]>, 60 } 61 } 62 63 ast_struct! { 64 /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`. 65 /// 66 /// *This type is available only if Syn is built with the `"derive"` or 67 /// `"full"` feature.* 68 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 69 pub struct FieldsUnnamed { 70 pub paren_token: token::Paren, 71 pub unnamed: Punctuated<Field, Token![,]>, 72 } 73 } 74 75 impl Fields { 76 /// Get an iterator over the borrowed [`Field`] items in this object. This 77 /// iterator can be used to iterate over a named or unnamed struct or 78 /// variant's fields uniformly. iter(&self) -> punctuated::Iter<Field>79 pub fn iter(&self) -> punctuated::Iter<Field> { 80 match self { 81 Fields::Unit => crate::punctuated::empty_punctuated_iter(), 82 Fields::Named(f) => f.named.iter(), 83 Fields::Unnamed(f) => f.unnamed.iter(), 84 } 85 } 86 87 /// Get an iterator over the mutably borrowed [`Field`] items in this 88 /// object. This iterator can be used to iterate over a named or unnamed 89 /// struct or variant's fields uniformly. iter_mut(&mut self) -> punctuated::IterMut<Field>90 pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> { 91 match self { 92 Fields::Unit => crate::punctuated::empty_punctuated_iter_mut(), 93 Fields::Named(f) => f.named.iter_mut(), 94 Fields::Unnamed(f) => f.unnamed.iter_mut(), 95 } 96 } 97 98 /// Returns the number of fields. len(&self) -> usize99 pub fn len(&self) -> usize { 100 match self { 101 Fields::Unit => 0, 102 Fields::Named(f) => f.named.len(), 103 Fields::Unnamed(f) => f.unnamed.len(), 104 } 105 } 106 107 /// Returns `true` if there are zero fields. is_empty(&self) -> bool108 pub fn is_empty(&self) -> bool { 109 match self { 110 Fields::Unit => true, 111 Fields::Named(f) => f.named.is_empty(), 112 Fields::Unnamed(f) => f.unnamed.is_empty(), 113 } 114 } 115 } 116 117 impl IntoIterator for Fields { 118 type Item = Field; 119 type IntoIter = punctuated::IntoIter<Field>; 120 into_iter(self) -> Self::IntoIter121 fn into_iter(self) -> Self::IntoIter { 122 match self { 123 Fields::Unit => Punctuated::<Field, ()>::new().into_iter(), 124 Fields::Named(f) => f.named.into_iter(), 125 Fields::Unnamed(f) => f.unnamed.into_iter(), 126 } 127 } 128 } 129 130 impl<'a> IntoIterator for &'a Fields { 131 type Item = &'a Field; 132 type IntoIter = punctuated::Iter<'a, Field>; 133 into_iter(self) -> Self::IntoIter134 fn into_iter(self) -> Self::IntoIter { 135 self.iter() 136 } 137 } 138 139 impl<'a> IntoIterator for &'a mut Fields { 140 type Item = &'a mut Field; 141 type IntoIter = punctuated::IterMut<'a, Field>; 142 into_iter(self) -> Self::IntoIter143 fn into_iter(self) -> Self::IntoIter { 144 self.iter_mut() 145 } 146 } 147 148 ast_struct! { 149 /// A field of a struct or enum variant. 150 /// 151 /// *This type is available only if Syn is built with the `"derive"` or `"full"` 152 /// feature.* 153 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 154 pub struct Field { 155 /// Attributes tagged on the field. 156 pub attrs: Vec<Attribute>, 157 158 /// Visibility of the field. 159 pub vis: Visibility, 160 161 /// Name of the field, if any. 162 /// 163 /// Fields of tuple structs have no names. 164 pub ident: Option<Ident>, 165 166 pub colon_token: Option<Token![:]>, 167 168 /// Type of the field. 169 pub ty: Type, 170 } 171 } 172 173 ast_enum_of_structs! { 174 /// The visibility level of an item: inherited or `pub` or 175 /// `pub(restricted)`. 176 /// 177 /// *This type is available only if Syn is built with the `"derive"` or `"full"` 178 /// feature.* 179 /// 180 /// # Syntax tree enum 181 /// 182 /// This type is a [syntax tree enum]. 183 /// 184 /// [syntax tree enum]: Expr#syntax-tree-enums 185 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 186 pub enum Visibility { 187 /// A public visibility level: `pub`. 188 Public(VisPublic), 189 190 /// A crate-level visibility: `crate`. 191 Crate(VisCrate), 192 193 /// A visibility level restricted to some path: `pub(self)` or 194 /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. 195 Restricted(VisRestricted), 196 197 /// An inherited visibility, which usually means private. 198 Inherited, 199 } 200 } 201 202 ast_struct! { 203 /// A public visibility level: `pub`. 204 /// 205 /// *This type is available only if Syn is built with the `"derive"` or 206 /// `"full"` feature.* 207 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 208 pub struct VisPublic { 209 pub pub_token: Token![pub], 210 } 211 } 212 213 ast_struct! { 214 /// A crate-level visibility: `crate`. 215 /// 216 /// *This type is available only if Syn is built with the `"derive"` or 217 /// `"full"` feature.* 218 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 219 pub struct VisCrate { 220 pub crate_token: Token![crate], 221 } 222 } 223 224 ast_struct! { 225 /// A visibility level restricted to some path: `pub(self)` or 226 /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. 227 /// 228 /// *This type is available only if Syn is built with the `"derive"` or 229 /// `"full"` feature.* 230 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 231 pub struct VisRestricted { 232 pub pub_token: Token![pub], 233 pub paren_token: token::Paren, 234 pub in_token: Option<Token![in]>, 235 pub path: Box<Path>, 236 } 237 } 238 239 #[cfg(feature = "parsing")] 240 pub mod parsing { 241 use super::*; 242 use crate::ext::IdentExt; 243 use crate::parse::discouraged::Speculative; 244 use crate::parse::{Parse, ParseStream, Result}; 245 246 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 247 impl Parse for Variant { parse(input: ParseStream) -> Result<Self>248 fn parse(input: ParseStream) -> Result<Self> { 249 let attrs = input.call(Attribute::parse_outer)?; 250 let _visibility: Visibility = input.parse()?; 251 let ident: Ident = input.parse()?; 252 let fields = if input.peek(token::Brace) { 253 Fields::Named(input.parse()?) 254 } else if input.peek(token::Paren) { 255 Fields::Unnamed(input.parse()?) 256 } else { 257 Fields::Unit 258 }; 259 let discriminant = if input.peek(Token![=]) { 260 let eq_token: Token![=] = input.parse()?; 261 let discriminant: Expr = input.parse()?; 262 Some((eq_token, discriminant)) 263 } else { 264 None 265 }; 266 Ok(Variant { 267 attrs, 268 ident, 269 fields, 270 discriminant, 271 }) 272 } 273 } 274 275 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 276 impl Parse for FieldsNamed { parse(input: ParseStream) -> Result<Self>277 fn parse(input: ParseStream) -> Result<Self> { 278 let content; 279 Ok(FieldsNamed { 280 brace_token: braced!(content in input), 281 named: content.parse_terminated(Field::parse_named)?, 282 }) 283 } 284 } 285 286 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 287 impl Parse for FieldsUnnamed { parse(input: ParseStream) -> Result<Self>288 fn parse(input: ParseStream) -> Result<Self> { 289 let content; 290 Ok(FieldsUnnamed { 291 paren_token: parenthesized!(content in input), 292 unnamed: content.parse_terminated(Field::parse_unnamed)?, 293 }) 294 } 295 } 296 297 impl Field { 298 /// Parses a named (braced struct) field. 299 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_named(input: ParseStream) -> Result<Self>300 pub fn parse_named(input: ParseStream) -> Result<Self> { 301 Ok(Field { 302 attrs: input.call(Attribute::parse_outer)?, 303 vis: input.parse()?, 304 ident: Some(if input.peek(Token![_]) { 305 input.call(Ident::parse_any) 306 } else { 307 input.parse() 308 }?), 309 colon_token: Some(input.parse()?), 310 ty: input.parse()?, 311 }) 312 } 313 314 /// Parses an unnamed (tuple struct) field. 315 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_unnamed(input: ParseStream) -> Result<Self>316 pub fn parse_unnamed(input: ParseStream) -> Result<Self> { 317 Ok(Field { 318 attrs: input.call(Attribute::parse_outer)?, 319 vis: input.parse()?, 320 ident: None, 321 colon_token: None, 322 ty: input.parse()?, 323 }) 324 } 325 } 326 327 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 328 impl Parse for Visibility { parse(input: ParseStream) -> Result<Self>329 fn parse(input: ParseStream) -> Result<Self> { 330 // Recognize an empty None-delimited group, as produced by a $:vis 331 // matcher that matched no tokens. 332 if input.peek(token::Group) { 333 let ahead = input.fork(); 334 let group = crate::group::parse_group(&ahead)?; 335 if group.content.is_empty() { 336 input.advance_to(&ahead); 337 return Ok(Visibility::Inherited); 338 } 339 } 340 341 if input.peek(Token![pub]) { 342 Self::parse_pub(input) 343 } else if input.peek(Token![crate]) { 344 Self::parse_crate(input) 345 } else { 346 Ok(Visibility::Inherited) 347 } 348 } 349 } 350 351 impl Visibility { parse_pub(input: ParseStream) -> Result<Self>352 fn parse_pub(input: ParseStream) -> Result<Self> { 353 let pub_token = input.parse::<Token![pub]>()?; 354 355 if input.peek(token::Paren) { 356 let ahead = input.fork(); 357 358 let content; 359 let paren_token = parenthesized!(content in ahead); 360 if content.peek(Token![crate]) 361 || content.peek(Token![self]) 362 || content.peek(Token![super]) 363 { 364 let path = content.call(Ident::parse_any)?; 365 366 // Ensure there are no additional tokens within `content`. 367 // Without explicitly checking, we may misinterpret a tuple 368 // field as a restricted visibility, causing a parse error. 369 // e.g. `pub (crate::A, crate::B)` (Issue #720). 370 if content.is_empty() { 371 input.advance_to(&ahead); 372 return Ok(Visibility::Restricted(VisRestricted { 373 pub_token, 374 paren_token, 375 in_token: None, 376 path: Box::new(Path::from(path)), 377 })); 378 } 379 } else if content.peek(Token![in]) { 380 let in_token: Token![in] = content.parse()?; 381 let path = content.call(Path::parse_mod_style)?; 382 383 input.advance_to(&ahead); 384 return Ok(Visibility::Restricted(VisRestricted { 385 pub_token, 386 paren_token, 387 in_token: Some(in_token), 388 path: Box::new(path), 389 })); 390 } 391 } 392 393 Ok(Visibility::Public(VisPublic { pub_token })) 394 } 395 parse_crate(input: ParseStream) -> Result<Self>396 fn parse_crate(input: ParseStream) -> Result<Self> { 397 if input.peek2(Token![::]) { 398 Ok(Visibility::Inherited) 399 } else { 400 Ok(Visibility::Crate(VisCrate { 401 crate_token: input.parse()?, 402 })) 403 } 404 } 405 406 #[cfg(feature = "full")] is_some(&self) -> bool407 pub(crate) fn is_some(&self) -> bool { 408 match self { 409 Visibility::Inherited => false, 410 _ => true, 411 } 412 } 413 } 414 } 415 416 #[cfg(feature = "printing")] 417 mod printing { 418 use super::*; 419 use crate::print::TokensOrDefault; 420 use proc_macro2::TokenStream; 421 use quote::{ToTokens, TokenStreamExt}; 422 423 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 424 impl ToTokens for Variant { to_tokens(&self, tokens: &mut TokenStream)425 fn to_tokens(&self, tokens: &mut TokenStream) { 426 tokens.append_all(&self.attrs); 427 self.ident.to_tokens(tokens); 428 self.fields.to_tokens(tokens); 429 if let Some((eq_token, disc)) = &self.discriminant { 430 eq_token.to_tokens(tokens); 431 disc.to_tokens(tokens); 432 } 433 } 434 } 435 436 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 437 impl ToTokens for FieldsNamed { to_tokens(&self, tokens: &mut TokenStream)438 fn to_tokens(&self, tokens: &mut TokenStream) { 439 self.brace_token.surround(tokens, |tokens| { 440 self.named.to_tokens(tokens); 441 }); 442 } 443 } 444 445 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 446 impl ToTokens for FieldsUnnamed { to_tokens(&self, tokens: &mut TokenStream)447 fn to_tokens(&self, tokens: &mut TokenStream) { 448 self.paren_token.surround(tokens, |tokens| { 449 self.unnamed.to_tokens(tokens); 450 }); 451 } 452 } 453 454 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 455 impl ToTokens for Field { to_tokens(&self, tokens: &mut TokenStream)456 fn to_tokens(&self, tokens: &mut TokenStream) { 457 tokens.append_all(&self.attrs); 458 self.vis.to_tokens(tokens); 459 if let Some(ident) = &self.ident { 460 ident.to_tokens(tokens); 461 TokensOrDefault(&self.colon_token).to_tokens(tokens); 462 } 463 self.ty.to_tokens(tokens); 464 } 465 } 466 467 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 468 impl ToTokens for VisPublic { to_tokens(&self, tokens: &mut TokenStream)469 fn to_tokens(&self, tokens: &mut TokenStream) { 470 self.pub_token.to_tokens(tokens); 471 } 472 } 473 474 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 475 impl ToTokens for VisCrate { to_tokens(&self, tokens: &mut TokenStream)476 fn to_tokens(&self, tokens: &mut TokenStream) { 477 self.crate_token.to_tokens(tokens); 478 } 479 } 480 481 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 482 impl ToTokens for VisRestricted { to_tokens(&self, tokens: &mut TokenStream)483 fn to_tokens(&self, tokens: &mut TokenStream) { 484 self.pub_token.to_tokens(tokens); 485 self.paren_token.surround(tokens, |tokens| { 486 // TODO: If we have a path which is not "self" or "super" or 487 // "crate", automatically add the "in" token. 488 self.in_token.to_tokens(tokens); 489 self.path.to_tokens(tokens); 490 }); 491 } 492 } 493 } 494