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