src/instance.rs

branch
dev
changeset 59
9226980e45a7
child 75
e9f4550cfa18
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/instance.rs	Tue Dec 31 08:30:02 2024 -0500
@@ -0,0 +1,282 @@
+/*!
+Helper traits to work with references or owned values of types and their subsets.
+*/
+
+#[derive(Clone, Copy)]
+pub enum EitherDecomp<A, B> {
+    Owned(A),
+    Borrowed(B),
+}
+
+/// A very basic implementation of [`Cow`] without a [`Clone`] trait dependency.
+pub type MyCow<'b, X> = EitherDecomp<X, &'b X>;
+
+impl<'b, X> std::ops::Deref for MyCow<'b, X> {
+    type Target = X;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        match self {
+            EitherDecomp::Owned(x) => &x,
+            EitherDecomp::Borrowed(x) => x,
+        }
+    }
+}
+
+impl<'b, X> MyCow<'b, X> {
+    #[inline]
+    pub fn into_owned(self) -> X where X : Clone {
+        match self {
+            EitherDecomp::Owned(x) => x,
+            EitherDecomp::Borrowed(x) => x.clone(),
+        }
+    }
+}
+
+/// Trait for abitrary mathematical spaces.
+pub trait Space : Instance<Self, Self::Decomp> {
+    /// Default decomposition for the space
+    type Decomp : Decomposition<Self>;
+}
+
+#[macro_export]
+macro_rules! impl_basic_space {
+    ($($type:ty)*) => { $(
+        impl $crate::instance::Space for $type {
+            type Decomp = $crate::instance::BasicDecomposition;
+        }
+    )* };
+    ($type:ty where $($where:tt)*) => {
+        impl<$($where)*> $crate::instance::Space for $type {
+            type Decomp = $crate::instance::BasicDecomposition;
+        }
+    };
+}
+
+impl_basic_space!(u8 u16 u32 u64 u128 usize
+                  i8 i16 i32 i64 i128 isize
+                  f32 f64);
+
+/// Marker type for decompositions to be used with [`Instance`].
+pub trait Decomposition<X : Space> : Sized {
+    /// Possibly owned form of the decomposition
+    type Decomposition<'b> : Instance<X, Self> where X : 'b;
+    /// Unlikely owned form of the decomposition.
+    /// Type for a lightweight intermediate conversion that does not own the original variable.
+    /// Usually this is just a reference, but may also be a lightweight structure that
+    /// contains references; see the implementation for [`crate::direct_product::Pair`].
+    type Reference<'b> : Instance<X, Self> + Copy where X : 'b;
+
+    /// Left the lightweight reference type into a full decomposition type.
+    fn lift<'b>(r : Self::Reference<'b>) -> Self::Decomposition<'b>;
+}
+
+/// Most common [`Decomposition`] (into `Either<X, &'b X>`) that allows working with owned
+/// values and all sorts of references.
+#[derive(Copy, Clone, Debug)]
+pub struct BasicDecomposition;
+
+impl<X : Space + Clone> Decomposition<X> for BasicDecomposition {
+    type Decomposition<'b> = MyCow<'b, X> where X : 'b;
+    type Reference<'b> = &'b X where X : 'b;
+
+    #[inline]
+    fn lift<'b>(r : Self::Reference<'b>) -> Self::Decomposition<'b> {
+        MyCow::Borrowed(r)
+    }
+}
+
+/// Helper trait for functions to work with either owned values or references to either the
+/// “principal type” `X` or types some present a subset of `X`. In the latter sense, this
+/// generalises [`std::borrow::ToOwned`], [`std::borrow::Borrow`], and [`std::borrow::Cow`].
+/// This type also includes iteratation facilities when `X` is a [`Collection`], to avoid
+/// the possibly costly conversion of such subset types into `X`.
+pub trait Instance<X : Space, D = <X as Space>::Decomp> : Sized where D : Decomposition<X> {
+    /// Decomposes self according to `decomposer`.
+    fn decompose<'b>(self) -> D::Decomposition<'b>
+    where Self : 'b, X : 'b;
+  
+    /// Returns a lightweight instance of `self`.
+    fn ref_instance(&self) -> D::Reference<'_>;
+
+    /// Returns an owned instance of `X`, cloning or converting non-true instances when necessary.
+    fn own(self) -> X;
+
+    // ************** automatically implemented methods below from here **************
+
+    /// Returns an owned instance or reference to `X`, converting non-true instances when necessary.
+    ///
+    /// Default implementation uses [`Self::own`]. Consumes the input.
+    fn cow<'b>(self) -> MyCow<'b, X> where Self : 'b {
+        MyCow::Owned(self.own())
+    }
+    
+    #[inline]
+    /// Evaluates `f` on a reference to self.
+    ///
+    /// Default implementation uses [`Self::cow`]. Consumes the input.
+    fn eval<'b, R>(self, f : impl FnOnce(&X) -> R) -> R
+    where X : 'b, Self : 'b
+    {
+        f(&*self.cow())
+    }
+
+    #[inline]
+    /// Evaluates `f` or `g` depending on whether a reference or owned value is available.
+    ///
+    /// Default implementation uses [`Self::cow`]. Consumes the input.
+    fn either<'b, R>(
+        self,
+        f : impl FnOnce(X) -> R,
+        g : impl FnOnce(&X) -> R
+    ) -> R
+    where Self : 'b
+    {
+        match self.cow() {
+            EitherDecomp::Owned(x) => f(x),
+            EitherDecomp::Borrowed(x) => g(x),
+        }
+    }
+}
+
+
+impl<X : Space + Clone> Instance<X, BasicDecomposition> for X {
+    #[inline]
+    fn decompose<'b>(self) -> <BasicDecomposition as Decomposition<X>>::Decomposition<'b>
+    where Self : 'b, X : 'b
+    {
+        MyCow::Owned(self)
+    }
+
+    #[inline]
+    fn own(self) -> X {
+        self
+    }
+
+    #[inline]
+    fn cow<'b>(self) -> MyCow<'b, X> where Self : 'b {
+        MyCow::Owned(self)
+    }
+
+    #[inline]
+    fn ref_instance(&self) -> <BasicDecomposition as Decomposition<X>>::Reference<'_> {
+        self
+    }
+}
+
+impl<'a, X : Space + Clone> Instance<X, BasicDecomposition> for &'a X {
+    #[inline]
+    fn decompose<'b>(self) -> <BasicDecomposition as Decomposition<X>>::Decomposition<'b>
+    where Self : 'b, X : 'b
+    {
+        MyCow::Borrowed(self)
+    }
+
+    #[inline]
+    fn own(self) -> X {
+        self.clone()
+    }
+
+    #[inline]
+    fn cow<'b>(self) -> MyCow<'b, X> where Self : 'b {
+        MyCow::Borrowed(self)
+    }
+
+    #[inline]
+    fn ref_instance(&self) -> <BasicDecomposition as Decomposition<X>>::Reference<'_> {
+        *self
+    }
+}
+
+impl<'a, X : Space + Clone> Instance<X, BasicDecomposition> for &'a mut X {
+    #[inline]
+    fn  decompose<'b>(self) -> <BasicDecomposition as Decomposition<X>>::Decomposition<'b>
+    where Self : 'b, X : 'b
+    {
+        EitherDecomp::Borrowed(self)
+    }
+
+    #[inline]
+    fn own(self) -> X {
+        self.clone()
+    }
+
+    #[inline]
+    fn cow<'b>(self) -> MyCow<'b, X> where Self : 'b, X : Clone {
+        EitherDecomp::Borrowed(self)
+    }
+
+    #[inline]
+    fn ref_instance(&self) -> <BasicDecomposition as Decomposition<X>>::Reference<'_> {
+        *self
+    }
+}
+
+impl<'a, X : Space + Clone> Instance<X, BasicDecomposition> for MyCow<'a, X> {
+
+    #[inline]
+    fn  decompose<'b>(self) -> <BasicDecomposition as Decomposition<X>>::Decomposition<'b>
+    where Self : 'b, X : 'b
+    {
+        self
+    }
+
+    #[inline]
+    fn own(self) -> X {
+        match self {
+            MyCow::Borrowed(a) => a.own(),
+            MyCow::Owned(b) => b.own()
+        }
+    }
+
+    #[inline]
+    fn cow<'b>(self) -> MyCow<'b, X> where Self : 'b {
+        match self {
+            MyCow::Borrowed(a) => a.cow(),
+            MyCow::Owned(b) => b.cow()
+        }
+    }
+
+    #[inline]
+    fn ref_instance(&self) -> <BasicDecomposition as Decomposition<X>>::Reference<'_> {
+        match self {
+            MyCow::Borrowed(a) => a,
+            MyCow::Owned(b) => &b,
+        }
+    }
+}
+
+/// Marker type for mutable decompositions to be used with [`InstanceMut`].
+pub trait DecompositionMut<X : Space> : Sized {
+    type ReferenceMut<'b> : InstanceMut<X, Self> where X : 'b;
+}
+
+
+/// Helper trait for functions to work with mutable references.
+pub trait InstanceMut<X : Space , D = <X as Space>::Decomp> : Sized where D : DecompositionMut<X> {
+    /// Returns a mutable decomposition of self.
+    fn ref_instance_mut(&mut self) -> D::ReferenceMut<'_>;
+}
+
+impl<X : Space> DecompositionMut<X> for BasicDecomposition {
+    type ReferenceMut<'b> = &'b mut X where X : 'b;
+}
+
+/// This impl may seem pointless, but allows throwaway mutable scratch variables
+impl<'a, X : Space> InstanceMut<X, BasicDecomposition> for X {
+    #[inline]
+    fn ref_instance_mut(&mut self)
+        -> <BasicDecomposition as DecompositionMut<X>>::ReferenceMut<'_>
+    {
+        self
+    }
+}
+
+impl<'a, X : Space> InstanceMut<X, BasicDecomposition> for &'a mut X {
+    #[inline]
+    fn ref_instance_mut(&mut self)
+        -> <BasicDecomposition as DecompositionMut<X>>::ReferenceMut<'_>
+    {
+        self
+    }
+}

mercurial