summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs68
-rw-r--r--src/parser.rs2
-rw-r--r--src/pattern.rs9
-rw-r--r--src/vm.rs33
4 files changed, 79 insertions, 33 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 08609ab..b5d7bc6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,47 +6,73 @@ mod vm;
 pub use pattern::Pattern;
 
 // TODO replace with GATs
-/// The key returned from pairs and get.
-pub enum Key<'b, T, U> {
-    /// Reference.
+/// A borrowed or owned value of various types.
+pub enum RefOwn<'b, T: ?Sized, U> {
+    /// Borrowed T.
     Ref(&'b T),
     /// Borrowed string.
     Str(&'b str),
-    /// Owned types.
+    /// Owned U.
     Own(U),
 }
 
-impl<'b, T, U: Copy> Copy for Key<'b, T, U> {
+impl<'b, T, U> PartialEq for RefOwn<'b, T, U> 
+where
+    T: ?Sized + PartialEq<T> + PartialEq<U> + PartialEq<str>,
+    U: PartialEq<T> + PartialEq<U> + PartialEq<str>,
+    str: PartialEq<T> + PartialEq<U> + PartialEq<str>
+{
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (RefOwn::Ref(l), RefOwn::Ref(r)) => l.eq(r),
+            (RefOwn::Own(l), RefOwn::Own(r)) => l.eq(r),
+            (RefOwn::Str(l), RefOwn::Str(r)) => l.eq(r),
+            (RefOwn::Ref(l), RefOwn::Own(r)) => PartialEq::eq(*l, r),
+            (RefOwn::Own(l), RefOwn::Str(r)) => PartialEq::eq(l, *r),
+            (RefOwn::Str(l), RefOwn::Ref(r)) => l.eq(r),
+            (RefOwn::Ref(l), RefOwn::Str(r)) => l.eq(r),
+            (RefOwn::Own(l), RefOwn::Ref(r)) => PartialEq::eq(l, *r),
+            (RefOwn::Str(l), RefOwn::Own(r)) => PartialEq::eq(*l, r),
+        }
+    }
+}
+
+impl<'b, T: ?Sized, U: Copy> Copy for RefOwn<'b, T, U> {
 }
 
