Sun, 19 Jan 2025 22:33:21 +0100
doc updates
/*! 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 [`std::borrow::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 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<'_>; /// 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 } }