| // SPDX-License-Identifier: Apache-2.0 OR MIT | |
| use crate::path::Path; | |
| use crate::token; | |
| ast_enum! { | |
| /// The visibility level of an item: inherited or `pub` or | |
| /// `pub(restricted)`. | |
| /// | |
| /// # Syntax tree enum | |
| /// | |
| /// This type is a [syntax tree enum]. | |
| /// | |
| /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums | |
| #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] | |
| pub enum Visibility { | |
| /// A public visibility level: `pub`. | |
| Public(Token![pub]), | |
| /// A visibility level restricted to some path: `pub(self)` or | |
| /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. | |
| Restricted(VisRestricted), | |
| /// An inherited visibility, which usually means private. | |
| Inherited, | |
| } | |
| } | |
| ast_struct! { | |
| /// A visibility level restricted to some path: `pub(self)` or | |
| /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. | |
| #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] | |
| pub struct VisRestricted { | |
| pub pub_token: Token![pub], | |
| pub paren_token: token::Paren, | |
| pub in_token: Option<Token![in]>, | |
| pub path: Box<Path>, | |
| } | |
| } | |
| ast_enum! { | |
| /// Unused, but reserved for RFC 3323 restrictions. | |
| #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] | |
| #[non_exhaustive] | |
| pub enum FieldMutability { | |
| None, | |
| // TODO: https://rust-lang.github.io/rfcs/3323-restrictions.html | |
| // | |
| // FieldMutability::Restricted(MutRestricted) | |
| // | |
| // pub struct MutRestricted { | |
| // pub mut_token: Token![mut], | |
| // pub paren_token: token::Paren, | |
| // pub in_token: Option<Token![in]>, | |
| // pub path: Box<Path>, | |
| // } | |
| } | |
| } | |
| #[cfg(feature = "parsing")] | |
| pub(crate) mod parsing { | |
| use crate::error::Result; | |
| use crate::ext::IdentExt as _; | |
| use crate::ident::Ident; | |
| use crate::parse::discouraged::Speculative as _; | |
| use crate::parse::{Parse, ParseStream}; | |
| use crate::path::Path; | |
| use crate::restriction::{VisRestricted, Visibility}; | |
| use crate::token; | |
| #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] | |
| impl Parse for Visibility { | |
| fn parse(input: ParseStream) -> Result<Self> { | |
| // Recognize an empty None-delimited group, as produced by a $:vis | |
| // matcher that matched no tokens. | |
| if input.peek(token::Group) { | |
| let ahead = input.fork(); | |
| let group = crate::group::parse_group(&ahead)?; | |
| if group.content.is_empty() { | |
| input.advance_to(&ahead); | |
| return Ok(Visibility::Inherited); | |
| } | |
| } | |
| if input.peek(Token![pub]) { | |
| Self::parse_pub(input) | |
| } else { | |
| Ok(Visibility::Inherited) | |
| } | |
| } | |
| } | |
| impl Visibility { | |
| fn parse_pub(input: ParseStream) -> Result<Self> { | |
| let pub_token = input.parse::<Token![pub]>()?; | |
| if input.peek(token::Paren) { | |
| let ahead = input.fork(); | |
| let content; | |
| let paren_token = parenthesized!(content in ahead); | |
| if content.peek(Token![crate]) | |
| || content.peek(Token![self]) | |
| || content.peek(Token![super]) | |
| { | |
| let path = content.call(Ident::parse_any)?; | |
| // Ensure there are no additional tokens within `content`. | |
| // Without explicitly checking, we may misinterpret a tuple | |
| // field as a restricted visibility, causing a parse error. | |
| // e.g. `pub (crate::A, crate::B)` (Issue #720). | |
| if content.is_empty() { | |
| input.advance_to(&ahead); | |
| return Ok(Visibility::Restricted(VisRestricted { | |
| pub_token, | |
| paren_token, | |
| in_token: None, | |
| path: Box::new(Path::from(path)), | |
| })); | |
| } | |
| } else if content.peek(Token![in]) { | |
| let in_token: Token![in] = content.parse()?; | |
| let path = content.call(Path::parse_mod_style)?; | |
| input.advance_to(&ahead); | |
| return Ok(Visibility::Restricted(VisRestricted { | |
| pub_token, | |
| paren_token, | |
| in_token: Some(in_token), | |
| path: Box::new(path), | |
| })); | |
| } | |
| } | |
| Ok(Visibility::Public(pub_token)) | |
| } | |
| #[cfg(feature = "full")] | |
| pub(crate) fn is_some(&self) -> bool { | |
| match self { | |
| Visibility::Inherited => false, | |
| _ => true, | |
| } | |
| } | |
| } | |
| } | |
| #[cfg(feature = "printing")] | |
| mod printing { | |
| use crate::path; | |
| use crate::path::printing::PathStyle; | |
| use crate::restriction::{VisRestricted, Visibility}; | |
| use proc_macro2::TokenStream; | |
| use quote::ToTokens; | |
| #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] | |
| impl ToTokens for Visibility { | |
| fn to_tokens(&self, tokens: &mut TokenStream) { | |
| match self { | |
| Visibility::Public(pub_token) => pub_token.to_tokens(tokens), | |
| Visibility::Restricted(vis_restricted) => vis_restricted.to_tokens(tokens), | |
| Visibility::Inherited => {} | |
| } | |
| } | |
| } | |
| #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] | |
| impl ToTokens for VisRestricted { | |
| fn to_tokens(&self, tokens: &mut TokenStream) { | |
| self.pub_token.to_tokens(tokens); | |
| self.paren_token.surround(tokens, |tokens| { | |
| // TODO: If we have a path which is not "self" or "super" or | |
| // "crate", automatically add the "in" token. | |
| self.in_token.to_tokens(tokens); | |
| path::printing::print_path(tokens, &self.path, PathStyle::Mod); | |
| }); | |
| } | |
| } | |
| } |