src/instance.rs

changeset 198
3868555d135c
parent 173
102421d462d1
--- a/src/instance.rs	Sun Apr 27 20:29:43 2025 -0500
+++ b/src/instance.rs	Fri May 15 14:46:30 2026 -0500
@@ -23,32 +23,252 @@
     }
 }
 
-impl<'b, X> MyCow<'b, X> {
+/// Trait for ownable-by-consumption objects
+pub trait Ownable {
+    type OwnedVariant: Clone;
+
+    /// Returns an owned instance, possibly consuming the original,
+    /// avoiding cloning when possible.
+    fn into_owned(self) -> Self::OwnedVariant;
+
+    /// Returns an owned instance of a reference.
+    fn clone_owned(&self) -> Self::OwnedVariant;
+
+    /// Returns an owned instance or a reference to one.
+    fn cow_owned<'b>(self) -> MyCow<'b, Self::OwnedVariant>
+    where
+        Self: 'b;
+
+    /// Returns an owned instance or a reference to one.
+    fn ref_cow_owned<'b>(&'b self) -> MyCow<'b, Self::OwnedVariant>
+    where
+        Self: 'b;
+}
+
+impl<'a, X: Ownable> Ownable for &'a X {
+    type OwnedVariant = X::OwnedVariant;
+
+    #[inline]
+    fn into_owned(self) -> Self::OwnedVariant {
+        X::clone_owned(self)
+    }
+
+    #[inline]
+    fn clone_owned(&self) -> Self::OwnedVariant {
+        X::clone_owned(self)
+    }
+
     #[inline]
-    pub fn into_owned(self) -> X where X : Clone {
+    fn cow_owned<'b>(self) -> MyCow<'b, Self::OwnedVariant>
+    where
+        Self: 'b,
+    {
+        X::ref_cow_owned(self)
+    }
+
+    fn ref_cow_owned<'b>(&self) -> MyCow<'b, Self::OwnedVariant>
+    where
+        Self: 'b,
+    {
+        X::ref_cow_owned(self)
+    }
+}
+
+impl<'a, X: Ownable> Ownable for &'a mut X {
+    type OwnedVariant = X::OwnedVariant;
+
+    #[inline]
+    fn into_owned(self) -> Self::OwnedVariant {
+        X::clone_owned(self)
+    }
+
+    #[inline]
+    fn clone_owned(&self) -> Self::OwnedVariant {
+        X::clone_owned(self)
+    }
+
+    #[inline]
+    fn cow_owned<'b>(self) -> MyCow<'b, Self::OwnedVariant>
+    where
+        Self: 'b,
+    {
+        X::ref_cow_owned(self)
+    }
+
+    fn ref_cow_owned<'b>(&'b self) -> MyCow<'b, Self::OwnedVariant>
+    where
+        Self: 'b,
+    {
+        X::ref_cow_owned(self)
+    }
+}
+
+impl<'a, A, B> Ownable for EitherDecomp<A, B>
+where
+    A: Ownable,
+    B: Ownable<OwnedVariant = A::OwnedVariant>,
+{
+    type OwnedVariant = A::OwnedVariant;
+
+    #[inline]
+    fn into_owned(self) -> Self::OwnedVariant {
         match self {
-            EitherDecomp::Owned(x) => x,
-            EitherDecomp::Borrowed(x) => x.clone(),
+            EitherDecomp::Owned(a) => A::into_owned(a),
+            EitherDecomp::Borrowed(b) => B::into_owned(b),
+        }
+    }
+
+    #[inline]
+    fn clone_owned(&self) -> Self::OwnedVariant {
+        match self {
+            EitherDecomp::Owned(a) => A::clone_owned(a),
+            EitherDecomp::Borrowed(b) => B::clone_owned(b),
+        }
+    }
+
+    #[inline]
+    fn cow_owned<'b>(self) -> MyCow<'b, Self::OwnedVariant>
+    where
+        A: 'b,
+        B: 'b,
+    {
+        match self {
+            EitherDecomp::Owned(a) => A::cow_owned(a),
+            EitherDecomp::Borrowed(b) => B::cow_owned(b),
+        }
+    }
+
+    #[inline]
+    fn ref_cow_owned<'b>(&'b self) -> MyCow<'b, Self::OwnedVariant>
+    where
+        Self: 'b,
+    {
+        match self {
+            EitherDecomp::Owned(a) => A::ref_cow_owned(a),
+            EitherDecomp::Borrowed(b) => B::ref_cow_owned(b),
         }
     }
 }
 
