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 { |
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 { |
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" )] |
138 | 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 { |
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 { |
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 | |