mech_range/
inclusive.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// Inclusive ------------------------------------------------------------------
13
14#[derive(Debug)]
15pub struct RangeInclusiveScalar<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 RangeInclusiveScalar<T, naMatrix<T, R1, C1, S1>>
22where
23  T: Copy + Debug + Clone + Sync + Send + 
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(MechError2::new(
39          IncorrectNumberOfArguments { expected: 3, found: args.len() },
40          None
41        ).with_compiler_loc()
42      ),
43    }
44  }
45}
46impl<T, R1, C1, S1> MechFunctionImpl for RangeInclusiveScalar<T, naMatrix<T, R1, C1, S1>>
47where
48  Ref<naMatrix<T, R1, C1, S1>>: ToValue,
49  T: Scalar + Clone + Debug + Sync + Send + 'static + PartialOrd + One + Add<Output = T> + 'static,
50  R1: Dim, C1: Dim, S1: StorageMut<T, R1, C1> + Clone + Debug,
51{
52  fn solve(&self) {
53    let from_ptr = self.from.as_ptr();
54    let to_ptr = self.to.as_ptr();
55    let out_ptr = self.out.as_mut_ptr();
56    let mut current = from_ptr;
57    unsafe {
58      for val in (*out_ptr).iter_mut() {
59        *val = (*current).clone();
60        current = &(*current).clone().add(T::one());
61      }
62    }
63  }
64  fn out(&self) -> Value { self.out.to_value() }
65  fn to_string(&self) -> String { format!("{:#?}", self) }
66}
67#[cfg(feature = "compiler")]
68impl<T, R1, C1, S1> MechFunctionCompiler for RangeInclusiveScalar<T, naMatrix<T, R1, C1, S1>> 
69where
70  T: CompileConst + ConstElem + AsValueKind,
71  naMatrix<T, R1, C1, S1>: CompileConst + ConstElem + AsNaKind,
72{
73  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
74    let name = format!("RangeInclusiveScalar<{}{}>", T::as_value_kind(), naMatrix::<T, R1, C1, S1>::as_na_kind());
75    compile_binop!(name, self.out, self.from, self.to, ctx, FeatureFlag::Builtin(FeatureKind::RangeInclusive) );
76  }
77}
78
79
80
81#[macro_export]
82macro_rules! impl_range_inclusive_match_arms {
83  ($fxn:ident, $arg1:expr, $arg2:expr, $($ty:tt, $feat:tt);+ $(;)?) => {
84    paste! {
85      match ($arg1, $arg2) {
86        $(
87          #[cfg(feature = $feat)]
88          (Value::[<$ty:camel>](from), Value::[<$ty:camel>](to))  => {
89            let from_val = *from.borrow();
90            let to_val = *to.borrow();
91            let diff = to_val - from_val + $ty::one();
92            if diff < $ty::zero() {
93              return Err(MechError2::new(
94                EmptyRangeError{},
95                None
96              ).with_compiler_loc());
97            }
98            let size = range_size_to_usize!(diff, $ty);           
99            let mut vec = vec![from_val; size];
100            match size {
101              0 => Err(MechError2::new(
102                EmptyRangeError{},
103                None
104              ).with_compiler_loc()),
105              #[cfg(feature = "matrix1")]
106              1 => {
107                register_range!($fxn, $ty, $feat, Matrix1);
108                Ok(Box::new($fxn::<$ty,Matrix1<$ty>>{from: from.clone(), to: to.clone(), out: Ref::new(Matrix1::from_element(vec[0])), phantom: PhantomData::default()}))
109              }
110              #[cfg(all(not(feature = "matrix1"), feature = "matrixd")  )]
111              1 => {
112                register_range!($fxn, $ty, $feat, DMatrix);
113                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()}))
114              }
115              #[cfg(feature = "row_vector2")]
116              2 => {
117                register_range!($fxn, $ty, $feat, RowVector2);
118                Ok(Box::new($fxn::<$ty,RowVector2<$ty>>{from: from.clone(), to: to.clone(), out: Ref::new(RowVector2::from_vec(vec)), phantom: PhantomData::default()}))
119              }
120              #[cfg(feature = "row_vector3")]
121              3 => {              
122                register_range!($fxn, $ty, $feat, RowVector3);
123                Ok(Box::new($fxn::<$ty,RowVector3<$ty>>{from: from.clone(), to: to.clone(), out: Ref::new(RowVector3::from_vec(vec)), phantom: PhantomData::default()}))
124              }
125              #[cfg(feature = "row_vector4")]
126              4 => {
127                register_range!($fxn, $ty, $feat, RowVector4);
128                Ok(Box::new($fxn::<$ty,RowVector4<$ty>>{from: from.clone(), to: to.clone(), out: Ref::new(RowVector4::from_vec(vec)), phantom: PhantomData::default()}))
129              }
130              #[cfg(feature = "row_vectord")]
131              n => {
132                register_range!($fxn, $ty, $feat, RowDVector);
133                Ok(Box::new($fxn::<$ty,RowDVector<$ty>>{from: from.clone(), to: to.clone(), out: Ref::new(RowDVector::from_vec(vec)), phantom: PhantomData::default()}))
134              }
135            }
136          }
137        )+
138        (arg1,arg2) => Err(MechError2::new(
139          UnhandledFunctionArgumentKind2 {arg: (arg1.kind(),arg2.kind()), fxn_name: stringify!($fxn).to_string() },
140          None
141        ).with_compiler_loc()),
142      }
143    }
144  }
145}
146
147fn impl_range_inclusive_fxn(arg1_value: Value, arg2_value: Value) -> MResult<Box<dyn MechFunction>> {
148  impl_range_inclusive_match_arms!(RangeInclusiveScalar, arg1_value, arg2_value,
149    f32, "f32";
150    f64, "f64";
151    i8,  "i8";
152    i16, "i16";
153    i32, "i32";
154    i64, "i64";
155    i128,"i128";
156    u8,  "u8";
157    u16, "u16";
158    u32, "u32";
159    u64, "u64";
160    u128,"u128";
161  )
162}
163
164pub struct RangeInclusive {}
165
166impl NativeFunctionCompiler for RangeInclusive {
167  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
168    if arguments.len() != 2 {
169      return Err(MechError2::new(IncorrectNumberOfArguments { expected: 1, found: arguments.len() },None).with_compiler_loc());
170    }
171    let arg1 = arguments[0].clone();
172    let arg2 = arguments[1].clone();
173    match impl_range_inclusive_fxn(arg1.clone(), arg2.clone()) {
174      Ok(fxn) => Ok(fxn),
175      Err(_) => {
176        match (arg1,arg2) {
177          (Value::MutableReference(arg1),Value::MutableReference(arg2)) => {impl_range_inclusive_fxn(arg1.borrow().clone(),arg2.borrow().clone())}
178          (Value::MutableReference(arg1),arg2) => {impl_range_inclusive_fxn(arg1.borrow().clone(),arg2.clone())}
179          (arg1,Value::MutableReference(arg2)) => {impl_range_inclusive_fxn(arg1.clone(),arg2.borrow().clone())}
180          (arg1,arg2) => Err(MechError2::new(
181              UnhandledFunctionArgumentKind2 { arg: (arg1.kind(),arg2.kind()), fxn_name: "range/inclusive".to_string() },
182              None
183            ).with_compiler_loc()
184          ),
185        }
186      }
187    }
188  }
189}
190
191register_descriptor! {
192  FunctionCompilerDescriptor {
193    name: "range/inclusive",
194    ptr: &RangeInclusive{},
195  }
196}