#![allow(missing_docs)] //! Traits and tags for identifying the dimension of all algebraic entities. use std::any::{Any, TypeId}; use std::cmp; use std::fmt::Debug; use std::ops::{Add, Div, Mul, Sub}; use typenum::{self, Diff, Max, Maximum, Min, Minimum, Prod, Quot, Sum, Unsigned}; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// Dim of dynamically-sized algebraic entities. #[derive(Clone, Copy, Eq, PartialEq, Debug)] pub struct Dynamic { value: usize, } impl Dynamic { /// A dynamic size equal to `value`. #[inline] pub fn new(value: usize) -> Self { Self { value } } } #[cfg(feature = "serde-serialize-no-std")] impl Serialize for Dynamic { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.value.serialize(serializer) } } #[cfg(feature = "serde-serialize-no-std")] impl<'de> Deserialize<'de> for Dynamic { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { usize::deserialize(deserializer).map(|x| Dynamic { value: x }) } } /// Trait implemented by `Dynamic`. pub trait IsDynamic {} /// Trait implemented by `Dynamic` and type-level integers different from `U1`. pub trait IsNotStaticOne {} impl IsDynamic for Dynamic {} impl IsNotStaticOne for Dynamic {} /// Trait implemented by any type that can be used as a dimension. This includes type-level /// integers and `Dynamic` (for dimensions not known at compile-time). pub trait Dim: Any + Debug + Copy + PartialEq + Send + Sync { #[inline(always)] fn is() -> bool { TypeId::of::() == TypeId::of::() } /// Gets the compile-time value of `Self`. Returns `None` if it is not known, i.e., if `Self = /// Dynamic`. fn try_to_usize() -> Option; /// Gets the run-time value of `self`. For type-level integers, this is the same as /// `Self::try_to_usize().unwrap()`. fn value(&self) -> usize; /// Builds an instance of `Self` from a run-time value. Panics if `Self` is a type-level /// integer and `dim != Self::try_to_usize().unwrap()`. fn from_usize(dim: usize) -> Self; } impl Dim for Dynamic { #[inline] fn try_to_usize() -> Option { None } #[inline] fn from_usize(dim: usize) -> Self { Self::new(dim) } #[inline] fn value(&self) -> usize { self.value } } impl Add for Dynamic { type Output = Dynamic; #[inline] fn add(self, rhs: usize) -> Self { Self::new(self.value + rhs) } } impl Sub for Dynamic { type Output = Dynamic; #[inline] fn sub(self, rhs: usize) -> Self { Self::new(self.value - rhs) } } /* * * Operations. * */ macro_rules! dim_ops( ($($DimOp: ident, $DimNameOp: ident, $Op: ident, $op: ident, $op_path: path, $DimResOp: ident, $DimNameResOp: ident, $ResOp: ident);* $(;)*) => {$( pub type $DimResOp = >::Output; pub trait $DimOp: Dim { type Output: Dim; fn $op(self, other: D) -> Self::Output; } impl $DimOp> for Const where Const: ToTypenum, Const: ToTypenum, as ToTypenum>::Typenum: $Op< as ToTypenum>::Typenum>, $ResOp< as ToTypenum>::Typenum, as ToTypenum>::Typenum>: ToConst, { type Output = <$ResOp< as ToTypenum>::Typenum, as ToTypenum>::Typenum> as ToConst>::Const; fn $op(self, _: Const) -> Self::Output { Self::Output::name() } } impl $DimOp for Dynamic { type Output = Dynamic; #[inline] fn $op(self, other: D) -> Dynamic { Dynamic::new($op_path(self.value, other.value())) } } // TODO: use Const instead of D: DimName? impl $DimOp for D { type Output = Dynamic; #[inline] fn $op(self, other: Dynamic) -> Dynamic { Dynamic::new($op_path(self.value(), other.value)) } } pub type $DimNameResOp = >::Output; pub trait $DimNameOp: DimName { type Output: DimName; fn $op(self, other: D) -> Self::Output; } impl $DimNameOp> for Const where Const: ToTypenum, Const: ToTypenum, as ToTypenum>::Typenum: $Op< as ToTypenum>::Typenum>, $ResOp< as ToTypenum>::Typenum, as ToTypenum>::Typenum>: ToConst, { type Output = <$ResOp< as ToTypenum>::Typenum, as ToTypenum>::Typenum> as ToConst>::Const; fn $op(self, _: Const) -> Self::Output { Self::Output::name() } } )*} ); dim_ops!( DimAdd, DimNameAdd, Add, add, Add::add, DimSum, DimNameSum, Sum; DimMul, DimNameMul, Mul, mul, Mul::mul, DimProd, DimNameProd, Prod; DimSub, DimNameSub, Sub, sub, Sub::sub, DimDiff, DimNameDiff, Diff; DimDiv, DimNameDiv, Div, div, Div::div, DimQuot, DimNameQuot, Quot; DimMin, DimNameMin, Min, min, cmp::min, DimMinimum, DimNameMinimum, Minimum; DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum; ); #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Const; /// Trait implemented exclusively by type-level integers. pub trait DimName: Dim { const USIZE: usize; /// The name of this dimension, i.e., the singleton `Self`. fn name() -> Self; // TODO: this is not a very idiomatic name. /// The value of this dimension. fn dim() -> usize; } pub trait ToConst { type Const: DimName; } pub trait ToTypenum { type Typenum: Unsigned; } impl Dim for Const { fn try_to_usize() -> Option { Some(T) } fn value(&self) -> usize { T } fn from_usize(dim: usize) -> Self { assert_eq!(dim, T); Self } } impl DimName for Const { const USIZE: usize = T; #[inline] fn name() -> Self { Self } #[inline] fn dim() -> usize { T } } pub type U1 = Const<1>; impl ToTypenum for Const<{ typenum::U1::USIZE }> { type Typenum = typenum::U1; } impl ToConst for typenum::U1 { type Const = Const<{ typenum::U1::USIZE }>; } macro_rules! from_to_typenum ( ($($D: ident),* $(,)*) => {$( pub type $D = Const<{ typenum::$D::USIZE }>; impl ToTypenum for Const<{ typenum::$D::USIZE }> { type Typenum = typenum::$D; } impl ToConst for typenum::$D { type Const = Const<{ typenum::$D::USIZE }>; } impl IsNotStaticOne for $D { } )*} ); from_to_typenum!( U0, /*U1,*/ U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19, U20, U21, U22, U23, U24, U25, U26, U27, U28, U29, U30, U31, U32, U33, U34, U35, U36, U37, U38, U39, U40, U41, U42, U43, U44, U45, U46, U47, U48, U49, U50, U51, U52, U53, U54, U55, U56, U57, U58, U59, U60, U61, U62, U63, U64, U65, U66, U67, U68, U69, U70, U71, U72, U73, U74, U75, U76, U77, U78, U79, U80, U81, U82, U83, U84, U85, U86, U87, U88, U89, U90, U91, U92, U93, U94, U95, U96, U97, U98, U99, U100, U101, U102, U103, U104, U105, U106, U107, U108, U109, U110, U111, U112, U113, U114, U115, U116, U117, U118, U119, U120, U121, U122, U123, U124, U125, U126, U127 );