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 Ok(Variant { 252 attrs, 253 ident: input.parse()?, 254 fields: { 255 if input.peek(token::Brace) { 256 Fields::Named(input.parse()?) 257 } else if input.peek(token::Paren) { 258 Fields::Unnamed(input.parse()?) 259 } else { 260 Fields::Unit 261 } 262 }, 263 discriminant: { 264 if input.peek(Token![=]) { 265 let eq_token: Token![=] = input.parse()?; 266 let discriminant: Expr = input.parse()?; 267 Some((eq_token, discriminant)) 268 } else { 269 None 270 } 271 }, 272 }) 273 } 274 } 275 276 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 277 impl Parse for FieldsNamed { parse(input: ParseStream) -> Result<Self>278 fn parse(input: ParseStream) -> Result<Self> { 279 let content; 280 Ok(FieldsNamed { 281 brace_token: braced!(content in input), 282 named: content.parse_terminated(Field::parse_named)?, 283 }) 284 } 285 } 286 287 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 288 impl Parse for FieldsUnnamed { parse(input: ParseStream) -> Result<Self>289 fn parse(input: ParseStream) -> Result<Self> { 290 let content; 291 Ok(FieldsUnnamed { 292 paren_token: parenthesized!(content in input), 293 unnamed: content.parse_terminated(Field::parse_unnamed)?, 294 }) 295 } 296 } 297 298 impl Field { 299 /// Parses a named (braced struct) field. 300 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_named(input: ParseStream) -> Result<Self>301 pub fn parse_named(input: ParseStream) -> Result<Self> { 302 Ok(Field { 303 attrs: input.call(Attribute::parse_outer)?, 304 vis: input.parse()?, 305 ident: Some(input.parse()?), 306 colon_token: Some(input.parse()?), 307 ty: input.parse()?, 308 }) 309 } 310 311 /// Parses an unnamed (tuple struct) field. 312 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_unnamed(input: ParseStream) -> Result<Self>313 pub fn parse_unnamed(input: ParseStream) -> Result<Self> { 314 Ok(Field { 315 attrs: input.call(Attribute::parse_outer)?, 316 vis: input.parse()?, 317 ident: None, 318 colon_token: None, 319 ty: input.parse()?, 320 }) 321 } 322 } 323 324 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 325 impl Parse for Visibility { parse(input: ParseStream) -> Result<Self>326 fn parse(input: ParseStream) -> Result<Self> { 327 // Recognize an empty None-delimited group, as produced by a $:vis 328 // matcher that matched no tokens. 329 if input.peek(token::Group) { 330 let ahead = input.fork(); 331 let group = crate::group::parse_group(&ahead)?; 332 if group.content.is_empty() { 333 input.advance_to(&ahead); 334 return Ok(Visibility::Inherited); 335 } 336 } 337 338 if input.peek(Token![pub]) { 339 Self::parse_pub(input) 340 } else if input.peek(Token![crate]) { 341 Self::parse_crate(input) 342 } else { 343 Ok(Visibility::Inherited) 344 } 345 } 346 } 347 348 impl Visibility { parse_pub(input: ParseStream) -> Result<Self>349 fn parse_pub(input: ParseStream) -> Result<Self> { 350 let pub_token = input.parse::<Token![pub]>()?; 351 352 if input.peek(token::Paren) { 353 let ahead = input.fork(); 354 355 let content; 356 let paren_token = parenthesized!(content in ahead); 357 if content.peek(Token![crate]) 358 || content.peek(Token![self]) 359 || content.peek(Token![super]) 360 { 361 let path = content.call(Ident::parse_any)?; 362 363 // Ensure there are no additional tokens within `content`. 364 // Without explicitly checking, we may misinterpret a tuple 365 // field as a restricted visibility, causing a parse error. 366 // e.g. `pub (crate::A, crate::B)` (Issue #720). 367 if content.is_empty() { 368 input.advance_to(&ahead); 369 return Ok(Visibility::Restricted(VisRestricted { 370 pub_token, 371 paren_token, 372 in_token: None, 373 path: Box::new(Path::from(path)), 374 })); 375 } 376 } else if content.peek(Token![in]) { 377 let in_token: Token![in] = content.parse()?; 378 let path = content.call(Path::parse_mod_style)?; 379 380 input.advance_to(&ahead); 381 return Ok(Visibility::Restricted(VisRestricted { 382 pub_token, 383 paren_token, 384 in_token: Some(in_token), 385 path: Box::new(path), 386 })); 387 } 388 } 389 390 Ok(Visibility::Public(VisPublic { pub_token })) 391 } 392 parse_crate(input: ParseStream) -> Result<Self>393 fn parse_crate(input: ParseStream) -> Result<Self> { 394 if input.peek2(Token![::]) { 395 Ok(Visibility::Inherited) 396 } else { 397 Ok(Visibility::Crate(VisCrate { 398 crate_token: input.parse()?, 399 })) 400 } 401 } 402 403 #[cfg(feature = "full")] is_some(&self) -> bool404 pub(crate) fn is_some(&self) -> bool { 405 match self { 406 Visibility::Inherited => false, 407 _ => true, 408 } 409 } 410 } 411 } 412 413 #[cfg(feature = "printing")] 414 mod printing { 415 use super::*; 416 use crate::print::TokensOrDefault; 417 use proc_macro2::TokenStream; 418 use quote::{ToTokens, TokenStreamExt}; 419 420 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 421 impl ToTokens for Variant { to_tokens(&self, tokens: &mut TokenStream)422 fn to_tokens(&self, tokens: &mut TokenStream) { 423 tokens.append_all(&self.attrs); 424 self.ident.to_tokens(tokens); 425 self.fields.to_tokens(tokens); 426 if let Some((eq_token, disc)) = &self.discriminant { 427 eq_token.to_tokens(tokens); 428 disc.to_tokens(tokens); 429 } 430 } 431 } 432 433 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 434 impl ToTokens for FieldsNamed { to_tokens(&self, tokens: &mut TokenStream)435 fn to_tokens(&self, tokens: &mut TokenStream) { 436 self.brace_token.surround(tokens, |tokens| { 437 self.named.to_tokens(tokens); 438 }); 439 } 440 } 441 442 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 443 impl ToTokens for FieldsUnnamed { to_tokens(&self, tokens: &mut TokenStream)444 fn to_tokens(&self, tokens: &mut TokenStream) { 445 self.paren_token.surround(tokens, |tokens| { 446 self.unnamed.to_tokens(tokens); 447 }); 448 } 449 } 450 451 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 452 impl ToTokens for Field { to_tokens(&self, tokens: &mut TokenStream)453 fn to_tokens(&self, tokens: &mut TokenStream) { 454 tokens.append_all(&self.attrs); 455 self.vis.to_tokens(tokens); 456 if let Some(ident) = &self.ident { 457 ident.to_tokens(tokens); 458 TokensOrDefault(&self.colon_token).to_tokens(tokens); 459 } 460 self.ty.to_tokens(tokens); 461 } 462 } 463 464 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 465 impl ToTokens for VisPublic { to_tokens(&self, tokens: &mut TokenStream)466 fn to_tokens(&self, tokens: &mut TokenStream) { 467 self.pub_token.to_tokens(tokens) 468 } 469 } 470 471 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 472 impl ToTokens for VisCrate { to_tokens(&self, tokens: &mut TokenStream)473 fn to_tokens(&self, tokens: &mut TokenStream) { 474 self.crate_token.to_tokens(tokens); 475 } 476 } 477 478 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 479 impl ToTokens for VisRestricted { to_tokens(&self, tokens: &mut TokenStream)480 fn to_tokens(&self, tokens: &mut TokenStream) { 481 self.pub_token.to_tokens(tokens); 482 self.paren_token.surround(tokens, |tokens| { 483 // TODO: If we have a path which is not "self" or "super" or 484 // "crate", automatically add the "in" token. 485 self.in_token.to_tokens(tokens); 486 self.path.to_tokens(tokens); 487 }); 488 } 489 } 490 } 491