From 8e64a9c4a5f0cb67b23bc9f7585ce15e89172c91 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Sun, 9 Dec 2018 13:28:01 +0000 Subject: [PATCH] Initial sketches --- src/bag.rs | 94 +++++++++++++++++++++++++++++++++++++++++ src/main.rs | 61 +++++++++++++++++++++++++++ src/skeleton.rs | 75 +++++++++++++++++++++++++++++++++ src/term.rs | 110 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 340 insertions(+) create mode 100644 src/bag.rs create mode 100644 src/main.rs create mode 100644 src/skeleton.rs create mode 100644 src/term.rs diff --git a/src/bag.rs b/src/bag.rs new file mode 100644 index 0000000..a373d6b --- /dev/null +++ b/src/bag.rs @@ -0,0 +1,94 @@ +use std::collections::HashMap; +use std::collections::HashSet; +use std::collections::hash_map::Iter; +use std::collections::hash_map::Keys; +use std::collections::hash_map::RandomState; +use std::hash::BuildHasher; +use std::hash::Hash; + +type Count = i32; + +pub enum Net { + PresentToAbsent, + AbsentToAbsent, + AbsentToPresent, + PresentToPresent, +} + +// Allows negative counts - a "delta" +pub struct HashBag { + counts: HashMap, +} + +impl HashBag +where V: Eq + Hash, S: BuildHasher + Default +{ + pub fn new() -> HashBag { + HashBag { + counts: HashMap::with_hasher(Default::default()), + } + } + + pub fn change(&mut self, key: V, delta: Count) -> Net { self._change(key, delta, false) } + pub fn change_clamped(&mut self, key: V, delta: Count) -> Net { self._change(key, delta, true) } + + pub fn _change(&mut self, key: V, delta: Count, clamp: bool) -> Net { + let old_count = self[&key]; + let mut new_count = old_count + delta; + if clamp { new_count = new_count.max(0) } + if new_count == 0 { + self.counts.remove(&key); + if old_count == 0 { Net::AbsentToAbsent } else { Net::PresentToAbsent } + } else { + self.counts.insert(key, new_count); + if old_count == 0 { Net::AbsentToPresent } else { Net::PresentToPresent } + } + } + + pub fn clear(&mut self) { + self.counts.clear(); + } + + pub fn contains_key(&self, key: &V) -> bool { + self.counts.contains_key(key) + } + + pub fn is_empty(&self) -> bool { + self.counts.is_empty() + } + + pub fn len(&self) -> usize { + self.counts.len() + } + + pub fn keys(&self) -> Keys { + self.counts.keys() + } + + pub fn iter(&self) -> Iter { + self.counts.iter() + } +} + +impl std::convert::From> for HashBag +where V: Eq + Hash + Clone, S: BuildHasher + Default +{ + fn from(xs: HashSet) -> Self { + let mut cs = HashMap::with_hasher(Default::default()); + for k in xs.iter() { + cs.insert(k.clone(), 1); + } + HashBag { + counts: cs + } + } +} + +impl std::ops::Index<&V> for HashBag +where V: Eq + Hash, S: BuildHasher +{ + type Output = Count; + fn index(&self, i: &V) -> &Count { + self.counts.get(i).unwrap_or(&0) + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e68c36a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,61 @@ +mod term; +mod bag; +mod skeleton; + +use self::term::Term; +use self::skeleton::Index; + +// Ord +// Hash + +fn main() { + let capture_label = Term::Symbol("capture".to_string()); + let discard_label = Term::Symbol("discard".to_string()); + let v2 = Term::Double(1234.56); + let v = Term::Seq(vec![ + Term::Boolean(true), + Term::Float(123.34), + v2.clone(), + Term::SignedInteger(999), + Term::SignedInteger(-101), + Term::String("hello".to_string()), + Term::ByteString("world".as_bytes()), + Term::Symbol("sym".to_string()), + Term::Rec(&capture_label, vec![ + Term::Rec(&discard_label, vec![]), + ]), + ]); + let v3 = Term::Double(1234.57); + println!("v = {:?}", v); + println!("v[2] = {:?}", v[2]); + println!("v == v = {:?}", v == v); + println!("v3 == v = {:?}", v3 == v); + println!("v[2] == v3 {:?}", v[2] == v3); + println!("v[2] == v2 {:?}", v[2] == v2); + println!("v[2] < v3 {:?}", v[2] < v3); + println!("v[2] < v2 {:?}", v[2] < v2); + println!("v[2] > v3 {:?}", v[2] > v3); + println!("v[2] > v2 {:?}", v[2] > v2); + println!("v[2] <= v3 {:?}", v[2] <= v3); + println!("v[2] <= v2 {:?}", v[2] <= v2); + println!("v[2] >= v3 {:?}", v[2] >= v3); + println!("v[2] >= v2 {:?}", v[2] >= v2); + println!("v == v3 {:?}", v == v3); + println!("v == v2 {:?}", v == v2); + println!("v < v3 {:?}", v < v3); + println!("v < v2 {:?}", v < v2); + println!("v > v3 {:?}", v > v3); + println!("v > v2 {:?}", v > v2); + println!("v <= v3 {:?}", v <= v3); + println!("v <= v2 {:?}", v <= v2); + println!("v >= v3 {:?}", v >= v3); + println!("v >= v2 {:?}", v >= v2); + println!("v[8].label() = {:?}", v[8].label()); + println!("v[8].len() = {:?}", v[8].len()); + println!("v[8][0] = {:?}", v[8][0]); + println!("v[8][0].label() = {:?}", v[8][0].label()); + println!("v[8][0].len() = {:?}", v[8][0].len()); + println!("v.len() = {:?}", v.len()); + + let i = Index::new(); +} diff --git a/src/skeleton.rs b/src/skeleton.rs new file mode 100644 index 0000000..5e0c19f --- /dev/null +++ b/src/skeleton.rs @@ -0,0 +1,75 @@ +// use std::sync::Arc; +use std::collections::HashMap; +use std::collections::HashSet; + +use super::bag::HashBag; +use super::term::Term; + +pub enum Event { + Removed, + Message, + Added, +} + +type Path = Vec; +type Paths = Vec; +type Captures<'a> = Vec>; + +type Callback<'a> = FnMut(Event, Captures<'a>) -> (); + +pub enum Skeleton<'a> { + Blank, + Guarded(Guard<'a>, Vec>) +} + +pub struct AnalysisResults<'a> { + skeleton: Skeleton<'a>, + constPaths: Paths, + constVals: Vec>, + capturePaths: Captures<'a>, + assertion: Term<'a>, +} + +pub struct Index<'a> { + all_assertions: HashBag>, +} + +impl<'a> Index<'a> { + pub fn new() -> Self { + Index { + all_assertions: HashBag::new(), + } + } + + pub fn add_handler(analysis_results: AnalysisResults, +} + +struct Node<'a> { + continuation: Continuation<'a>, + edges: HashMap, Node<'a>>>, +} + +struct Continuation<'a> { + cached_assertions: HashSet>, + leaf_map: HashMap>, Leaf<'a>>>, +} + +struct Selector { + pop_count: usize, + index: usize, +} + +enum Guard<'a> { + Rec(&'a Term<'a>, usize), + Seq(usize), +} + +struct Leaf<'a> { // aka Topic + cached_assertions: HashSet>, + handler_map: HashMap>, +} + +struct Handler<'a> { + cached_captures: HashBag>, + callbacks: HashSet<&'a Callback<'a>>, +} diff --git a/src/term.rs b/src/term.rs new file mode 100644 index 0000000..b3e3dba --- /dev/null +++ b/src/term.rs @@ -0,0 +1,110 @@ +use std::hash::Hash; +use std::hash::Hasher; + +#[derive(Debug, PartialOrd, Clone)] +pub enum Term<'a> { + Boolean(bool), + Float(f32), + Double(f64), + SignedInteger(i64), // TODO: bignums + String(std::string::String), + ByteString(&'a [u8]), + Symbol(std::string::String), + + Rec(&'a Term<'a>, Vec>), + Seq(Vec>), +} + +impl<'a> Term<'a> { + pub fn is_rec(&self) -> bool { match self { Term::Rec(_, _) => true, _ => false } } + pub fn is_seq(&self) -> bool { match self { Term::Seq(_) => true, _ => false } } + + pub fn label(&self) -> &Term { + match self { + Term::Rec(l, _) => l, + _ => panic!() + } + } + + pub fn len(&self) -> usize { + match self { + Term::Seq(vs) => vs.len(), + Term::Rec(_, fs) => fs.len(), + _ => 0, + } + } +} + +impl<'a> std::ops::Index for Term<'a> { + type Output = Term<'a>; + fn index(&self, i: usize) -> &Term<'a> { + match self { + Term::Seq(vs) => &vs[i], + Term::Rec(_, fs) => &fs[i], + _ => panic!() + } + } +} + +impl<'a> Eq for Term<'a> {} +impl<'a> PartialEq for Term<'a> { + fn eq(&self, other: &Term<'a>) -> bool { + match (self, other) { + (Term::Boolean(a), Term::Boolean(b)) => a == b, + (Term::Float(a), Term::Float(b)) => a.to_bits() == b.to_bits(), + (Term::Double(a), Term::Double(b)) => a.to_bits() == b.to_bits(), + (Term::SignedInteger(a), Term::SignedInteger(b)) => a == b, + (Term::String(a), Term::String(b)) => a == b, + (Term::ByteString(a), Term::ByteString(b)) => a == b, + (Term::Symbol(a), Term::Symbol(b)) => a == b, + (Term::Seq(a), Term::Seq(b)) => a == b, + (Term::Rec(la, fa), Term::Rec(lb, fb)) => la == lb && fa == fb, + (_, _) => false + } + } +} + +impl<'a> Ord for Term<'a> { + fn cmp(&self, other: &Term<'a>) -> std::cmp::Ordering { + match (self, other) { + (Term::Float(a), Term::Float(b)) => { + let mut va: i32 = a.to_bits() as i32; + let mut vb: i32 = b.to_bits() as i32; + if va < 0 { va ^= 0x7fffffff; } + if vb < 0 { vb ^= 0x7fffffff; } + va.cmp(&vb) + } + (Term::Double(a), Term::Double(b)) => { + let mut va: i64 = a.to_bits() as i64; + let mut vb: i64 = b.to_bits() as i64; + if va < 0 { va ^= 0x7fffffffffffffff; } + if vb < 0 { vb ^= 0x7fffffffffffffff; } + va.cmp(&vb) + } + (Term::Seq(a), Term::Seq(b)) => a.cmp(b), + (Term::Rec(la, fa), Term::Rec(lb, fb)) => { + match la.cmp(lb) { + std::cmp::Ordering::Equal => fa.cmp(fb), + o => o + } + } + (_, _) => self.partial_cmp(other).expect("total order"), + } + } +} + +impl<'a> Hash for Term<'a> { + fn hash(&self, state: &mut H) { + match self { + Term::Boolean(b) => { 1.hash(state); b.hash(state) } + Term::Float(f) => { 2.hash(state); f.to_bits().hash(state) } + Term::Double(d) => { 3.hash(state); d.to_bits().hash(state) } + Term::SignedInteger(i) => { 4.hash(state); i.hash(state) } + Term::String(s) => { 5.hash(state); s.hash(state) } + Term::ByteString(b) => { 6.hash(state); b.hash(state) } + Term::Symbol(s) => { 7.hash(state); s.hash(state) } + Term::Rec(l, fs) => { 8.hash(state); l.hash(state); fs.hash(state) } + Term::Seq(vs) => { 9.hash(state); vs.hash(state) } + } + } +}