use quote::ToTokens;
use syn::Visibility;
#[derive(Clone, Debug, PartialEq)]
pub enum VisibilityKind {
Public,
Private,
Restricted(String),
}
pub fn visibility_to_kind(vis: &Visibility) -> VisibilityKind {
match vis {
Visibility::Public(_) => VisibilityKind::Public,
Visibility::Inherited => VisibilityKind::Private,
Visibility::Restricted(restricted) => {
let path = restricted.path.to_token_stream().to_string();
VisibilityKind::Restricted(path)
}
}
}
pub fn kind_to_visibility(kind: &VisibilityKind) -> Visibility {
match kind {
VisibilityKind::Public => syn::parse_quote!(pub),
VisibilityKind::Private => Visibility::Inherited,
VisibilityKind::Restricted(path_str) => {
match path_str.as_str() {
"crate" => syn::parse_quote!(pub(crate)),
"super" => syn::parse_quote!(pub(super)),
"self" => syn::parse_quote!(pub(self)),
_ => {
let path: syn::Path = syn::parse_str(path_str)
.unwrap_or_else(|_| syn::parse_quote!(self));
Visibility::Restricted(syn::VisRestricted {
pub_token: syn::token::Pub::default(),
paren_token: syn::token::Paren::default(),
in_token: Some(syn::token::In::default()),
path: Box::new(path),
})
}
}
}
}
}
pub fn can_access_field(
vis: &VisibilityKind,
target_module: &str,
source_module: &str,
) -> bool {
match vis {
VisibilityKind::Public => true,
VisibilityKind::Private => {
if target_module.is_empty() && source_module.is_empty() {
true
} else {
let same_module = source_module == target_module;
let is_child = source_module.starts_with(target_module)
&& source_module[target_module.len()..].starts_with("::");
same_module || is_child
}
}
VisibilityKind::Restricted(restriction) => match restriction.as_str() {
"crate" => true,
"super" => source_module.starts_with(target_module),
"self" => target_module == source_module,
path => {
let path = path.trim_start_matches("in ");
source_module.starts_with(path)
}
},
}
}