Skip to content

Commit f712a83

Browse files
committed
async lookups
1 parent 1e82e23 commit f712a83

File tree

11 files changed

+241
-42
lines changed

11 files changed

+241
-42
lines changed

scopegraphs-lib/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ futures = "0.3.30"
1818
scopegraphs = {path = "../scopegraphs"}
1919
env_logger = "0.10.1"
2020
ctor = "0.2.5"
21+
smol = "1.3.0"

scopegraphs-lib/src/completeness/critical_edge.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::{completeness::Completeness, Scope, ScopeGraph};
22
use std::cell::RefCell;
33
use std::{collections::HashSet, hash::Hash};
44

5+
#[derive(Debug)]
56
pub(super) struct CriticalEdgeSet<LABEL> {
67
open_edges: RefCell<Vec<HashSet<LABEL>>>,
78
}

scopegraphs-lib/src/completeness/explicit.rs

+85
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::completeness::FutureCompleteness;
12
use crate::{
23
completeness::private::Sealed,
34
completeness::{
@@ -20,6 +21,7 @@ use std::{collections::HashSet, hash::Hash};
2021
///
2122
/// Returns [`Delay`] when edges are retrieved (e.g. during query resolution) for an edge that is
2223
/// not yet closed.
24+
#[derive(Debug)]
2325
pub struct ExplicitClose<LABEL> {
2426
critical_edges: CriticalEdgeSet<LABEL>,
2527
}
@@ -189,3 +191,86 @@ impl<LABEL: Hash + Eq, DATA> ScopeGraph<LABEL, DATA, ExplicitClose<LABEL>> {
189191
self.completeness.close(scope, label)
190192
}
191193
}
194+
195+
impl<LABEL: Hash + Eq + Copy, DATA> ScopeGraph<LABEL, DATA, FutureCompleteness<LABEL>> {
196+
/// TODO: update this example to use futures
197+
/// Closes an edge, (i.e., prohibit future new
198+
///
199+
/// For example, the following program will return an error.
200+
/// ```
201+
/// # use scopegraphs_lib::completeness::ExplicitClose;
202+
/// # use scopegraphs_lib::ScopeGraph;
203+
/// # use scopegraphs_macros::Label;
204+
/// # #[derive(Eq, Hash, PartialEq, Label)] enum Lbl { Def }
205+
/// # use Lbl::*;
206+
/// let mut sg = ScopeGraph::<Lbl, usize, _>::new(ExplicitClose::default());
207+
///
208+
/// let s1 = sg.add_scope_with(0, [Def]);
209+
/// let s2 = sg.add_scope_closed(42);
210+
///
211+
/// sg.close(s1, &Def);
212+
/// sg.add_edge(s1, Def, s2).expect_err("cannot add edge after closing edge");
213+
/// ```
214+
///
215+
/// Closing is required to permit queries to traverse these edges:
216+
/// ```
217+
///
218+
/// # use scopegraphs_lib::completeness::ExplicitClose;
219+
/// # use scopegraphs_lib::ScopeGraph;
220+
/// # use scopegraphs_lib::resolve::{DefaultDataEquiv, DefaultLabelOrder, EdgeOrData, Resolve};
221+
/// # use scopegraphs_macros::{compile_regex, Label};
222+
/// #
223+
/// # #[derive(Eq, Hash, PartialEq, Label, Debug, Copy, Clone)]
224+
/// # enum Lbl { Def }
225+
/// # use Lbl::*;
226+
/// # type LblD = EdgeOrData<Lbl>;
227+
/// #
228+
/// # compile_regex!(type Regex<Lbl> = Def);
229+
/// let mut sg = ScopeGraph::<Lbl, usize, _>::new(ExplicitClose::default());
230+
///
231+
/// let s1 = sg.add_scope_with(0, [Def]);
232+
/// let s2 = sg.add_scope_closed(42);
233+
///
234+
/// // Note: not calling `sg.close(s1, &Def)`
235+
///
236+
/// let query_result = sg.query()
237+
/// .with_path_wellformedness(Regex::new()) // regex: `Def`
238+
/// .with_data_wellformedness(|x: &usize| *x == 42) // match `42`
239+
/// .resolve(s1);
240+
///
241+
/// query_result.expect_err("require s1/Def to be closed");
242+
/// ```
243+
///
244+
/// Closing allows queries to resolve:
245+
/// ```
246+
///
247+
/// # use scopegraphs_lib::completeness::ExplicitClose;
248+
/// # use scopegraphs_lib::ScopeGraph;
249+
/// # use scopegraphs_lib::resolve::{DefaultDataEquiv, DefaultLabelOrder, EdgeOrData, Resolve};
250+
/// # use scopegraphs_macros::{compile_regex, Label};
251+
/// #
252+
/// # #[derive(Eq, Hash, PartialEq, Label, Debug, Copy, Clone)]
253+
/// # enum Lbl { Def }
254+
/// # use Lbl::*;
255+
/// # type LblD = EdgeOrData<Lbl>;
256+
/// #
257+
/// # compile_regex!(type Regex<Lbl> = Def);
258+
/// let mut sg = ScopeGraph::<Lbl, usize, _>::new(ExplicitClose::default());
259+
///
260+
/// let s1 = sg.add_scope_with(0, [Def]);
261+
/// let s2 = sg.add_scope_closed(42);
262+
///
263+
/// // Note: closing the edge *after* creating all edges, *before* doing the query
264+
/// sg.close(s1, &Def);
265+
///
266+
/// let query_result = sg.query()
267+
/// .with_path_wellformedness(Regex::new()) // regex: `Def`
268+
/// .with_data_wellformedness(|x: &usize| *x == 42) // match `42`
269+
/// .resolve(s1);
270+
///
271+
/// query_result.expect("query should return result");
272+
/// ```
273+
pub fn close(&self, scope: Scope, label: &LABEL) {
274+
self.completeness.close(scope, label)
275+
}
276+
}

scopegraphs-lib/src/completeness/future.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,21 @@ use std::future::poll_fn;
99
use std::hash::Hash;
1010
use std::task::{Poll, Waker};
1111

12+
#[derive(Debug)]
1213
pub struct FutureCompleteness<LABEL> {
1314
explicit_close: ExplicitClose<LABEL>,
1415
wakers: RefCell<HashMap<Delay<LABEL>, Vec<Waker>>>,
1516
}
1617

18+
impl<LABEL> Default for FutureCompleteness<LABEL> {
19+
fn default() -> Self {
20+
Self {
21+
explicit_close: ExplicitClose::<LABEL>::default(),
22+
wakers: RefCell::new(HashMap::default()),
23+
}
24+
}
25+
}
26+
1727
impl<LABEL> Sealed for FutureCompleteness<LABEL> {}
1828

1929
impl<'sg, LABEL: Hash + Eq + Label + Copy, DATA> Completeness<LABEL, DATA>
@@ -48,7 +58,7 @@ impl<'sg, LABEL: Hash + Eq + Label + Copy, DATA> Completeness<LABEL, DATA>
4858
LABEL: 'rslv,
4959
DATA: 'rslv,
5060
{
51-
FutureWrapper(Box::new(poll_fn(move |cx| {
61+
FutureWrapper::new(poll_fn(move |cx| {
5262
match self
5363
.explicit_close
5464
.cmpl_get_edges(inner_scope_graph, src, lbl)
@@ -63,12 +73,12 @@ impl<'sg, LABEL: Hash + Eq + Label + Copy, DATA> Completeness<LABEL, DATA>
6373
Poll::Pending
6474
}
6575
}
66-
})))
76+
}))
6777
}
6878
}
6979

