1use super::axis::Axis;
2
3pub trait Axes: Axis {}
5
6#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct AxesTuple<T> {
11 axes: T,
12 shape: Vec<usize>,
13}
14
15impl<T> AxesTuple<T> {
16 pub fn as_tuple(&self) -> &T {
18 &self.axes
19 }
20}
21
22macro_rules! count_idents {
24 ($($idents:ident),* $(,)*) => {
25 {
26 #[allow(dead_code, non_camel_case_types)]
27 enum Idents { $($idents,)* __CountIdentsLast }
28 const COUNT: usize = Idents::__CountIdentsLast as usize;
29 COUNT
30 }
31 };
32}
33
34macro_rules! impl_axes {
35 () => {
36
37 };
38 ( $type_parameter:ident: $index:tt, ) => {
40
41 impl<X: Axis> Axes for AxesTuple<(X,)> {
42 }
43
44 impl<X:Axis> From<(X,)> for AxesTuple<(X,)> {
45 fn from(item: (X,)) -> Self {
46 let shape = vec![item.0.num_bins()];
47 Self { axes: item, shape }
48 }
49 }
50
51 impl<X: Axis> Axis for AxesTuple<(X,)> {
52 type Coordinate = X::Coordinate;
53 type BinInterval = X::BinInterval;
54
55 #[inline]
56 fn index(&self, coordinate: &Self::Coordinate) -> Option<usize> {
57 self.axes.0.index(coordinate)
58 }
59
60 fn num_bins(&self) -> usize {
61 self.axes.0.num_bins()
62 }
63
64 fn bin(&self, index: usize) -> Option<Self::BinInterval> {
65 self.axes.0.bin(index)
66 }
67
68 }
69
70 impl_axes!();
71 };
72 ( $($nth_type_parameter:ident: $nth_index:tt, )+ ) => {
74 impl<$($nth_type_parameter: Axis),*> Axes for AxesTuple<($($nth_type_parameter),*)> {
75 }
76
77 impl<$($nth_type_parameter: Axis),*> From<($($nth_type_parameter),*)> for AxesTuple<($($nth_type_parameter),*)> {
78 fn from(item: ($($nth_type_parameter),*)) -> Self {
79 let shape = [$(item.$nth_index.num_bins()),*].iter().scan(1, |acc, nbin| {*acc *= *nbin; Some(*acc)}).collect();
80 Self { axes: item, shape }
81 }
82 }
83
84 impl<$($nth_type_parameter: Axis),*> Axis for AxesTuple<($($nth_type_parameter),*)> {
85 type Coordinate = ($($nth_type_parameter::Coordinate),*);
86 type BinInterval = ($($nth_type_parameter::BinInterval),*);
87
88 #[inline]
89 fn index(&self, coordinate: &Self::Coordinate) -> Option<usize> {
90 let indices = [$(self.axes.$nth_index.index(&coordinate.$nth_index)?),*];
91
92 let index = self.shape.iter()
93 .rev()
94 .skip(1)
95 .zip(indices.iter().rev())
96 .fold(indices[0], |acc, (nbin, idx)| acc + nbin*idx);
97 Some(index)
98 }
99
100 fn num_bins(&self) -> usize {
101 $(self.axes.$nth_index.num_bins()*)* 1
103 }
104
105 fn num_dim(&self) -> usize {
106 count_idents!($($nth_type_parameter,)*)
107 }
108
109 fn bin(&self, index: usize) -> Option<Self::BinInterval> {
110 let num_bins = [$(self.axes.$nth_index.num_bins()),*];
111 let product = num_bins.iter().scan(1, |acc, it| Some(*acc * *it));
112 let mut index = index;
113 let index: Vec<_> = product.map(|nb| {
114 let v = index % nb;
115 index /= nb;
116 v
117 } ).collect();
118 Some(
119 (
120 $(self.axes.$nth_index.bin(index[$nth_index])?),*
121 )
122 )
123 }
124 }
125
126 impl_axes!(@REMOVELAST $([$nth_index AND $nth_type_parameter],)*);
127 };
128
129 (@REMOVELAST [$index:tt AND $type_parameter:ident], $( [$nth_index:tt AND $nth_type_parameter:ident], )+ ) => {
133 impl_axes!(@REMOVELAST [$index AND $type_parameter], @SEPARATOR $([$nth_index AND $nth_type_parameter],)*);
134 };
135 (@REMOVELAST $( [$first_index:tt AND $first_type_parameter:ident], )+ @SEPARATOR [$index1:tt AND $type_parameter1:ident], [$index2:tt AND $type_parameter2:ident], [$index3:tt AND $type_parameter3:ident], [$index4:tt AND $type_parameter4:ident], $( [$nth_index:tt AND $nth_type_parameter:ident], )+ ) => {
137 impl_axes!(@REMOVELAST $([$first_index AND $first_type_parameter],)* [$index1 AND $type_parameter1], [$index2 AND $type_parameter2], [$index3 AND $type_parameter3], [$index4 AND $type_parameter4], @SEPARATOR $([$nth_index AND $nth_type_parameter],)*);
138 };
139 (@REMOVELAST $( [$first_index:tt AND $first_type_parameter:ident], )+ @SEPARATOR [$index1:tt AND $type_parameter1:ident], [$index2:tt AND $type_parameter2:ident], $( [$nth_index:tt AND $nth_type_parameter:ident], )+ ) => {
141 impl_axes!(@REMOVELAST $([$first_index AND $first_type_parameter],)* [$index1 AND $type_parameter1], [$index2 AND $type_parameter2], @SEPARATOR $([$nth_index AND $nth_type_parameter],)*);
142 };
143 (@REMOVELAST $( [$first_index:tt AND $first_type_parameter:ident], )+ @SEPARATOR [$index:tt AND $type_parameter:ident], $( [$nth_index:tt AND $nth_type_parameter:ident], )+ ) => {
144 impl_axes!(@REMOVELAST $([$first_index AND $first_type_parameter],)* [$index AND $type_parameter], @SEPARATOR $([$nth_index AND $nth_type_parameter],)*);
145 };
146 (@REMOVELAST $( [$first_index:tt AND $first_type_parameter:ident], )+ @SEPARATOR [$index:tt AND $type_parameter:ident], ) => {
148 impl_axes!($($first_type_parameter: $first_index,)*);
150 };
151}
152
153impl_axes! {
154 X: 0,
155 Y: 1,
156 Z: 2,
157 T: 3,
158 D4: 4,
159 D5: 5,
160 D6: 6,
161 D7: 7,
162 D8: 8,
163 D9: 9,
164 D10: 10,
165 D11: 11,
166 D12: 12,
167 D13: 13,
168 D14: 14,
169 D15: 15,
170 D16: 16,
171 D17: 17,
172 D18: 18,
173 D19: 19,
174 D20: 20,
175}