diff -r 1a38447a89fa -r 9226980e45a7 src/instance.rs --- /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 { + Owned(A), + Borrowed(B), +} + +/// A very basic implementation of [`Cow`] without a [`Clone`] trait dependency. +pub type MyCow<'b, X> = EitherDecomp; + +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 { + /// Default decomposition for the space + type Decomp : Decomposition; +} + +#[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 : Sized { + /// Possibly owned form of the decomposition + type Decomposition<'b> : Instance 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 + 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`) that allows working with owned +/// values and all sorts of references. +#[derive(Copy, Clone, Debug)] +pub struct BasicDecomposition; + +impl Decomposition 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::Decomp> : Sized where D : Decomposition { + /// 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 Instance for X { + #[inline] + fn decompose<'b>(self) -> >::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) -> >::Reference<'_> { + self + } +} + +impl<'a, X : Space + Clone> Instance for &'a X { + #[inline] + fn decompose<'b>(self) -> >::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) -> >::Reference<'_> { + *self + } +} + +impl<'a, X : Space + Clone> Instance for &'a mut X { + #[inline] + fn decompose<'b>(self) -> >::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) -> >::Reference<'_> { + *self + } +} + +impl<'a, X : Space + Clone> Instance for MyCow<'a, X> { + + #[inline] + fn decompose<'b>(self) -> >::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) -> >::Reference<'_> { + match self { + MyCow::Borrowed(a) => a, + MyCow::Owned(b) => &b, + } + } +} + +/// Marker type for mutable decompositions to be used with [`InstanceMut`]. +pub trait DecompositionMut : Sized { + type ReferenceMut<'b> : InstanceMut where X : 'b; +} + + +/// Helper trait for functions to work with mutable references. +pub trait InstanceMut::Decomp> : Sized where D : DecompositionMut { + /// Returns a mutable decomposition of self. + fn ref_instance_mut(&mut self) -> D::ReferenceMut<'_>; +} + +impl DecompositionMut 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 for X { + #[inline] + fn ref_instance_mut(&mut self) + -> >::ReferenceMut<'_> + { + self + } +} + +impl<'a, X : Space> InstanceMut for &'a mut X { + #[inline] + fn ref_instance_mut(&mut self) + -> >::ReferenceMut<'_> + { + self + } +}