src/metaprogramming.rs

Sat, 14 Dec 2024 09:31:27 -0500

author
Tuomo Valkonen <tuomov@iki.fi>
date
Sat, 14 Dec 2024 09:31:27 -0500
branch
dev
changeset 58
1a38447a89fa
parent 57
1b3b1687b9ed
child 59
9226980e45a7
permissions
-rw-r--r--

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);
    };
}

mercurial