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; |
62 | use crate::parse::discouraged::Speculative; |
63 | use crate::parse::{Parse, ParseStream, Result}; |
64 | |
65 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
66 | impl Parse for Visibility { |
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 { |
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" )] |
133 | 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 { |
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 { |
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 | |