+#[macro_export]
+macro_rules! self_ownable {
+    ($type:ty where $($qual:tt)*) => {
+        impl<$($qual)*> $crate::instance::Ownable for $type {
+            type OwnedVariant = Self;
+
+            #[inline]
+            fn into_owned(self) -> Self::OwnedVariant {
+                self
+            }
+
+            fn clone_owned(&self) -> Self::OwnedVariant {
+                self.clone()
+            }
+
+            fn cow_owned<'b>(self) -> $crate::instance::MyCow<'b, Self::OwnedVariant>
+            where
+                Self: 'b,
+            {
+                $crate::instance::MyCow::Owned(self)
+            }
+
+            fn ref_cow_owned<'b>(&'b self) -> $crate::instance::MyCow<'b, Self::OwnedVariant>
+            where
+                Self: 'b,
+            {
+                $crate::instance::MyCow::Borrowed(self)
+            }
+        }
+    };
+}
+
+self_ownable!(Vec<T> where T : Clone);
+
+impl<'a, T: Clone> Ownable for &'a [T] {
+    type OwnedVariant = Vec<T>;
+
+    #[inline]
+    fn into_owned(self) -> Self::OwnedVariant {
+        Vec::from(self)
+    }
+
+    #[inline]
+    fn clone_owned(&self) -> Self::OwnedVariant {
+        Vec::from(*self)
+    }
+
+    #[inline]
+    fn cow_owned<'b>(self) -> MyCow<'b, Self::OwnedVariant>
+    where
+        Self: 'b,
+    {
+        MyCow::Owned(Vec::from(self))
+    }
+
+    fn ref_cow_owned<'b>(&'b self) -> MyCow<'b, Self::OwnedVariant>
+    where
+        Self: 'b,
+    {
+        MyCow::Owned(Vec::from(*self))
+    }
+}
+
 /// Trait for abitrary mathematical spaces.
