Sat, 14 Dec 2024 09:31:27 -0500
Convex analysis basics
/*! 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); }; }