1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
   Appellation: create <module>
   Contrib: FL03 <jo3mccain@icloud.com>
*/
use nd::{ArrayBase, DataOwned, Dimension, RawData, ShapeBuilder};
use num::traits::Num;

pub trait TensorConstructor<T, O = Self>
where
    Self: DefaultLike<Output = O>
        + FillLike<T, Output = O>
        + OnesLike<Output = O>
        + ZerosLike<Output = O>,
{
}

pub trait ArrayLike<A, S, D>
where
    D: Dimension,
    S: RawData<Elem = A>,
{
    fn array_like<Sh>(&self, shape: Sh, elem: A) -> ArrayBase<S, D>
    where
        Sh: ShapeBuilder<Dim = D>;
}

impl<A, S, D> ArrayLike<A, S, D> for ArrayBase<S, D>
where
    A: Clone,
    D: Dimension,
    S: nd::DataOwned<Elem = A>,
{
    fn array_like<Sh>(&self, shape: Sh, elem: A) -> ArrayBase<S, D>
    where
        Sh: ShapeBuilder<Dim = D>,
    {
        if self.is_standard_layout() {
            ArrayBase::from_elem(shape, elem)
        } else {
            ArrayBase::from_elem(shape.f(), elem)
        }
    }
}

pub trait DefaultLike {
    type Output;

    fn default_like(&self) -> Self::Output;
}

pub trait FillLike<T> {
    type Output;

    fn fill_like(&self, elem: T) -> Self::Output;
}

pub trait OnesLike {
    type Output;

    fn ones_like(&self) -> Self::Output;
}

pub trait ZerosLike {
    type Output;

    fn zeros_like(&self) -> Self::Output;
}

/*
 ******** implementations ********
*/

impl<A, S, D> TensorConstructor<A, ArrayBase<S, D>> for ArrayBase<S, D>
where
    A: Clone + Default + Num,
    D: Dimension,
    S: DataOwned<Elem = A>,
{
}

impl<A, S, D> FillLike<A> for ArrayBase<S, D>
where
    A: Clone,
    D: Dimension,
    S: DataOwned<Elem = A>,
{
    type Output = ArrayBase<S, D>;

    fn fill_like(&self, elem: A) -> Self::Output {
        ArrayBase::from_elem(self.dim(), elem)
    }
}

macro_rules! impl_like {
    ($name:ident::$method:ident.$call:ident: $($p:tt)*) => {
        impl_like!(@impl $name::$method.$call: $($p)*);
    };
    (@impl $name:ident::$method:ident.$call:ident: $($p:tt)*) => {
        impl<A, S, D> $name for ArrayBase<S, D>
        where
            A: $($p)*,
            D: Dimension,
            S: DataOwned<Elem = A>,
        {
            type Output = ArrayBase<S, D>;

            fn $method(&self) -> Self::Output {
                ArrayBase::$call(self.dim())
            }
        }
    };
}

impl_like!(DefaultLike::default_like.default: Default);
impl_like!(OnesLike::ones_like.ones: Clone + num::One);
impl_like!(ZerosLike::zeros_like.zeros: Clone + num::Zero);