1#[macro_use]
2use crate::stdlib::*;
3
4#[cfg(feature = "enum")]
7#[derive(Debug)]
8struct ConvertSEnum {
9 out: Ref<MechEnum>,
10}
11#[cfg(feature = "enum")]
12impl MechFunctionFactory for ConvertSEnum {
13 fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
14 match args {
15 FunctionArgs::Unary(out, _) => {
16 let out: Ref<MechEnum> = unsafe { out.as_unchecked() }.clone();
17 Ok(Box::new(Self {out}))
18 },
19 _ => Err(MechError::new(
20 IncorrectNumberOfArguments { expected: 1, found: args.len() },
21 None
22 ).with_compiler_loc()
23 ),
24 }
25 }
26}
27#[cfg(feature = "enum")]
28impl MechFunctionImpl for ConvertSEnum
29{
30 fn solve(&self) { }
31 fn out(&self) -> Value { Value::Enum(self.out.clone()) }
32 fn to_string(&self) -> String { format!("{:#?}", self) }
33}
34#[cfg(all(feature = "compiler", feature = "enum"))]
35impl MechFunctionCompiler for ConvertSEnum {
36 fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
37 let name = format!("ConvertSEnum<enum>");
38 compile_nullop!(name, self.out, ctx, FeatureFlag::Builtin(FeatureKind::Convert));
39 }
40}
41#[cfg(feature = "enum")]
42register_descriptor! {
43 FunctionDescriptor {
44 name: "ConvertSEnum<enum>",
45 ptr: ConvertSEnum::new,
46 }
47}
48
49#[derive(Debug)]
50struct ConvertSEmpty {
51 out: Ref<Value>,
52}
53
54impl MechFunctionImpl for ConvertSEmpty {
55 fn solve(&self) { }
56 fn out(&self) -> Value { self.out.borrow().clone() }
57 fn to_string(&self) -> String { format!("{:#?}", self) }
58}
59#[cfg(feature = "compiler")]
60impl MechFunctionCompiler for ConvertSEmpty {
61 fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
62 let name = format!("ConvertSEmpty<empty>");
63 compile_nullop!(name, self.out, ctx, FeatureFlag::Builtin(FeatureKind::Convert));
64 }
65}
66register_descriptor! {
67 FunctionDescriptor {
68 name: "ConvertSEmpty<empty>",
69 ptr: |args: FunctionArgs| -> MResult<Box<dyn MechFunction>> {
70 match args {
71 FunctionArgs::Nullary(out) => {
72 let out: Ref<Value> = unsafe { out.as_unchecked() }.clone();
73 Ok(Box::new(ConvertSEmpty { out }))
74 },
75 _ => Err(MechError::new(
76 IncorrectNumberOfArguments { expected: 0, found: args.len() },
77 None
78 ).with_compiler_loc()
79 ),
80 }
81 },
82 }
83}
84
85#[cfg(all(feature = "matrix", feature = "table"))]
86#[derive(Debug)]
87struct ConvertMat2Table<T> {
88 arg: Matrix<T>,
89 out: Ref<MechTable>,
90}
91
92#[cfg(all(feature = "matrix", feature = "table"))]
93impl<T> MechFunctionImpl for ConvertMat2Table<T>
94where T: Debug + Clone + PartialEq + Into<Value> + 'static,
95{
96 fn solve(&self) {
97 let arg = &self.arg;
98 let mut out_table = self.out.borrow_mut();
99 let rows = arg.rows().min(out_table.rows);
100
101 for (col_ix, (ix, (col_kind, out_col))) in out_table.data.iter_mut().enumerate() {
102 for row_ix in 0..rows {
103 let value = arg.index2d(row_ix + 1, col_ix + 1).clone().into();
104 let converted_value = value.convert_to(col_kind).unwrap();
105 out_col.set_index1d(row_ix, converted_value);
106 }
107 }
108 }
109 fn out(&self) -> Value { Value::Table(self.out.clone()) }
110 fn to_string(&self) -> String { format!("{:#?}", self) }
111}
112#[cfg(all(feature = "compiler", feature = "matrix", feature = "table"))]
113impl<T> MechFunctionCompiler for ConvertMat2Table<T>
114where
115 T: ConstElem + CompileConst + AsValueKind,
116{
117 fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
118 let mut registers = [0,0];
119
120 registers[0] = compile_register_brrw!(self.out, ctx);
121 registers[1] = compile_register!(self.arg, ctx);
122
123 ctx.features.insert(FeatureFlag::Builtin(FeatureKind::Convert));
124
125 ctx.emit_unop(
126 hash_str("ConvertMat2Table"),
127 registers[0],
128 registers[1],
129 );
130
131 return Ok(registers[0]);
132 }
133}
134
135#[cfg(all(feature = "matrix", feature = "table"))]
136fn resolve_table_column_kinds(tbl: &Vec<(String, ValueKind)>, mat_knd: ValueKind) -> MResult<Vec<(String, ValueKind)>> {
137 tbl
138 .iter()
139 .map(|(col_name, col_kind)| {
140 if *col_kind == ValueKind::Any {
141 Ok((col_name.clone(), mat_knd.clone()))
142 } else if *col_kind == mat_knd || mat_knd.is_convertible_to(col_kind) {
143 Ok((col_name.clone(), col_kind.clone()))
144 } else {
145 Err(
146 MechError::new(
147 ColumnConvertKindMismatchError { from: mat_knd.clone(), to: col_kind.clone() },
148 None,
149 ).with_compiler_loc()
150 )
151 }
152 })
153 .collect()
154}
155
156#[cfg(all(feature = "matrix", feature = "set"))]
157fn matrix_to_values(value: &Value) -> Option<Vec<Value>> {
158 match value {
159 Value::MutableReference(reference) => matrix_to_values(&reference.borrow()),
160 Value::MatrixIndex(matrix) => Some(matrix.as_vec().into_iter().map(|value| Value::Index(Ref::new(value))).collect()),
161 #[cfg(feature = "bool")]
162 Value::MatrixBool(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
163 #[cfg(feature = "u8")]
164 Value::MatrixU8(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
165 #[cfg(feature = "u16")]
166 Value::MatrixU16(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
167 #[cfg(feature = "u32")]
168 Value::MatrixU32(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
169 #[cfg(feature = "u64")]
170 Value::MatrixU64(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
171 #[cfg(feature = "u128")]
172 Value::MatrixU128(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
173 #[cfg(feature = "i8")]
174 Value::MatrixI8(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
175 #[cfg(feature = "i16")]
176 Value::MatrixI16(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
177 #[cfg(feature = "i32")]
178 Value::MatrixI32(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
179 #[cfg(feature = "i64")]
180 Value::MatrixI64(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
181 #[cfg(feature = "i128")]
182 Value::MatrixI128(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
183 #[cfg(feature = "f32")]
184 Value::MatrixF32(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
185 #[cfg(feature = "f64")]
186 Value::MatrixF64(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
187 #[cfg(feature = "string")]
188 Value::MatrixString(matrix) => Some(matrix.as_vec().into_iter().map(Value::from).collect()),
189 #[cfg(feature = "rational")]
190 Value::MatrixR64(matrix) => Some(matrix.as_vec().into_iter().map(|value| value.to_value()).collect()),
191 #[cfg(feature = "complex")]
192 Value::MatrixC64(matrix) => Some(matrix.as_vec().into_iter().map(|value| value.to_value()).collect()),
193 Value::MatrixValue(matrix) => Some(matrix.as_vec()),
194 _ => None,
195 }
196}
197
198#[cfg(all(feature = "matrix", feature = "set"))]
199#[derive(Debug)]
200struct ConvertMatToSet {
201 arg: Value,
202 target_kind: ValueKind,
203 out: Ref<MechSet>,
204}
205
206#[cfg(all(feature = "matrix", feature = "set"))]
207impl MechFunctionImpl for ConvertMatToSet {
208 fn solve(&self) {
209 let values = matrix_to_values(&self.arg).unwrap_or_default();
210 let converted_values = values
211 .into_iter()
212 .map(|value| {
213 value
214 .convert_to(&self.target_kind)
215 .unwrap_or_else(|| panic!("Unable to convert matrix element to target set kind {}", self.target_kind))
216 })
217 .collect::<Vec<_>>();
218 *self.out.borrow_mut() = MechSet::from_vec(converted_values);
219 }
220 fn out(&self) -> Value { Value::Set(self.out.clone()) }
221 fn to_string(&self) -> String { format!("{:#?}", self) }
222}
223#[cfg(all(feature = "compiler", feature = "matrix", feature = "set"))]
224impl MechFunctionCompiler for ConvertMatToSet {
225 fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
226 let name = format!("ConvertMatToSet");
227 compile_nullop!(name, self.out, ctx, FeatureFlag::Builtin(FeatureKind::Convert));
228 }
229}
230
231#[cfg(all(feature = "rational", feature = "f64"))]
232#[derive(Debug)]
233struct ConvertSRationalToF64 {
234 arg: Ref<R64>,
235 out: Ref<f64>,
236}
237
238#[cfg(all(feature = "rational", feature = "f64"))]
239impl MechFunctionImpl for ConvertSRationalToF64 {
240 fn solve(&self) {
241 let arg_ptr = self.arg.as_ptr();
242 let out_ptr = self.out.as_mut_ptr();
243 unsafe{ *out_ptr = (*arg_ptr).into(); }
244 }
245 fn out(&self) -> Value { Value::F64(self.out.clone()) }
246 fn to_string(&self) -> String { format!("{:#?}", self) }
247}
248#[cfg(all(feature = "compiler", feature = "rational", feature = "f64"))]
249impl MechFunctionCompiler for ConvertSRationalToF64 {
250 fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
251 let name = format!("ConvertSRationalToF64<f64>");
252 compile_unop!(name, self.out, self.arg, ctx, FeatureFlag::Builtin(FeatureKind::Convert));
253 }
254}
255
256macro_rules! impl_conversion_match_arms {
257 ($arg:expr, $($input_type:ident, $input_type_string:tt => $($target_type:ident, $target_type_string:tt),+);+ $(;)?) => {
258 paste!{
259 match $arg {
260 $(
261 #[cfg(all(feature = "matrix", feature = "table", feature = $input_type_string))]
262 (Value::[<Matrix $input_type:camel>](mat), Value::Kind(ValueKind::Table(tbl, sze))) => {
263 let in_shape = mat.shape();
264 let tbl_cols = tbl.len();
265 let mat_knd = ValueKind::[<$input_type:camel>];
266 if in_shape[1] != tbl_cols {
268 return Err(MechError::new(
269 ConvertIncorrectNumberOfColumnsError{from: in_shape[1], to: tbl_cols},
270 None,
271 ).with_compiler_loc());
272 }
273 let resolved_tbl = resolve_table_column_kinds(&tbl, mat_knd)?;
274 let out_rows = if sze == 0 { in_shape[0] } else { sze };
276 let out = MechTable::from_kind(ValueKind::Table(resolved_tbl, out_rows))?;
277 Ok(Box::new(ConvertMat2Table::<$input_type>{arg: mat.clone(), out: Ref::new(out)}))
278 }
279 $(
280 #[cfg(all(feature = $input_type_string, feature = $target_type_string))]
281 (Value::[<$input_type:camel>](arg), Value::Kind(ValueKind::[<$target_type:camel>])) => {Ok(Box::new(ConvertScalarToScalarBasic{arg: arg.clone(), out: Ref::new($target_type::default())}))},
282 )+
283 )+
284 #[cfg(feature = "rational")]
285 (Value::R64(ref rat), Value::Kind(ValueKind::F64)) => {
286 Ok(Box::new(ConvertSRationalToF64{arg: rat.clone(), out: Ref::new(f64::default())}))
287 }
288 #[cfg(all(feature = "atom", feature = "enum"))]
289 (Value::Atom(atom), Value::Kind(ValueKind::Enum(enum_id, enum_variant_name))) => {
290 let atom_brrw = atom.borrow();
291 let variant_id = atom_brrw.id();
292 let atom_name = atom_brrw.name();
293 let variants = vec![(variant_id,None)];
294 let dictionary = (*atom_brrw).dictionary();
295 let enm = MechEnum{id: enum_id, variants, names: dictionary};
296 let val = Ref::new(enm.clone());
297 todo!("This isn't finished yet");
298 Ok(Box::new(ConvertSEnum{out: val}))
299 }
300 (Value::Empty, Value::Kind(ValueKind::Empty)) => {
301 Ok(Box::new(ConvertSEmpty { out: Ref::new(Value::Empty) }))
302 }
303 (value, Value::Kind(ValueKind::Option(inner_kind))) => {
304 let converted = if value == Value::Empty {
305 Value::Empty
306 } else {
307 value
308 .convert_to(inner_kind.as_ref())
309 .ok_or_else(|| MechError::new(
310 UnsupportedConversionError { from: value.kind(), to: ValueKind::Option(inner_kind.clone()) },
311 None,
312 ).with_compiler_loc())?
313 };
314 Ok(Box::new(ConvertSEmpty { out: Ref::new(converted) }))
315 }
316 x => Err(MechError::new(
317 UnsupportedConversionError{from: x.0.kind(), to: x.1.kind()},
318 None,
319 ).with_compiler_loc()
320 ),
321 }
322 }
323 }
324}
325
326#[derive(Debug)]
327pub struct ConvertScalarToScalar<F, T> {
328 pub arg: Ref<F>,
329 pub out: Ref<T>,
330}
331
332impl<F, T> MechFunctionImpl for ConvertScalarToScalar<F, T>
333where
334 Ref<T>: ToValue,
335 F: LosslessInto<T> + Debug + Clone,
336 T: Debug,
337{
338 fn solve(&self) {
339 let arg_ptr = self.arg.as_ptr();
340 let out_ptr = self.out.as_mut_ptr();
341 unsafe {
342 let out_ref: &mut T = &mut *out_ptr;
343 let arg_ref: &F = &*arg_ptr;
344 *out_ref = arg_ref.clone().lossless_into();
345 }
346 }
347 fn out(&self) -> Value { self.out.to_value() }
348 fn to_string(&self) -> String { format!("{:#?}", self) }
349}
350#[cfg(feature = "compiler")]
351impl<F, T> MechFunctionCompiler for ConvertScalarToScalar<F, T>
352where
353 F: ConstElem + CompileConst + AsValueKind,
354 T: ConstElem + CompileConst + AsValueKind,
355{
356 fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
357 let name = format!("ConvertScalarToScalar<{},{}>", F::as_value_kind(), T::as_value_kind());
358 compile_unop!(name, self.out, self.arg, ctx, FeatureFlag::Builtin(FeatureKind::Convert));
359 }
360}
361
362#[derive(Debug)]
363pub struct ConvertScalarToScalarBasic<F, T> {
364 pub arg: Ref<F>,
365 pub out: Ref<T>,
366}
367
368impl<F, T> MechFunctionImpl for ConvertScalarToScalarBasic<F, T>
369where
370 Ref<T>: ToValue,
371 F: Debug + Clone,
372 T: Debug + LossyFrom<F>,
373{
374 fn solve(&self) {
375 let arg_ptr = self.arg.as_ptr();
376 let out_ptr = self.out.as_mut_ptr();
377 unsafe {
378 let out_ref: &mut T = &mut *out_ptr;
379 let arg_ref: &F = &*arg_ptr;
380 *out_ref = T::lossy_from(arg_ref.clone());
381 }
382 }
383 fn out(&self) -> Value { self.out.to_value() }
384 fn to_string(&self) -> String { format!("{:#?}", self) }
385}
386#[cfg(feature = "compiler")]
387impl<F,T> MechFunctionCompiler for ConvertScalarToScalarBasic<F, T>
388where
389 F: ConstElem + CompileConst + AsValueKind,
390 T: ConstElem + CompileConst + AsValueKind,
391{
392 fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
393 let name = format!("ConvertScalarToScalarBasic<{},{}>", F::as_value_kind(), T::as_value_kind());
394 compile_unop!(name, self.out, self.arg, ctx, FeatureFlag::Builtin(FeatureKind::Convert));
395 }
396}
397
398fn impl_conversion_fxn(source_value: Value, target_kind: Value) -> MResult<Box<dyn MechFunction>> {
399 if let (Value::Typed(inner, declared_kind), Value::Kind(target_vk)) = (&source_value, &target_kind) {
400 if declared_kind == target_vk {
401 return Ok(Box::new(ConvertSEmpty {
402 out: Ref::new(Value::Typed(inner.clone(), declared_kind.clone())),
403 }));
404 }
405 return impl_conversion_fxn((**inner).clone(), target_kind);
406 }
407
408 match (&source_value, &target_kind) {
409 #[cfg(all(feature = "matrix", feature = "set"))]
410 (source, Value::Kind(ValueKind::Set(target_kind, _))) => {
411 if let Some(values) = matrix_to_values(source) {
412 let converted_values = values
413 .into_iter()
414 .map(|value| value.convert_to(target_kind))
415 .collect::<Option<Vec<_>>>();
416 if let Some(converted_values) = converted_values {
417 return Ok(Box::new(ConvertMatToSet {
418 arg: source_value.clone(),
419 target_kind: target_kind.as_ref().clone(),
420 out: Ref::new(MechSet::from_vec(converted_values)),
421 }));
422 }
423 }
424 }
425 #[cfg(all(feature = "rational", feature = "f64"))]
426 (Value::R64(r), Value::Kind(ValueKind::F64)) => {return Ok(Box::new(ConvertScalarToScalar{arg: r.clone(),out: Ref::new(f64::default()),}));}
427 #[cfg(all(feature = "matrix", feature = "table", feature = "string"))]
428 (Value::MatrixString(mat), Value::Kind(ValueKind::Table(tbl, sze))) => {
429 let in_shape = mat.shape();
430 if in_shape[1] != tbl.len() {
432 return Err(MechError::new(
433 ConvertIncorrectNumberOfColumnsError{from: in_shape[1], to: tbl.len()},
434 None,
435 ).with_compiler_loc());
436 }
437 let resolved_tbl = resolve_table_column_kinds(tbl, ValueKind::String)?;
438 let out_rows = if *sze == 0 { in_shape[0] } else { *sze };
440 let out = MechTable::from_kind(ValueKind::Table(resolved_tbl, out_rows))?;
441 return Ok(Box::new(ConvertMat2Table::<String>{arg: mat.clone(), out: Ref::new(out)}));
442 }
443 #[cfg(all(feature = "matrix", feature = "table", feature = "bool"))]
444 (Value::MatrixBool(mat), Value::Kind(ValueKind::Table(tbl, sze))) => {
445 let in_shape = mat.shape();
446 if in_shape[1] != tbl.len() {
448 return Err(MechError::new(
449 ConvertIncorrectNumberOfColumnsError{from: in_shape[1], to: tbl.len()},
450 None,
451 ).with_compiler_loc());
452 }
453 let resolved_tbl = resolve_table_column_kinds(tbl, ValueKind::Bool)?;
454 let out_rows = if *sze == 0 { in_shape[0] } else { *sze };
456 let out = MechTable::from_kind(ValueKind::Table(resolved_tbl, out_rows))?;
457 return Ok(Box::new(ConvertMat2Table::<bool>{arg: mat.clone(), out: Ref::new(out)}));
458 }
459 #[cfg(all(feature = "matrix", feature = "table"))]
460 (Value::Table(table), Value::Kind(ValueKind::Matrix(target_kind, dims))) => {
461 let table = table.borrow();
462 let rows = table.rows();
463 let cols = table.cols();
464
465 if !dims.is_empty() {
466 let dim_count = dims.iter().product::<usize>();
467 if dim_count != rows * cols {
468 return Err(MechError::new(
469 ConvertIncorrectNumberOfColumnsError { from: rows * cols, to: dim_count },
470 None,
471 ).with_compiler_loc());
472 }
473 }
474
475 let mut elements = Vec::with_capacity(rows * cols);
476 for (_column_id, (_kind, column_values)) in table.data.iter() {
477 elements.extend(column_values.as_vec());
478 }
479
480 if target_kind.as_ref() != &ValueKind::Any {
481 return Err(MechError::new(
482 UnhandledFunctionArgumentKind2 {
483 arg: (
484 source_value.kind(),
485 ValueKind::Matrix(target_kind.clone(), dims.clone()),
486 ),
487 fxn_name: "convert/scalar".to_string(),
488 },
489 None,
490 ).with_compiler_loc());
491 }
492
493 let matrix = Value::MatrixValue(Matrix::from_vec(elements, rows, cols));
494 return Ok(Box::new(ConvertSEmpty { out: Ref::new(matrix) }));
495 }
496 _ =>(),
497 }
498 impl_conversion_match_arms!(
499 (source_value, target_kind),
500 i8, "i8" => String, "string", i8, "i8", i16, "i16", i32, "i32", i64, "i64", i128, "i128", u8, "u8", u16, "u16", u32, "u32", u64, "u64", u128, "u128", f32, "f32", f64, "f64";
501 i16, "i16" => String, "string", i8, "i8", i16, "i16", i32, "i32", i64, "i64", i128, "i128", u8, "u8", u16, "u16", u32, "u32", u64, "u64", u128, "u128", f32, "f32", f64, "f64";
502 i32, "i32" => String, "string", i8, "i8", i16, "i16", i32, "i32", i64, "i64", i128, "i128", u8, "u8", u16, "u16", u32, "u32", u64, "u64", u128, "u128", f32, "f32", f64, "f64";
503 i64, "i64" => String, "string", i8, "i8", i16, "i16", i32, "i32", i64, "i64", i128, "i128", u8, "u8", u16, "u16", u32, "u32", u64, "u64", u128, "u128", f32, "f32", f64, "f64";
504 i128, "i128" => String, "string", i8, "i8", i16, "i16", i32, "i32", i64, "i64", i128, "i128", u8, "u8", u16, "u16", u32, "u32", u64, "u64", u128, "u128", f32, "f32", f64, "f64";
505 u8, "u8" => String, "string", i8, "i8", i16, "i16", i32, "i32", i64, "i64", i128, "i128", u8, "u8", u16, "u16", u32, "u32", u64, "u64", u128, "u128", f32, "f32", f64, "f64";
506 u16, "u16" => String, "string", i8, "i8", i16, "i16", i32, "i32", i64, "i64", i128, "i128", u8, "u8", u16, "u16", u32, "u32", u64, "u64", u128, "u128", f32, "f32", f64, "f64";
507 u32, "u32" => String, "string", i8, "i8", i16, "i16", i32, "i32", i64, "i64", i128, "i128", u8, "u8", u16, "u16", u32, "u32", u64, "u64", u128, "u128", f32, "f32", f64, "f64";
508 u64, "u64" => String, "string", i8, "i8", i16, "i16", i32, "i32", i64, "i64", i128, "i128", u8, "u8", u16, "u16", u32, "u32", u64, "u64", u128, "u128", f32, "f32", f64, "f64";
509 u128, "u128" => String, "string", i8, "i8", i16, "i16", i32, "i32", i64, "i64", i128, "i128", u8, "u8", u16, "u16", u32, "u32", u64, "u64", u128, "u128", f32, "f32", f64, "f64";
510 f32, "f32" => String, "string", i8, "i8", i16, "i16", i32, "i32", i64, "i64", i128, "i128", u8, "u8", u16, "u16", u32, "u32", u64, "u64", u128, "u128", f32, "f32", f64, "f64";
511 f64, "f64" => String, "string", i8, "i8", i16, "i16", i32, "i32", i64, "i64", i128, "i128", u8, "u8", u16, "u16", u32, "u32", u64, "u64", u128, "u128", f32, "f32", f64, "f64", R64, "rational";
512 R64, "rational" => String, "string", f64, "f64";
513 String, "string" => String, "string";
514 bool, "bool" => String, "string", bool, "bool";
515 )
516}
517
518pub struct ConvertKind {}
519
520impl NativeFunctionCompiler for ConvertKind {
521 fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
522 if arguments.len() != 2 {
523 return Err(MechError::new(IncorrectNumberOfArguments { expected: 1, found: arguments.len() }, None).with_compiler_loc());
524 }
525 let source_value = arguments[0].clone();
526 let target_kind = arguments[1].clone();
527 match impl_conversion_fxn(source_value.clone(), target_kind.clone()) {
528 Ok(fxn) => Ok(fxn),
529 Err(_) => {
530 match source_value {
531 Value::MutableReference(rhs) => impl_conversion_fxn(rhs.borrow().clone(), target_kind.clone()),
532 #[cfg(feature = "atom")]
533 Value::Atom(ref atom_id) => impl_conversion_fxn(source_value, target_kind.clone()),
534 #[cfg(all(feature = "matrix", feature = "u8"))]
535 Value::MatrixU8(ref mat) => impl_conversion_fxn(source_value, target_kind.clone()),
536 #[cfg(all(feature = "matrix", feature = "u16"))]
537 Value::MatrixU16(ref mat) => impl_conversion_fxn(source_value, target_kind.clone()),
538 #[cfg(all(feature = "matrix", feature = "u32"))]
539 Value::MatrixU32(ref mat) => impl_conversion_fxn(source_value, target_kind.clone()),
540 #[cfg(all(feature = "matrix", feature = "u64"))]
541 Value::MatrixU64(ref mat) => impl_conversion_fxn(source_value, target_kind.clone()),
542 #[cfg(all(feature = "matrix", feature = "u128"))]
543 Value::MatrixU128(ref mat) => impl_conversion_fxn(source_value, target_kind.clone()),
544 #[cfg(all(feature = "matrix", feature = "i8"))]
545 Value::MatrixI8(ref mat) => impl_conversion_fxn(source_value, target_kind.clone()),
546 #[cfg(all(feature = "matrix", feature = "i16"))]
547 Value::MatrixI16(ref mat) => impl_conversion_fxn(source_value, target_kind.clone()),
548 #[cfg(all(feature = "matrix", feature = "i32"))]
549 Value::MatrixI32(ref mat) => impl_conversion_fxn(source_value, target_kind.clone()),
550 #[cfg(all(feature = "matrix", feature = "i64"))]
551 Value::MatrixI64(ref mat) => impl_conversion_fxn(source_value, target_kind.clone()),
552 #[cfg(all(feature = "matrix", feature = "i128"))]
553 Value::MatrixI128(ref mat) => impl_conversion_fxn(source_value, target_kind.clone()),
554 #[cfg(all(feature = "matrix", feature = "f32"))]
555 Value::MatrixF32(ref mat) => impl_conversion_fxn(source_value, target_kind.clone()),
556 #[cfg(all(feature = "matrix", feature = "f64"))]
557 Value::MatrixF64(ref mat) => impl_conversion_fxn(source_value, target_kind.clone()),
558 x => Err(MechError::new(
559 UnhandledFunctionArgumentKind2 { arg: (arguments[0].kind(), arguments[1].kind()), fxn_name: "convert/scalar".to_string() },
560 None,
561 ).with_compiler_loc()
562 ),
563 }
564 }
565 }
566 }
567}
568
569#[derive(Debug, Clone)]
570pub struct ColumnConvertKindMismatchError {
571 pub from: ValueKind,
572 pub to: ValueKind,
573}
574
575impl MechErrorKind for ColumnConvertKindMismatchError {
576 fn name(&self) -> &str { "ColumnTypeMismatch" }
577 fn message(&self) -> String {
578 format!(
579 "Matrix column kind {:?} does not match table column kind {:?}. Conversion requires the element types to be compatible.",
580 self.from, self.to
581 )
582 }
583}
584
585#[derive(Debug, Clone)]
586pub struct ConvertIncorrectNumberOfColumnsError {
587 pub from: usize,
588 pub to: usize,
589}
590impl MechErrorKind for ConvertIncorrectNumberOfColumnsError {
591 fn name(&self) -> &str { "IncorrectNumberOfColumns" }
592 fn message(&self) -> String {
593 format!(
594 "Matrix has {} columns, but table expects {}. Column count must match for assignment.",
595 self.from, self.to
596 )
597 }
598}