use core::ops::{Add, Div, Mul, Sub};
use crate::scalar::Numeric;
pub trait ScalarFn {
fn eval<S: Numeric>(&self, x: S) -> S;
}
pub trait ScalarFnN<const N: usize> {
fn eval<S: Numeric>(&self, point: &[S; N]) -> S;
}
pub trait VectorFn<const N: usize, const M: usize> {
fn eval<S: Numeric>(&self, point: &[S; N]) -> [S; M];
}
pub(crate) struct Component<'a, F, const N: usize, const M: usize> {
func: &'a F,
index: usize,
}
impl<'a, F: VectorFn<N, M>, const N: usize, const M: usize> Component<'a, F, N, M> {
#[inline]
pub fn new(func: &'a F, index: usize) -> Self {
Component { func, index }
}
}
impl<F: VectorFn<N, M>, const N: usize, const M: usize> ScalarFnN<N> for Component<'_, F, N, M> {
#[inline]
fn eval<S: Numeric>(&self, point: &[S; N]) -> S {
self.func.eval(point)[self.index]
}
}
#[derive(Debug, Clone, Copy)]
pub struct Const(f64);
#[inline]
pub fn c(value: f64) -> Const {
Const(value)
}
impl<S: Numeric> Mul<S> for Const {
type Output = S;
#[inline]
fn mul(self, rhs: S) -> S {
S::from_f64(self.0) * rhs
}
}
impl<S: Numeric> Add<S> for Const {
type Output = S;
#[inline]
fn add(self, rhs: S) -> S {
S::from_f64(self.0) + rhs
}
}
impl<S: Numeric> Sub<S> for Const {
type Output = S;
#[inline]
fn sub(self, rhs: S) -> S {
S::from_f64(self.0) - rhs
}
}
impl<S: Numeric> Div<S> for Const {
type Output = S;
#[inline]
fn div(self, rhs: S) -> S {
S::from_f64(self.0) / rhs
}
}
#[macro_export]
macro_rules! scalar_fn {
(| $p:ident : & [ f64 ; $n:literal ] | $body:expr) => {{
struct ScalarFnImpl;
impl $crate::scalar::ScalarFnN<$n> for ScalarFnImpl {
#[inline]
fn eval<S: $crate::scalar::Numeric>(&self, $p: &[S; $n]) -> S {
$body
}
}
ScalarFnImpl
}};
(| $p:ident : f64 | $body:expr) => {{
struct ScalarFnImpl;
impl $crate::scalar::ScalarFn for ScalarFnImpl {
#[inline]
fn eval<S: $crate::scalar::Numeric>(&self, $p: S) -> S {
$body
}
}
ScalarFnImpl
}};
(| $p:ident | $body:expr) => {{
struct ScalarFnImpl;
impl $crate::scalar::ScalarFn for ScalarFnImpl {
#[inline]
fn eval<S: $crate::scalar::Numeric>(&self, $p: S) -> S {
$body
}
}
ScalarFnImpl
}};
}
#[macro_export]
macro_rules! scalar_fn_vec {
(| $p:ident : & [ f64 ; $n:literal ] | [ $($e:expr),+ $(,)? ]) => {{
struct VectorFnImpl;
impl $crate::scalar::VectorFn<$n, { $crate::__scalar_fn_count!($($e),+) }> for VectorFnImpl {
#[inline]
fn eval<S: $crate::scalar::Numeric>(
&self,
$p: &[S; $n],
) -> [S; { $crate::__scalar_fn_count!($($e),+) }] {
[$($e),+]
}
}
VectorFnImpl
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __scalar_fn_count {
() => { 0usize };
($head:expr $(, $tail:expr)*) => { 1usize + $crate::__scalar_fn_count!($($tail),*) };
}