1 use super::*; 2 3 ast_enum! { 4 /// The visibility level of an item: inherited or `pub` or 5 /// `pub(restricted)`. 6 /// 7 /// # Syntax tree enum 8 /// 9 /// This type is a [syntax tree enum]. 10 /// 11 /// [syntax tree enum]: Expr#syntax-tree-enums 12 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 13 pub enum Visibility { 14 /// A public visibility level: `pub`. 15 Public(Token![pub]), 16 17 /// A visibility level restricted to some path: `pub(self)` or 18 /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. 19 Restricted(VisRestricted), 20 21 /// An inherited visibility, which usually means private. 22 Inherited, 23 } 24 } 25 26 ast_struct! { 27 /// A visibility level restricted to some path: `pub(self)` or 28 /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. 29 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 30 pub struct VisRestricted { 31 pub pub_token: Token![pub], 32 pub paren_token: token::Paren, 33 pub in_token: Option<Token![in]>, 34 pub path: Box<Path>, 35 } 36 } 37 38 ast_enum! { 39 /// Unused, but reserved for RFC 3323 restrictions. 40 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 41 #[non_exhaustive] 42 pub enum FieldMutability { 43 None, 44 45 // TODO: https://rust-lang.github.io/rfcs/3323-restrictions.html 46 // 47 // FieldMutability::Restricted(MutRestricted) 48 // 49 // pub struct MutRestricted { 50 // pub mut_token: Token![mut], 51 // pub paren_token: token::Paren, 52 // pub in_token: Option<Token![in]>, 53 // pub path: Box<Path>, 54 // } 55 } 56 } 57 58 #[cfg(feature = "parsing")] 59 pub(crate) mod parsing { 60 use super::*; 61 use crate::ext::IdentExt as _; 62 use crate::parse::discouraged::Speculative as _; 63 use crate::parse::{Parse, ParseStream, Result}; 64 65 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 66 impl Parse for Visibility { parse(input: ParseStream) -> Result<Self>67 fn parse(input: ParseStream) -> Result<Self> { 68 // Recognize an empty None-delimited group, as produced by a $:vis 69 // matcher that matched no tokens. 70 if input.peek(token::Group) { 71 let ahead = input.fork(); 72 let group = crate::group::parse_group(&ahead)?; 73 if group.content.is_empty() { 74 input.advance_to(&ahead); 75 return Ok(Visibility::Inherited); 76 } 77 } 78 79 if input.peek(Token![pub]) { 80 Self::parse_pub(input) 81 } else { 82 Ok(Visibility::Inherited) 83 } 84 } 85 } 86 87 impl Visibility { parse_pub(input: ParseStream) -> Result<Self>88 fn parse_pub(input: ParseStream) -> Result<Self> { 89 let pub_token = input.parse::<Token![pub]>()?; 90 91 if input.peek(token::Paren) { 92 let ahead = input.fork(); 93 94 let content; 95 let paren_token = parenthesized!(content in ahead); 96 if content.peek(Token![crate]) 97 || content.peek(Token![self]) 98 || content.peek(Token![super]) 99 { 100 let path = content.call(Ident::parse_any)?; 101 102 // Ensure there are no additional tokens within `content`. 103 // Without explicitly checking, we may misinterpret a tuple 104 // field as a restricted visibility, causing a parse error. 105 // e.g. `pub (crate::A, crate::B)` (Issue #720). 106 if content.is_empty() { 107 input.advance_to(&ahead); 108 return Ok(Visibility::Restricted(VisRestricted { 109 pub_token, 110 paren_token, 111 in_token: None, 112 path: Box::new(Path::from(path)), 113 })); 114 } 115 } else if content.peek(Token![in]) { 116 let in_token: Token![in] = content.parse()?; 117 let path = content.call(Path::parse_mod_style)?; 118 119 input.advance_to(&ahead); 120 return Ok(Visibility::Restricted(VisRestricted { 121 pub_token, 122 paren_token, 123 in_token: Some(in_token), 124 path: Box::new(path), 125 })); 126 } 127 } 128 129 Ok(Visibility::Public(pub_token)) 130 } 131 132 #[cfg(feature = "full")] is_some(&self) -> bool133 pub(crate) fn is_some(&self) -> bool { 134 match self { 135 Visibility::Inherited => false, 136 _ => true, 137 } 138 } 139 } 140 } 141 142 #[cfg(feature = "printing")] 143 mod printing { 144 use super::*; 145 use proc_macro2::TokenStream; 146 use quote::ToTokens; 147 148 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 149 impl ToTokens for Visibility { to_tokens(&self, tokens: &mut TokenStream)150 fn to_tokens(&self, tokens: &mut TokenStream) { 151 match self { 152 Visibility::Public(pub_token) => pub_token.to_tokens(tokens), 153 Visibility::Restricted(vis_restricted) => vis_restricted.to_tokens(tokens), 154 Visibility::Inherited => {} 155 } 156 } 157 } 158 159 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 160 impl ToTokens for VisRestricted { to_tokens(&self, tokens: &mut TokenStream)161 fn to_tokens(&self, tokens: &mut TokenStream) { 162 self.pub_token.to_tokens(tokens); 163 self.paren_token.surround(tokens, |tokens| { 164 // TODO: If we have a path which is not "self" or "super" or 165 // "crate", automatically add the "in" token. 166 self.in_token.to_tokens(tokens); 167 self.path.to_tokens(tokens); 168 }); 169 } 170 } 171 } 172