diff --git a/lhlist/src/lib.rs b/lhlist/src/lib.rs index b0f3134..7720048 100644 --- a/lhlist/src/lib.rs +++ b/lhlist/src/lib.rs @@ -107,4 +107,7 @@ pub use relation::{Bool, False, LabelEq, Member, ToBool, True}; mod lookup; pub use lookup::LookupElemByLabel; +mod ordered_set; +pub use ordered_set::{OrderedHSet, Union}; + pub mod iter; diff --git a/lhlist/src/ordered_set.rs b/lhlist/src/ordered_set.rs new file mode 100644 index 0000000..5e80a96 --- /dev/null +++ b/lhlist/src/ordered_set.rs @@ -0,0 +1,121 @@ +use crate::Label; +use crate::{Cons, False, Member, Nil}; + +/// Nil corresponds to an empty set. +impl OrderedHSet for Nil {} + +/// A labeled heterogeneous list is an `OrderedHSet` if: +/// - the head `H` is labeled; +/// - the tail `T` is a set; +/// - `T` does not contain any element with same **label** of `H`. +impl OrderedHSet for Cons +where + H: Label, + T: OrderedHSet + Member, +{} + +/// An `OrderedHSet` is a labeled heterogeneous list that does not contain +/// elements with the same label. +pub trait OrderedHSet { + /// It creates a new set by prepending `h` to `self`. + /// + /// If there is another element in `self` with the same + /// label as `h`, it fails at compile-time. + fn prepend(self, h: H) -> Cons + where + H: Label, + Self: Member + Sized, + { + Cons { + head: h, + tail: self, + } + } +} + +/// The union operation for [OrderedHSet](trait.OrderedHSet.html)s. +/// +/// It is not commutative: the order of the elements in the final +/// depends on the order of the operands. +pub trait Union { + /// The result type of the union operation. + type Output: OrderedHSet; + + /// It returns the union of two [OrderedHSet](trait.OrderedHSet.html)s. + /// + /// The elements of `Self` are added at the beginning of the resulting + /// [OrderedHSet](trait.OrderedHSet.html). + fn union(self, rhs: Rhs) -> Self::Output + where + Self: OrderedHSet; +} + +impl Union for Nil +where + Rhs: OrderedHSet +{ + type Output = Rhs; + + fn union(self, rhs: Rhs) -> Self::Output { + rhs + } +} + +impl Union for Cons +where + H: Label, + T: OrderedHSet + Union, + Rhs: OrderedHSet, + Cons>::Output>: OrderedHSet, +{ + type Output = Cons>::Output>; + + fn union(self, rhs: Rhs) -> Self::Output { + Cons { + head: self.head, + tail: self.tail.union(rhs), + } + } +} + +#[cfg(test)] +mod tests { + use crate::ordered_set::{OrderedHSet, Union}; + use crate::*; + + #[test] + fn create_ordered_set() { + #[label(type=String, crate=crate)] + struct ProductName; + + #[label(type=u8, crate=crate)] + struct ProductId; + + #[label(type=u8, crate=crate)] + struct ShelfId; + + #[label(type=String, crate=crate)] + struct ShelfName; + + #[label(type=String, crate=crate)] + struct StoreName; + + #[label(type=f64, crate=crate)] + struct Price; + + let name = LabeledValue::::new("Shampoo".to_string()); + let product_id = LabeledValue::::new(10); + let shelf_id = LabeledValue::::new(10); + let shelf_name = LabeledValue::::new("Home".to_string()); + let store_name = LabeledValue::::new("X".to_string()); + let price = LabeledValue::::new(12.0); + let ordered_set = Nil + .prepend(name) + .prepend(product_id) + .prepend(shelf_id); + let singleton = Nil.prepend(shelf_name); + let another_set = Nil.prepend(store_name).prepend(price); + + ordered_set.union(singleton).union(another_set); + } +}