use crate::{
Body, CategorySet, FuncId, Graph,
args::{Closures, Generics},
util::Map,
};
#[derive(Debug, Clone, Copy)]
pub struct Selection {
pub all_crates: bool,
pub closures: Closures,
pub generics: Generics,
pub only: Option<CategorySet>,
}
impl Default for Selection {
fn default() -> Self {
Self {
all_crates: false,
closures: Closures::Separate,
generics: Generics::Written,
only: None,
}
}
}
#[derive(Debug, Clone, Copy, Default)]
struct Named {
owned: bool,
instantiated: bool,
}
impl Selection {
#[must_use]
pub fn name<'a>(&self, body: &'a Body) -> &'a str {
match self.closures {
Closures::Separate => &body.display,
Closures::Parent => body
.display
.split("::{closure")
.next()
.unwrap_or(&body.display),
}
}
#[must_use]
pub fn shown(&self, enabled: CategorySet) -> CategorySet {
self.only.map_or(enabled, |only| enabled.intersection(only))
}
#[must_use]
pub const fn admits(&self, body: &Body) -> bool {
!body.opaque && (self.all_crates || body.local)
}
pub fn functions<'a>(
&self,
graph: &'a Graph,
) -> impl Iterator<Item = (FuncId, &'a Body)> + use<'a> {
let selection = *self;
let mut names: Map<(&str, &str), Named> = Map::default();
for (_, body) in graph.iter().filter(|(_, body)| self.admits(body)) {
let known = names
.entry((body.krate.as_str(), self.name(body)))
.or_default();
known.owned |= !body.from_tests;
known.instantiated |= !body.key.is_open();
}
graph.iter().filter(move |(_, body)| {
selection.admits(body)
&& names
.get(&(body.krate.as_str(), selection.name(body)))
.is_some_and(|known| selection.keeps(body, *known))
})
}
fn keeps(&self, body: &Body, known: Named) -> bool {
let yields = self.generics == Generics::Instantiated
&& known.instantiated
&& body.key.is_open();
known.owned && !yields
}
}