mech_core/
lib.rs

1#![feature(get_mut_unchecked)]
2#![feature(concat_idents)]
3#![allow(warnings)]
4#![feature(iter_intersperse)]
5#![feature(extract_if)]
6#![cfg_attr(feature = "no-std", no_std)]
7#![cfg_attr(feature = "no-std", alloc)]
8#![allow(dead_code)]
9#![feature(step_trait)]
10
11#[cfg(feature="no-std")] #[macro_use] extern crate alloc;
12#[cfg(not(feature = "no-std"))] extern crate core;
13#[macro_use]
14extern crate lazy_static;
15extern crate nalgebra as na;
16extern crate tabled;
17extern crate libm;
18
19#[cfg(feature = "no-std")]
20extern crate alloc;
21extern crate core as rust_core;
22extern crate hashbrown;
23#[macro_use]
24extern crate serde_derive;
25extern crate serde;
26extern crate num_traits;
27extern crate ed25519_dalek;
28extern crate rand;
29extern crate getrandom;
30
31extern crate seahash;
32extern crate indexmap;
33use std::rc::Rc;
34use std::cell::RefCell;
35use std::fmt;
36use num_traits::*;
37use std::ops::*;
38use std::mem;
39
40pub mod value;
41pub mod matrix;
42pub mod types;
43pub mod functions;
44pub mod kind;
45pub mod error;
46pub mod nodes;
47
48pub use self::value::*;
49pub use self::matrix::*;
50pub use self::types::*;
51pub use self::functions::*;
52pub use self::kind::*;
53pub use self::error::*;
54pub use self::nodes::*;
55
56pub fn hash_chars(input: &Vec<char>) -> u64 {
57  seahash::hash(input.iter().map(|s| String::from(*s)).collect::<String>().as_bytes()) & 0x00FFFFFFFFFFFFFF
58}
59
60pub fn hash_bytes(input: &Vec<u8>) -> u64 {
61  seahash::hash(input) & 0x00FFFFFFFFFFFFFF
62}
63
64pub fn hash_str(input: &str) -> u64 {
65  seahash::hash(input.to_string().as_bytes()) & 0x00FFFFFFFFFFFFFF
66}
67
68pub fn humanize(hash: &u64) -> String {
69  let bytes: [u8; 8] = hash.to_be_bytes();
70  let mut string = "".to_string();
71  let mut ix = 0;
72  for byte in bytes.iter() {
73    if ix % 2 == 0 {
74      ix += 1;
75      continue;
76    }
77    string.push_str(&WORDLIST[*byte as usize]);
78    if ix < 7 {
79      string.push_str("-");
80    }
81    ix += 1;
82  }
83  string
84}
85
86#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
87pub enum MechSourceCode {
88  String(String),
89  Tree(Program),
90}
91
92pub const WORDLIST: &[&str;256] = &[
93  "nil", "ama", "ine", "ska", "pha", "gel", "art", 
94  "ona", "sas", "ist", "aus", "pen", "ust", "umn",
95  "ado", "con", "loo", "man", "eer", "lin", "ium",
96  "ack", "som", "lue", "ird", "avo", "dog", "ger",
97  "ter", "nia", "bon", "nal", "ina", "pet", "cat",
98  "ing", "lie", "ken", "fee", "ola", "old", "rad",
99  "met", "cut", "azy", "cup", "ota", "dec", "del",
100  "elt", "iet", "don", "ble", "ear", "rth", "eas", 
101  "war", "eig", "tee", "ele", "emm", "ene", "qua",
102  "tst", "fan", "fif", "fil", "fin", "fis", "fiv", 
103  "flo", "for", "foo", "fou", "fot", "fox", "fre",
104  "fri", "fru", "gee", "gia", "glu", "fol", "gre", 
105  "ham", "hap", "har", "haw", "hel", "hig", "hot", 
106  "hyd", "ida", "ill", "ind", "ini", "ink", "iwa",
107  "and", "ite", "jer", "jig", "joh", "jul", "uly", 
108  "kan", "ket", "kil", "kin", "kit", "lac", "lak", 
109  "lem", "ard", "lim", "lio", "lit", "lon", "lou",
110  "low", "mag", "nes", "mai", "gam", "arc", "mar",
111  "mao", "mas", "may", "mex", "mic", "mik", "ril",
112  "min", "mir", "mis", "mio", "mob", "moc", "ech",
113  "moe", "tan", "oon", "ain", "mup", "sic", "neb",
114  "une", "net", "nev", "nin", "een", "nit", "nor",
115  "nov", "nut", "oct", "ohi", "okl", "one", "ora",
116  "ges", "ore", "osc", "ove", "oxy", "pap", "par", 
117  "pey", "pip", "piz", "plu", "pot", "pri", "pur",
118  "que", "uqi", "qui", "red", "riv", "rob", "roi", 
119  "rug", "sad", "sal", "sat", "sep", "sev", "eve",
120  "sha", "sie", "sin", "sik", "six", "sit", "sky", 
121  "soc", "sod", "sol", "sot", "tir", "ker", "spr",
122  "sta", "ste", "mam", "mer", "swe", "tab", "tag", 
123  "see", "nis", "tex", "thi", "the", "tim", "tri",
124  "twe", "ent", "two", "unc", "ess", "uni", "ura", 
125  "veg", "ven", "ver", "vic", "vid", "vio", "vir",
126  "was", "est", "whi", "hit", "iam", "win", "his",
127  "wis", "olf", "wyo", "ray", "ank", "yel", "zeb",
128  "ulu", "fix", "gry", "hol", "jup", "lam", "pas",
129  "rom", "sne", "ten", "uta"];
130
131// ============================================================================
132// The Standard Library!
133// ============================================================================
134
135#[macro_export]
136macro_rules! impl_binop {
137  ($struct_name:ident, $arg1_type:ty, $arg2_type:ty, $out_type:ty, $op:ident) => {
138      #[derive(Debug)]
139      struct $struct_name<T> {
140      lhs: Ref<$arg1_type>,
141      rhs: Ref<$arg2_type>,
142      out: Ref<$out_type>,
143      }
144      impl<T> MechFunction for $struct_name<T>
145      where
146      T: Copy + Debug + Clone + Sync + Send + 'static + 
147      PartialEq + PartialOrd +
148      Add<Output = T> + AddAssign +
149      Sub<Output = T> + SubAssign +
150      Mul<Output = T> + MulAssign +
151      Div<Output = T> + DivAssign +
152      Zero + One,
153      Ref<$out_type>: ToValue
154      {
155      fn solve(&self) {
156          let lhs_ptr = self.lhs.as_ptr();
157          let rhs_ptr = self.rhs.as_ptr();
158          let out_ptr = self.out.as_ptr();
159          $op!(lhs_ptr,rhs_ptr,out_ptr);
160      }
161      fn out(&self) -> Value { self.out.to_value() }
162      fn to_string(&self) -> String { format!("{:#?}", self) }
163      }};}
164
165#[macro_export]
166macro_rules! impl_bool_binop {
167  ($struct_name:ident, $arg1_type:ty, $arg2_type:ty, $out_type:ty, $op:ident) => {
168    #[derive(Debug)]
169    struct $struct_name<T> {
170      lhs: Ref<$arg1_type>,
171      rhs: Ref<$arg2_type>,
172      out: Ref<$out_type>,
173    }
174    impl<T> MechFunction for $struct_name<T>
175    where
176      T: Copy + Debug + Clone + Sync + Send + 'static + 
177      PartialEq + PartialOrd,
178      Ref<$out_type>: ToValue
179    {
180      fn solve(&self) {
181        let lhs_ptr = self.lhs.as_ptr();
182        let rhs_ptr = self.rhs.as_ptr();
183        let out_ptr = self.out.as_ptr();
184        $op!(lhs_ptr,rhs_ptr,out_ptr);
185      }
186      fn out(&self) -> Value { self.out.to_value() }
187      fn to_string(&self) -> String { format!("{:#?}", self) }
188    }};}
189
190#[macro_export]  
191macro_rules! impl_bool_urop {
192  ($struct_name:ident, $arg_type:ty, $out_type:ty, $op:ident) => {
193    #[derive(Debug)]
194    struct $struct_name<T> {
195      arg: Ref<$arg_type>,
196      out: Ref<$out_type>,
197    }
198    impl<T> MechFunction for $struct_name<T>
199    where
200      T: Copy + Debug + Clone + Sync + Send + 'static + 
201      PartialEq + PartialOrd,
202      Ref<$out_type>: ToValue
203    {
204      fn solve(&self) {
205        let arg_ptr = self.arg.as_ptr();
206        let out_ptr = self.out.as_ptr();
207        $op!(arg_ptr,out_ptr);
208      }
209      fn out(&self) -> Value { self.out.to_value() }
210      fn to_string(&self) -> String { format!("{:#?}", self) }
211    }};}
212
213#[macro_export]  
214macro_rules! impl_urop {
215  ($struct_name:ident, $arg_type:ty, $out_type:ty, $op:ident) => {
216    #[derive(Debug)]
217    struct $struct_name {
218      arg: Ref<$arg_type>,
219      out: Ref<$out_type>,
220    }
221    impl MechFunction for $struct_name {
222      fn solve(&self) {
223        let arg_ptr = self.arg.as_ptr();
224        let out_ptr = self.out.as_ptr();
225        $op!(arg_ptr,out_ptr);
226      }
227      fn out(&self) -> Value { self.out.to_value() }
228      fn to_string(&self) -> String { format!("{:#?}", self) }
229    }};}  
230
231#[macro_export]
232macro_rules! impl_fxns {
233  ($lib:ident, $in:ident, $out:ident, $op:ident) => {
234    paste!{
235      // Scalar
236      $op!([<$lib SS>], $in, $in, $out, [<$lib:lower _op>]);
237      // Scalar Matrix
238      #[cfg(feature = "Matrix1")]
239      $op!([<$lib SM1>], $in, Matrix1<$in>, Matrix1<$out>,[<$lib:lower _scalar_rhs_op>]);
240      #[cfg(feature = "Matrix2")]
241      $op!([<$lib SM2>], $in, Matrix2<$in>, Matrix2<$out>,[<$lib:lower _scalar_rhs_op>]);
242      #[cfg(feature = "Matrix3")]
243      $op!([<$lib SM3>], $in, Matrix3<$in>, Matrix3<$out>,[<$lib:lower _scalar_rhs_op>]);
244      #[cfg(feature = "Matrix4")]
245      $op!([<$lib SM4>], $in, Matrix4<$in>, Matrix4<$out>,[<$lib:lower _scalar_rhs_op>]);
246      #[cfg(feature = "Matrix2x3")]
247      $op!([<$lib SM2x3>], $in, Matrix2x3<$in>, Matrix2x3<$out>,[<$lib:lower _scalar_rhs_op>]);
248      #[cfg(feature = "Matrix3x2")]
249      $op!([<$lib SM3x2>], $in, Matrix3x2<$in>, Matrix3x2<$out>,[<$lib:lower _scalar_rhs_op>]);
250      #[cfg(feature = "MatrixD")]
251      $op!([<$lib SMD>], $in, DMatrix<$in>, DMatrix<$out>,[<$lib:lower _scalar_rhs_op>]);
252      // Scalar Row
253      #[cfg(feature = "RowVector2")]
254      $op!([<$lib SR2>], $in, RowVector2<$in>, RowVector2<$out>,[<$lib:lower _scalar_rhs_op>]);
255      #[cfg(feature = "RowVector3")]
256      $op!([<$lib SR3>], $in, RowVector3<$in>, RowVector3<$out>,[<$lib:lower _scalar_rhs_op>]);
257      #[cfg(feature = "RowVector4")]
258      $op!([<$lib SR4>], $in, RowVector4<$in>, RowVector4<$out>,[<$lib:lower _scalar_rhs_op>]);
259      #[cfg(feature = "RowVectorD")]
260      $op!([<$lib SRD>], $in, RowDVector<$in>, RowDVector<$out>,[<$lib:lower _scalar_rhs_op>]);
261      // Scalar Vector
262      #[cfg(feature = "Vector2")]
263      $op!([<$lib SV2>], $in, Vector2<$in>, Vector2<$out>,[<$lib:lower _scalar_rhs_op>]);
264      #[cfg(feature = "Vector3")]
265      $op!([<$lib SV3>], $in, Vector3<$in>, Vector3<$out>,[<$lib:lower _scalar_rhs_op>]);
266      #[cfg(feature = "Vector4")]
267      $op!([<$lib SV4>], $in, Vector4<$in>, Vector4<$out>,[<$lib:lower _scalar_rhs_op>]);
268      #[cfg(feature = "VectorD")]
269      $op!([<$lib SVD>], $in, DVector<$in>, DVector<$out>,[<$lib:lower _scalar_rhs_op>]);
270      // Matrix Scalar
271      #[cfg(feature = "Matrix1")]
272      $op!([<$lib M1S>], Matrix1<$in>, $in, Matrix1<$out>,[<$lib:lower _scalar_lhs_op>]);
273      #[cfg(feature = "Matrix2")]
274      $op!([<$lib M2S>], Matrix2<$in>, $in, Matrix2<$out>,[<$lib:lower _scalar_lhs_op>]);
275      #[cfg(feature = "Matrix3")]
276      $op!([<$lib M3S>], Matrix3<$in>, $in, Matrix3<$out>,[<$lib:lower _scalar_lhs_op>]);
277      #[cfg(feature = "Matrix4")]
278      $op!([<$lib M4S>], Matrix4<$in>, $in, Matrix4<$out>,[<$lib:lower _scalar_lhs_op>]);
279      #[cfg(feature = "Matrix2x3")]
280      $op!([<$lib M2x3S>], Matrix2x3<$in>, $in, Matrix2x3<$out>,[<$lib:lower _scalar_lhs_op>]);
281      #[cfg(feature = "Matrix3x2")]
282      $op!([<$lib M3x2S>], Matrix3x2<$in>, $in, Matrix3x2<$out>,[<$lib:lower _scalar_lhs_op>]);
283      #[cfg(feature = "MatrixD")]
284      $op!([<$lib MDS>], DMatrix<$in>, $in, DMatrix<$out>,[<$lib:lower _scalar_lhs_op>]);
285      // Row Scalar
286      #[cfg(feature = "RowVector2")]
287      $op!([<$lib R2S>], RowVector2<$in>, $in, RowVector2<$out>,[<$lib:lower _scalar_lhs_op>]);
288      #[cfg(feature = "RowVector3")]
289      $op!([<$lib R3S>], RowVector3<$in>, $in, RowVector3<$out>,[<$lib:lower _scalar_lhs_op>]);
290      #[cfg(feature = "RowVector4")]
291      $op!([<$lib R4S>], RowVector4<$in>, $in, RowVector4<$out>,[<$lib:lower _scalar_lhs_op>]);
292      #[cfg(feature = "RowVectorD")]
293      $op!([<$lib RDS>], RowDVector<$in>, $in, RowDVector<$out>,[<$lib:lower _scalar_lhs_op>]);
294      // Vector Scalar
295      #[cfg(feature = "Vector2")]
296      $op!([<$lib V2S>], Vector2<$in>, $in, Vector2<$out>,[<$lib:lower _scalar_lhs_op>]);
297      #[cfg(feature = "Vector3")]
298      $op!([<$lib V3S>], Vector3<$in>, $in, Vector3<$out>,[<$lib:lower _scalar_lhs_op>]);
299      #[cfg(feature = "Vector4")]
300      $op!([<$lib V4S>], Vector4<$in>, $in, Vector4<$out>,[<$lib:lower _scalar_lhs_op>]);
301      #[cfg(feature = "VectorD")]
302      $op!([<$lib VDS>], DVector<$in>, $in, DVector<$out>,[<$lib:lower _scalar_lhs_op>]);
303      // Matrix Matrix
304      #[cfg(feature = "Matrix1")]
305      $op!([<$lib M1M1>], Matrix1<$in>, Matrix1<$in>, Matrix1<$out>, [<$lib:lower _vec_op>]);
306      #[cfg(feature = "Matrix2")]
307      $op!([<$lib M2M2>], Matrix2<$in>, Matrix2<$in>, Matrix2<$out>, [<$lib:lower _vec_op>]);
308      #[cfg(feature = "Matrix3")]
309      $op!([<$lib M3M3>], Matrix3<$in>, Matrix3<$in>, Matrix3<$out>, [<$lib:lower _vec_op>]);
310      #[cfg(feature = "Matrix4")]
311      $op!([<$lib M4M4>], Matrix4<$in>, Matrix4<$in>, Matrix4<$out>, [<$lib:lower _vec_op>]);
312      #[cfg(feature = "Matrix2x3")]
313      $op!([<$lib M2x3M2x3>], Matrix2x3<$in>, Matrix2x3<$in>, Matrix2x3<$out>, [<$lib:lower _vec_op>]);
314      #[cfg(feature = "Matrix3x2")]
315      $op!([<$lib M3x2M3x2>], Matrix3x2<$in>, Matrix3x2<$in>, Matrix3x2<$out>, [<$lib:lower _vec_op>]);
316      #[cfg(feature = "MatrixD")]
317      $op!([<$lib MDMD>], DMatrix<$in>, DMatrix<$in>, DMatrix<$out>, [<$lib:lower _vec_op>]);
318      // Matrix Vector
319      #[cfg(feature = "Matrix2")]
320      $op!([<$lib M2V2>], Matrix2<$in>, Vector2<$in>, Matrix2<$out>, [<$lib:lower _mat_vec_op>]);
321      #[cfg(feature = "Matrix3")]
322      $op!([<$lib M3V3>], Matrix3<$in>, Vector3<$in>, Matrix3<$out>, [<$lib:lower _mat_vec_op>]);
323      #[cfg(feature = "Matrix4")]
324      $op!([<$lib M4V4>], Matrix4<$in>, Vector4<$in>, Matrix4<$out>, [<$lib:lower _mat_vec_op>]);
325      #[cfg(feature = "Matrix2x3")]
326      $op!([<$lib M2x3V2>], Matrix2x3<$in>, Vector2<$in>, Matrix2x3<$out>, [<$lib:lower _mat_vec_op>]);
327      #[cfg(feature = "Matrix3x2")]
328      $op!([<$lib M3x2V3>], Matrix3x2<$in>, Vector3<$in>, Matrix3x2<$out>, [<$lib:lower _mat_vec_op>]);
329      #[cfg(feature = "MatrixD")]
330      $op!([<$lib MDVD>], DMatrix<$in>, DVector<$in>, DMatrix<$out>, [<$lib:lower _mat_vec_op>]);
331      #[cfg(feature = "MatrixD")]
332      $op!([<$lib MDV2>], DMatrix<$in>, Vector2<$in>, DMatrix<$out>, [<$lib:lower _mat_vec_op>]);
333      #[cfg(feature = "MatrixD")]
334      $op!([<$lib MDV3>], DMatrix<$in>, Vector3<$in>, DMatrix<$out>, [<$lib:lower _mat_vec_op>]);
335      #[cfg(feature = "MatrixD")]
336      $op!([<$lib MDV4>], DMatrix<$in>, Vector4<$in>, DMatrix<$out>, [<$lib:lower _mat_vec_op>]);
337      // Vector Matrix
338      #[cfg(feature = "Vector2")]
339      $op!([<$lib V2M2>], Vector2<$in>, Matrix2<$in>, Matrix2<$out>, [<$lib:lower _vec_mat_op>]);
340      #[cfg(feature = "Vector3")]
341      $op!([<$lib V3M3>], Vector3<$in>, Matrix3<$in>, Matrix3<$out>, [<$lib:lower _vec_mat_op>]);
342      #[cfg(feature = "Vector4")]
343      $op!([<$lib V4M4>], Vector4<$in>, Matrix4<$in>, Matrix4<$out>, [<$lib:lower _vec_mat_op>]);
344      #[cfg(feature = "Vector2")]
345      $op!([<$lib V2M2x3>], Vector2<$in>, Matrix2x3<$in>, Matrix2x3<$out>, [<$lib:lower _vec_mat_op>]);
346      #[cfg(feature = "Vector3")]
347      $op!([<$lib V3M3x2>], Vector3<$in>, Matrix3x2<$in>, Matrix3x2<$out>, [<$lib:lower _vec_mat_op>]);
348      #[cfg(feature = "VectorD")]
349      $op!([<$lib VDMD>], DVector<$in>, DMatrix<$in>, DMatrix<$out>, [<$lib:lower _vec_mat_op>]);
350      #[cfg(feature = "Vector2")]
351      $op!([<$lib V2MD>], Vector2<$in>, DMatrix<$in>, DMatrix<$out>, [<$lib:lower _vec_mat_op>]);
352      #[cfg(feature = "Vector3")]
353      $op!([<$lib V3MD>], Vector3<$in>, DMatrix<$in>, DMatrix<$out>, [<$lib:lower _vec_mat_op>]);
354      #[cfg(feature = "Vector4")]
355      $op!([<$lib V4MD>], Vector4<$in>, DMatrix<$in>, DMatrix<$out>, [<$lib:lower _vec_mat_op>]);
356      // Matrix Row
357      #[cfg(feature = "Matrix2")]
358      $op!([<$lib M2R2>], Matrix2<$in>, RowVector2<$in>, Matrix2<$out>, [<$lib:lower _mat_row_op>]); 
359      #[cfg(feature = "Matrix3")]
360      $op!([<$lib M3R3>], Matrix3<$in>, RowVector3<$in>, Matrix3<$out>, [<$lib:lower _mat_row_op>]);
361      #[cfg(feature = "Matrix4")]
362      $op!([<$lib M4R4>], Matrix4<$in>, RowVector4<$in>, Matrix4<$out>, [<$lib:lower _mat_row_op>]);
363      #[cfg(feature = "Matrix2x3")]
364      $op!([<$lib M2x3R3>], Matrix2x3<$in>, RowVector3<$in>, Matrix2x3<$out>, [<$lib:lower _mat_row_op>]);
365      #[cfg(feature = "Matrix3x2")]
366      $op!([<$lib M3x2R2>], Matrix3x2<$in>, RowVector2<$in>, Matrix3x2<$out>, [<$lib:lower _mat_row_op>]);
367      #[cfg(feature = "MatrixD")]
368      $op!([<$lib MDRD>], DMatrix<$in>, RowDVector<$in>, DMatrix<$out>, [<$lib:lower _mat_row_op>]);
369      #[cfg(feature = "MatrixD")]
370      $op!([<$lib MDR2>], DMatrix<$in>, RowVector2<$in>, DMatrix<$out>, [<$lib:lower _mat_row_op>]);
371      #[cfg(feature = "MatrixD")]
372      $op!([<$lib MDR3>], DMatrix<$in>, RowVector3<$in>, DMatrix<$out>, [<$lib:lower _mat_row_op>]);
373      #[cfg(feature = "MatrixD")]
374      $op!([<$lib MDR4>], DMatrix<$in>, RowVector4<$in>, DMatrix<$out>, [<$lib:lower _mat_row_op>]); 
375      // Row Matrix
376      #[cfg(feature = "RowVector2")]
377      $op!([<$lib R2M2>], RowVector2<$in>, Matrix2<$in>, Matrix2<$out>, [<$lib:lower _row_mat_op>]); 
378      #[cfg(feature = "RowVector3")]
379      $op!([<$lib R3M3>], RowVector3<$in>, Matrix3<$in>, Matrix3<$out>, [<$lib:lower _row_mat_op>]);
380      #[cfg(feature = "RowVector4")]
381      $op!([<$lib R4M4>], RowVector4<$in>, Matrix4<$in>, Matrix4<$out>, [<$lib:lower _row_mat_op>]);
382      #[cfg(feature = "RowVector3")]
383      $op!([<$lib R3M2x3>], RowVector3<$in>, Matrix2x3<$in>, Matrix2x3<$out>, [<$lib:lower _row_mat_op>]);
384      #[cfg(feature = "RowVector2")]
385      $op!([<$lib R2M3x2>], RowVector2<$in>, Matrix3x2<$in>, Matrix3x2<$out>, [<$lib:lower _row_mat_op>]);
386      #[cfg(feature = "RowVectorD")]
387      $op!([<$lib RDMD>], RowDVector<$in>, DMatrix<$in>, DMatrix<$out>, [<$lib:lower _row_mat_op>]);
388      #[cfg(feature = "RowVector2")]
389      $op!([<$lib R2MD>], RowVector2<$in>, DMatrix<$in>, DMatrix<$out>, [<$lib:lower _row_mat_op>]);
390      #[cfg(feature = "RowVector3")]
391      $op!([<$lib R3MD>], RowVector3<$in>, DMatrix<$in>, DMatrix<$out>, [<$lib:lower _row_mat_op>]);
392      #[cfg(feature = "RowVector4")]
393      $op!([<$lib R4MD>], RowVector4<$in>, DMatrix<$in>, DMatrix<$out>, [<$lib:lower _row_mat_op>]);
394      // Row Row
395      #[cfg(feature = "RowVector2")]
396      $op!([<$lib R2R2>], RowVector2<$in>, RowVector2<$in>, RowVector2<$out>, [<$lib:lower _vec_op>]);
397      #[cfg(feature = "RowVector3")]
398      $op!([<$lib R3R3>], RowVector3<$in>, RowVector3<$in>, RowVector3<$out>, [<$lib:lower _vec_op>]);
399      #[cfg(feature = "RowVector4")]
400      $op!([<$lib R4R4>], RowVector4<$in>, RowVector4<$in>, RowVector4<$out>, [<$lib:lower _vec_op>]);
401      #[cfg(feature = "RowVectorD")]
402      $op!([<$lib RDRD>], RowDVector<$in>, RowDVector<$in>, RowDVector<$out>, [<$lib:lower _vec_op>]);
403      // Vector Vector
404      #[cfg(feature = "Vector2")]
405      $op!([<$lib V2V2>], Vector2<$in>, Vector2<$in>, Vector2<$out>, [<$lib:lower _vec_op>]);
406      #[cfg(feature = "Vector3")]
407      $op!([<$lib V3V3>], Vector3<$in>, Vector3<$in>, Vector3<$out>, [<$lib:lower _vec_op>]);
408      #[cfg(feature = "Vector4")]
409      $op!([<$lib V4V4>], Vector4<$in>, Vector4<$in>, Vector4<$out>, [<$lib:lower _vec_op>]);
410      #[cfg(feature = "VectorD")]
411      $op!([<$lib VDVD>], DVector<$in>, DVector<$in>, DVector<$out>, [<$lib:lower _vec_op>]);
412    }
413  }}
414
415#[macro_export]
416macro_rules! impl_binop_match_arms {
417  ($lib:ident, $arg:expr, $($lhs_type:ident, $rhs_type:ident => $($matrix_kind:ident, $target_type:ident, $default:expr, $value_string:tt),+);+ $(;)?) => {
418    paste!{
419      match $arg {
420        $(
421          $(
422            // Scalar Scalar
423            (Value::$lhs_type(lhs), Value::$rhs_type(rhs)) => Ok(Box::new([<$lib SS>]{lhs: lhs.clone(), rhs: rhs.clone(), out: new_ref($default) })),
424            // Scalar Matrix
425            #[cfg(all(feature = $value_string, feature = "Matrix1"))]
426            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::Matrix1(rhs))) => Ok(Box::new([<$lib SM1>]{lhs, rhs, out: new_ref(Matrix1::from_element($default))})),
427            #[cfg(all(feature = $value_string, feature = "Matrix2"))]
428            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::Matrix2(rhs))) => Ok(Box::new([<$lib SM2>]{lhs, rhs, out: new_ref(Matrix2::from_element($default))})),
429            #[cfg(all(feature = $value_string, feature = "Matrix3"))]
430            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::Matrix3(rhs))) => Ok(Box::new([<$lib SM3>]{lhs, rhs, out: new_ref(Matrix3::from_element($default))})),
431            #[cfg(all(feature = $value_string, feature = "Matrix4"))]
432            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::Matrix4(rhs))) => Ok(Box::new([<$lib SM4>]{lhs, rhs, out: new_ref(Matrix4::from_element($default))})),
433            #[cfg(all(feature = $value_string, feature = "Matrix2x3"))]
434            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::Matrix2x3(rhs))) => Ok(Box::new([<$lib SM2x3>]{lhs, rhs, out: new_ref(Matrix2x3::from_element($default))})),
435            #[cfg(all(feature = $value_string, feature = "Matrix3x2"))]
436            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::Matrix3x2(rhs))) => Ok(Box::new([<$lib SM3x2>]{lhs, rhs, out: new_ref(Matrix3x2::from_element($default))})),
437            #[cfg(all(feature = $value_string, feature = "MatrixD"))]
438            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::DMatrix(rhs))) => {
439              let (rows,cols) = {rhs.borrow().shape()};
440              Ok(Box::new([<$lib SMD>]{lhs, rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))}))},   
441            // Scalar Row
442            #[cfg(all(feature = $value_string, feature = "RowVector2"))]
443            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::RowVector2(rhs))) => Ok(Box::new([<$lib SR2>]{lhs, rhs, out: new_ref(RowVector2::from_element($default))})),
444            #[cfg(all(feature = $value_string, feature = "RowVector3"))]
445            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::RowVector3(rhs))) => Ok(Box::new([<$lib SR3>]{lhs, rhs, out: new_ref(RowVector3::from_element($default))})),
446            #[cfg(all(feature = $value_string, feature = "RowVector4"))]
447            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::RowVector4(rhs))) => Ok(Box::new([<$lib SR4>]{lhs, rhs, out: new_ref(RowVector4::from_element($default))})),
448            #[cfg(all(feature = $value_string, feature = "RowVectorD"))]
449            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::RowDVector(rhs))) => Ok(Box::new([<$lib SRD>]{lhs, rhs: rhs.clone(), out: new_ref(RowDVector::from_element(rhs.borrow().len(),$default))})),
450            // Scalar Vector
451            #[cfg(all(feature = $value_string, feature = "Vector2"))]
452            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::Vector2(rhs))) => Ok(Box::new([<$lib SV2>]{lhs, rhs, out: new_ref(Vector2::from_element($default))})),
453            #[cfg(all(feature = $value_string, feature = "Vector3"))]
454            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::Vector3(rhs))) => Ok(Box::new([<$lib SV3>]{lhs, rhs, out: new_ref(Vector3::from_element($default))})),
455            #[cfg(all(feature = $value_string, feature = "Vector4"))]
456            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::Vector4(rhs))) => Ok(Box::new([<$lib SV4>]{lhs, rhs, out: new_ref(Vector4::from_element($default))})),
457            #[cfg(all(feature = $value_string, feature = "VectorD"))]
458            (Value::$lhs_type(lhs), Value::$matrix_kind(Matrix::DVector(rhs))) => Ok(Box::new([<$lib SVD>]{lhs, rhs: rhs.clone(), out: new_ref(DVector::from_element(rhs.borrow().len(),$default))})),
459            // Matrix Scalar
460            #[cfg(all(feature = $value_string, feature = "Matrix1"))]
461            (Value::$matrix_kind(Matrix::Matrix1(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib M1S>]{lhs, rhs, out: new_ref(Matrix1::from_element($default))})),
462            #[cfg(all(feature = $value_string, feature = "Matrix2"))]
463            (Value::$matrix_kind(Matrix::Matrix2(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib M2S>]{lhs, rhs, out: new_ref(Matrix2::from_element($default))})),
464            #[cfg(all(feature = $value_string, feature = "Matrix3"))]
465            (Value::$matrix_kind(Matrix::Matrix3(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib M3S>]{lhs, rhs, out: new_ref(Matrix3::from_element($default))})),
466            #[cfg(all(feature = $value_string, feature = "Matrix4"))]
467            (Value::$matrix_kind(Matrix::Matrix4(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib M4S>]{lhs, rhs, out: new_ref(Matrix4::from_element($default))})),
468            #[cfg(all(feature = $value_string, feature = "Matrix2x3"))]
469            (Value::$matrix_kind(Matrix::Matrix2x3(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib M2x3S>]{lhs, rhs, out: new_ref(Matrix2x3::from_element($default))})),
470            #[cfg(all(feature = $value_string, feature = "Matrix3x2"))]
471            (Value::$matrix_kind(Matrix::Matrix3x2(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib M3x2S>]{lhs, rhs, out: new_ref(Matrix3x2::from_element($default))})),
472            #[cfg(all(feature = $value_string, feature = "MatrixD"))]
473            (Value::$matrix_kind(Matrix::DMatrix(lhs)),Value::$lhs_type(rhs)) => {
474              let (rows,cols) = {lhs.borrow().shape()};
475              Ok(Box::new([<$lib MDS>]{lhs: lhs.clone(), rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))}))},
476            // Row Scalar
477            #[cfg(all(feature = $value_string, feature = "RowVector2"))]
478            (Value::$matrix_kind(Matrix::RowVector2(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib R2S>]{lhs, rhs, out: new_ref(RowVector2::from_element($default))})),
479            #[cfg(all(feature = $value_string, feature = "RowVector3"))]
480            (Value::$matrix_kind(Matrix::RowVector3(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib R3S>]{lhs, rhs, out: new_ref(RowVector3::from_element($default))})),
481            #[cfg(all(feature = $value_string, feature = "RowVector4"))]
482            (Value::$matrix_kind(Matrix::RowVector4(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib R4S>]{lhs, rhs, out: new_ref(RowVector4::from_element($default))})),
483            #[cfg(all(feature = $value_string, feature = "RowVectorD"))]
484            (Value::$matrix_kind(Matrix::RowDVector(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib RDS>]{lhs: lhs.clone(), rhs, out: new_ref(RowDVector::from_element(lhs.borrow().len(),$default))})),
485            // Vector Scalar
486            #[cfg(all(feature = $value_string, feature = "Vector2"))]
487            (Value::$matrix_kind(Matrix::Vector2(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib V2S>]{lhs, rhs, out: new_ref(Vector2::from_element($default))})),
488            #[cfg(all(feature = $value_string, feature = "Vector3"))]
489            (Value::$matrix_kind(Matrix::Vector3(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib V3S>]{lhs, rhs, out: new_ref(Vector3::from_element($default))})),
490            #[cfg(all(feature = $value_string, feature = "Vector4"))]
491            (Value::$matrix_kind(Matrix::Vector4(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib V4S>]{lhs, rhs, out: new_ref(Vector4::from_element($default))})),
492            #[cfg(all(feature = $value_string, feature = "VectorD"))]
493            (Value::$matrix_kind(Matrix::DVector(lhs)),Value::$lhs_type(rhs)) => Ok(Box::new([<$lib VDS>]{lhs: lhs.clone(), rhs, out: new_ref(DVector::from_element(lhs.borrow().len(),$default))})),
494            // Matrix Matrix
495            #[cfg(all(feature = $value_string, feature = "Matrix1"))]
496            (Value::$matrix_kind(Matrix::Matrix1(lhs)), Value::$matrix_kind(Matrix::Matrix1(rhs))) => Ok(Box::new([<$lib M1M1>]{lhs, rhs, out: new_ref(Matrix1::from_element($default))})),
497            #[cfg(all(feature = $value_string, feature = "Matrix2"))]
498            (Value::$matrix_kind(Matrix::Matrix2(lhs)), Value::$matrix_kind(Matrix::Matrix2(rhs))) => Ok(Box::new([<$lib M2M2>]{lhs, rhs, out: new_ref(Matrix2::from_element($default))})),
499            #[cfg(all(feature = $value_string, feature = "Matrix3"))]
500            (Value::$matrix_kind(Matrix::Matrix3(lhs)), Value::$matrix_kind(Matrix::Matrix3(rhs))) => Ok(Box::new([<$lib M3M3>]{lhs, rhs, out: new_ref(Matrix3::from_element($default))})),
501            #[cfg(all(feature = $value_string, feature = "Matrix4"))]
502            (Value::$matrix_kind(Matrix::Matrix4(lhs)), Value::$matrix_kind(Matrix::Matrix4(rhs))) => Ok(Box::new([<$lib M4M4>]{lhs, rhs, out: new_ref(Matrix4::from_element($default))})),
503            #[cfg(all(feature = $value_string, feature = "Matrix2x3"))]
504            (Value::$matrix_kind(Matrix::Matrix2x3(lhs)), Value::$matrix_kind(Matrix::Matrix2x3(rhs))) => Ok(Box::new([<$lib M2x3M2x3>]{lhs, rhs, out: new_ref(Matrix2x3::from_element($default))})),  
505            #[cfg(all(feature = $value_string, feature = "Matrix3x2"))]
506            (Value::$matrix_kind(Matrix::Matrix3x2(lhs)), Value::$matrix_kind(Matrix::Matrix3x2(rhs))) => Ok(Box::new([<$lib M3x2M3x2>]{lhs, rhs, out: new_ref(Matrix3x2::from_element($default))})),
507            #[cfg(all(feature = $value_string, feature = "MatrixD"))]
508            (Value::$matrix_kind(Matrix::DMatrix(lhs)), Value::$matrix_kind(Matrix::DMatrix(rhs))) => {
509              let (rows,cols) = {lhs.borrow().shape()};
510              Ok(Box::new([<$lib MDMD>]{lhs, rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))}))},
511            // Row Row
512            #[cfg(all(feature = $value_string, feature = "RowVector2"))]
513            (Value::$matrix_kind(Matrix::RowVector2(lhs)), Value::$matrix_kind(Matrix::RowVector2(rhs))) => Ok(Box::new([<$lib R2R2>]{lhs: lhs.clone(), rhs: rhs.clone(), out: new_ref(RowVector2::from_element($default)) })),
514            #[cfg(all(feature = $value_string, feature = "RowVector3"))]
515            (Value::$matrix_kind(Matrix::RowVector3(lhs)), Value::$matrix_kind(Matrix::RowVector3(rhs))) => Ok(Box::new([<$lib R3R3>]{lhs: lhs.clone(), rhs: rhs.clone(), out: new_ref(RowVector3::from_element($default)) })),
516            #[cfg(all(feature = $value_string, feature = "RowVector4"))]
517            (Value::$matrix_kind(Matrix::RowVector4(lhs)), Value::$matrix_kind(Matrix::RowVector4(rhs))) => Ok(Box::new([<$lib R4R4>]{lhs: lhs.clone(), rhs: rhs.clone(), out: new_ref(RowVector4::from_element($default)) })),
518            #[cfg(all(feature = $value_string, feature = "RowVectorD"))]
519            (Value::$matrix_kind(Matrix::RowDVector(lhs)), Value::$matrix_kind(Matrix::RowDVector(rhs))) => Ok(Box::new([<$lib RDRD>]{lhs: lhs.clone(), rhs, out: new_ref(RowDVector::from_element(lhs.borrow().len(),$default))})),
520            // Vector Vector
521            #[cfg(all(feature = $value_string, feature = "Vector2"))]
522            (Value::$matrix_kind(Matrix::Vector2(lhs)), Value::$matrix_kind(Matrix::Vector2(rhs))) => Ok(Box::new([<$lib V2V2>]{lhs: lhs.clone(), rhs: rhs.clone(), out: new_ref(Vector2::from_element($default)) })),
523            #[cfg(all(feature = $value_string, feature = "Vector3"))]
524            (Value::$matrix_kind(Matrix::Vector3(lhs)), Value::$matrix_kind(Matrix::Vector3(rhs))) => Ok(Box::new([<$lib V3V3>]{lhs: lhs.clone(), rhs: rhs.clone(), out: new_ref(Vector3::from_element($default)) })),
525            #[cfg(all(feature = $value_string, feature = "Vector4"))]
526            (Value::$matrix_kind(Matrix::Vector4(lhs)), Value::$matrix_kind(Matrix::Vector4(rhs))) => Ok(Box::new([<$lib V4V4>]{lhs: lhs.clone(), rhs: rhs.clone(), out: new_ref(Vector4::from_element($default)) })),
527            #[cfg(all(feature = $value_string, feature = "VectorD"))]
528            (Value::$matrix_kind(Matrix::DVector(lhs)), Value::$matrix_kind(Matrix::DVector(rhs))) => Ok(Box::new([<$lib VDVD>]{lhs: lhs.clone(), rhs, out: new_ref(DVector::from_element(lhs.borrow().len(),$default))})),
529            // Matrix Vector     
530            #[cfg(all(feature = $value_string, feature = "Matrix2"))]
531            (Value::$matrix_kind(Matrix::Matrix2(lhs)),Value::$matrix_kind(Matrix::Vector2(rhs))) => Ok(Box::new([<$lib M2V2>]{lhs, rhs, out: new_ref(Matrix2::from_element($default))})),         
532            #[cfg(all(feature = $value_string, feature = "Matrix3"))]
533            (Value::$matrix_kind(Matrix::Matrix3(lhs)),Value::$matrix_kind(Matrix::Vector3(rhs))) => Ok(Box::new([<$lib M3V3>]{lhs, rhs, out: new_ref(Matrix3::from_element($default))})),         
534            #[cfg(all(feature = $value_string, feature = "Matrix2x3"))]
535            (Value::$matrix_kind(Matrix::Matrix2x3(lhs)),Value::$matrix_kind(Matrix::Vector2(rhs))) => Ok(Box::new([<$lib M2x3V2>]{lhs, rhs, out: new_ref(Matrix2x3::from_element($default))})),         
536            #[cfg(all(feature = $value_string, feature = "Matrix3x2"))]
537            (Value::$matrix_kind(Matrix::Matrix3x2(lhs)),Value::$matrix_kind(Matrix::Vector3(rhs))) => Ok(Box::new([<$lib M3x2V3>]{lhs, rhs, out: new_ref(Matrix3x2::from_element($default))})),         
538            #[cfg(all(feature = $value_string, feature = "Matrix4"))]
539            (Value::$matrix_kind(Matrix::Matrix4(lhs)),Value::$matrix_kind(Matrix::Vector4(rhs))) => Ok(Box::new([<$lib M4V4>]{lhs, rhs, out: new_ref(Matrix4::from_element($default))})),         
540            #[cfg(all(feature = $value_string, feature = "MatrixD"))]
541            // Matrix Row     
542            #[cfg(all(feature = $value_string, feature = "Matrix2"))]
543            (Value::$matrix_kind(Matrix::Matrix2(lhs)),Value::$matrix_kind(Matrix::RowVector2(rhs))) => Ok(Box::new([<$lib M2R2>]{lhs, rhs, out: new_ref(Matrix2::from_element($default))})),         
544            #[cfg(all(feature = $value_string, feature = "Matrix3"))]
545            (Value::$matrix_kind(Matrix::Matrix3(lhs)),Value::$matrix_kind(Matrix::RowVector3(rhs))) => Ok(Box::new([<$lib M3R3>]{lhs, rhs, out: new_ref(Matrix3::from_element($default))})),         
546            #[cfg(all(feature = $value_string, feature = "Matrix2x3"))]
547            (Value::$matrix_kind(Matrix::Matrix2x3(lhs)),Value::$matrix_kind(Matrix::RowVector3(rhs))) => Ok(Box::new([<$lib M2x3R3>]{lhs, rhs, out: new_ref(Matrix2x3::from_element($default))})),         
548            #[cfg(all(feature = $value_string, feature = "Matrix3x2"))]
549            (Value::$matrix_kind(Matrix::Matrix3x2(lhs)),Value::$matrix_kind(Matrix::RowVector2(rhs))) => Ok(Box::new([<$lib M3x2R2>]{lhs, rhs, out: new_ref(Matrix3x2::from_element($default))})),         
550            #[cfg(all(feature = $value_string, feature = "Matrix4"))]
551            (Value::$matrix_kind(Matrix::Matrix4(lhs)),Value::$matrix_kind(Matrix::RowVector4(rhs))) => Ok(Box::new([<$lib M4R4>]{lhs, rhs, out: new_ref(Matrix4::from_element($default))})),         
552            #[cfg(all(feature = $value_string, feature = "MatrixD"))]
553            (Value::$matrix_kind(Matrix::DMatrix(lhs)),Value::$matrix_kind(rhs)) => {
554              let (rows,cols) = {lhs.borrow().shape()};
555              let rhs_shape = rhs.shape();
556              match (rows,cols,rhs_shape[0],rhs_shape[1]) {
557                // matching rows
558                (n,_,m,1) if n == m => (),
559                // matching cols
560                (_,n,1,m) if n == m => (),
561                // mismatching dimensions
562                _ => {return Err(MechError{file: file!().to_string(),  tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::DimensionMismatch(vec![]) });},
563              }
564              match rhs {
565                Matrix::Vector2(rhs) => Ok(Box::new([<$lib MDV2>]{lhs: lhs.clone(), rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
566                Matrix::Vector3(rhs) => Ok(Box::new([<$lib MDV3>]{lhs: lhs.clone(), rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
567                Matrix::Vector4(rhs) => Ok(Box::new([<$lib MDV4>]{lhs: lhs.clone(), rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
568                Matrix::DVector(rhs) => Ok(Box::new([<$lib MDVD>]{lhs: lhs.clone(), rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
569                Matrix::RowVector2(rhs) => Ok(Box::new([<$lib MDR2>]{lhs: lhs.clone(), rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
570                Matrix::RowVector3(rhs) => Ok(Box::new([<$lib MDR3>]{lhs: lhs.clone(), rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
571                Matrix::RowVector4(rhs) => Ok(Box::new([<$lib MDR4>]{lhs: lhs.clone(), rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
572                Matrix::RowDVector(rhs) => Ok(Box::new([<$lib MDRD>]{lhs: lhs.clone(), rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
573                _ => {return Err(MechError{file: file!().to_string(),  tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::DimensionMismatch(vec![]) });},
574              }
575            },
576            // Vector Matrix
577            #[cfg(all(feature = $value_string, feature = "Matrix2"))]
578            (Value::$matrix_kind(Matrix::Vector2(lhs)), Value::$matrix_kind(Matrix::Matrix2(rhs))) => Ok(Box::new([<$lib V2M2>]{lhs, rhs, out: new_ref(Matrix2::from_element($default))})),         
579            #[cfg(all(feature = $value_string, feature = "Matrix3"))]
580            (Value::$matrix_kind(Matrix::Vector3(lhs)), Value::$matrix_kind(Matrix::Matrix3(rhs))) => Ok(Box::new([<$lib V3M3>]{lhs, rhs, out: new_ref(Matrix3::from_element($default))})),         
581            #[cfg(all(feature = $value_string, feature = "Matrix2x3"))]
582            (Value::$matrix_kind(Matrix::Vector2(lhs)), Value::$matrix_kind(Matrix::Matrix2x3(rhs))) => Ok(Box::new([<$lib V2M2x3>]{lhs, rhs, out: new_ref(Matrix2x3::from_element($default))})),         
583            #[cfg(all(feature = $value_string, feature = "Matrix3x2"))]
584            (Value::$matrix_kind(Matrix::Vector3(lhs)), Value::$matrix_kind(Matrix::Matrix3x2(rhs))) => Ok(Box::new([<$lib V3M3x2>]{lhs, rhs, out: new_ref(Matrix3x2::from_element($default))})),                     
585            #[cfg(all(feature = $value_string, feature = "Matrix4"))]
586            (Value::$matrix_kind(Matrix::Vector4(lhs)), Value::$matrix_kind(Matrix::Matrix4(rhs))) => Ok(Box::new([<$lib V4M4>]{lhs, rhs, out: new_ref(Matrix4::from_element($default))})),                     
587            // Row Matrix     
588            #[cfg(all(feature = $value_string, feature = "RowVector2"))]
589            (Value::$matrix_kind(Matrix::RowVector2(lhs)), Value::$matrix_kind(Matrix::Matrix2(rhs))) => Ok(Box::new([<$lib R2M2>]{lhs, rhs, out: new_ref(Matrix2::from_element($default))})),         
590            #[cfg(all(feature = $value_string, feature = "RowVector3"))]
591            (Value::$matrix_kind(Matrix::RowVector3(lhs)), Value::$matrix_kind(Matrix::Matrix3(rhs))) => Ok(Box::new([<$lib R3M3>]{lhs, rhs, out: new_ref(Matrix3::from_element($default))})),         
592            #[cfg(all(feature = $value_string, feature = "RowVector3"))]
593            (Value::$matrix_kind(Matrix::RowVector3(lhs)), Value::$matrix_kind(Matrix::Matrix2x3(rhs))) => Ok(Box::new([<$lib R3M2x3>]{lhs, rhs, out: new_ref(Matrix2x3::from_element($default))})),         
594            #[cfg(all(feature = $value_string, feature = "RowVector2"))]
595            (Value::$matrix_kind(Matrix::RowVector2(lhs)), Value::$matrix_kind(Matrix::Matrix3x2(rhs))) => Ok(Box::new([<$lib R2M3x2>]{lhs, rhs, out: new_ref(Matrix3x2::from_element($default))})),         
596            #[cfg(all(feature = $value_string, feature = "RowVector4"))]
597            (Value::$matrix_kind(Matrix::RowVector4(lhs)), Value::$matrix_kind(Matrix::Matrix4(rhs))) => Ok(Box::new([<$lib R4M4>]{lhs, rhs, out: new_ref(Matrix4::from_element($default))})),         
598            #[cfg(all(feature = $value_string, feature = "MatrixD"))]
599            (Value::$matrix_kind(lhs),Value::$matrix_kind(Matrix::DMatrix(rhs))) => {
600              let (rows,cols) = {rhs.borrow().shape()};
601              let lhs_shape = lhs.shape();
602              match (lhs_shape[0],lhs_shape[1],rows,cols) {
603                // matching rows
604                (m,1,n,_) if n == m => (),
605                // matching cols
606                (1,m,_,n) if n == m => (),
607                // mismatching dimensions
608                _ => {return Err(MechError{file: file!().to_string(),  tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::DimensionMismatch(vec![]) });},
609              }
610              match lhs {
611                Matrix::Vector2(lhs) => Ok(Box::new([<$lib V2MD>]{lhs, rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
612                Matrix::Vector3(lhs) => Ok(Box::new([<$lib V3MD>]{lhs, rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
613                Matrix::Vector4(lhs) => Ok(Box::new([<$lib V4MD>]{lhs, rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
614                Matrix::DVector(lhs) => Ok(Box::new([<$lib VDMD>]{lhs, rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
615                Matrix::RowVector2(lhs) => Ok(Box::new([<$lib R2MD>]{lhs, rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
616                Matrix::RowVector3(lhs) => Ok(Box::new([<$lib R3MD>]{lhs, rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
617                Matrix::RowVector4(lhs) => Ok(Box::new([<$lib R4MD>]{lhs, rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
618                Matrix::RowDVector(lhs) => Ok(Box::new([<$lib RDMD>]{lhs, rhs, out: new_ref(DMatrix::from_element(rows,cols,$default))})),
619                _ => {return Err(MechError{file: file!().to_string(),  tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::DimensionMismatch(vec![]) });},
620              }
621            }
622          )+
623        )+
624        x => Err(MechError{file: file!().to_string(),  tokens: vec![], msg: format!("{:?}",x), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind }),
625      }
626    }
627  }
628}
629
630#[macro_export]
631macro_rules! impl_urnop_match_arms {
632  ($lib:ident, $arg:expr, $($lhs_type:ident => $($matrix_kind:ident, $target_type:ident, $default:expr, $value_string:tt),+);+ $(;)?) => {
633    paste!{
634      match $arg {
635        $(
636          $(
637            (Value::$lhs_type(arg)) => Ok(Box::new([<$lib S>]{arg: arg.clone(), out: new_ref($default) })),
638            #[cfg(all(feature = $value_string, feature = "Matrix1"))]
639            (Value::$matrix_kind(Matrix::Matrix1(arg))) => Ok(Box::new([<$lib M1>]{arg, out: new_ref(Matrix1::from_element($default))})),
640            #[cfg(all(feature = $value_string, feature = "Matrix2"))]
641            (Value::$matrix_kind(Matrix::Matrix2(arg))) => Ok(Box::new([<$lib M2>]{arg, out: new_ref(Matrix2::from_element($default))})),
642            #[cfg(all(feature = $value_string, feature = "Matrix3"))]
643            (Value::$matrix_kind(Matrix::Matrix3(arg))) => Ok(Box::new([<$lib M3>]{arg, out: new_ref(Matrix3::from_element($default))})),
644            #[cfg(all(feature = $value_string, feature = "Matrix4"))]
645            (Value::$matrix_kind(Matrix::Matrix4(arg))) => Ok(Box::new([<$lib M4>]{arg, out: new_ref(Matrix4::from_element($default))})),
646            #[cfg(all(feature = $value_string, feature = "Matrix2x3"))]
647            (Value::$matrix_kind(Matrix::Matrix2x3(arg))) => Ok(Box::new([<$lib M2x3>]{arg, out: new_ref(Matrix2x3::from_element($default))})),         
648            #[cfg(all(feature = $value_string, feature = "Matrix3x2"))]
649            (Value::$matrix_kind(Matrix::Matrix3x2(arg))) => Ok(Box::new([<$lib M3x2>]{arg, out: new_ref(Matrix3x2::from_element($default))})),         
650            #[cfg(all(feature = $value_string, feature = "RowVector2"))]
651            (Value::$matrix_kind(Matrix::RowVector2(arg))) => Ok(Box::new([<$lib R2>]{arg: arg.clone(), out: new_ref(RowVector2::from_element($default)) })),
652            #[cfg(all(feature = $value_string, feature = "RowVector3"))]
653            (Value::$matrix_kind(Matrix::RowVector3(arg))) => Ok(Box::new([<$lib R3>]{arg: arg.clone(), out: new_ref(RowVector3::from_element($default)) })),
654            #[cfg(all(feature = $value_string, feature = "RowVector4"))]
655            (Value::$matrix_kind(Matrix::RowVector4(arg))) => Ok(Box::new([<$lib R4>]{arg: arg.clone(), out: new_ref(RowVector4::from_element($default)) })),
656            #[cfg(all(feature = $value_string, feature = "RowVectorD"))]
657            (Value::$matrix_kind(Matrix::RowDVector(arg))) => Ok(Box::new([<$lib RD>]{arg: arg.clone(), out: new_ref(RowDVector::from_element(arg.borrow().len(),$default))})),
658            #[cfg(all(feature = $value_string, feature = "Vector2"))]
659            (Value::$matrix_kind(Matrix::Vector2(arg))) => Ok(Box::new([<$lib V2>]{arg: arg.clone(), out: new_ref(Vector2::from_element($default)) })),
660            #[cfg(all(feature = $value_string, feature = "Vector3"))]
661            (Value::$matrix_kind(Matrix::Vector3(arg))) => Ok(Box::new([<$lib V3>]{arg: arg.clone(), out: new_ref(Vector3::from_element($default)) })),
662            #[cfg(all(feature = $value_string, feature = "Vector4"))]
663            (Value::$matrix_kind(Matrix::Vector4(arg))) => Ok(Box::new([<$lib V4>]{arg: arg.clone(), out: new_ref(Vector4::from_element($default)) })),
664            #[cfg(all(feature = $value_string, feature = "VectorD"))]
665            (Value::$matrix_kind(Matrix::DVector(arg))) => Ok(Box::new([<$lib VD>]{arg: arg.clone(), out: new_ref(DVector::from_element(arg.borrow().len(),$default))})),
666            #[cfg(all(feature = $value_string, feature = "MatrixD"))]
667            (Value::$matrix_kind(Matrix::DMatrix(arg))) => {
668              let (rows,cols) = {arg.borrow().shape()};
669              Ok(Box::new([<$lib MD>]{arg, out: new_ref(DMatrix::from_element(rows,cols,$default))}))},
670          )+
671        )+
672        x => Err(MechError{file: file!().to_string(),  tokens: vec![], msg: format!("{:?}",x), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind }),
673      }
674    }
675  }
676}
677
678#[macro_export]
679macro_rules! impl_mech_binop_fxn {
680  ($fxn_name:ident, $gen_fxn:ident) => {
681    pub struct $fxn_name {}
682    impl NativeFunctionCompiler for $fxn_name {
683      fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
684        if arguments.len() != 2 {
685          return Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::IncorrectNumberOfArguments});
686        }
687        let lhs_value = arguments[0].clone();
688        let rhs_value = arguments[1].clone();
689        match $gen_fxn(lhs_value.clone(), rhs_value.clone()) {
690          Ok(fxn) => Ok(fxn),
691          Err(_) => {
692            match (lhs_value,rhs_value) {
693              (Value::MutableReference(lhs),Value::MutableReference(rhs)) => {$gen_fxn(lhs.borrow().clone(), rhs.borrow().clone())}
694              (lhs_value,Value::MutableReference(rhs)) => { $gen_fxn(lhs_value.clone(), rhs.borrow().clone())}
695              (Value::MutableReference(lhs),rhs_value) => { $gen_fxn(lhs.borrow().clone(), rhs_value.clone()) }
696              x => Err(MechError{file: file!().to_string(),  tokens: vec![], msg: format!("{:?}",x), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind }),
697            }
698          }
699        }
700      }
701    }
702  }
703}
704
705#[macro_export]
706macro_rules! impl_mech_urnop_fxn {
707  ($fxn_name:ident, $gen_fxn:ident) => {
708    pub struct $fxn_name {}
709    impl NativeFunctionCompiler for $fxn_name {
710      fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
711        if arguments.len() != 1 {
712          return Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::IncorrectNumberOfArguments});
713        }
714        let input = arguments[0].clone();
715        match $gen_fxn(input.clone()) {
716          Ok(fxn) => Ok(fxn),
717          Err(_) => {
718            match (input) {
719              (Value::MutableReference(input)) => {$gen_fxn(input.borrow().clone())}
720              x => Err(MechError{file: file!().to_string(),  tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind }),
721            }
722          }
723        }
724      }
725    }
726  }
727}