-impl<'b, T, U: Clone> Clone for Key<'b, T, U> {
+impl<'b, T: ?Sized, U: Clone> Clone for RefOwn<'b, T, U> {
     fn clone(&self) -> Self {
         match self {
-            Key::Ref(r) => Key::Ref(r),
-            Key::Str(r) => Key::Str(r),
-            Key::Own(v) => Key::Own(v.clone()),
+            RefOwn::Ref(r) => RefOwn::Ref(r),
+            RefOwn::Str(r) => RefOwn::Str(r),
+            RefOwn::Own(v) => RefOwn::Own(v.clone()),
         }
     }
 }
 
-pub type KVPair<'b, T> = (Key<'b, <T as PatternTypes>::Value, <T as PatternTypes>::OwnKey>, &'b <T as PatternTypes>::Value);
+pub type KVPair<'b, T> = (RefOwn<'b, <T as PatternTypes>::Ref, <T as PatternTypes>::Own>, RefOwn<'b, <T as PatternTypes>::Ref, <T as PatternTypes>::Own>);
+
+impl<'b, T, U> From<&'b T> for RefOwn<'b, T, U> {
+    fn from(x: &'b T) -> RefOwn<'b, T, U> {
+        RefOwn::Ref(x)
+    }
+}
 
 // TODO investigate if this should be PatternTypes: Default
 /// Defines the types and operations used for matching.
 pub trait PatternTypes {
-    // TODO investigate Value: ?Sized
-    /// The value type.
-    type Value;
+    /// The borrowed type.
+    type Ref: ?Sized;
 
     // TODO replace with GATs.
     // TODO potentially relax with Clone?
-    /// The owned key type. May be uninhabited.
-    type OwnKey: Copy + 'static;
+    /// The owned type.
+    type Own: Copy + 'static;
 
     /// Returns an iterator over key-value pairs contained within an item, or
     /// None if this operation is unsupported for the given value.
     fn pairs<'b>(
-        item: &'b Self::Value
+        item: RefOwn<'b, Self::Ref, Self::Own>
     ) -> Option<Box<dyn Iterator<Item=KVPair<'b, Self>> + 'b>> {
         // TODO remove these default impls that only exist for testing purposes
         let x = None;
@@ -56,8 +82,8 @@ pub trait PatternTypes {
     /// Returns an optional key-value pair keyed by the given key, or None if
     /// this operation is unsupported for the given value.
     fn get<'a, 'b>(
-        item: &'b Self::Value,
-        key: Key<'a, Self::Value, Self::OwnKey>
+        item: RefOwn<'b, Self::Ref, Self::Own>,
+        key: RefOwn<'a, Self::Ref, Self::Own>
     ) -> Option<Option<KVPair<'b, Self>>> {
         // TODO remove these default impls that only exist for testing purposes
         Some(None)
@@ -68,10 +94,10 @@ pub trait PatternTypes {
     /// the same guarantees as PartialEq. In fact, this is a replacement for
     /// PartialEq for cases where it's not possible to just use PartialEq.
     fn matches(
-        left: Key<'_, Self::Value, Self::OwnKey>,
-        right: Key<'_, Self::Value, Self::OwnKey>
+        left: RefOwn<'_, Self::Ref, Self::Own>,
+        right: RefOwn<'_, Self::Ref, Self::Own>
     ) -> bool;
 }
 
 // TODO
-type Predicate<T> = dyn (Fn(&<T as PatternTypes>::Value) -> bool) + Send + Sync;
+type Predicate<T> = dyn (Fn(RefOwn<<T as PatternTypes>::Ref, <T as PatternTypes>::Own>) -> bool) + Send + Sync;
diff --git a/src/parser.rs b/src/parser.rs
index 0a7d858..17c0529 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -5,6 +5,6 @@ use crate::errors::PatternError;
 use crate::vm::PatternConstants;
 //use crate::vm::PatternElement;
 
-pub(crate) fn parse<T: PatternTypes>(s: &str) -> Result<PatternConstants<T>, PatternError> {
+pub(crate) fn parse<T: PatternTypes>(s: &str, defs: Option<()>/*TODO*/) -> Result<PatternConstants<T>, PatternError> {
     unimplemented!()
 }
diff --git a/src/pattern.rs b/src/pattern.rs
index 0368a88..2b99163 100644
--- a/src/pattern.rs
+++ b/src/pattern.rs
@@ -1,4 +1,5 @@
 use crate::PatternTypes;
+use crate::RefOwn;
 use crate::errors::PatternError;
 use crate::parser::parse;
 use crate::vm::Matcher;
@@ -10,16 +11,16 @@ pub struct Pattern<T: PatternTypes> {
 }
 
 impl<T: PatternTypes> Pattern<T> {
-    pub fn compile(s: &str) -> Result<Self, PatternError> {
+    pub fn compile(s: &str, defs: Option<()>/*TODO*/) -> Result<Self, PatternError> {
         Ok(Self {
-            consts: parse(s)?
+            consts: parse(s, defs)?
         })
     }
 
     pub fn attempt_match<'a, 'b>(
         &'a self,
-        value: &'b T::Value
+        value: impl Into<RefOwn<'b, T::Ref, T::Own>>
     ) -> Matcher<'a, 'b, T> {
-        Matcher::new(value, &self.consts, self.consts.protos.len() - 1, MAX_CALLS).ok().expect("datafu internal error: MAX_CALLS must not be 0")
+        Matcher::new(value.into(), &self.consts, self.consts.protos.len() - 1, MAX_CALLS).ok().expect("datafu internal error: MAX_CALLS must not be 0")
     }
 }
diff --git a/src/vm.rs b/src/vm.rs
index 5b27a36..44675f3 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -1,4 +1,23 @@
+/*
+ * This file is part of Datafu
+ * Copyright (C) 2021  Soni L.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
 use crate::KVPair;
+use crate::RefOwn;
 use crate::PatternTypes;
 use crate::Predicate;
 use crate::errors::MatchError;
@@ -23,7 +42,7 @@ pub(crate) struct PatternConstants<T: PatternTypes> {
     // NOTE these are part of the constant pool and so have lifetime analogous
     // to 'a (consistently used to indicate constant pool lifetime) when used
     // elsewhere. In particular, they can't be yielded by the iterator.
-    pub(crate) defs: Vec<T::Value>,
+    pub(crate) defs: Vec<T::Own>,
 }
 
 /// A pattern element.
@@ -49,7 +68,7 @@ impl<T: PatternTypes> Clone for PatternElement<T> {
 }
 
 struct Frame<'a, 'b, T: PatternTypes> {
-    obj: &'b T::Value,
+    obj: RefOwn<'b, T::Ref, T::Own>,
     ops: &'a Vec<PatternElement<T>>,
     iar: Option<usize>,
     depth: usize,
@@ -97,7 +116,7 @@ enum HolderState<'a, 'b, T: PatternTypes> {
     EmptyKey,
     EmptySubtree,
     Key(KVPair<'b, T>),
-    Subtree(Matches<'a, 'b, T>, &'b T::Value),
+    Subtree(Matches<'a, 'b, T>, RefOwn<'b, T::Ref, T::Own>),
 }
 
 impl<'a, 'b, T: PatternTypes> Clone for HolderState<'a, 'b, T> {
@@ -120,8 +139,8 @@ impl<'a, 'b, T: PatternTypes> HolderState<'a, 'b, T> {
         matches!(self, HolderState::EmptySubtree | HolderState::Subtree {..})
     }
 
-    fn value(&self) -> Option<&'b T::Value> {
-        match self {
+    fn value(&self) -> Option<RefOwn<'b, T::Ref, T::Own>> {
+        match *self {
             HolderState::Key((_, value)) => Some(value),
             HolderState::Subtree(_, value) => Some(value),
             _ => None
@@ -136,7 +155,7 @@ impl<'a, 'b, T: PatternTypes> HolderState<'a, 'b, T> {
 struct Holder<'a, 'b, T: PatternTypes> {
      name: Option<&'a str>,
      value: HolderState<'a, 'b, T>,
-     parent: Option<&'b T::Value>,
+     parent: Option<RefOwn<'b, T::Ref, T::Own>>,
      iterator: Box<dyn Iterator<Item=KVPair<'b, T>> + 'b>,
      filters: Vec<Box<dyn for<'c> Fn(&'c mut HolderState<'a, 'b, T>) + 'a>>,
 }
@@ -176,7 +195,7 @@ pub struct Matcher<'a, 'b, T: PatternTypes> {
 }
 
 impl<'a, 'b, T: PatternTypes> Matcher<'a, 'b, T> {
-    pub(crate) fn new(obj: &'b T::Value, defs: &'a PatternConstants<T>, proto: usize, rlimit: usize) -> Result<Self, MatchError> {
+    pub(crate) fn new(obj: RefOwn<'b, T::Ref, T::Own>, defs: &'a PatternConstants<T>, proto: usize, rlimit: usize) -> Result<Self, MatchError> {
         let depth = rlimit.checked_sub(1).ok_or(MatchError::StackOverflow)?;
         let ops: &Vec<_> = &defs.protos[proto];
         Ok(Self {