-pub trait Space : Instance<Self, Self::Decomp> {
+pub trait Space: Ownable<OwnedVariant = Self::Principal> + Sized {
+    /// Principal, typically owned realisation of the space.
+    type Principal: ClosedSpace;
+
     /// Default decomposition for the space
-    type Decomp : Decomposition<Self>;
+    type Decomp: Decomposition<Self>;
+}
+
+mod private {
+    pub trait Sealed {}
 }
 
+/// Helper trait for working with own types.
+pub trait Owned: Ownable<OwnedVariant = Self> + private::Sealed {}
+impl<X: Ownable<OwnedVariant = X>> private::Sealed for X {}
+impl<X: Ownable<OwnedVariant = X>> Owned for X {}
+
+/// Helper trait for working with closed spaces, operations in which should
+/// return members of the same space
+pub trait ClosedSpace: Space<Principal = Self> + Owned + Instance<Self> {}
+impl<X: Space<Principal = Self> + Owned + Instance<Self>> ClosedSpace for X {}
+
 #[macro_export]
 macro_rules! impl_basic_space {
-    ($($type:ty)*) => { $(
-        impl $crate::instance::Space for $type {
+    ($($type:ty)*) => {
+        $( $crate::impl_basic_space!($type where ); )*
+    };
+    ($type:ty where $($where:tt)*) => {
+        impl<$($where)*> $crate::instance::Space for $type {
+            type Principal = Self;
             type Decomp = $crate::instance::BasicDecomposition;
         }
-    )* };
-    ($type:ty where $($where:tt)*) => {
-        impl<$($where)*> $crate::instance::Space for $type {
-            type Decomp = $crate::instance::BasicDecomposition;
+
+        impl<$($where)*> $crate::instance::Ownable for $type {
+            type OwnedVariant = Self;
+
+            #[inline]
+            fn into_owned(self) -> Self::OwnedVariant {
+                self
+            }
+
+            #[inline]
+            fn clone_owned(&self) -> Self::OwnedVariant {
+                *self
+            }
+
+            #[inline]
+            fn cow_owned<'b>(self) -> MyCow<'b, Self::OwnedVariant> where Self : 'b {
+                MyCow::Owned(self)
+            }
+
+            #[inline]
+            fn ref_cow_owned<'b>(&self) -> MyCow<'b, Self::OwnedVariant> where Self : 'b {
+                MyCow::Owned(*self)
+            }
         }
     };
 }
@@ -58,17 +278,21 @@
                   f32 f64);
 
 /// Marker type for decompositions to be used with [`Instance`].
-pub trait Decomposition<X : Space> : Sized {
+pub trait Decomposition<X: Space>: Sized {
     /// Possibly owned form of the decomposition
-    type Decomposition<'b> : Instance<X, Self> where X : 'b;
+    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;
+    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>;
+    /// Lift 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
@@ -76,12 +300,18 @@
 #[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;
+impl<X: Space> 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> {
+    fn lift<'b>(r: Self::Reference<'b>) -> Self::Decomposition<'b> {
         MyCow::Borrowed(r)
     }
 }
@@ -91,192 +321,225 @@
 /// generalises [`std::borrow::ToOwned`], [`std::borrow::Borrow`], and [`std::borrow::Cow`].
 ///
 /// This is used, for example, by [`crate::mapping::Mapping::apply`].
-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<'_>;
+pub trait Instance<X, D = <X as Space>::Decomp>: Sized
+where
+    X: Space,
+    D: Decomposition<X>,
+{
+    /// Decomposes self according to `decomposer`, and evaluate `f` on the result.
+    /// Consumes self.
+    #[inline]
+    fn eval_decompose<'b, R>(self, f: impl FnOnce(D::Decomposition<'b>) -> R) -> R
+    where
+        X: 'b,
+        Self: 'b,
+    {
+        f(self.decompose())
+    }
+
+    /// Does a light decomposition of self `decomposer`, and evaluates `f` on the result.
+    /// Does not consume self.
+    fn eval_ref<'b, R>(&'b self, f: impl FnOnce(D::Reference<'b>) -> R) -> R
+    where
+        X: 'b,
+        Self: 'b;
 
     /// Returns an owned instance of `X`, cloning or converting non-true instances when necessary.
-    fn own(self) -> X;
+    fn own(self) -> X::Principal;
 
-    // ************** automatically implemented methods below from here **************
+    fn decompose<'b>(self) -> D::Decomposition<'b>
+    where
+        Self: 'b;
 
     /// 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())
-    }
-    
+    fn cow<'b>(self) -> MyCow<'b, X::Principal>
+    where
+        Self: 'b;
+
     #[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
