nalgebra/src/base/dimension.rs

521 lines
12 KiB
Rust

#![allow(missing_docs)]
//! Traits and tags for identifying the dimension of all algebraic entities.
use std::fmt::Debug;
use std::any::{Any, TypeId};
use std::cmp;
use std::ops::{Add, Div, Mul, Sub};
use typenum::{self, B1, Bit, Diff, Max, Maximum, Min, Minimum, Prod, Quot, Sum, UInt, UTerm,
Unsigned};
#[cfg(feature = "serde-serialize")]
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) -> Dynamic {
Dynamic { value: value }
}
}
#[cfg(feature = "serde-serialize")]
impl Serialize for Dynamic {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.value.serialize(serializer)
}
}
#[cfg(feature = "serde-serialize")]
impl<'de> Deserialize<'de> for Dynamic {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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 {
#[inline(always)]
fn is<D: Dim>() -> bool {
TypeId::of::<Self>() == TypeId::of::<D>()
}
/// Gets the compile-time value of `Self`. Returns `None` if it is not known, i.e., if `Self =
/// Dynamic`.
fn try_to_usize() -> Option<usize>;
/// 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<usize> {
None
}
#[inline]
fn from_usize(dim: usize) -> Self {
Dynamic::new(dim)
}
#[inline]
fn value(&self) -> usize {
self.value
}
}
impl Add<usize> for Dynamic {
type Output = Dynamic;
#[inline]
fn add(self, rhs: usize) -> Dynamic {
Dynamic::new(self.value + rhs)
}
}
impl Sub<usize> for Dynamic {
type Output = Dynamic;
#[inline]
fn sub(self, rhs: usize) -> Dynamic {
Dynamic::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<D1, D2> = <D1 as $DimOp<D2>>::Output;
pub trait $DimOp<D: Dim>: Dim {
type Output: Dim;
fn $op(self, other: D) -> Self::Output;
}
impl<D1: DimName, D2: DimName> $DimOp<D2> for D1
where D1::Value: $Op<D2::Value>,
$ResOp<D1::Value, D2::Value>: NamedDim {
type Output = <$ResOp<D1::Value, D2::Value> as NamedDim>::Name;
#[inline]
fn $op(self, _: D2) -> Self::Output {
Self::Output::name()
}
}
impl<D: Dim> $DimOp<D> for Dynamic {
type Output = Dynamic;
#[inline]
fn $op(self, other: D) -> Dynamic {
Dynamic::new($op_path(self.value, other.value()))
}
}
impl<D: DimName> $DimOp<Dynamic> for D {
type Output = Dynamic;
#[inline]
fn $op(self, other: Dynamic) -> Dynamic {
Dynamic::new($op_path(self.value(), other.value))
}
}
pub type $DimNameResOp<D1, D2> = <D1 as $DimNameOp<D2>>::Output;
pub trait $DimNameOp<D: DimName>: DimName {
type Output: DimName;
fn $op(self, other: D) -> Self::Output;
}
impl<D1: DimName, D2: DimName> $DimNameOp<D2> for D1
where D1::Value: $Op<D2::Value>,
$ResOp<D1::Value, D2::Value>: NamedDim {
type Output = <$ResOp<D1::Value, D2::Value> as NamedDim>::Name;
#[inline]
fn $op(self, _: D2) -> 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, DimNameNimimum, Minimum;
DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum;
);
/// Trait implemented exclusively by type-level integers.
pub trait DimName: Dim {
type Value: NamedDim<Name = Self>;
/// The name of this dimension, i.e., the singleton `Self`.
#[inline]
fn name() -> Self;
// FIXME: this is not a very idiomatic name.
/// The value of this dimension.
#[inline]
fn dim() -> usize {
Self::Value::to_usize()
}
}
pub trait NamedDim: Sized + Any + Unsigned {
type Name: DimName<Value = Self>;
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct U1;
impl Dim for U1 {
#[inline]
fn try_to_usize() -> Option<usize> {
Some(1)
}
#[inline]
fn from_usize(dim: usize) -> Self {
assert!(dim == 1, "Mismatched dimension.");
U1
}
#[inline]
fn value(&self) -> usize {
1
}
}
impl DimName for U1 {
type Value = typenum::U1;
#[inline]
fn name() -> Self {
U1
}
}
impl NamedDim for typenum::U1 {
type Name = U1;
}
macro_rules! named_dimension(
($($D: ident),* $(,)*) => {$(
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct $D;
impl Dim for $D {
#[inline]
fn try_to_usize() -> Option<usize> {
Some(typenum::$D::to_usize())
}
#[inline]
fn from_usize(dim: usize) -> Self {
assert!(dim == typenum::$D::to_usize(), "Mismatched dimension.");
$D
}
#[inline]
fn value(&self) -> usize {
typenum::$D::to_usize()
}
}
impl DimName for $D {
type Value = typenum::$D;
#[inline]
fn name() -> Self {
$D
}
}
impl NamedDim for typenum::$D {
type Name = $D;
}
impl IsNotStaticOne for $D { }
)*}
);
// We give explicit names to all Unsigned in [0, 128[
named_dimension!(
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
);
// For values greater than U1023, just use the typenum binary representation directly.
impl<
A: Bit + Any + Debug + Copy + PartialEq + Send,
B: Bit + Any + Debug + Copy + PartialEq + Send,
C: Bit + Any + Debug + Copy + PartialEq + Send,
D: Bit + Any + Debug + Copy + PartialEq + Send,
E: Bit + Any + Debug + Copy + PartialEq + Send,
F: Bit + Any + Debug + Copy + PartialEq + Send,
G: Bit + Any + Debug + Copy + PartialEq + Send,
> NamedDim for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G> {
type Name = Self;
}
impl<
A: Bit + Any + Debug + Copy + PartialEq + Send,
B: Bit + Any + Debug + Copy + PartialEq + Send,
C: Bit + Any + Debug + Copy + PartialEq + Send,
D: Bit + Any + Debug + Copy + PartialEq + Send,
E: Bit + Any + Debug + Copy + PartialEq + Send,
F: Bit + Any + Debug + Copy + PartialEq + Send,
G: Bit + Any + Debug + Copy + PartialEq + Send,
> Dim for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G> {
#[inline]
fn try_to_usize() -> Option<usize> {
Some(Self::to_usize())
}
#[inline]
fn from_usize(dim: usize) -> Self {
assert!(dim == Self::to_usize(), "Mismatched dimension.");
Self::new()
}
#[inline]
fn value(&self) -> usize {
Self::to_usize()
}
}
impl<
A: Bit + Any + Debug + Copy + PartialEq + Send,
B: Bit + Any + Debug + Copy + PartialEq + Send,
C: Bit + Any + Debug + Copy + PartialEq + Send,
D: Bit + Any + Debug + Copy + PartialEq + Send,
E: Bit + Any + Debug + Copy + PartialEq + Send,
F: Bit + Any + Debug + Copy + PartialEq + Send,
G: Bit + Any + Debug + Copy + PartialEq + Send,
> DimName for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G> {
type Value = Self;
#[inline]
fn name() -> Self {
Self::new()
}
}
impl<
A: Bit + Any + Debug + Copy + PartialEq + Send,
B: Bit + Any + Debug + Copy + PartialEq + Send,
C: Bit + Any + Debug + Copy + PartialEq + Send,
D: Bit + Any + Debug + Copy + PartialEq + Send,
E: Bit + Any + Debug + Copy + PartialEq + Send,
F: Bit + Any + Debug + Copy + PartialEq + Send,
G: Bit + Any + Debug + Copy + PartialEq + Send,
> IsNotStaticOne
for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G> {
}
impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send> NamedDim
for UInt<U, B> {
type Name = UInt<U, B>;
}
impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send> Dim for UInt<U, B> {
#[inline]
fn try_to_usize() -> Option<usize> {
Some(Self::to_usize())
}
#[inline]
fn from_usize(dim: usize) -> Self {
assert!(dim == Self::to_usize(), "Mismatched dimension.");
Self::new()
}
#[inline]
fn value(&self) -> usize {
Self::to_usize()
}
}
impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send> DimName for UInt<U, B> {
type Value = UInt<U, B>;
#[inline]
fn name() -> Self {
Self::new()
}
}
impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send> IsNotStaticOne
for UInt<U, B> {
}