2021-08-14 01:25:31 +00:00
|
|
|
//! High-speed index over a set of assertions and a set of
|
|
|
|
//! [`Observe`rs][crate::schemas::dataspace::Observe] of those
|
|
|
|
//! assertions.
|
|
|
|
//!
|
|
|
|
//! Generally speaking, you will not need to use this module; instead,
|
|
|
|
//! create [`Dataspace`][crate::dataspace::Dataspace] entities.
|
|
|
|
|
2019-10-22 21:37:37 +00:00
|
|
|
use super::bag;
|
2019-10-20 21:25:01 +00:00
|
|
|
|
2021-07-22 14:53:56 +00:00
|
|
|
use preserves::value::{Map, NestedValue, Set, Value};
|
2019-10-20 21:25:01 +00:00
|
|
|
use std::collections::btree_map::Entry;
|
2021-07-03 07:03:52 +00:00
|
|
|
use std::convert::TryFrom;
|
|
|
|
use std::convert::TryInto;
|
2019-10-22 21:37:37 +00:00
|
|
|
use std::sync::Arc;
|
2019-10-20 21:25:01 +00:00
|
|
|
|
2021-08-11 21:16:01 +00:00
|
|
|
use crate::actor::AnyValue;
|
2021-07-03 07:03:52 +00:00
|
|
|
use crate::actor::Activation;
|
2021-07-22 08:07:49 +00:00
|
|
|
use crate::actor::Handle;
|
2021-07-22 14:53:56 +00:00
|
|
|
use crate::actor::Cap;
|
2021-07-03 07:03:52 +00:00
|
|
|
use crate::schemas::dataspace_patterns as ds;
|
|
|
|
use crate::pattern::{self, PathStep, Path, Paths};
|
|
|
|
|
2019-10-22 21:37:37 +00:00
|
|
|
type Bag<A> = bag::BTreeBag<A>;
|
2019-10-20 21:25:01 +00:00
|
|
|
|
2021-08-11 21:16:01 +00:00
|
|
|
type Captures = AnyValue;
|
2019-10-20 21:25:01 +00:00
|
|
|
|
2019-10-22 21:37:37 +00:00
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
|
2021-08-14 01:25:31 +00:00
|
|
|
enum Guard {
|
2021-08-11 21:16:01 +00:00
|
|
|
Rec(AnyValue, usize),
|
2021-07-03 07:03:52 +00:00
|
|
|
Seq(usize),
|
|
|
|
Map,
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
|
|
|
|
2021-08-14 01:25:31 +00:00
|
|
|
/// Index of assertions and [`Observe`rs][crate::schemas::dataspace::Observe].
|
|
|
|
///
|
|
|
|
/// Generally speaking, you will not need to use this structure;
|
|
|
|
/// instead, create [`Dataspace`][crate::dataspace::Dataspace]
|
|
|
|
/// entities.
|
2019-10-24 19:05:39 +00:00
|
|
|
#[derive(Debug)]
|
2021-07-03 07:03:52 +00:00
|
|
|
pub struct Index {
|
2021-08-11 21:16:01 +00:00
|
|
|
all_assertions: Bag<AnyValue>,
|
2021-07-03 07:03:52 +00:00
|
|
|
observer_count: usize,
|
|
|
|
root: Node,
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
|
|
|
|
2019-10-24 19:05:39 +00:00
|
|
|
#[derive(Debug)]
|
2021-07-03 07:03:52 +00:00
|
|
|
struct Node {
|
|
|
|
continuation: Continuation,
|
|
|
|
edges: Map<Selector, Map<Guard, Node>>,
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2021-07-03 07:03:52 +00:00
|
|
|
struct Continuation {
|
2021-08-11 21:16:01 +00:00
|
|
|
cached_assertions: Set<AnyValue>,
|
2021-07-03 07:03:52 +00:00
|
|
|
leaf_map: Map<Paths, Map<Captures, Leaf>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
|
|
struct Selector {
|
|
|
|
pop_count: usize,
|
|
|
|
step: PathStep,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct Leaf { // aka Topic
|
2021-08-11 21:16:01 +00:00
|
|
|
cached_assertions: Set<AnyValue>,
|
2021-07-03 07:03:52 +00:00
|
|
|
endpoints_map: Map<Paths, Endpoints>,
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
|
|
|
|
2021-07-03 07:03:52 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct Endpoints {
|
|
|
|
cached_captures: Bag<Captures>,
|
2021-07-22 14:53:56 +00:00
|
|
|
endpoints: Map<Arc<Cap>, Map<Captures, Handle>>,
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2019-10-20 21:25:01 +00:00
|
|
|
impl Index {
|
2021-08-14 01:25:31 +00:00
|
|
|
/// Construct a new `Index`.
|
2019-10-20 21:25:01 +00:00
|
|
|
pub fn new() -> Self {
|
2021-07-03 07:03:52 +00:00
|
|
|
Index {
|
|
|
|
all_assertions: Bag::new(),
|
|
|
|
observer_count: 0,
|
|
|
|
root: Node::new(Continuation::new(Set::new())),
|
|
|
|
}
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
|
|
|
|
2021-08-14 01:25:31 +00:00
|
|
|
/// Adds a new observer. If any existing assertions in the index
|
|
|
|
/// match `pat`, establishes corresponding assertions at
|
|
|
|
/// `observer`. Once the observer is registered, subsequent
|
|
|
|
/// arriving assertions will be matched against `pat` and
|
|
|
|
/// delivered to `observer` if they match.
|
2021-07-03 07:03:52 +00:00
|
|
|
pub fn add_observer(
|
|
|
|
&mut self,
|
|
|
|
t: &mut Activation,
|
|
|
|
pat: &ds::Pattern,
|
2021-07-22 14:53:56 +00:00
|
|
|
observer: &Arc<Cap>,
|
2021-07-03 07:03:52 +00:00
|
|
|
) {
|
|
|
|
let analysis = pattern::PatternAnalysis::new(pat);
|
|
|
|
self.root.extend(pat).add_observer(t, &analysis, observer);
|
|
|
|
self.observer_count += 1;
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
|
|
|
|
2021-08-14 01:25:31 +00:00
|
|
|
/// Removes an existing observer.
|
2021-07-03 07:03:52 +00:00
|
|
|
pub fn remove_observer(
|
|
|
|
&mut self,
|
2021-07-08 22:04:11 +00:00
|
|
|
t: &mut Activation,
|
2021-07-03 07:03:52 +00:00
|
|
|
pat: ds::Pattern,
|
2021-07-22 14:53:56 +00:00
|
|
|
observer: &Arc<Cap>,
|
2021-07-03 07:03:52 +00:00
|
|
|
) {
|
|
|
|
let analysis = pattern::PatternAnalysis::new(&pat);
|
2021-07-08 22:04:11 +00:00
|
|
|
self.root.extend(&pat).remove_observer(t, analysis, observer);
|
2021-07-03 07:03:52 +00:00
|
|
|
self.observer_count -= 1;
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
2019-10-22 21:37:37 +00:00
|
|
|
|
2021-08-14 01:25:31 +00:00
|
|
|
/// Inserts an assertion into the index, notifying matching observers.
|
2021-08-11 21:16:01 +00:00
|
|
|
pub fn insert(&mut self, t: &mut Activation, outer_value: &AnyValue) {
|
2020-06-15 17:43:42 +00:00
|
|
|
let net = self.all_assertions.change(outer_value.clone(), 1);
|
2019-10-22 21:37:37 +00:00
|
|
|
match net {
|
|
|
|
bag::Net::AbsentToPresent => {
|
|
|
|
Modification::new(
|
|
|
|
true,
|
|
|
|
&outer_value,
|
|
|
|
|c, v| { c.cached_assertions.insert(v.clone()); },
|
|
|
|
|l, v| { l.cached_assertions.insert(v.clone()); },
|
|
|
|
|es, cs| {
|
|
|
|
if es.cached_captures.change(cs.clone(), 1) == bag::Net::AbsentToPresent {
|
2021-07-03 07:03:52 +00:00
|
|
|
for (observer, capture_map) in &mut es.endpoints {
|
2021-07-22 14:53:56 +00:00
|
|
|
if let Some(h) = observer.assert(t, cs.clone()) {
|
|
|
|
capture_map.insert(cs.clone(), h);
|
|
|
|
}
|
2020-06-15 19:14:01 +00:00
|
|
|
}
|
2019-10-22 21:37:37 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.perform(&mut self.root);
|
|
|
|
}
|
2020-06-15 17:43:42 +00:00
|
|
|
bag::Net::PresentToPresent => (),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-14 01:25:31 +00:00
|
|
|
/// Removes an assertion from the index, notifying matching observers.
|
2021-08-11 21:16:01 +00:00
|
|
|
pub fn remove(&mut self, t: &mut Activation, outer_value: &AnyValue) {
|
2020-06-15 17:43:42 +00:00
|
|
|
let net = self.all_assertions.change(outer_value.clone(), -1);
|
|
|
|
match net {
|
2019-10-22 21:37:37 +00:00
|
|
|
bag::Net::PresentToAbsent => {
|
|
|
|
Modification::new(
|
|
|
|
false,
|
|
|
|
&outer_value,
|
|
|
|
|c, v| { c.cached_assertions.remove(v); },
|
|
|
|
|l, v| { l.cached_assertions.remove(v); },
|
|
|
|
|es, cs| {
|
|
|
|
if es.cached_captures.change(cs.clone(), -1) == bag::Net::PresentToAbsent {
|
2021-07-03 07:03:52 +00:00
|
|
|
for capture_map in es.endpoints.values_mut() {
|
|
|
|
if let Some(h) = capture_map.remove(&cs) {
|
|
|
|
t.retract(h);
|
|
|
|
}
|
2020-06-15 19:14:01 +00:00
|
|
|
}
|
2019-10-22 21:37:37 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.perform(&mut self.root);
|
|
|
|
}
|
2020-06-15 17:43:42 +00:00
|
|
|
bag::Net::PresentToPresent => (),
|
|
|
|
_ => unreachable!(),
|
2019-10-22 21:37:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-14 01:25:31 +00:00
|
|
|
/// Routes a message using the index, notifying matching observers.
|
2021-08-14 00:39:27 +00:00
|
|
|
pub fn send(&mut self, t: &mut Activation, outer_value: &AnyValue) {
|
2019-10-22 21:37:37 +00:00
|
|
|
Modification::new(
|
|
|
|
false,
|
|
|
|
&outer_value,
|
|
|
|
|_c, _v| (),
|
|
|
|
|_l, _v| (),
|
2020-05-18 10:08:57 +00:00
|
|
|
|es, cs| {
|
2021-08-14 00:39:27 +00:00
|
|
|
// *delivery_count += es.endpoints.len();
|
2021-07-03 07:03:52 +00:00
|
|
|
for observer in es.endpoints.keys() {
|
2021-07-22 14:53:56 +00:00
|
|
|
observer.message(t, cs.clone());
|
2020-06-15 19:14:01 +00:00
|
|
|
}
|
2020-05-18 10:08:57 +00:00
|
|
|
}).perform(&mut self.root);
|
2019-10-22 21:37:37 +00:00
|
|
|
}
|
2020-05-18 08:44:57 +00:00
|
|
|
|
2021-08-14 01:25:31 +00:00
|
|
|
/// Retrieves the current count of distinct assertions in the index.
|
2020-05-18 08:44:57 +00:00
|
|
|
pub fn assertion_count(&self) -> usize {
|
|
|
|
return self.all_assertions.len()
|
|
|
|
}
|
|
|
|
|
2021-08-14 01:25:31 +00:00
|
|
|
/// Retrieves the current count of assertions in the index,
|
|
|
|
/// including duplicates.
|
2020-05-18 08:44:57 +00:00
|
|
|
pub fn endpoint_count(&self) -> isize {
|
|
|
|
return self.all_assertions.total()
|
|
|
|
}
|
2019-10-20 21:25:01 +00:00
|
|
|
|
2021-08-14 01:25:31 +00:00
|
|
|
/// Retrieves the current count of observers of the index.
|
2021-07-03 07:03:52 +00:00
|
|
|
pub fn observer_count(&self) -> usize {
|
|
|
|
return self.observer_count
|
|
|
|
}
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Node {
|
|
|
|
fn new(continuation: Continuation) -> Self {
|
|
|
|
Node { continuation, edges: Map::new() }
|
|
|
|
}
|
|
|
|
|
2021-07-03 07:03:52 +00:00
|
|
|
fn extend(&mut self, pat: &ds::Pattern) -> &mut Continuation {
|
|
|
|
let (_pop_count, final_node) = self.extend_walk(&mut Vec::new(), 0, PathStep::Index(0), pat);
|
2019-10-20 21:25:01 +00:00
|
|
|
&mut final_node.continuation
|
|
|
|
}
|
|
|
|
|
2021-07-03 07:03:52 +00:00
|
|
|
fn extend_walk(
|
|
|
|
&mut self,
|
|
|
|
path: &mut Path,
|
|
|
|
pop_count: usize,
|
|
|
|
step: PathStep,
|
|
|
|
pat: &ds::Pattern,
|
|
|
|
) -> (usize, &mut Node) {
|
|
|
|
let (guard, members): (Guard, Vec<(PathStep, &ds::Pattern)>) = match pat {
|
|
|
|
ds::Pattern::DCompound(b) => match &**b {
|
|
|
|
ds::DCompound::Arr { ctor, members } =>
|
|
|
|
(Guard::Seq(usize::try_from(&ctor.arity).unwrap_or(0)),
|
|
|
|
members.iter().map(|(i, p)| (PathStep::Index(i.try_into().unwrap_or(0)), p)).collect()),
|
|
|
|
ds::DCompound::Rec { ctor, members } =>
|
|
|
|
(Guard::Rec(ctor.label.clone(), usize::try_from(&ctor.arity).unwrap_or(0)),
|
|
|
|
members.iter().map(|(i, p)| (PathStep::Index(i.try_into().unwrap_or(0)), p)).collect()),
|
|
|
|
ds::DCompound::Dict { members, .. } =>
|
|
|
|
(Guard::Map,
|
|
|
|
members.iter().map(|(k, p)| (PathStep::Key(k.clone()), p)).collect()),
|
|
|
|
}
|
|
|
|
ds::Pattern::DBind(b) => {
|
|
|
|
let ds::DBind { pattern, .. } = &**b;
|
|
|
|
return self.extend_walk(path, pop_count, step, pattern);
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
ds::Pattern::DDiscard(_) | ds::Pattern::DLit(_) =>
|
|
|
|
return (pop_count, self),
|
|
|
|
};
|
|
|
|
|
|
|
|
let selector = Selector { pop_count, step };
|
|
|
|
let continuation = &self.continuation;
|
|
|
|
let table = self.edges.entry(selector).or_insert_with(Map::new);
|
|
|
|
let mut next_node = table.entry(guard.clone()).or_insert_with(|| {
|
|
|
|
Self::new(Continuation::new(
|
|
|
|
continuation.cached_assertions.iter()
|
|
|
|
.filter(|a| match project_path(a, path) {
|
|
|
|
Some(v) => Some(&guard) == class_of(v).as_ref(),
|
|
|
|
None => false,
|
|
|
|
})
|
|
|
|
.cloned()
|
|
|
|
.collect()))
|
|
|
|
});
|
|
|
|
let mut pop_count = 0;
|
|
|
|
for (step, kid) in members.into_iter() {
|
|
|
|
path.push(step.clone());
|
|
|
|
let (pc, nn) = next_node.extend_walk(path, pop_count, step, kid);
|
|
|
|
pop_count = pc;
|
|
|
|
next_node = nn;
|
|
|
|
path.pop();
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
(pop_count + 1, next_node)
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-22 21:37:37 +00:00
|
|
|
#[derive(Debug)]
|
2021-08-14 01:25:31 +00:00
|
|
|
enum Stack<'a, T> {
|
2019-10-22 21:37:37 +00:00
|
|
|
Empty,
|
|
|
|
Item(T, &'a Stack<'a, T>)
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T> Stack<'a, T> {
|
|
|
|
fn pop(&self) -> &Self {
|
|
|
|
match self {
|
|
|
|
Stack::Empty => panic!("Internal error: pop: Incorrect pop_count computation"),
|
|
|
|
Stack::Item(_, tail) => tail
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn top(&self) -> &T {
|
|
|
|
match self {
|
|
|
|
Stack::Empty => panic!("Internal error: top: Incorrect pop_count computation"),
|
|
|
|
Stack::Item(item, _) => item
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Modification<'op, FCont, FLeaf, FEndpoints>
|
2021-08-11 21:16:01 +00:00
|
|
|
where FCont: FnMut(&mut Continuation, &AnyValue) -> (),
|
|
|
|
FLeaf: FnMut(&mut Leaf, &AnyValue) -> (),
|
2019-10-22 21:37:37 +00:00
|
|
|
FEndpoints: FnMut(&mut Endpoints, Captures) -> ()
|
|
|
|
{
|
|
|
|
create_leaf_if_absent: bool,
|
2021-08-11 21:16:01 +00:00
|
|
|
outer_value: &'op AnyValue,
|
2019-10-22 21:37:37 +00:00
|
|
|
m_cont: FCont,
|
|
|
|
m_leaf: FLeaf,
|
|
|
|
m_endpoints: FEndpoints,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'op, FCont, FLeaf, FEndpoints> Modification<'op, FCont, FLeaf, FEndpoints>
|
2021-08-11 21:16:01 +00:00
|
|
|
where FCont: FnMut(&mut Continuation, &AnyValue) -> (),
|
|
|
|
FLeaf: FnMut(&mut Leaf, &AnyValue) -> (),
|
2019-10-22 21:37:37 +00:00
|
|
|
FEndpoints: FnMut(&mut Endpoints, Captures) -> ()
|
|
|
|
{
|
|
|
|
fn new(create_leaf_if_absent: bool,
|
2021-08-11 21:16:01 +00:00
|
|
|
outer_value: &'op AnyValue,
|
2019-10-22 21:37:37 +00:00
|
|
|
m_cont: FCont,
|
|
|
|
m_leaf: FLeaf,
|
2021-07-03 07:03:52 +00:00
|
|
|
m_endpoints: FEndpoints,
|
|
|
|
) -> Self {
|
2019-10-22 21:37:37 +00:00
|
|
|
Modification {
|
|
|
|
create_leaf_if_absent,
|
|
|
|
outer_value,
|
|
|
|
m_cont,
|
|
|
|
m_leaf,
|
|
|
|
m_endpoints,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn perform(&mut self, n: &mut Node) {
|
2021-07-03 07:03:52 +00:00
|
|
|
self.node(n, &Stack::Item(&Value::from(vec![self.outer_value.clone()]).wrap(), &Stack::Empty))
|
2019-10-22 21:37:37 +00:00
|
|
|
}
|
|
|
|
|
2021-08-11 21:16:01 +00:00
|
|
|
fn node(&mut self, n: &mut Node, term_stack: &Stack<&AnyValue>) {
|
2019-10-22 21:37:37 +00:00
|
|
|
self.continuation(&mut n.continuation);
|
|
|
|
for (selector, table) in &mut n.edges {
|
|
|
|
let mut next_stack = term_stack;
|
|
|
|
for _ in 0..selector.pop_count { next_stack = next_stack.pop() }
|
2021-07-03 07:03:52 +00:00
|
|
|
if let Some(next_value) = step(next_stack.top(), &selector.step) {
|
|
|
|
if let Some(next_class) = class_of(next_value) {
|
|
|
|
if let Some(next_node) = table.get_mut(&next_class) {
|
|
|
|
self.node(next_node, &Stack::Item(next_value, next_stack))
|
|
|
|
}
|
2019-10-22 21:37:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn continuation(&mut self, c: &mut Continuation) {
|
|
|
|
(self.m_cont)(c, self.outer_value);
|
|
|
|
let mut empty_const_paths = Vec::new();
|
|
|
|
for (const_paths, const_val_map) in &mut c.leaf_map {
|
2021-07-03 07:03:52 +00:00
|
|
|
if let Some(const_vals) = project_paths(self.outer_value, const_paths) {
|
|
|
|
let leaf_opt = if self.create_leaf_if_absent {
|
|
|
|
Some(const_val_map.entry(const_vals.clone()).or_insert_with(Leaf::new))
|
|
|
|
} else {
|
|
|
|
const_val_map.get_mut(&const_vals)
|
|
|
|
};
|
|
|
|
if let Some(leaf) = leaf_opt {
|
|
|
|
(self.m_leaf)(leaf, self.outer_value);
|
|
|
|
for (capture_paths, endpoints) in &mut leaf.endpoints_map {
|
|
|
|
if let Some(cs) = project_paths(self.outer_value, &capture_paths) {
|
|
|
|
(self.m_endpoints)(endpoints, cs);
|
|
|
|
}
|
2019-10-22 21:37:37 +00:00
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
if leaf.is_empty() {
|
|
|
|
const_val_map.remove(&const_vals);
|
|
|
|
if const_val_map.is_empty() {
|
|
|
|
empty_const_paths.push(const_paths.clone());
|
|
|
|
}
|
2019-10-22 21:37:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for const_paths in empty_const_paths {
|
|
|
|
c.leaf_map.remove(&const_paths);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-11 21:16:01 +00:00
|
|
|
fn class_of(v: &AnyValue) -> Option<Guard> {
|
2019-10-20 21:25:01 +00:00
|
|
|
match v.value() {
|
2021-07-03 07:03:52 +00:00
|
|
|
Value::Sequence(vs) => Some(Guard::Seq(vs.len())),
|
|
|
|
Value::Record(r) => Some(Guard::Rec(r.label().clone(), r.arity())),
|
|
|
|
Value::Dictionary(_) => Some(Guard::Map),
|
2019-10-20 21:25:01 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-11 21:16:01 +00:00
|
|
|
fn project_path<'a>(v: &'a AnyValue, p: &Path) -> Option<&'a AnyValue> {
|
2019-10-20 21:25:01 +00:00
|
|
|
let mut v = v;
|
|
|
|
for i in p {
|
2021-07-03 07:03:52 +00:00
|
|
|
match step(v, i) {
|
|
|
|
Some(w) => v = w,
|
|
|
|
None => return None,
|
2019-10-22 21:37:37 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
Some(v)
|
2019-10-22 21:37:37 +00:00
|
|
|
}
|
|
|
|
|
2021-08-11 21:16:01 +00:00
|
|
|
fn project_paths<'a>(v: &'a AnyValue, ps: &Paths) -> Option<Captures> {
|
2021-07-03 07:03:52 +00:00
|
|
|
let mut vs = Vec::new();
|
|
|
|
for p in ps {
|
|
|
|
match project_path(v, p) {
|
|
|
|
Some(c) => vs.push(c.clone()),
|
|
|
|
None => return None,
|
|
|
|
}
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
Some(Captures::new(vs))
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
|
|
|
|
2021-08-11 21:16:01 +00:00
|
|
|
fn step<'a>(v: &'a AnyValue, s: &PathStep) -> Option<&'a AnyValue> {
|
2021-07-03 07:03:52 +00:00
|
|
|
match (v.value(), s) {
|
|
|
|
(Value::Sequence(vs), PathStep::Index(i)) =>
|
|
|
|
if *i < vs.len() { Some(&vs[*i]) } else { None },
|
|
|
|
(Value::Record(r), PathStep::Index(i)) =>
|
|
|
|
if *i < r.arity() { Some(&r.fields()[*i]) } else { None },
|
|
|
|
(Value::Dictionary(m), PathStep::Key(k)) =>
|
|
|
|
m.get(k),
|
|
|
|
_ =>
|
|
|
|
None,
|
2019-10-24 19:05:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-03 07:03:52 +00:00
|
|
|
impl Continuation {
|
2021-08-11 21:16:01 +00:00
|
|
|
fn new(cached_assertions: Set<AnyValue>) -> Self {
|
2021-07-03 07:03:52 +00:00
|
|
|
Continuation { cached_assertions, leaf_map: Map::new() }
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
|
|
|
|
2021-08-14 01:25:31 +00:00
|
|
|
fn add_observer(
|
2021-07-03 07:03:52 +00:00
|
|
|
&mut self,
|
|
|
|
t: &mut Activation,
|
|
|
|
analysis: &pattern::PatternAnalysis,
|
2021-07-22 14:53:56 +00:00
|
|
|
observer: &Arc<Cap>,
|
2021-07-03 07:03:52 +00:00
|
|
|
) {
|
|
|
|
let cached_assertions = &self.cached_assertions;
|
|
|
|
let const_val_map =
|
|
|
|
self.leaf_map.entry(analysis.const_paths.clone()).or_insert_with({
|
|
|
|
|| {
|
|
|
|
let mut cvm = Map::new();
|
|
|
|
for a in cached_assertions {
|
|
|
|
if let Some(key) = project_paths(a, &analysis.const_paths) {
|
|
|
|
cvm.entry(key).or_insert_with(Leaf::new)
|
|
|
|
.cached_assertions.insert(a.clone());
|
2019-10-24 13:49:54 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
cvm
|
|
|
|
}
|
|
|
|
});
|
|
|
|
let leaf = const_val_map.entry(analysis.const_values.clone()).or_insert_with(Leaf::new);
|
|
|
|
let leaf_cached_assertions = &leaf.cached_assertions;
|
|
|
|
let endpoints = leaf.endpoints_map.entry(analysis.capture_paths.clone()).or_insert_with(|| {
|
|
|
|
let mut b = Bag::new();
|
|
|
|
for term in leaf_cached_assertions {
|
|
|
|
if let Some(captures) = project_paths(term, &analysis.capture_paths) {
|
|
|
|
*b.entry(captures).or_insert(0) += 1;
|
2019-10-24 13:49:54 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
Endpoints { cached_captures: b, endpoints: Map::new() }
|
|
|
|
});
|
|
|
|
let mut capture_map = Map::new();
|
|
|
|
for cs in endpoints.cached_captures.keys() {
|
2021-07-22 14:53:56 +00:00
|
|
|
if let Some(h) = observer.assert(t, cs.clone()) {
|
|
|
|
capture_map.insert(cs.clone(), h);
|
|
|
|
}
|
2019-10-24 13:49:54 +00:00
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
endpoints.endpoints.insert(observer.clone(), capture_map);
|
2019-10-20 21:25:01 +00:00
|
|
|
}
|
2019-10-22 21:37:37 +00:00
|
|
|
|
2021-08-14 01:25:31 +00:00
|
|
|
fn remove_observer(
|
2021-07-03 07:03:52 +00:00
|
|
|
&mut self,
|
2021-07-08 22:04:11 +00:00
|
|
|
t: &mut Activation,
|
2021-07-03 07:03:52 +00:00
|
|
|
analysis: pattern::PatternAnalysis,
|
2021-07-22 14:53:56 +00:00
|
|
|
observer: &Arc<Cap>,
|
2021-07-03 07:03:52 +00:00
|
|
|
) {
|
|
|
|
if let Entry::Occupied(mut const_val_map_entry)
|
|
|
|
= self.leaf_map.entry(analysis.const_paths)
|
|
|
|
{
|
|
|
|
let const_val_map = const_val_map_entry.get_mut();
|
|
|
|
if let Entry::Occupied(mut leaf_entry)
|
|
|
|
= const_val_map.entry(analysis.const_values)
|
|
|
|
{
|
|
|
|
let leaf = leaf_entry.get_mut();
|
|
|
|
if let Entry::Occupied(mut endpoints_entry)
|
|
|
|
= leaf.endpoints_map.entry(analysis.capture_paths)
|
|
|
|
{
|
|
|
|
let endpoints = endpoints_entry.get_mut();
|
2021-07-08 22:04:11 +00:00
|
|
|
if let Some(capture_map) = endpoints.endpoints.remove(observer) {
|
|
|
|
for handle in capture_map.into_values() {
|
|
|
|
t.retract(handle)
|
|
|
|
}
|
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
if endpoints.endpoints.is_empty() {
|
|
|
|
endpoints_entry.remove_entry();
|
|
|
|
}
|
2019-10-22 21:37:37 +00:00
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
if leaf.is_empty() {
|
|
|
|
leaf_entry.remove_entry();
|
2019-10-22 21:37:37 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
if const_val_map.is_empty() {
|
|
|
|
const_val_map_entry.remove_entry();
|
|
|
|
}
|
2019-10-22 21:37:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-03 07:03:52 +00:00
|
|
|
impl Leaf {
|
|
|
|
fn new() -> Self {
|
|
|
|
Leaf { cached_assertions: Set::new(), endpoints_map: Map::new() }
|
2019-10-24 13:50:44 +00:00
|
|
|
}
|
|
|
|
|
2021-07-03 07:03:52 +00:00
|
|
|
fn is_empty(&self) -> bool {
|
|
|
|
self.cached_assertions.is_empty() && self.endpoints_map.is_empty()
|
|
|
|
}
|
|
|
|
}
|