diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 46 | ||||
-rw-r--r-- | src/vm.rs | 9 |
2 files changed, 44 insertions, 11 deletions
diff --git a/src/lib.rs b/src/lib.rs index f41b4c6..08609ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,21 +5,49 @@ mod vm; pub use pattern::Pattern; +// TODO replace with GATs +/// The key returned from pairs and get. +pub enum Key<'b, T, U> { + /// Reference. + Ref(&'b T), + /// Borrowed string. + Str(&'b str), + /// Owned types. + Own(U), +} + +impl<'b, T, U: Copy> Copy for Key<'b, T, U> { +} + +impl<'b, T, U: Clone> Clone for Key<'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()), + } + } +} + +pub type KVPair<'b, T> = (Key<'b, <T as PatternTypes>::Value, <T as PatternTypes>::OwnKey>, &'b <T as PatternTypes>::Value); + // 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 owned key type. May be uninhabited. // TODO replace with GATs. - type Key; + // TODO potentially relax with Clone? + /// The owned key type. May be uninhabited. + type OwnKey: 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 - ) -> Option<Box<dyn Iterator<Item=(&'b Self::Value, &'b Self::Value)> + 'b>> { + ) -> Option<Box<dyn Iterator<Item=KVPair<'b, Self>> + 'b>> { // TODO remove these default impls that only exist for testing purposes let x = None; Some(Box::new(x.into_iter())) @@ -29,16 +57,20 @@ pub trait PatternTypes { /// this operation is unsupported for the given value. fn get<'a, 'b>( item: &'b Self::Value, - key: &'a str - ) -> Option<Option<(&'b Self::Value, &'b Self::Value)>> { + key: Key<'a, Self::Value, Self::OwnKey> + ) -> Option<Option<KVPair<'b, Self>>> { // TODO remove these default impls that only exist for testing purposes Some(None) } - /// Returns whether two values are the same/equivalent. This must provide + // TODO replace with GATs + newtypes + /// Returns whether two keys/values are the same/equivalent. This must provide /// 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: &Self::Value, right: &Self::Value) -> bool; + fn matches( + left: Key<'_, Self::Value, Self::OwnKey>, + right: Key<'_, Self::Value, Self::OwnKey> + ) -> bool; } // TODO diff --git a/src/vm.rs b/src/vm.rs index 595fac1..5b27a36 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,3 +1,4 @@ +use crate::KVPair; use crate::PatternTypes; use crate::Predicate; use crate::errors::MatchError; @@ -7,7 +8,7 @@ use std::marker::PhantomData; pub(crate) const MAX_CALLS: usize = 250; -type Matches<'a, 'b, T> = BTreeMap<&'a str, (&'b <T as PatternTypes>::Value, &'b <T as PatternTypes>::Value)>; +type Matches<'a, 'b, T> = BTreeMap<&'a str, KVPair<'b, T>>; // TODO: use a builder for this? /// The constant pool for a pattern. @@ -95,7 +96,7 @@ impl<'a, 'b, T: PatternTypes> Frame<'a, 'b, T> { enum HolderState<'a, 'b, T: PatternTypes> { EmptyKey, EmptySubtree, - Key((&'b T::Value, &'b T::Value)), + Key(KVPair<'b, T>), Subtree(Matches<'a, 'b, T>, &'b T::Value), } @@ -136,7 +137,7 @@ struct Holder<'a, 'b, T: PatternTypes> { name: Option<&'a str>, value: HolderState<'a, 'b, T>, parent: Option<&'b T::Value>, - iterator: Box<dyn Iterator<Item=(&'b T::Value, &'b T::Value)> + 'b>, + iterator: Box<dyn Iterator<Item=KVPair<'b, T>> + 'b>, filters: Vec<Box<dyn for<'c> Fn(&'c mut HolderState<'a, 'b, T>) + 'a>>, } @@ -262,7 +263,7 @@ impl<'a, 'b, T: PatternTypes> Matcher<'a, 'b, T> { } impl<'a, 'b, T: PatternTypes> Iterator for Matcher<'a, 'b, T> { - type Item = Result<BTreeMap<&'a str, (&'b T::Value, &'b T::Value)>, MatchError>; + type Item = Result<BTreeMap<&'a str, KVPair<'b, T>>, MatchError>; fn next(&mut self) -> Option<Self::Item> { while !self.frame.path.is_empty() { |