+    fn eval<'b, R>(self, f: impl FnOnce(&X::Principal) -> 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 {
+impl<X: Space> Instance<X, BasicDecomposition> for X {
     #[inline]
-    fn decompose<'b>(self) -> <BasicDecomposition as Decomposition<X>>::Decomposition<'b>
-    where Self : 'b, X : 'b
+    fn eval_ref<'b, R>(&'b self, f: impl FnOnce(&'b X) -> R) -> R
+    where
+        X: 'b,
+        Self: 'b,
     {
-        MyCow::Owned(self)
+        f(self)
     }
 
     #[inline]
-    fn own(self) -> X {
-        self
+    fn own(self) -> X::Principal {
+        self.into_owned()
+    }
+
+    #[inline]
+    fn cow<'b>(self) -> MyCow<'b, X::Principal>
+    where
+        Self: 'b,
+    {
+        self.cow_owned()
     }
 
     #[inline]
-    fn cow<'b>(self) -> MyCow<'b, X> where Self : 'b {
+    fn decompose<'b>(self) -> MyCow<'b, X>
+    where
+        Self: 'b,
+    {
         MyCow::Owned(self)
     }
+}
+
+impl<'a, X: Space> Instance<X, BasicDecomposition> for &'a X {
+    #[inline]
+    fn eval_ref<'b, R>(&'b self, f: impl FnOnce(&'b X) -> R) -> R
+    where
+        X: 'b,
+        Self: 'b,
+    {
+        f(*self)
+    }
 
     #[inline]
-    fn ref_instance(&self) -> <BasicDecomposition as Decomposition<X>>::Reference<'_> {
-        self
+    fn own(self) -> X::Principal {
+        self.into_owned()
     }
-}
 
-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
+    fn cow<'b>(self) -> MyCow<'b, X::Principal>
+    where
+        Self: 'b,
+    {
+        self.cow_owned()
+    }
+
+    #[inline]
+    fn decompose<'b>(self) -> MyCow<'b, X>
+    where
+        Self: 'b,
     {
         MyCow::Borrowed(self)
     }
+}
 
+impl<'a, X: Space> Instance<X, BasicDecomposition> for &'a mut X {
     #[inline]
-    fn own(self) -> X {
-        self.clone()
-    }
-
-    #[inline]
-    fn cow<'b>(self) -> MyCow<'b, X> where Self : 'b {
-        MyCow::Borrowed(self)
+    fn eval_ref<'b, R>(&'b self, f: impl FnOnce(&'b X) -> R) -> R
+    where
+        X: 'b,
+        Self: 'b,
+    {
+        f(*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)
+    fn own(self) -> X::Principal {
+        self.into_owned()
     }
 
     #[inline]
-    fn own(self) -> X {
-        self.clone()
+    fn cow<'b>(self) -> MyCow<'b, X::Principal>
+    where
+        Self: 'b,
+    {
+        self.cow_owned()
     }
 
     #[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
+    fn decompose<'b>(self) -> MyCow<'b, X>
+    where
+        Self: 'b,
+    {
+        MyCow::Borrowed(self)
     }
 }
 
-impl<'a, X : Space + Clone> Instance<X, BasicDecomposition> for MyCow<'a, X> {
-
+impl<'a, X: Space> Instance<X, BasicDecomposition> for MyCow<'a, X> {
     #[inline]
-    fn  decompose<'b>(self) -> <BasicDecomposition as Decomposition<X>>::Decomposition<'b>
-    where Self : 'b, X : 'b
+    fn eval_ref<'b, R>(&'b self, f: impl FnOnce(&'b X) -> R) -> R
+    where
+        X: 'b,
+        Self: 'b,
     {
-        self
-    }
-
-    #[inline]
-    fn own(self) -> X {
         match self {
-            MyCow::Borrowed(a) => a.own(),
-            MyCow::Owned(b) => b.own()
+            MyCow::Borrowed(a) => f(a),
+            MyCow::Owned(b) => f(&b),
         }
     }
 
     #[inline]
-    fn cow<'b>(self) -> MyCow<'b, X> where Self : 'b {
-        match self {
-            MyCow::Borrowed(a) => a.cow(),
-            MyCow::Owned(b) => b.cow()
-        }
+    fn own(self) -> X::Principal {
+        self.into_owned()
     }
 
     #[inline]
-    fn ref_instance(&self) -> <BasicDecomposition as Decomposition<X>>::Reference<'_> {
-        match self {
-            MyCow::Borrowed(a) => a,
-            MyCow::Owned(b) => &b,
-        }
+    fn cow<'b>(self) -> MyCow<'b, X::Principal>
+    where
+        Self: 'b,
+    {
+        self.cow_owned()
     }
-}
-
-/// 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<'_>
+    fn decompose<'b>(self) -> MyCow<'b, X>
+    where
+        Self: 'b,
     {
         self
     }
 }
 
-impl<'a, X : Space> InstanceMut<X, BasicDecomposition> for &'a mut X {
+/// 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<'_>
-    {
+    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