--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/metaprogramming.rs Fri Dec 13 22:37:12 2024 -0500 @@ -0,0 +1,103 @@ +/*! +Metaprogramming tools +*/ + +/// Reference `x` if so indicated by the first parameter. +/// Typically to be used from another macro. See the implementation of +/// [power][crate::vectorspace::powerspace] and [product spaces][crate::vectorspace::productspace]. +/// +/// ```ignore +/// maybe_ref!(ref, V) // ➡ &V +/// maybe_ref!(noref, V) // ➡ V +/// ``` +#[macro_export] +macro_rules! maybe_ref { + (ref, $x:expr) => { &$x }; + (noref, $x:expr) => { $x }; + (ref, $x:ty) => { &$x }; + (noref, $x:ty) => { $x }; +} + +/// Choose `a` if first argument is the literal `ref`, otherwise `b`. +#[macro_export] +macro_rules! ifref { + (noref, $a:expr, $b:expr) => { $b }; + (ref, $a:expr, $b:expr) => { $a }; +} + + +/// Annotate `x` with a lifetime if the first parameter +/// Typically to be used from another macro. See the implementation of +/// [power][crate::vectorspace::powerspace] and [product spaces][crate::vectorspace::productspace]. +/// +/// ```ignore +/// maybe_ref!(ref, &'a V) // ➡ &'a V +/// maybe_ref!(noref, &'a V) // ➡ V +/// ``` +#[macro_export] +macro_rules! maybe_lifetime { + (ref, $x:ty) => { $x }; + (noref, &$lt:lifetime $x:ty) => { $x }; + (noref, &$x:ty) => { $x }; +} + +/// Use as +/// ```ignore +/// impl_vectorspace_ops!(impl_binop, impl_assignop, impl_scalarop, impl_scalar_assignop, impl_unaryop); +/// ``` +/// with `impl_binop`, `impl_assignop`, `impl_scalarop`, and `impl_unaryop` macros provided. +/// For example usage see the [power][crate::vectorspace::powerspace] and +/// [product spaces][crate::vectorspace::productspace] implementations. +#[macro_export] +macro_rules! impl_vectorspace_ops { + ($impl_binop:ident, $impl_assignop:ident, $impl_scalarop:ident, $impl_scalarlhs_op:ident, + $impl_scalar_assignop:ident, $impl_unaryop:ident) => { + impl_vectorspace_ops!($impl_binop, $impl_assignop, $impl_scalarop, $impl_scalarlhs_op, + $impl_scalar_assignop, $impl_unaryop, + (f32, f64, + num::complex::Complex<f32>, + num::complex::Complex<f64>)); + }; + ($impl_binop:ident, $impl_assignop:ident, $impl_scalarop:ident, $impl_scalarlhs_op:ident, + $impl_scalar_assignop:ident, $impl_unaryop:ident, ($($field:ty),+)) => { + impl_vectorspace_ops!(@binary, $impl_binop, Add, add); + impl_vectorspace_ops!(@binary, $impl_binop, Sub, sub); + impl_vectorspace_ops!(@assign, $impl_assignop, AddAssign, add_assign); + impl_vectorspace_ops!(@assign, $impl_assignop, SubAssign, sub_assign); + impl_vectorspace_ops!(@scalar, $impl_scalarop, Mul, mul); + impl_vectorspace_ops!(@scalar, $impl_scalarop, Div, div); + // Compiler overflow + // $( + // impl_vectorspace_ops!(@scalar_lhs, $impl_scalarlhs_op, Mul, mul, $field); + // )* + impl_vectorspace_ops!(@scalar_assign, $impl_scalar_assignop, MulAssign, mul_assign); + impl_vectorspace_ops!(@scalar_assign, $impl_scalar_assignop, DivAssign, div_assign); + impl_vectorspace_ops!(@unary, $impl_unaryop, Neg, neg); + }; + (@binary, $impl:ident, $trait : ident, $fn : ident) => { + $impl!($trait, $fn, ref, ref); + $impl!($trait, $fn, ref, noref); + $impl!($trait, $fn, noref, ref); + $impl!($trait, $fn, noref, noref); + }; + (@assign, $impl:ident, $trait : ident, $fn :ident) => { + $impl!($trait, $fn, ref); + $impl!($trait, $fn, noref); + }; + (@scalar, $impl:ident, $trait : ident, $fn :ident) => { + $impl!($trait, $fn, ref); + $impl!($trait, $fn, noref); + }; + (@scalar_lhs, $impl:ident, $trait : ident, $fn : ident, $field: ty) => { + // These operators need workarounds + $impl!($trait, $fn, ref, $field); + $impl!($trait, $fn, noref, $field); + }; + (@scalar_assign, $impl:ident, $trait : ident, $fn :ident) => { + $impl!($trait, $fn); + }; + (@unary, $impl:ident, $trait : ident, $fn :ident) => { + $impl!($trait, $fn, ref); + $impl!($trait, $fn, noref); + }; +}