Skip to content

Commit a1bed84

Browse files
authored
Merge pull request #22 from nikomatsakis/api-2.0
Proposal: extend API to support more operations on relations [breaking change]
2 parents 2689e39 + 03d55fd commit a1bed84

File tree

6 files changed

+724
-175
lines changed

6 files changed

+724
-175
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ description = "Lightweight Datalog engine intended to be embedded in other Rust
77
readme = "README.md"
88
keywords = ["datalog", "analysis"]
99
repository = "https://github.com/rust-lang-nursery/datafrog"
10+
edition = "2018"
1011

1112
[badges]
1213
is-it-maintained-issue-resolution = { repository = "https://github.com/rust-lang-nursery/datafrog" }
1314
is-it-maintained-open-issues = { repository = "https://github.com/rust-lang-nursery/datafrog" }
15+
16+
[dev-dependencies]
17+
proptest = "0.8.7"

src/join.rs

Lines changed: 80 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,35 @@
11
//! Join functionality.
22
33
use super::{Relation, Variable};
4-
5-
pub fn join_into<Key: Ord, Val1: Ord, Val2: Ord, Result: Ord>(
4+
use std::cell::Ref;
5+
use std::ops::Deref;
6+
7+
/// Implements `join`. Note that `input1` must be a variable, but
8+
/// `input2` can be either a variable or a relation. This is necessary
9+
/// because relations have no "recent" tuples, so the fn would be a
10+
/// guaranteed no-op if both arguments were relations. See also
11+
/// `join_into_relation`.
12+
pub(crate) fn join_into<'me, Key: Ord, Val1: Ord, Val2: Ord, Result: Ord>(
613
input1: &Variable<(Key, Val1)>,
7-
input2: &Variable<(Key, Val2)>,
14+
input2: impl JoinInput<'me, (Key, Val2)>,
815
output: &Variable<Result>,
916
mut logic: impl FnMut(&Key, &Val1, &Val2) -> Result,
1017
) {
1118
let mut results = Vec::new();
1219

13-
let recent1 = input1.recent.borrow();
14-
let recent2 = input2.recent.borrow();
20+
let recent1 = input1.recent();
21+
let recent2 = input2.recent();
1522

1623
{
1724
// scoped to let `closure` drop borrow of `results`.
1825

1926
let mut closure = |k: &Key, v1: &Val1, v2: &Val2| results.push(logic(k, v1, v2));
2027

21-
for batch2 in input2.stable.borrow().iter() {
28+
for batch2 in input2.stable().iter() {
2229
join_helper(&recent1, &batch2, &mut closure);
2330
}
2431

25-
for batch1 in input1.stable.borrow().iter() {
32+
for batch1 in input1.stable().iter() {
2633
join_helper(&batch1, &recent2, &mut closure);
2734
}
2835

@@ -32,18 +39,31 @@ pub fn join_into<Key: Ord, Val1: Ord, Val2: Ord, Result: Ord>(
3239
output.insert(Relation::from_vec(results));
3340
}
3441

42+
/// Join, but for two relations.
43+
pub(crate) fn join_into_relation<'me, Key: Ord, Val1: Ord, Val2: Ord, Result: Ord>(
44+
input1: &Relation<(Key, Val1)>,
45+
input2: &Relation<(Key, Val2)>,
46+
mut logic: impl FnMut(&Key, &Val1, &Val2) -> Result,
47+
) -> Relation<Result> {
48+
let mut results = Vec::new();
49+
50+
join_helper(&input1.elements, &input2.elements, |k, v1, v2| {
51+
results.push(logic(k, v1, v2));
52+
});
53+
54+
Relation::from_vec(results)
55+
}
56+
3557
/// Moves all recent tuples from `input1` that are not present in `input2` into `output`.
36-
pub fn antijoin_into<Key: Ord, Val: Ord, Result: Ord>(
37-
input1: &Variable<(Key, Val)>,
58+
pub(crate) fn antijoin<'me, Key: Ord, Val: Ord, Result: Ord>(
59+
input1: impl JoinInput<'me, (Key, Val)>,
3860
input2: &Relation<Key>,
39-
output: &Variable<Result>,
4061
mut logic: impl FnMut(&Key, &Val) -> Result,
41-
) {
62+
) -> Relation<Result> {
4263
let mut tuples2 = &input2[..];
4364

4465
let results = input1
45-
.recent
46-
.borrow()
66+
.recent()
4767
.iter()
4868
.filter(|(ref key, _)| {
4969
tuples2 = gallop(tuples2, |k| k < key);
@@ -52,7 +72,7 @@ pub fn antijoin_into<Key: Ord, Val: Ord, Result: Ord>(
5272
.map(|(ref key, ref val)| logic(key, val))
5373
.collect::<Vec<_>>();
5474

55-
output.insert(Relation::from_vec(results));
75+
Relation::from_vec(results)
5676
}
5777

5878
fn join_helper<K: Ord, V1, V2>(
@@ -91,7 +111,7 @@ fn join_helper<K: Ord, V1, V2>(
91111
}
92112
}
93113

94-
pub fn gallop<T>(mut slice: &[T], mut cmp: impl FnMut(&T) -> bool) -> &[T] {
114+
pub(crate) fn gallop<T>(mut slice: &[T], mut cmp: impl FnMut(&T) -> bool) -> &[T] {
95115
// if empty slice, or already >= element, return
96116
if !slice.is_empty() && cmp(&slice[0]) {
97117
let mut step = 1;
@@ -113,3 +133,48 @@ pub fn gallop<T>(mut slice: &[T], mut cmp: impl FnMut(&T) -> bool) -> &[T] {
113133

114134
slice
115135
}
136+
137+
/// An input that can be used with `from_join`; either a `Variable` or a `Relation`.
138+
pub trait JoinInput<'me, Tuple: Ord>: Copy {
139+
/// If we are on iteration N of the loop, these are the tuples
140+
/// added on iteration N-1. (For a `Relation`, this is always an
141+
/// empty slice.)
142+
type RecentTuples: Deref<Target = [Tuple]>;
143+
144+
/// If we are on iteration N of the loop, these are the tuples
145+
/// added on iteration N - 2 or before. (For a `Relation`, this is
146+
/// just `self`.)
147+
type StableTuples: Deref<Target = [Relation<Tuple>]>;
148+
149+
/// Get the set of recent tuples.
150+
fn recent(self) -> Self::RecentTuples;
151+
152+
/// Get the set of stable tuples.
153+
fn stable(self) -> Self::StableTuples;
154+
}
155+
156+
impl<'me, Tuple: Ord> JoinInput<'me, Tuple> for &'me Variable<Tuple> {
157+
type RecentTuples = Ref<'me, [Tuple]>;
158+
type StableTuples = Ref<'me, [Relation<Tuple>]>;
159+
160+
fn recent(self) -> Self::RecentTuples {
161+
Ref::map(self.recent.borrow(), |r| &r.elements[..])
162+
}
163+
164+
fn stable(self) -> Self::StableTuples {
165+
Ref::map(self.stable.borrow(), |v| &v[..])
166+
}
167+
}
168+
169+
impl<'me, Tuple: Ord> JoinInput<'me, Tuple> for &'me Relation<Tuple> {
170+
type RecentTuples = &'me [Tuple];
171+
type StableTuples = &'me [Relation<Tuple>];
172+
173+
fn recent(self) -> Self::RecentTuples {
174+
&[]
175+
}
176+
177+
fn stable(self) -> Self::StableTuples {
178+
std::slice::from_ref(self)
179+
}
180+
}

0 commit comments

Comments
 (0)