1 use super::*; 2 use crate::punctuated::Punctuated; 3 4 ast_struct! { 5 /// An enum variant. 6 /// 7 /// *This type is available if Syn is built with the `"derive"` or `"full"` 8 /// feature.* 9 pub struct Variant { 10 /// Attributes tagged on the variant. 11 pub attrs: Vec<Attribute>, 12 13 /// Name of the variant. 14 pub ident: Ident, 15 16 /// Content stored in the variant. 17 pub fields: Fields, 18 19 /// Explicit discriminant: `Variant = 1` 20 pub discriminant: Option<(Token![=], Expr)>, 21 } 22 } 23 24 ast_enum_of_structs! { 25 /// Data stored within an enum variant or struct. 26 /// 27 /// *This type is available if Syn is built with the `"derive"` or `"full"` 28 /// feature.* 29 /// 30 /// # Syntax tree enum 31 /// 32 /// This type is a [syntax tree enum]. 33 /// 34 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums 35 // 36 // TODO: change syntax-tree-enum link to an intra rustdoc link, currently 37 // blocked on https://github.com/rust-lang/rust/issues/62833 38 pub enum Fields { 39 /// Named fields of a struct or struct variant such as `Point { x: f64, 40 /// y: f64 }`. 41 Named(FieldsNamed), 42 43 /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`. 44 Unnamed(FieldsUnnamed), 45 46 /// Unit struct or unit variant such as `None`. 47 Unit, 48 } 49 } 50 51 ast_struct! { 52 /// Named fields of a struct or struct variant such as `Point { x: f64, 53 /// y: f64 }`. 54 /// 55 /// *This type is available if Syn is built with the `"derive"` or 56 /// `"full"` feature.* 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 if Syn is built with the `"derive"` or 67 /// `"full"` feature.* 68 pub struct FieldsUnnamed { 69 pub paren_token: token::Paren, 70 pub unnamed: Punctuated<Field, Token![,]>, 71 } 72 } 73 74 impl Fields { 75 /// Get an iterator over the borrowed [`Field`] items in this object. This 76 /// iterator can be used to iterate over a named or unnamed struct or 77 /// variant's fields uniformly. iter(&self) -> punctuated::Iter<Field>78 pub fn iter(&self) -> punctuated::Iter<Field> { 79 match self { 80 Fields::Unit => crate::punctuated::empty_punctuated_iter(), 81 Fields::Named(f) => f.named.iter(), 82 Fields::Unnamed(f) => f.unnamed.iter(), 83 } 84 } 85 86 /// Get an iterator over the mutably borrowed [`Field`] items in this 87 /// object. This iterator can be used to iterate over a named or unnamed 88 /// struct or variant's fields uniformly. iter_mut(&mut self) -> punctuated::IterMut<Field>89 pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> { 90 match self { 91 Fields::Unit => crate::punctuated::empty_punctuated_iter_mut(), 92 Fields::Named(f) => f.named.iter_mut(), 93 Fields::Unnamed(f) => f.unnamed.iter_mut(), 94 } 95 } 96 } 97 98 impl IntoIterator for Fields { 99 type Item = Field; 100 type IntoIter = punctuated::IntoIter<Field>; 101 into_iter(self) -> Self::IntoIter102 fn into_iter(self) -> Self::IntoIter { 103 match self { 104 Fields::Unit => Punctuated::<Field, ()>::new().into_iter(), 105 Fields::Named(f) => f.named.into_iter(), 106 Fields::Unnamed(f) => f.unnamed.into_iter(), 107 } 108 } 109 } 110 111 impl<'a> IntoIterator for &'a Fields { 112 type Item = &'a Field; 113 type IntoIter = punctuated::Iter<'a, Field>; 114 into_iter(self) -> Self::IntoIter115 fn into_iter(self) -> Self::IntoIter { 116 self.iter() 117 } 118 } 119 120 impl<'a> IntoIterator for &'a mut Fields { 121 type Item = &'a mut Field; 122 type IntoIter = punctuated::IterMut<'a, Field>; 123 into_iter(self) -> Self::IntoIter124 fn into_iter(self) -> Self::IntoIter { 125 self.iter_mut() 126 } 127 } 128 129 ast_struct! { 130 /// A field of a struct or enum variant. 131 /// 132 /// *This type is available if Syn is built with the `"derive"` or `"full"` 133 /// feature.* 134 pub struct Field { 135 /// Attributes tagged on the field. 136 pub attrs: Vec<Attribute>, 137 138 /// Visibility of the field. 139 pub vis: Visibility, 140 141 /// Name of the field, if any. 142 /// 143 /// Fields of tuple structs have no names. 144 pub ident: Option<Ident>, 145 146 pub colon_token: Option<Token![:]>, 147 148 /// Type of the field. 149 pub ty: Type, 150 } 151 } 152 153 ast_enum_of_structs! { 154 /// The visibility level of an item: inherited or `pub` or 155 /// `pub(restricted)`. 156 /// 157 /// *This type is available if Syn is built with the `"derive"` or `"full"` 158 /// feature.* 159 /// 160 /// # Syntax tree enum 161 /// 162 /// This type is a [syntax tree enum]. 163 /// 164 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums 165 // 166 // TODO: change syntax-tree-enum link to an intra rustdoc link, currently 167 // blocked on https://github.com/rust-lang/rust/issues/62833 168 pub enum Visibility { 169 /// A public visibility level: `pub`. 170 Public(VisPublic), 171 172 /// A crate-level visibility: `crate`. 173 Crate(VisCrate), 174 175 /// A visibility level restricted to some path: `pub(self)` or 176 /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. 177 Restricted(VisRestricted), 178 179 /// An inherited visibility, which usually means private. 180 Inherited, 181 } 182 } 183 184 ast_struct! { 185 /// A public visibility level: `pub`. 186 /// 187 /// *This type is available if Syn is built with the `"derive"` or 188 /// `"full"` feature.* 189 pub struct VisPublic { 190 pub pub_token: Token![pub], 191 } 192 } 193 194 ast_struct! { 195 /// A crate-level visibility: `crate`. 196 /// 197 /// *This type is available if Syn is built with the `"derive"` or 198 /// `"full"` feature.* 199 pub struct VisCrate { 200 pub crate_token: Token![crate], 201 } 202 } 203 204 ast_struct! { 205 /// A visibility level restricted to some path: `pub(self)` or 206 /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. 207 /// 208 /// *This type is available if Syn is built with the `"derive"` or 209 /// `"full"` feature.* 210 pub struct VisRestricted { 211 pub pub_token: Token![pub], 212 pub paren_token: token::Paren, 213 pub in_token: Option<Token![in]>, 214 pub path: Box<Path>, 215 } 216 } 217 218 #[cfg(feature = "parsing")] 219 pub mod parsing { 220 use super::*; 221 222 use crate::ext::IdentExt; 223 use crate::parse::{Parse, ParseStream, Result}; 224 225 impl Parse for Variant { parse(input: ParseStream) -> Result<Self>226 fn parse(input: ParseStream) -> Result<Self> { 227 Ok(Variant { 228 attrs: input.call(Attribute::parse_outer)?, 229 ident: input.parse()?, 230 fields: { 231 if input.peek(token::Brace) { 232 Fields::Named(input.parse()?) 233 } else if input.peek(token::Paren) { 234 Fields::Unnamed(input.parse()?) 235 } else { 236 Fields::Unit 237 } 238 }, 239 discriminant: { 240 if input.peek(Token![=]) { 241 let eq_token: Token![=] = input.parse()?; 242 let discriminant: Expr = input.parse()?; 243 Some((eq_token, discriminant)) 244 } else { 245 None 246 } 247 }, 248 }) 249 } 250 } 251 252 impl Parse for FieldsNamed { parse(input: ParseStream) -> Result<Self>253 fn parse(input: ParseStream) -> Result<Self> { 254 let content; 255 Ok(FieldsNamed { 256 brace_token: braced!(content in input), 257 named: content.parse_terminated(Field::parse_named)?, 258 }) 259 } 260 } 261 262 impl Parse for FieldsUnnamed { parse(input: ParseStream) -> Result<Self>263 fn parse(input: ParseStream) -> Result<Self> { 264 let content; 265 Ok(FieldsUnnamed { 266 paren_token: parenthesized!(content in input), 267 unnamed: content.parse_terminated(Field::parse_unnamed)?, 268 }) 269 } 270 } 271 272 impl Field { 273 /// Parses a named (braced struct) field. parse_named(input: ParseStream) -> Result<Self>274 pub fn parse_named(input: ParseStream) -> Result<Self> { 275 Ok(Field { 276 attrs: input.call(Attribute::parse_outer)?, 277 vis: input.parse()?, 278 ident: Some(input.parse()?), 279 colon_token: Some(input.parse()?), 280 ty: input.parse()?, 281 }) 282 } 283 284 /// Parses an unnamed (tuple struct) field. parse_unnamed(input: ParseStream) -> Result<Self>285 pub fn parse_unnamed(input: ParseStream) -> Result<Self> { 286 Ok(Field { 287 attrs: input.call(Attribute::parse_outer)?, 288 vis: input.parse()?, 289 ident: None, 290 colon_token: None, 291 ty: input.parse()?, 292 }) 293 } 294 } 295 296 impl Parse for Visibility { parse(input: ParseStream) -> Result<Self>297 fn parse(input: ParseStream) -> Result<Self> { 298 if input.peek(Token![pub]) { 299 Self::parse_pub(input) 300 } else if input.peek(Token![crate]) { 301 Self::parse_crate(input) 302 } else { 303 Ok(Visibility::Inherited) 304 } 305 } 306 } 307 308 impl Visibility { parse_pub(input: ParseStream) -> Result<Self>309 fn parse_pub(input: ParseStream) -> Result<Self> { 310 let pub_token = input.parse::<Token![pub]>()?; 311 312 if input.peek(token::Paren) { 313 // TODO: optimize using advance_to 314 let ahead = input.fork(); 315 let mut content; 316 parenthesized!(content in ahead); 317 318 if content.peek(Token![crate]) 319 || content.peek(Token![self]) 320 || content.peek(Token![super]) 321 { 322 return Ok(Visibility::Restricted(VisRestricted { 323 pub_token, 324 paren_token: parenthesized!(content in input), 325 in_token: None, 326 path: Box::new(Path::from(content.call(Ident::parse_any)?)), 327 })); 328 } else if content.peek(Token![in]) { 329 return Ok(Visibility::Restricted(VisRestricted { 330 pub_token, 331 paren_token: parenthesized!(content in input), 332 in_token: Some(content.parse()?), 333 path: Box::new(content.call(Path::parse_mod_style)?), 334 })); 335 } 336 } 337 338 Ok(Visibility::Public(VisPublic { pub_token })) 339 } 340 parse_crate(input: ParseStream) -> Result<Self>341 fn parse_crate(input: ParseStream) -> Result<Self> { 342 if input.peek2(Token![::]) { 343 Ok(Visibility::Inherited) 344 } else { 345 Ok(Visibility::Crate(VisCrate { 346 crate_token: input.parse()?, 347 })) 348 } 349 } 350 } 351 } 352 353 #[cfg(feature = "printing")] 354 mod printing { 355 use super::*; 356 357 use proc_macro2::TokenStream; 358 use quote::{ToTokens, TokenStreamExt}; 359 360 use crate::print::TokensOrDefault; 361 362 impl ToTokens for Variant { to_tokens(&self, tokens: &mut TokenStream)363 fn to_tokens(&self, tokens: &mut TokenStream) { 364 tokens.append_all(&self.attrs); 365 self.ident.to_tokens(tokens); 366 self.fields.to_tokens(tokens); 367 if let Some((eq_token, disc)) = &self.discriminant { 368 eq_token.to_tokens(tokens); 369 disc.to_tokens(tokens); 370 } 371 } 372 } 373 374 impl ToTokens for FieldsNamed { to_tokens(&self, tokens: &mut TokenStream)375 fn to_tokens(&self, tokens: &mut TokenStream) { 376 self.brace_token.surround(tokens, |tokens| { 377 self.named.to_tokens(tokens); 378 }); 379 } 380 } 381 382 impl ToTokens for FieldsUnnamed { to_tokens(&self, tokens: &mut TokenStream)383 fn to_tokens(&self, tokens: &mut TokenStream) { 384 self.paren_token.surround(tokens, |tokens| { 385 self.unnamed.to_tokens(tokens); 386 }); 387 } 388 } 389 390 impl ToTokens for Field { to_tokens(&self, tokens: &mut TokenStream)391 fn to_tokens(&self, tokens: &mut TokenStream) { 392 tokens.append_all(&self.attrs); 393 self.vis.to_tokens(tokens); 394 if let Some(ident) = &self.ident { 395 ident.to_tokens(tokens); 396 TokensOrDefault(&self.colon_token).to_tokens(tokens); 397 } 398 self.ty.to_tokens(tokens); 399 } 400 } 401 402 impl ToTokens for VisPublic { to_tokens(&self, tokens: &mut TokenStream)403 fn to_tokens(&self, tokens: &mut TokenStream) { 404 self.pub_token.to_tokens(tokens) 405 } 406 } 407 408 impl ToTokens for VisCrate { to_tokens(&self, tokens: &mut TokenStream)409 fn to_tokens(&self, tokens: &mut TokenStream) { 410 self.crate_token.to_tokens(tokens); 411 } 412 } 413 414 impl ToTokens for VisRestricted { to_tokens(&self, tokens: &mut TokenStream)415 fn to_tokens(&self, tokens: &mut TokenStream) { 416 self.pub_token.to_tokens(tokens); 417 self.paren_token.surround(tokens, |tokens| { 418 // TODO: If we have a path which is not "self" or "super" or 419 // "crate", automatically add the "in" token. 420 self.in_token.to_tokens(tokens); 421 self.path.to_tokens(tokens); 422 }); 423 } 424 } 425 } 426