guppy/graph/feature/
weak.rsuse crate::graph::{
feature::{ConditionalLink, FeatureEdgeReference},
PackageIx,
};
use indexmap::IndexSet;
use itertools::Either;
use petgraph::graph::EdgeIndex;
use smallvec::SmallVec;
#[derive(Clone, Debug)]
pub(super) struct WeakDependencies {
ixs: IndexSet<EdgeIndex<PackageIx>>,
}
impl WeakDependencies {
pub(super) fn new() -> Self {
Self {
ixs: IndexSet::new(),
}
}
pub(super) fn insert(&mut self, edge_ix: EdgeIndex<PackageIx>) -> WeakIndex {
WeakIndex(self.ixs.insert_full(edge_ix).0)
}
pub(super) fn get(&self, edge_ix: EdgeIndex<PackageIx>) -> Option<WeakIndex> {
self.ixs.get_index_of(&edge_ix).map(WeakIndex)
}
#[inline]
pub(super) fn new_buffer_states<'g, F>(&self, accept_fn: F) -> WeakBufferStates<'g, '_, F>
where
F: FnMut(ConditionalLink<'g>) -> bool,
{
WeakBufferStates::new(self, self.ixs.len(), accept_fn)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[doc(hidden)]
pub struct WeakIndex(pub(super) usize);
pub(super) struct WeakBufferStates<'g, 'a, F> {
deps: &'a WeakDependencies,
states: SmallVec<[SingleBufferState<'g>; 8]>,
accept_fn: F,
}
impl<'g, 'a, F> WeakBufferStates<'g, 'a, F>
where
F: FnMut(ConditionalLink<'g>) -> bool,
{
#[inline]
fn new(deps: &'a WeakDependencies, len: usize, accept_fn: F) -> Self {
let mut states = SmallVec::with_capacity(len);
states.resize_with(len, Default::default);
Self {
deps,
states,
accept_fn,
}
}
pub(super) fn track(
&mut self,
edge_ref: FeatureEdgeReference<'g>,
link: ConditionalLink<'g>,
weak_index: Option<WeakIndex>,
) -> Either<Option<FeatureEdgeReference<'g>>, Vec<FeatureEdgeReference<'g>>> {
match weak_index {
Some(index) => {
match &mut self.states[index.0] {
SingleBufferState::Buffered(buffer) => {
buffer.push((link, edge_ref));
Either::Left(None)
}
SingleBufferState::Accepted => {
Either::Left((self.accept_fn)(link).then_some(edge_ref))
}
}
}
None => {
if !(self.accept_fn)(link) {
return Either::Left(None);
}
match self.deps.get(link.package_edge_ix()) {
Some(weak_index) => {
match std::mem::replace(
&mut self.states[weak_index.0],
SingleBufferState::Accepted,
) {
SingleBufferState::Buffered(buffer) => {
let mut edge_refs: Vec<_> = buffer
.into_iter()
.filter_map(|(link, edge_ref)| {
(self.accept_fn)(link).then_some(edge_ref)
})
.collect();
edge_refs.push(edge_ref);
Either::Right(edge_refs)
}
SingleBufferState::Accepted => {
Either::Left(Some(edge_ref))
}
}
}
None => {
Either::Left(Some(edge_ref))
}
}
}
}
}
}
pub(super) enum SingleBufferState<'g> {
Buffered(SingleBufferVec<'g>),
Accepted,
}
impl Default for SingleBufferState<'_> {
fn default() -> Self {
Self::Buffered(SingleBufferVec::new())
}
}
type SingleBufferVec<'g> = Vec<(ConditionalLink<'g>, FeatureEdgeReference<'g>)>;