scopegraphs/completeness/
future.rs

1use crate::completeness::private::Sealed;
2use crate::completeness::{Completeness, CriticalEdgeBasedCompleteness, Delay, ExplicitClose};
3use crate::future_wrapper::FutureWrapper;
4use crate::label::Label;
5use crate::scopegraph::{InnerScopeGraph, Scope};
6use std::cell::RefCell;
7use std::collections::{HashMap, HashSet};
8use std::future::poll_fn;
9use std::hash::Hash;
10use std::task::{Poll, Waker};
11
12use super::{UserClosed, Witness};
13
14/// A completeness strategy that makes queries return a [`Future`](std::future::Future)
15/// in case one of the scopes that the query runs over was not yet closed.
16/// The future resolves once all such scopes *are* closed.
17///
18/// Using [`FutureCompleteness`], you can somewhat delegate the task of scheduling
19/// typechecking to one of rust's executors, be it [`tokio`](https://docs.rs/tokio)
20/// or [`futures::block_on`](https://docs.rs/futures/latest/futures/executor/fn.block_on.html).
21// TODO: add practical lessons from Lace.
22///
23/// Extends, and contains an instance of, [`ExplicitClose`].
24#[derive(Debug)]
25pub struct FutureCompleteness<LABEL: Label> {
26    explicit_close: ExplicitClose<LABEL>,
27    wakers: RefCell<HashMap<Delay<LABEL>, Vec<Waker>>>,
28}
29
30impl<LABEL: Label> Default for FutureCompleteness<LABEL> {
31    fn default() -> Self {
32        Self {
33            explicit_close: ExplicitClose::<LABEL>::default(),
34            wakers: RefCell::new(HashMap::default()),
35        }
36    }
37}
38
39impl<LABEL: Label> Sealed for FutureCompleteness<LABEL> {}
40
41impl<LABEL: Hash + Label + Copy, DATA> Completeness<LABEL, DATA> for FutureCompleteness<LABEL> {
42    fn cmpl_new_scope(&self, inner_scope_graph: &InnerScopeGraph<LABEL, DATA>, scope: Scope) {
43        self.explicit_close.cmpl_new_scope(inner_scope_graph, scope)
44    }
45
46    fn cmpl_new_complete_scope(&self, _: &InnerScopeGraph<LABEL, DATA>, _: Scope) {
47        <FutureCompleteness<LABEL> as CriticalEdgeBasedCompleteness<LABEL, DATA>>::init_scope_with(
48            self,
49            HashSet::new(), // init with empty label set to prevent extension
50        )
51    }
52
53    type NewEdgeResult = <ExplicitClose<LABEL> as Completeness<LABEL, DATA>>::NewEdgeResult;
54
55    fn cmpl_new_edge(
56        &self,
57        inner_scope_graph: &InnerScopeGraph<LABEL, DATA>,
58        src: Scope,
59        lbl: LABEL,
60        dst: Scope,
61    ) -> Self::NewEdgeResult {
62        self.explicit_close
63            .cmpl_new_edge(inner_scope_graph, src, lbl, dst)
64    }
65
66    type GetEdgesResult<'rslv>
67        = FutureWrapper<'rslv, Vec<Scope>>
68    where
69        Self: 'rslv,
70        LABEL: 'rslv,
71        DATA: 'rslv;
72
73    fn cmpl_get_edges<'rslv>(
74        &'rslv self,
75        inner_scope_graph: &'rslv InnerScopeGraph<LABEL, DATA>,
76        src: Scope,
77        lbl: LABEL,
78    ) -> Self::GetEdgesResult<'rslv>
79    where
80        LABEL: 'rslv,
81        DATA: 'rslv,
82    {
83        FutureWrapper::new(poll_fn(move |cx| {
84            match self
85                .explicit_close
86                .cmpl_get_edges(inner_scope_graph, src, lbl)
87            {
88                Ok(scopes) => Poll::Ready(scopes),
89                Err(delay) => {
90                    self.wakers
91                        .borrow_mut()
92                        .entry(delay)
93                        .or_default()
94                        .push(cx.waker().clone());
95                    Poll::Pending
96                }
97            }
98        }))
99    }
100}
101
102impl<LABEL: Hash + Label + Copy, DATA> CriticalEdgeBasedCompleteness<LABEL, DATA>
103    for FutureCompleteness<LABEL>
104{
105    fn init_scope_with(&self, open_edges: HashSet<LABEL>) {
106        <ExplicitClose<LABEL> as CriticalEdgeBasedCompleteness<LABEL, DATA>>::init_scope_with(
107            &self.explicit_close,
108            open_edges,
109        );
110    }
111}
112
113impl<LABEL: Hash + Label + Copy, DATA> UserClosed<LABEL, DATA> for FutureCompleteness<LABEL> {
114    /// Close a scope for a certain label
115    /// // TODO: link to "closing" in concepts
116    fn close(&self, scope: Scope, label: &LABEL, _witness: Witness) {
117        UserClosed::<_, DATA>::close(&self.explicit_close, scope, label, _witness);
118        for waker in self
119            .wakers
120            .borrow()
121            .get(&Delay {
122                scope,
123                label: *label,
124            })
125            .into_iter()
126            .flatten()
127        {
128            waker.wake_by_ref()
129        }
130    }
131}