1use super::*;
2
3ast_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
26ast_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
38ast_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")]
59pub(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")]
143mod 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