syn/
restriction.rs

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(docsrs, 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(docsrs, 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(docsrs, 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(docsrs, 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::path;
150    use crate::path::printing::PathStyle;
151    use crate::restriction::{VisRestricted, Visibility};
152    use proc_macro2::TokenStream;
153    use quote::ToTokens;
154
155    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
156    impl ToTokens for Visibility {
157        fn to_tokens(&self, tokens: &mut TokenStream) {
158            match self {
159                Visibility::Public(pub_token) => pub_token.to_tokens(tokens),
160                Visibility::Restricted(vis_restricted) => vis_restricted.to_tokens(tokens),
161                Visibility::Inherited => {}
162            }
163        }
164    }
165
166    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
167    impl ToTokens for VisRestricted {
168        fn to_tokens(&self, tokens: &mut TokenStream) {
169            self.pub_token.to_tokens(tokens);
170            self.paren_token.surround(tokens, |tokens| {
171                // TODO: If we have a path which is not "self" or "super" or
172                // "crate", automatically add the "in" token.
173                self.in_token.to_tokens(tokens);
174                path::printing::print_path(tokens, &self.path, PathStyle::Mod);
175            });
176        }
177    }
178}