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