1use crate::path::Path;
2use crate::token;
3
4ast_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
27ast_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
39ast_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")]
60pub(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")]
148mod 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