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