scopegraphs_lib/completeness/
implicit.rs

1use crate::{
2    completeness::private::Sealed,
3    completeness::{Completeness, CriticalEdgeBasedCompleteness, CriticalEdgeSet, EdgeClosedError},
4    label::Label,
5    InnerScopeGraph, Scope,
6};
7use std::collections::HashSet;
8use std::hash::Hash;
9
10/// Critical-edge based [`Completeness`] implementation.
11///
12/// Unlike [`ExplicitClose`], this implementation will implicitly close edges once traversed.
13/// This does not require special attention from the type checker writer.
14///
15/// Returns [`EdgeClosedError`] when an edge is added to a scope in which the label is already
16/// closed (because `get_edges(s, l, ...)` was called earlier.
17///
18/// When edges are retrieved (e.g. during query resolution) the `(src, label)` edge is closed.
19pub struct ImplicitClose<LABEL> {
20    critical_edges: CriticalEdgeSet<LABEL>,
21}
22
23impl<LABEL> Default for ImplicitClose<LABEL> {
24    fn default() -> Self {
25        Self {
26            critical_edges: Default::default(),
27        }
28    }
29}
30
31impl<LABEL> Sealed for ImplicitClose<LABEL> {}
32
33impl<LABEL: Hash + Eq + Label, DATA> Completeness<LABEL, DATA> for ImplicitClose<LABEL> {
34    fn cmpl_new_scope(&self, _: &InnerScopeGraph<LABEL, DATA>, _: Scope) {
35        <ImplicitClose<LABEL> as CriticalEdgeBasedCompleteness<LABEL, DATA>>::init_scope_with(
36            self,
37            HashSet::from_iter(LABEL::iter()),
38        )
39    }
40
41    fn cmpl_new_complete_scope(&self, _: &InnerScopeGraph<LABEL, DATA>, _: Scope) {
42        <ImplicitClose<LABEL> as CriticalEdgeBasedCompleteness<LABEL, DATA>>::init_scope_with(
43            self,
44            HashSet::new(),
45        )
46    }
47
48    type NewEdgeResult = Result<(), EdgeClosedError<LABEL>>;
49
50    // FIXME: identical to `ExplicitClose` impl.
51    fn cmpl_new_edge(
52        &self,
53        inner_scope_graph: &InnerScopeGraph<LABEL, DATA>,
54        src: Scope,
55        lbl: LABEL,
56        dst: Scope,
57    ) -> Self::NewEdgeResult {
58        if self.critical_edges.is_open(src, &lbl) {
59            inner_scope_graph.add_edge(src, lbl, dst);
60            Ok(())
61        } else {
62            // FIXME: provide reason (queries) that made this edge closed?
63            Err(EdgeClosedError {
64                scope: src,
65                label: lbl,
66            })
67        }
68    }
69
70    type GetEdgesResult<'rslv> = Vec<Scope>
71        where
72            Self: 'rslv, LABEL: 'rslv, DATA: 'rslv;
73
74    fn cmpl_get_edges<'rslv>(
75        &self,
76        inner_scope_graph: &InnerScopeGraph<LABEL, DATA>,
77        src: Scope,
78        lbl: LABEL,
79    ) -> Self::GetEdgesResult<'rslv>
80    where
81        LABEL: 'rslv,
82        DATA: 'rslv,
83    {
84        self.critical_edges.close(src, &lbl);
85        inner_scope_graph.get_edges(src, lbl)
86    }
87}
88
89impl<LABEL: Hash + Eq + Label, DATA> CriticalEdgeBasedCompleteness<LABEL, DATA>
90    for ImplicitClose<LABEL>
91{
92    fn init_scope_with(&self, open_labels: HashSet<LABEL>) {
93        self.critical_edges.init_scope(open_labels)
94    }
95}