Skip to main content

mech_range/
inclusive_increment.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 RangeIncrementInclusiveScalar<T, MatA> {
16  pub from: Ref<T>,
17  pub step: Ref<T>,
18  pub to: Ref<T>,
19  pub out: Ref<MatA>,
20  phantom: PhantomData<T>,
21}
22impl<T, R1, C1, S1> MechFunctionFactory for RangeIncrementInclusiveScalar<T, naMatrix<T, R1, C1, S1>>
23where
24  T: Copy + Debug + Clone + Sync + Send + 
25  CompileConst + ConstElem + AsValueKind +
26  PartialOrd + 'static + One + Add<Output = T>,
27  Ref<naMatrix<T, R1, C1, S1>>: ToValue,
28  naMatrix<T, R1, C1, S1>: CompileConst + ConstElem + AsNaKind,
29  R1: Dim + 'static, C1: Dim, S1: StorageMut<T, R1, C1> + Clone + Debug + 'static,
30{
31  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
32    match args {
33      FunctionArgs::Ternary(out, from, step, to) => {
34        let from: Ref<T> = unsafe { from.as_unchecked() }.clone();
35        let step: Ref<T> = unsafe { step.as_unchecked() }.clone();
36        let to: Ref<T> = unsafe { to.as_unchecked() }.clone();
37        let out: Ref<naMatrix<T, R1, C1, S1>> = unsafe { out.as_unchecked() }.clone();
38        Ok(Box::new(Self { from, step, to, out, phantom: PhantomData::default() }))
39      },
40      _ => Err(MechError2::new(
41          IncorrectNumberOfArguments { expected: 3, found: args.len() },
42          None
43        ).with_compiler_loc()
44      ),
45    }
46  }
47}
48impl<T, R1, C1, S1> MechFunctionImpl for RangeIncrementInclusiveScalar<T, naMatrix<T, R1, C1, S1>>
49where
50  Ref<naMatrix<T, R1, C1, S1>>: ToValue,
51  T: Copy + Scalar + Clone + Debug + Sync + Send + 'static + PartialOrd + One + Add<Output = T> + 'static,
52  R1: Dim, C1: Dim, S1: StorageMut<T, R1, C1> + Clone + Debug,
53{
54  fn solve(&self) {
55    unsafe {
56      let out_ptr = self.out.as_ptr() as *mut naMatrix<T, R1, C1, S1>;
57      let mut current = *self.from.as_ptr();
58      let step = *self.step.as_ptr();
59      for i in 0..(*out_ptr).len() {
60        (&mut (*out_ptr))[i] = current;
61        current = current + step;
62      }
63    }
64  }
65  fn out(&self) -> Value { self.out.to_value() }
66  fn to_string(&self) -> String { format!("{:#?}", self) }
67}
68#[cfg(feature = "compiler")]
69impl<T, R1, C1, S1> MechFunctionCompiler for RangeIncrementInclusiveScalar<T, naMatrix<T, R1, C1, S1>> 
70where
71  T: CompileConst + ConstElem + AsValueKind,
72  naMatrix<T, R1, C1, S1>: CompileConst + ConstElem + AsNaKind,
73{
74  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
75    let name = format!("RangeIncrementInclusiveScalar<{}{}>", T::as_value_kind(), naMatrix::<T, R1, C1, S1>::as_na_kind());
76    compile_ternop!(name, self.out, self.from, self.step, self.to, ctx, FeatureFlag::Builtin(FeatureKind::RangeInclusive) );
77  }
78}
79
80#[macro_export]
81macro_rules! impl_range_increment_inclusive_match_arms {
82  ($fxn:ident, $arg1:expr, $arg2:expr, $arg3:expr, $($ty:tt, $feat:tt);+ $(;)?) => {
83    paste! {
84      match ($arg1, $arg2, $arg3) {
85        $(
86          #[cfg(feature = $feat)]
87          (Value::[<$ty:camel>](from), Value::[<$ty:camel>](step), Value::[<$ty:camel>](to))  => {
88            let from_val = *from.borrow();
89            let step_val = *step.borrow();
90            let to_val = *to.borrow();
91            let diff = to_val - from_val;
92            if diff < $ty::zero() {
93              return Err(MechError2::new(
94                EmptyRangeError{},
95                None
96              ).with_compiler_loc());
97            }
98            let size = {
99              let diff = to_val as f64 - from_val as f64;
100              let step = step_val as f64;
101              if step == 0.0 {
102                return Err(MechError2::new(EmptyRangeError {}, None).with_compiler_loc());
103              }
104              if (diff > 0.0 && step > 0.0) || (diff < 0.0 && step < 0.0) {
105                (diff / step).floor() as usize + 1
106              } else if diff == 0.0 {
107                1
108              } else {
109                return Err(MechError2::new(EmptyRangeError {}, None).with_compiler_loc());
110              }
111            };
112            let mut vec = vec![from_val; size];
113            match size {
114              0 => Err(MechError2::new(
115                EmptyRangeError{},
116                None
117              ).with_compiler_loc()),
118              #[cfg(feature = "matrix1")]
119              1 => {
120                register_range!($fxn, $ty, $feat, Matrix1);
121                Ok(Box::new($fxn::<$ty,Matrix1<$ty>>{from: from.clone(), step: step.clone(), to: to.clone(), out: Ref::new(Matrix1::from_element(vec[0])), phantom: PhantomData::default()}))
122              }
123              #[cfg(all(not(feature = "matrix1"), feature = "matrixd")  )]
124              1 => {
125                register_range!($fxn, $ty, $feat, DMatrix);
126                Ok(Box::new($fxn::<$ty,DMatrix<$ty>>{from: from.clone(), step: step.clone(), to: to.clone(), out: Ref::new(DMatrix::from_element(1,1,vec[0])), phantom: PhantomData::default()}))
127              }
128              #[cfg(feature = "row_vector2")]
129              2 => {
130                register_range!($fxn, $ty, $feat, RowVector2);
131                Ok(Box::new($fxn::<$ty,RowVector2<$ty>>{from: from.clone(), step: step.clone(), to: to.clone(), out: Ref::new(RowVector2::from_vec(vec)), phantom: PhantomData::default()}))
132              }
133              #[cfg(feature = "row_vector3")]
134              3 => {              
135                register_range!($fxn, $ty, $feat, RowVector3);
136                Ok(Box::new($fxn::<$ty,RowVector3<$ty>>{from: from.clone(), step: step.clone(), to: to.clone(), out: Ref::new(RowVector3::from_vec(vec)), phantom: PhantomData::default()}))
137              }
138              #[cfg(feature = "row_vector4")]
139              4 => {
140                register_range!($fxn, $ty, $feat, RowVector4);
141                Ok(Box::new($fxn::<$ty,RowVector4<$ty>>{from: from.clone(), step: step.clone(), to: to.clone(), out: Ref::new(RowVector4::from_vec(vec)), phantom: PhantomData::default()}))
142              }
143              #[cfg(feature = "row_vectord")]
144              n => {
145                register_range!($fxn, $ty, $feat, RowDVector);
146                Ok(Box::new($fxn::<$ty,RowDVector<$ty>>{from: from.clone(), step: step.clone(), to: to.clone(), out: Ref::new(RowDVector::from_vec(vec)), phantom: PhantomData::default()}))
147              }
148            }
149          }
150        )+
151        (arg1,arg2,arg3) => Err(MechError2::new(
152          UnhandledFunctionArgumentKind3 {arg: (arg1.kind(),arg2.kind(), arg3.kind()), fxn_name: stringify!($fxn).to_string() },
153          None
154        ).with_compiler_loc()),
155      }
156    }
157  }
158}
159
160fn impl_range_increment_inclusive_fxn(arg1_value: Value, arg2_value: Value, arg3_value: Value) -> MResult<Box<dyn MechFunction>> {
161  impl_range_increment_inclusive_match_arms!(RangeIncrementInclusiveScalar, arg1_value, arg2_value, arg3_value,
162    f32, "f32";
163    f64, "f64";
164    i8,  "i8";
165    i16, "i16";
166    i32, "i32";
167    i64, "i64";
168    i128,"i128";
169    u8,  "u8";
170    u16, "u16";
171    u32, "u32";
172    u64, "u64";
173    u128,"u128";
174  )
175}
176
177pub struct RangeIncrementInclusive {}
178
179impl NativeFunctionCompiler for RangeIncrementInclusive {
180  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
181    if arguments.len() != 3 {
182      return Err(MechError2::new(IncorrectNumberOfArguments { expected: 3, found: arguments.len() },None).with_compiler_loc());
183    }
184    let arg1 = arguments[0].clone();
185    let arg2 = arguments[1].clone();
186    let arg3 = arguments[2].clone();
187    match impl_range_increment_inclusive_fxn(arg1.clone(), arg2.clone(), arg3.clone()) {
188      Ok(fxn) => Ok(fxn),
189      Err(_) => {
190        match (arg1, arg2, arg3) {
191          (Value::MutableReference(arg1), Value::MutableReference(arg2), Value::MutableReference(arg3)) => {
192            impl_range_increment_inclusive_fxn(arg1.borrow().clone(), arg2.borrow().clone(), arg3.borrow().clone())
193          }
194          (Value::MutableReference(arg1), Value::MutableReference(arg2), arg3) => {
195            impl_range_increment_inclusive_fxn(arg1.borrow().clone(), arg2.borrow().clone(), arg3.clone())
196          }
197          (Value::MutableReference(arg1), arg2, Value::MutableReference(arg3)) => {
198            impl_range_increment_inclusive_fxn(arg1.borrow().clone(), arg2.clone(), arg3.borrow().clone())
199          }
200          (Value::MutableReference(arg1), arg2, arg3) => {
201            impl_range_increment_inclusive_fxn(arg1.borrow().clone(), arg2.clone(), arg3.clone())
202          }
203          (arg1, Value::MutableReference(arg2), Value::MutableReference(arg3)) => {
204            impl_range_increment_inclusive_fxn(arg1.clone(), arg2.borrow().clone(), arg3.borrow().clone())
205          }
206          (arg1, Value::MutableReference(arg2), arg3) => {
207            impl_range_increment_inclusive_fxn(arg1.clone(), arg2.borrow().clone(), arg3.clone())
208          }
209          (arg1, arg2, Value::MutableReference(arg3)) => {
210            impl_range_increment_inclusive_fxn(arg1.clone(), arg2.clone(), arg3.borrow().clone())
211          }
212          (arg1, arg2, arg3) => Err(MechError2::new(
213            UnhandledFunctionArgumentKind3 { arg: (arg1.kind(), arg2.kind(), arg3.kind()), fxn_name: "range/inclusive-increment".to_string() },
214            None
215          ).with_compiler_loc()),
216        }
217      }
218    }
219  }
220}
221
222register_descriptor! {
223  FunctionCompilerDescriptor {
224    name: "range/inclusive-increment",
225    ptr: &RangeIncrementInclusive{},
226  }
227}