//! In rust, it is possible to have a value, a type and a macro with the same //! name without conflicts. //! //! `PerNs` (per namespace) captures this. use bitflags::bitflags; use crate::{ MacroId, ModuleDefId, item_scope::{ImportId, ImportOrExternCrate, ImportOrGlob, ItemInNs}, visibility::Visibility, }; #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] pub enum Namespace { Types, Values, Macros, } bitflags! { /// Describes only the presence/absence of each namespace, without its value. #[derive(Debug, PartialEq, Eq)] pub(crate) struct NsAvailability : u32 { const TYPES = 1 << 0; const VALUES = 1 << 1; const MACROS = 1 << 2; } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Item { pub def: Def, pub vis: Visibility, pub import: Option, } pub type TypesItem = Item; pub type ValuesItem = Item; // May be Externcrate for `[macro_use]`'d macros pub type MacrosItem = Item; #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] pub struct PerNs { pub types: Option, pub values: Option, pub macros: Option, } impl PerNs { pub(crate) fn availability(&self) -> NsAvailability { let mut result = NsAvailability::empty(); result.set(NsAvailability::TYPES, self.types.is_some()); result.set(NsAvailability::VALUES, self.values.is_some()); result.set(NsAvailability::MACROS, self.macros.is_some()); result } pub fn none() -> PerNs { PerNs { types: None, values: None, macros: None } } pub fn values(def: ModuleDefId, vis: Visibility, import: Option) -> PerNs { PerNs { types: None, values: Some(Item { def, vis, import }), macros: None } } pub fn types(def: ModuleDefId, vis: Visibility, import: Option) -> PerNs { PerNs { types: Some(Item { def, vis, import }), values: None, macros: None } } pub fn both( types: ModuleDefId, values: ModuleDefId, vis: Visibility, import: Option, ) -> PerNs { PerNs { types: Some(Item { def: types, vis, import }), values: Some(Item { def: values, vis, import: import.and_then(ImportOrExternCrate::import_or_glob), }), macros: None, } } pub fn macros(def: MacroId, vis: Visibility, import: Option) -> PerNs { PerNs { types: None, values: None, macros: Some(Item { def, vis, import }) } } pub fn is_none(&self) -> bool { self.types.is_none() && self.values.is_none() && self.macros.is_none() } pub fn is_full(&self) -> bool { self.types.is_some() && self.values.is_some() && self.macros.is_some() } pub fn take_types(self) -> Option { self.types.map(|it| it.def) } pub fn take_types_full(self) -> Option { self.types } pub fn take_values(self) -> Option { self.values.map(|it| it.def) } pub fn take_values_import(self) -> Option<(ModuleDefId, Option)> { self.values.map(|it| (it.def, it.import)) } pub fn take_macros(self) -> Option { self.macros.map(|it| it.def) } pub fn take_macros_import(self) -> Option<(MacroId, Option)> { self.macros.map(|it| (it.def, it.import)) } pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs { let _p = tracing::info_span!("PerNs::filter_visibility").entered(); PerNs { types: self.types.filter(|def| f(def.vis)), values: self.values.filter(|def| f(def.vis)), macros: self.macros.filter(|def| f(def.vis)), } } pub fn with_visibility(self, vis: Visibility) -> PerNs { PerNs { types: self.types.map(|def| Item { vis, ..def }), values: self.values.map(|def| Item { vis, ..def }), macros: self.macros.map(|def| Item { vis, ..def }), } } pub fn or(self, other: PerNs) -> PerNs { PerNs { types: self.types.or(other.types), values: self.values.or(other.values), macros: self.macros.or(other.macros), } } pub fn or_else(self, f: impl FnOnce() -> PerNs) -> PerNs { if self.is_full() { self } else { self.or(f()) } } pub fn iter_items(self) -> impl Iterator)> { let _p = tracing::info_span!("PerNs::iter_items").entered(); self.types .map(|it| (ItemInNs::Types(it.def), it.import)) .into_iter() .chain( self.values .map(|it| (ItemInNs::Values(it.def), it.import.map(ImportOrExternCrate::from))), ) .chain(self.macros.map(|it| (ItemInNs::Macros(it.def), it.import))) } }