1 //! Compatibility constraints between matrix shapes, e.g., for addition or multiplication.
2 
3 use crate::base::dimension::{Dim, DimName, Dynamic};
4 
5 /// A type used in `where` clauses for enforcing constraints.
6 pub struct ShapeConstraint;
7 
8 /// Constraints `C1` and `R2` to be equivalent.
9 pub trait AreMultipliable<R1: Dim, C1: Dim, R2: Dim, C2: Dim>: DimEq<C1, R2> {}
10 
11 impl<R1: Dim, C1: Dim, R2: Dim, C2: Dim> AreMultipliable<R1, C1, R2, C2> for ShapeConstraint where ShapeConstraint: DimEq<C1, R2>
12 {}
13 
14 /// Constraints `D1` and `D2` to be equivalent.
15 pub trait DimEq<D1: Dim, D2: Dim> {
16     /// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level
17     /// constant.
18     type Representative: Dim;
19 }
20 
21 impl<D: Dim> DimEq<D, D> for ShapeConstraint {
22     type Representative = D;
23 }
24 
25 impl<D: DimName> DimEq<D, Dynamic> for ShapeConstraint {
26     type Representative = D;
27 }
28 
29 impl<D: DimName> DimEq<Dynamic, D> for ShapeConstraint {
30     type Representative = D;
31 }
32 
33 macro_rules! equality_trait_decl(
34     ($($doc: expr, $Trait: ident),* $(,)*) => {$(
35         // XXX: we can't do something like `DimEq<D1> for D2` because we would require a blancket impl…
36         #[doc = $doc]
37         pub trait $Trait<D1: Dim, D2: Dim>: DimEq<D1, D2> + DimEq<D2, D1> {
38             /// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level
39             /// constant.
40             type Representative: Dim;
41         }
42 
43         impl<D: Dim> $Trait<D, D> for ShapeConstraint {
44             type Representative = D;
45         }
46 
47         impl<D: DimName> $Trait<D, Dynamic> for ShapeConstraint {
48             type Representative = D;
49         }
50 
51         impl<D: DimName> $Trait<Dynamic, D> for ShapeConstraint {
52             type Representative = D;
53         }
54     )*}
55 );
56 
57 equality_trait_decl!(
58     "Constraints `D1` and `D2` to be equivalent. \
59      They are both assumed to be the number of \
60      rows of a matrix.",
61     SameNumberOfRows,
62     "Constraints `D1` and `D2` to be equivalent. \
63      They are both assumed to be the number of \
64      columns of a matrix.",
65     SameNumberOfColumns
66 );
67 
68 /// Constraints D1 and D2 to be equivalent, where they both designate dimensions of algebraic
69 /// entities (e.g. square matrices).
70 pub trait SameDimension<D1: Dim, D2: Dim>:
71     SameNumberOfRows<D1, D2> + SameNumberOfColumns<D1, D2>
72 {
73     /// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level
74     /// constant.
75     type Representative: Dim;
76 }
77 
78 impl<D: Dim> SameDimension<D, D> for ShapeConstraint {
79     type Representative = D;
80 }
81 
82 impl<D: DimName> SameDimension<D, Dynamic> for ShapeConstraint {
83     type Representative = D;
84 }
85 
86 impl<D: DimName> SameDimension<Dynamic, D> for ShapeConstraint {
87     type Representative = D;
88 }
89