7080
impl<LABEL: Hash + Eq + Copy> FutureCompleteness<LABEL> {
71-
pub(super) fn close(&mut self, scope: Scope, label: &LABEL) {
81+
pub(super) fn close(&self, scope: Scope, label: &LABEL) {
7282
self.explicit_close.close(scope, label);
7383
for waker in self
7484
.wakers

scopegraphs-lib/src/completeness/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use crate::{InnerScopeGraph, Scope};
1616

1717
mod future;
18+
pub use future::*;
1819

1920
mod critical_edge;
2021
pub use critical_edge::*;

scopegraphs-lib/src/containers/env.rs

+47-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
use crate::future_wrapper::FutureWrapper;
12
use crate::resolve::{Env, ResolvedPath};
3+
use futures::future::Shared;
24
use std::hash::Hash;
35
use std::rc::Rc;
46

@@ -10,7 +12,10 @@ pub trait EnvContainer<'sg, 'rslv, LABEL: 'sg, DATA: 'sg>:
1012
fn empty() -> Self;
1113

1214
/// Maps the current container to a new one, based a provided mapping of the underlying environment.
13-
fn flat_map(&self, map: impl FnOnce(&Env<'sg, LABEL, DATA>) -> Self) -> Self;
15+
fn flat_map(
16+
&self,
17+
map: impl 'rslv + for<'short> FnOnce(&'short Env<'sg, LABEL, DATA>) -> Self,
18+
) -> Self;
1419
}
1520

1621
impl<'sg: 'rslv, 'rslv, LABEL, DATA> EnvContainer<'sg, 'rslv, LABEL, DATA> for Env<'sg, LABEL, DATA>
@@ -21,7 +26,10 @@ where
2126
Self::new()
2227
}
2328

24-
fn flat_map(&self, map: impl FnOnce(&Env<'sg, LABEL, DATA>) -> Self) -> Self {
29+
fn flat_map(
30+
&self,
31+
map: impl 'rslv + for<'short> FnOnce(&'short Env<'sg, LABEL, DATA>) -> Self,
32+
) -> Self {
2533
map(self)
2634
}
2735
}
@@ -35,7 +43,10 @@ where
3543
Self::new(Env::empty())
3644
}
3745

38-
fn flat_map(&self, map: impl FnOnce(&Env<'sg, LABEL, DATA>) -> Self) -> Self {
46+
fn flat_map(
47+
&self,
48+
map: impl for<'short> FnOnce(&'short Env<'sg, LABEL, DATA>) -> Self,
49+
) -> Self {
3950
map(self)
4051
}
4152
}
@@ -59,10 +70,42 @@ where
5970
Ok(Env::empty())
6071
}
6172

62-
fn flat_map(&self, map: impl FnOnce(&Env<'sg, LABEL, DATA>) -> Self) -> Self {
73+
fn flat_map(&self, map: impl for<'short> FnOnce(&Env<'sg, LABEL, DATA>) -> Self) -> Self {
6374
match self {
6475
Ok(env) => map(env),
6576
Err(err) => Err(err.clone()),
6677
}
6778
}
6879
}
80+
81+
impl<'sg: 'rslv, 'rslv, LABEL: 'sg, DATA: 'sg> EnvContainer<'sg, 'rslv, LABEL, DATA>
82+
for FutureWrapper<'rslv, Env<'sg, LABEL, DATA>>
83+
where
84+
ResolvedPath<'sg, LABEL, DATA>: Hash + Eq,
85+
LABEL: Clone,
86+
{
87+
fn empty() -> Self {
88+
FutureWrapper::new(std::future::ready(Env::empty()))
89+
}
90+
91+
fn flat_map(
92+
&self,
93+
map: impl 'rslv + for<'short> FnOnce(&'short Env<'sg, LABEL, DATA>) -> Self,
94+
) -> Self {
95+
let fut = Shared::clone(&self.0);
96+
FutureWrapper::new(async move {
97+
let env = fut.await;
98+
map(&env).await
99+
})
100+
}
101+
}
102+
103+
impl<'sg: 'rslv, 'rslv, LABEL, DATA> From<Env<'sg, LABEL, DATA>>
104+
for FutureWrapper<'rslv, Env<'sg, LABEL, DATA>>
105+
where
106+
LABEL: Clone,
107+
{
108+
fn from(value: Env<'sg, LABEL, DATA>) -> Self {
109+
FutureWrapper::new(std::future::ready(value))
110+
}
111+
}

scopegraphs-lib/src/containers/path.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,12 @@ where
6666
self,
6767
f: F,
6868
) -> Self::EnvContainer {
69-
let p_self = Box::pin(self);
7069
let future = async move {
71-
let paths = p_self.await;
70+
let paths = self.0.await;
7271
let env_futures = paths.into_iter().map(f);
7372
let envs = join_all(env_futures).await;
7473
envs.into_iter().collect::<Env<_, _>>()
7574
};
76-
FutureWrapper(Box::new(future))
75+
FutureWrapper::new(future)
7776
}
7877
}

scopegraphs-lib/src/containers/scope.rs

+1-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
use crate::future_wrapper::FutureWrapper;
22
use crate::{resolve::Path, Scope};
3-
use std::future::{poll_fn, Future};
4-
use std::task::Poll;
53

64
/// Interface for scope containers that support the operations required for query resolution.
75
pub trait ScopeContainer<LABEL> {
@@ -44,11 +42,6 @@ where
4442
type PathContainer = FutureWrapper<'rslv, SC::PathContainer>;
4543

4644
fn lift_step(self, lbl: LABEL, prefix: Path<LABEL>) -> Self::PathContainer {
47-
let mut p_self = Box::pin(self); // FIXME: implement for pinned self?
48-
let fut = poll_fn(move |cx| match p_self.as_mut().poll(cx) {
49-
Poll::Ready(inner_sc) => Poll::Ready(inner_sc.lift_step(lbl, prefix.clone())),
50-
Poll::Pending => Poll::Pending,
51-
});
52-
FutureWrapper(Box::new(fut))
45+
FutureWrapper::new(async move { self.await.lift_step(lbl, prefix.clone()) })
5346
}
5447
}

scopegraphs-lib/src/future_wrapper.rs

+18-9
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,32 @@
1-
use std::ops::{Deref, DerefMut};
1+
use futures::future::Shared;
2+
use futures::FutureExt;
3+
use std::fmt::{Debug, Formatter};
24
use std::{
35
future::Future,
46
pin::Pin,
57
task::{Context, Poll},
68
};
79

8-
pub struct FutureWrapper<'fut, T>(pub Box<dyn Future<Output = T> + 'fut>);
10+
// TODO: fork futures and create our own shared future that can have a
11+
// ?Sized inner type (this should be possible)
12+
pub struct FutureWrapper<'fut, T>(pub Shared<Pin<Box<dyn Future<Output = T> + 'fut>>>);
913

10-
impl<'fut, T> Deref for FutureWrapper<'fut, T> {
11-
type Target = dyn Future<Output = T> + 'fut;
14+
impl<'fut, T> Clone for FutureWrapper<'fut, T> {
15+
fn clone(&self) -> Self {
16+
Self(Shared::clone(&self.0))
17+
}
18+
}
1219

13-
fn deref(&self) -> &Self::Target {
14-
self.0.deref()
20+
impl<'fut, T: Clone> FutureWrapper<'fut, T> {
21+
pub fn new(f: impl Future<Output = T> + 'fut) -> Self {
22+
let f: Pin<Box<dyn Future<Output = T> + 'fut>> = Box::pin(f);
23+
Self(f.shared())
1524
}
1625
}
1726

18-
impl<'fut, T> DerefMut for FutureWrapper<'fut, T> {
19-
fn deref_mut(&mut self) -> &mut Self::Target {
20-
self.0.deref_mut()
27+
impl<T> Debug for FutureWrapper<'_, T> {
28+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
29+
write!(f, "<future>")
2130
}
2231
}
2332

0 commit comments

Comments
 (0)