use crate::dimension::IntoDimension;
use crate::Dimension;
use crate::order::Order;
#[derive(Copy, Clone, Debug)]
pub struct Shape<D> {
pub(crate) dim: D,
pub(crate) strides: Strides<Contiguous>,
}
#[derive(Copy, Clone, Debug)]
pub(crate) enum Contiguous {}
impl<D> Shape<D> {
pub(crate) fn is_c(&self) -> bool {
matches!(self.strides, Strides::C)
}
}
#[derive(Copy, Clone, Debug)]
pub struct StrideShape<D> {
pub(crate) dim: D,
pub(crate) strides: Strides<D>,
}
impl<D> StrideShape<D>
where
D: Dimension,
{
pub fn raw_dim(&self) -> &D {
&self.dim
}
pub fn size(&self) -> usize {
self.dim.size()
}
}
#[derive(Copy, Clone, Debug)]
pub(crate) enum Strides<D> {
C,
F,
Custom(D),
}
impl<D> Strides<D> {
pub(crate) fn strides_for_dim(self, dim: &D) -> D
where
D: Dimension,
{
match self {
Strides::C => dim.default_strides(),
Strides::F => dim.fortran_strides(),
Strides::Custom(c) => {
debug_assert_eq!(
c.ndim(),
dim.ndim(),
"Custom strides given with {} dimensions, expected {}",
c.ndim(),
dim.ndim()
);
c
}
}
}
pub(crate) fn is_custom(&self) -> bool {
matches!(*self, Strides::Custom(_))
}
}
pub trait ShapeBuilder {
type Dim: Dimension;
type Strides;
fn into_shape(self) -> Shape<Self::Dim>;
fn f(self) -> Shape<Self::Dim>;
fn set_f(self, is_f: bool) -> Shape<Self::Dim>;
fn strides(self, strides: Self::Strides) -> StrideShape<Self::Dim>;
}
impl<D> From<D> for Shape<D>
where
D: Dimension,
{
fn from(dimension: D) -> Shape<D> {
dimension.into_shape()
}
}
impl<T, D> From<T> for StrideShape<D>
where
D: Dimension,
T: ShapeBuilder<Dim = D>,
{
fn from(value: T) -> Self {
let shape = value.into_shape();
let st = if shape.is_c() { Strides::C } else { Strides::F };
StrideShape {
strides: st,
dim: shape.dim,
}
}
}
impl<T> ShapeBuilder for T
where
T: IntoDimension,
{
type Dim = T::Dim;
type Strides = T;
fn into_shape(self) -> Shape<Self::Dim> {
Shape {
dim: self.into_dimension(),
strides: Strides::C,
}
}
fn f(self) -> Shape<Self::Dim> {
self.set_f(true)
}
fn set_f(self, is_f: bool) -> Shape<Self::Dim> {
self.into_shape().set_f(is_f)
}
fn strides(self, st: T) -> StrideShape<Self::Dim> {
self.into_shape().strides(st.into_dimension())
}
}
impl<D> ShapeBuilder for Shape<D>
where
D: Dimension,
{
type Dim = D;
type Strides = D;
fn into_shape(self) -> Shape<D> {
self
}
fn f(self) -> Self {
self.set_f(true)
}
fn set_f(mut self, is_f: bool) -> Self {
self.strides = if !is_f { Strides::C } else { Strides::F };
self
}
fn strides(self, st: D) -> StrideShape<D> {
StrideShape {
dim: self.dim,
strides: Strides::Custom(st),
}
}
}
impl<D> Shape<D>
where
D: Dimension,
{
pub fn raw_dim(&self) -> &D {
&self.dim
}
pub fn size(&self) -> usize {
self.dim.size()
}
}
pub trait ShapeArg {
type Dim: Dimension;
fn into_shape_and_order(self) -> (Self::Dim, Option<Order>);
}
impl<T> ShapeArg for T where T: IntoDimension {
type Dim = T::Dim;
fn into_shape_and_order(self) -> (Self::Dim, Option<Order>) {
(self.into_dimension(), None)
}
}
impl<T> ShapeArg for (T, Order) where T: IntoDimension {
type Dim = T::Dim;
fn into_shape_and_order(self) -> (Self::Dim, Option<Order>) {
(self.0.into_dimension(), Some(self.1))
}
}