guppy/graph/feature/
weak.rs
1use crate::graph::{
7 feature::{ConditionalLink, FeatureEdgeReference},
8 PackageIx,
9};
10use indexmap::IndexSet;
11use itertools::Either;
12use petgraph::graph::EdgeIndex;
13use smallvec::SmallVec;
14
15#[derive(Clone, Debug)]
17pub(super) struct WeakDependencies {
18 ixs: IndexSet<EdgeIndex<PackageIx>>,
19}
20
21impl WeakDependencies {
22 pub(super) fn new() -> Self {
23 Self {
24 ixs: IndexSet::new(),
25 }
26 }
27
28 pub(super) fn insert(&mut self, edge_ix: EdgeIndex<PackageIx>) -> WeakIndex {
29 WeakIndex(self.ixs.insert_full(edge_ix).0)
30 }
31
32 pub(super) fn get(&self, edge_ix: EdgeIndex<PackageIx>) -> Option<WeakIndex> {
33 self.ixs.get_index_of(&edge_ix).map(WeakIndex)
34 }
35
36 #[inline]
37 pub(super) fn new_buffer_states<'g, F>(&self, accept_fn: F) -> WeakBufferStates<'g, '_, F>
38 where
39 F: FnMut(ConditionalLink<'g>) -> bool,
40 {
41 WeakBufferStates::new(self, self.ixs.len(), accept_fn)
42 }
43}
44
45#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
47#[doc(hidden)]
48pub struct WeakIndex(pub(super) usize);
49
50pub(super) struct WeakBufferStates<'g, 'a, F> {
52 deps: &'a WeakDependencies,
53 states: SmallVec<[SingleBufferState<'g>; 8]>,
54 accept_fn: F,
55}
56
57impl<'g, 'a, F> WeakBufferStates<'g, 'a, F>
58where
59 F: FnMut(ConditionalLink<'g>) -> bool,
60{
61 #[inline]
62 fn new(deps: &'a WeakDependencies, len: usize, accept_fn: F) -> Self {
63 let mut states = SmallVec::with_capacity(len);
64 states.resize_with(len, Default::default);
65 Self {
66 deps,
67 states,
68 accept_fn,
69 }
70 }
71
72 pub(super) fn track(
73 &mut self,
74 edge_ref: FeatureEdgeReference<'g>,
75 link: ConditionalLink<'g>,
76 weak_index: Option<WeakIndex>,
77 ) -> Either<Option<FeatureEdgeReference<'g>>, Vec<FeatureEdgeReference<'g>>> {
78 match weak_index {
79 Some(index) => {
80 match &mut self.states[index.0] {
81 SingleBufferState::Buffered(buffer) => {
82 buffer.push((link, edge_ref));
84 Either::Left(None)
85 }
86 SingleBufferState::Accepted => {
87 Either::Left((self.accept_fn)(link).then_some(edge_ref))
89 }
90 }
91 }
92 None => {
93 if !(self.accept_fn)(link) {
94 return Either::Left(None);
96 }
97
98 match self.deps.get(link.package_edge_ix()) {
99 Some(weak_index) => {
100 match std::mem::replace(
101 &mut self.states[weak_index.0],
102 SingleBufferState::Accepted,
103 ) {
104 SingleBufferState::Buffered(buffer) => {
105 let mut edge_refs: Vec<_> = buffer
107 .into_iter()
108 .filter_map(|(link, edge_ref)| {
109 (self.accept_fn)(link).then_some(edge_ref)
111 })
112 .collect();
113 edge_refs.push(edge_ref);
114 Either::Right(edge_refs)
115 }
116 SingleBufferState::Accepted => {
117 Either::Left(Some(edge_ref))
119 }
120 }
121 }
122 None => {
123 Either::Left(Some(edge_ref))
125 }
126 }
127 }
128 }
129 }
130}
131
132pub(super) enum SingleBufferState<'g> {
134 Buffered(SingleBufferVec<'g>),
135 Accepted,
136}
137
138impl Default for SingleBufferState<'_> {
139 fn default() -> Self {
140 Self::Buffered(SingleBufferVec::new())
141 }
142}
143
144type SingleBufferVec<'g> = Vec<(ConditionalLink<'g>, FeatureEdgeReference<'g>)>;