mech_range/
exclusive.rs

1#![feature(step_trait)]
2use crate::*;
3use mech_core::*;
4use std::iter::Step;
5use nalgebra::{
6  base::{Matrix as naMatrix, Storage, StorageMut},
7  Dim, Scalar,
8};
9use mech_core::matrix::Matrix;
10use std::marker::PhantomData;
11
12// Exclusive ------------------------------------------------------------------
13
14#[derive(Debug)]
15pub struct RangeExclusiveScalar<T, MatA> {
16  pub from: Ref<T>,
17  pub to: Ref<T>,
18  pub out: Ref<MatA>,
19  phantom: PhantomData<T>,
20}
21impl<T, R1, C1, S1> MechFunctionFactory for RangeExclusiveScalar<T, naMatrix<T, R1, C1, S1>>
22where
23  T: Copy + Debug + Clone + Sync + Send + Step + 
24  CompileConst + ConstElem + AsValueKind +
25  PartialOrd + 'static + One + Add<Output = T>,
26  Ref<naMatrix<T, R1, C1, S1>>: ToValue,
27  naMatrix<T, R1, C1, S1>: CompileConst + ConstElem + AsNaKind,
28  R1: Dim + 'static, C1: Dim, S1: StorageMut<T, R1, C1> + Clone + Debug + 'static,
29{
30  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
31    match args {
32      FunctionArgs::Binary(out, from, to) => {
33        let from: Ref<T> = unsafe { from.as_unchecked() }.clone();
34        let to: Ref<T> = unsafe { to.as_unchecked() }.clone();
35        let out: Ref<naMatrix<T, R1, C1, S1>> = unsafe { out.as_unchecked() }.clone();
36        Ok(Box::new(Self { from, to, out, phantom: PhantomData::default() }))
37      },
38      _ => Err(MechError{file: file!().to_string(), tokens: vec![], msg: format!("RangeExclusiveScalar requires 3 arguments, got {:?}", args), id: line!(), kind: MechErrorKind::IncorrectNumberOfArguments})
39    }
40  }
41}
42impl<T, R1, C1, S1> MechFunctionImpl for RangeExclusiveScalar<T, naMatrix<T, R1, C1, S1>>
43where
44  Ref<naMatrix<T, R1, C1, S1>>: ToValue,
45  T: Scalar + Clone + Debug + Sync + Send + 'static + PartialOrd + One + Add<Output = T> + 'static,
46  R1: Dim, C1: Dim, S1: StorageMut<T, R1, C1> + Clone + Debug,
47{
48  fn solve(&self) {
49    let from_ptr = self.from.as_ptr();
50    let to_ptr = self.to.as_ptr();
51    let out_ptr = self.out.as_mut_ptr();
52    let mut current = from_ptr;
53    unsafe {
54      for val in (*out_ptr).iter_mut() {
55        *val = (*current).clone();
56        current = &(*current).clone().add(T::one());
57      }
58    }
59  }
60  fn out(&self) -> Value { self.out.to_value() }
61  fn to_string(&self) -> String { format!("{:#?}", self) }
62}
63#[cfg(feature = "compiler")]
64impl<T, R1, C1, S1> MechFunctionCompiler for RangeExclusiveScalar<T, naMatrix<T, R1, C1, S1>> 
65where
66  T: CompileConst + ConstElem + AsValueKind,
67  naMatrix<T, R1, C1, S1>: CompileConst + ConstElem + AsNaKind,
68{
69  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
70    let name = format!("RangeExclusiveScalar<{}{}>", T::as_value_kind(), naMatrix::<T, R1, C1, S1>::as_na_kind());
71    compile_binop!(name, self.out, self.from, self.to, ctx, FeatureFlag::Builtin(FeatureKind::RangeExclusive) );
72  }
73}
74
75#[macro_export]
76macro_rules! impl_range_exclusive_match_arms {
77  ($fxn:ident, $arg1:expr, $arg2:expr, $($ty:tt, $feat:tt);+ $(;)?) => {
78    paste! {
79      match ($arg1, $arg2) {
80        $(
81          #[cfg(feature = $feat)]
82          (Value::[<$ty:camel>](from), Value::[<$ty:camel>](to))  => {
83            let from_val = *from.borrow();
84            let to_val = *to.borrow();
85            let diff = to_val - from_val;
86            if diff < $ty::zero() {
87              return Err(MechError {file: file!().to_string(),tokens: vec![],msg: "Range size must be > 0".to_string(),id: line!(),kind: MechErrorKind::UnhandledFunctionArgumentKind,});
88            }
89            let size = diff.try_into().map_err(|_| MechError {file: file!().to_string(),tokens: vec![],msg: "Range size overflow".to_string(),id: line!(),kind: MechErrorKind::UnhandledFunctionArgumentKind,})?;            
90            let mut vec = vec![from_val; size];
91            match size {
92              0 => Err(MechError {file: file!().to_string(),tokens: vec![],msg: "Range size must be > 0".to_string(),id: line!(),kind: MechErrorKind::UnhandledFunctionArgumentKind,}),
93              #[cfg(feature = "matrix1")]
94              1 => {
95                register_range!($fxn, $ty, $feat, Matrix1);
96                Ok(Box::new($fxn::<$ty,Matrix1<$ty>>{from: from.clone(), to: to.clone(), out: Ref::new(Matrix1::from_element(vec[0])), phantom: PhantomData::default()}))
97              }
98              #[cfg(all(not(feature = "matrix1"), feature = "matrixd")  )]
99              1 => {
100                register_range!($fxn, $ty, $feat, DMatrix);
101                Ok(Box::new($fxn::<$ty,DMatrix<$ty>>{from: from.clone(), to: to.clone(), out: Ref::new(DMatrix::from_element(1,1,vec[0])), phantom: PhantomData::default()}))
102              }
103              #[cfg(feature = "row_vector2")]
104              2 => {
105                register_range!($fxn, $ty, $feat, RowVector2);
106                Ok(Box::new($fxn::<$ty,RowVector2<$ty>>{from: from.clone(), to: to.clone(), out: Ref::new(RowVector2::from_vec(vec)), phantom: PhantomData::default()}))
107              }
108              #[cfg(feature = "row_vector3")]
109              3 => {              
110                register_range!($fxn, $ty, $feat, RowVector3);
111                Ok(Box::new($fxn::<$ty,RowVector3<$ty>>{from: from.clone(), to: to.clone(), out: Ref::new(RowVector3::from_vec(vec)), phantom: PhantomData::default()}))
112              }
113              #[cfg(feature = "row_vector4")]
114              4 => {
115                register_range!($fxn, $ty, $feat, RowVector4);
116                Ok(Box::new($fxn::<$ty,RowVector4<$ty>>{from: from.clone(), to: to.clone(), out: Ref::new(RowVector4::from_vec(vec)), phantom: PhantomData::default()}))
117              }
118              #[cfg(feature = "row_vectord")]
119              n => {
120                register_range!($fxn, $ty, $feat, RowDVector);
121                Ok(Box::new($fxn::<$ty,RowDVector<$ty>>{from: from.clone(), to: to.clone(), out: Ref::new(RowDVector::from_vec(vec)), phantom: PhantomData::default()}))
122              }
123            }
124          }
125        )+
126        x => Err(MechError {file: file!().to_string(),tokens: vec![],msg: format!("{:?}", x),id: line!(),kind: MechErrorKind::UnhandledFunctionArgumentKind,})
127      }
128    }
129  }
130}
131
132fn impl_range_exclusive_fxn(arg1_value: Value, arg2_value: Value) -> MResult<Box<dyn MechFunction>> {
133  impl_range_exclusive_match_arms!(RangeExclusiveScalar, arg1_value, arg2_value,
134    F32, "f32";
135    F64, "f64";
136    i8,  "i8";
137    i16, "i16";
138    i32, "i32";
139    i64, "i64";
140    i128,"i128";
141    u8,  "u8";
142    u16, "u16";
143    u32, "u32";
144    u64, "u64";
145    u128,"u128";
146  )
147}
148
149pub struct RangeExclusive {}
150
151impl NativeFunctionCompiler for RangeExclusive {
152  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
153    if arguments.len() != 2 {
154      return Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::IncorrectNumberOfArguments});
155    }
156    let arg1 = arguments[0].clone();
157    let arg2 = arguments[1].clone();
158    match impl_range_exclusive_fxn(arg1.clone(), arg2.clone()) {
159      Ok(fxn) => Ok(fxn),
160      Err(_) => {
161        match (arg1,arg2) {
162          (Value::MutableReference(arg1),Value::MutableReference(arg2)) => {impl_range_exclusive_fxn(arg1.borrow().clone(),arg2.borrow().clone())}
163          (Value::MutableReference(arg1),arg2) => {impl_range_exclusive_fxn(arg1.borrow().clone(),arg2.clone())}
164          (arg1,Value::MutableReference(arg2)) => {impl_range_exclusive_fxn(arg1.clone(),arg2.borrow().clone())}
165          x => Err(MechError{file: file!().to_string(),  tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind }),
166        }
167      }
168    }
169  }
170}
171
172register_descriptor! {
173  FunctionCompilerDescriptor {
174    name: "range/exclusive",
175    ptr: &RangeExclusive{},
176  }
177}