rant/
convert.rs

1//! # rant::convert
2//! Provides conversions between `RantValue`s and native types.
3
4#![allow(unused_mut)]
5#![allow(unused_parens)]
6#![allow(unused_variables)]
7
8use crate::*;
9use crate::runtime::*;
10use crate::{lang::{Varity, Parameter, Identifier}, stdlib::RantStdResult};
11use cast::*;
12use cast::Error as CastError;
13use std::{rc::Rc, ops::{DerefMut, Deref}, convert::TryInto};
14
15/// Enables infallible conversion into a `RantValue`.
16pub trait IntoRant: Sized {
17  /// Converts to a `RantValue`.
18  fn into_rant(self) -> RantValue;
19}
20
21/// Enables fallible conversion into a `RantValue`.
22pub trait TryIntoRant: Sized {
23  /// Attempts to convert to a `RantValue`.
24  fn try_into_rant(self) -> Result<RantValue, ValueError>;
25}
26
27pub trait FromRant: Sized {
28  /// Converts from a `RantValue`.
29  fn from_rant(val: RantValue) -> Self;
30
31  /// Returns `true` if the type can be used to represent an optional Rant parameter in native functions; otherwise, `false`.
32  fn is_optional_param_type() -> bool {
33    false
34  }
35}
36
37/// Enables fallible conversion from a `RantValue`.
38pub trait TryFromRant: Sized {
39  /// Convert from a `RantValue`.
40  fn try_from_rant(val: RantValue) -> Result<Self, ValueError>;
41  
42  /// Returns `true` if the type can be used to represent an optional Rant parameter in native functions; otherwise, `false`.
43  fn is_optional_param_type() -> bool {
44    false
45  }
46}
47
48trait IntoCastResult<T> {
49  fn into_cast_result(self) -> Result<T, CastError>;
50}
51
52impl<T> IntoCastResult<T> for Result<T, CastError> {
53  fn into_cast_result(self) -> Result<T, CastError> {
54    self
55  }
56}
57
58impl IntoCastResult<i64> for i64 {
59  fn into_cast_result(self) -> Result<i64, CastError> {
60    Ok(self)
61  }
62}
63
64fn rant_cast_error(from: &'static str, to: &'static str, err: CastError) -> ValueError {
65  ValueError::InvalidConversion {
66    from,
67    to,
68    message: Some(match err {
69      CastError::Overflow => "integer overflow",
70      CastError::Underflow => "integer underflow",
71      CastError::Infinite => "infinity",
72      CastError::NaN => "NaN"
73    }.to_owned())
74  }
75}
76
77macro_rules! rant_fallible_int_conversions {
78  ($int_type: ident) => {
79    impl TryIntoRant for $int_type {
80      fn try_into_rant(self) -> ValueResult<RantValue> {
81        match i64(self).into_cast_result() {
82          Ok(i) => Ok(RantValue::Int(i)),
83          Err(err) => Err(rant_cast_error(
84            stringify!($int_type), 
85            stringify!(RantValue::Int), 
86            err
87          ))
88        }
89      }
90    }
91    
92    impl TryFromRant for $int_type {
93      fn try_from_rant(val: RantValue) -> ValueResult<Self> {
94        macro_rules! cast_int {
95          (i64, $val:expr) => {
96            Ok($val)
97          };
98          (isize, $val:expr) => {
99            {
100              let val = $val;
101              val.try_into().map_err(|_| if val < 0 {
102                CastError::Underflow
103              } else {
104                CastError::Overflow
105              })
106            }
107          };
108          ($to:ident, $val:expr) => {
109            $to($val)
110          };
111        }
112        macro_rules! cast_float_to_int {
113          (i64, $val:expr) => {
114            Ok($val as i64)
115          };
116          ($to:ident, $val:expr) => {
117            $to($val)
118          };
119        }
120        match val {
121          RantValue::Int(i) => {
122            let result: Result<$int_type, CastError> = cast_int!($int_type, i);
123            match result {
124              Ok(i) => Ok(i),
125              Err(err) => Err(rant_cast_error(
126                val.type_name(),
127                stringify!($int_type),
128                err
129              ))
130            }
131          },
132          RantValue::Float(f) => {
133            let result: Result<$int_type, CastError> = cast_float_to_int!($int_type, f);
134            match result {
135              Ok(i) => Ok(i),
136              Err(err) => Err(rant_cast_error(
137                val.type_name(),
138                stringify!($int_type),
139                err
140              ))
141            }
142          },
143          _ => {
144            // Other conversion failure
145            let src_type = val.type_name();
146            let dest_type = stringify!{$int_type};
147            
148            Err(ValueError::InvalidConversion {
149              from: src_type,
150              to: dest_type,
151              message: None
152            })
153          }
154        }
155      }
156    }
157  };
158  ($int_type: ident, $($int_type2: ident), *) => {
159    rant_fallible_int_conversions! { $int_type }
160    rant_fallible_int_conversions! { $($int_type2), + }
161  };
162}
163
164/// Implements `FromRant` and `TryFromRant` for a type.
165macro_rules! converts_from_rant {
166  ($param:ident -> $t:ty $b:block) => {
167    impl FromRant for $t {
168      fn from_rant($param: RantValue) -> $t {
169        $b
170      }
171    }
172
173    impl TryFromRant for $t {
174      fn try_from_rant(val: RantValue) -> Result<$t, ValueError> {
175        Ok(<$t as FromRant>::from_rant(val))
176      }
177    }
178  }
179}
180
181/// Implements `IntoRant` and `TryIntoRant` for a type.
182macro_rules! converts_into_rant {
183  ($param:ident: $t:ty $b:block) => {
184    impl IntoRant for $t {
185      fn into_rant(self) -> RantValue {
186        let $param = self;
187        $b
188      }
189    }
190
191    impl TryIntoRant for $t {
192      fn try_into_rant(self) -> Result<RantValue, ValueError> {
193        Ok(IntoRant::into_rant(self))
194      }
195    }
196  }
197}
198
199rant_fallible_int_conversions! { u8, i8, u16, i16, u32, i32, u64, i64, isize, usize }
200
201converts_from_rant!(v -> RantNothing { Self });
202converts_from_rant!(v -> RantValue { v });
203converts_from_rant!(v -> bool { v.to_bool() });
204converts_from_rant!(v -> InternalString { v.to_string().into() });
205converts_from_rant!(v -> RantString { v.to_string().into() });
206converts_from_rant!(v -> String { v.to_string() });
207
208converts_into_rant!(v: RantValue { v });
209converts_into_rant!(v: RantNothing { RantValue::Nothing });
210converts_into_rant!(v: bool { RantValue::Boolean(v) });
211converts_into_rant!(v: char { RantValue::String(RantString::from(v)) });
212converts_into_rant!(v: f32 { RantValue::Float(v as f64) });
213converts_into_rant!(v: f64 { RantValue::Float(v) });
214converts_into_rant!(v: String { RantValue::String(v.into()) });
215converts_into_rant!(v: RantString { RantValue::String(v) });
216converts_into_rant!(v: InternalString { RantString::from(v.as_str()).into_rant() });
217converts_into_rant!(v: RantMap { RantValue::Map(v.into_handle()) });
218converts_into_rant!(v: RantMapHandle { RantValue::Map(v) });
219converts_into_rant!(v: RantList { RantValue::List(v.into_handle()) });
220converts_into_rant!(v: RantListHandle { RantValue::List(v) });
221converts_into_rant!(v: RantTuple { RantValue::Tuple(v.into_handle()) });
222converts_into_rant!(v: RantTupleHandle { RantValue::Tuple(v) });
223converts_into_rant!(v: RantSelector { RantValue::Selector(v.into_handle()) });
224converts_into_rant!(v: RantSelectorHandle { RantValue::Selector(v) });
225converts_into_rant!(v: RantRange { RantValue::Range(v) });
226
227impl<'a> IntoRant for &'a str {
228  fn into_rant(self) -> RantValue {
229    RantValue::String(self.into())
230  }
231}
232
233impl<'a> TryIntoRant for &'a str {
234  fn try_into_rant(self) -> Result<RantValue, ValueError> {
235    Ok(self.into_rant())
236  }
237}
238
239impl IntoRant for isize {
240  fn into_rant(self) -> RantValue {
241    RantValue::Int(self as i64)
242  }
243}
244
245impl IntoRant for i64 {
246  fn into_rant(self) -> RantValue {
247    RantValue::Int(self)
248  }
249}
250
251impl IntoRant for i32 {
252  fn into_rant(self) -> RantValue {
253    RantValue::Int(self as i64)
254  }
255}
256
257impl IntoRant for u32 {
258  fn into_rant(self) -> RantValue {
259    RantValue::Int(self as i64)
260  }
261}
262
263impl IntoRant for i16 {
264  fn into_rant(self) -> RantValue {
265    RantValue::Int(self as i64)
266  }
267}
268
269impl IntoRant for u16 {
270  fn into_rant(self) -> RantValue {
271    RantValue::Int(self as i64)
272  }
273}
274
275impl IntoRant for i8 {
276  fn into_rant(self) -> RantValue {
277    RantValue::Int(self as i64)
278  }
279}
280
281impl IntoRant for u8 {
282  fn into_rant(self) -> RantValue {
283    RantValue::Int(self as i64)
284  }
285}
286
287impl TryFromRant for f32 {
288  fn try_from_rant(val: RantValue) -> ValueResult<Self> {
289    match val {
290      RantValue::Int(i) => Ok(f32(i)),
291      RantValue::Float(f) => match f32(f) {
292        Ok(f) => Ok(f),
293        Err(err) => Err(rant_cast_error(val.type_name(), "f32", err))
294      },
295      _ => Err(ValueError::InvalidConversion {
296        from: val.type_name(),
297        to: "f32",
298        message: Some(format!("Rant value type '{}' cannot be converted to f32", val.type_name()))
299      })
300    }
301  }
302}
303
304impl TryFromRant for f64 {
305  fn try_from_rant(val: RantValue) -> ValueResult<Self> {
306    match val {
307      RantValue::Int(i) => Ok(f64(i)),
308      RantValue::Float(f) => Ok(f),
309      _ => Err(ValueError::InvalidConversion {
310        from: val.type_name(),
311        to: "f64",
312        message: Some(format!("Rant value type '{}' cannot be converted to f64", val.type_name()))
313      })
314    }
315  }
316}
317
318impl<T: IntoRant> IntoRant for Vec<T> {
319  fn into_rant(mut self) -> RantValue {
320    let list = self.drain(..).map(|v| v.into_rant()).collect::<RantList>();
321    RantValue::List(list.into_handle())
322  }
323}
324
325impl<T: TryIntoRant> TryIntoRant for Vec<T> {
326  fn try_into_rant(mut self) -> Result<RantValue, ValueError> {
327    let list = self.drain(..).map(|v| v.try_into_rant()).collect::<Result<RantList, ValueError>>()?;
328    Ok(list.into_rant())
329  }
330}
331
332impl TryFromRant for RantTupleHandle {
333  fn try_from_rant(val: RantValue) -> ValueResult<Self> {
334    if let RantValue::Tuple(tuple_ref) = val {
335      Ok(tuple_ref)
336    } else {
337      Err(ValueError::InvalidConversion { from: val.type_name(), to: RantValueType::Tuple.name(), message: None })
338    }
339  }
340}
341
342impl TryFromRant for RantListHandle {
343  fn try_from_rant(val: RantValue) -> ValueResult<Self> {
344    if let RantValue::List(list_ref) = val {
345      Ok(list_ref)
346    } else {
347      Err(ValueError::InvalidConversion { from: val.type_name(), to: RantValueType::List.name(), message: None })
348    }
349  }
350}
351
352impl TryFromRant for RantMapHandle {
353  fn try_from_rant(val: RantValue) -> ValueResult<Self> {
354    if let RantValue::Map(map_ref) = val {
355      Ok(map_ref)
356    } else {
357      Err(ValueError::InvalidConversion { from: val.type_name(), to: RantValueType::Map.name(), message: None })
358    }
359  }
360}
361
362impl TryFromRant for RantFunctionHandle {
363  fn try_from_rant(val: RantValue) -> Result<Self, ValueError> {
364    if let RantValue::Function(func_ref) = val {
365      Ok(func_ref)
366    } else {
367      Err(ValueError::InvalidConversion { from: val.type_name(), to: RantValueType::Function.name(), message: None })
368    }
369  }
370}
371
372impl TryFromRant for RantSelectorHandle {
373  fn try_from_rant(val: RantValue) -> Result<Self, ValueError> {
374    if let RantValue::Selector(sel_ref) = val {
375      Ok(sel_ref)
376    } else {
377      Err(ValueError::InvalidConversion { from: val.type_name(), to: RantValueType::Selector.name(), message: None })
378    }
379  }
380}
381
382impl<T: TryFromRant> TryFromRant for Option<T> {
383  fn try_from_rant(val: RantValue) -> ValueResult<Self> {
384    match val {
385      RantValue::Nothing => Ok(None),
386      other => Ok(Some(T::try_from_rant(other)?))
387    }
388  }
389  fn is_optional_param_type() -> bool {
390    true
391  }
392}
393
394impl<T: TryIntoRant> TryIntoRant for Option<T> {
395  fn try_into_rant(self) -> ValueResult<RantValue> {
396    match self {
397      Some(val) => Ok(val.try_into_rant()?),
398      None => Ok(RantValue::Nothing),
399    }
400  }
401}
402
403impl<T: IntoRant> IntoRant for Option<T> {
404  fn into_rant(self) -> RantValue {
405    match self {
406      Some(val) => val.into_rant(),
407      None => RantValue::Nothing,
408    }
409  }
410}
411
412impl<T: TryFromRant> TryFromRant for Vec<T> {
413  fn try_from_rant(val: RantValue) -> ValueResult<Self> {
414    match val {
415      RantValue::List(vec) => Ok(vec.borrow().iter().cloned().map(T::try_from_rant).collect::<ValueResult<Vec<T>>>()?),
416      other => Err(ValueError::InvalidConversion {
417        from: other.type_name(),
418        to: stringify!(Vec<T>),
419        message: Some("only lists can be turned into vectors".to_owned())
420      })
421    }
422  }
423}
424
425#[inline(always)]
426fn as_varity<T: TryFromRant>() -> Varity {
427  if T::is_optional_param_type() {
428    Varity::Optional
429  } else {
430    Varity::Required
431  }
432}
433
434#[inline(always)]
435fn inc(counter: &mut usize) -> usize {
436  let prev = *counter;
437  *counter += 1;
438  prev
439}
440
441/// Converts from argument list to tuple of `impl TryFromRant` values
442pub trait FromRantArgs: Sized {
443  fn from_rant_args(args: Vec<RantValue>) -> ValueResult<Self>;
444  fn as_rant_params() -> Vec<Parameter>;
445}
446
447impl<T: TryFromRant> FromRantArgs for T {
448  fn from_rant_args(args: Vec<RantValue>) -> ValueResult<Self> {
449    let mut args = args.into_iter();
450    T::try_from_rant(args.next().unwrap_or(RantValue::Nothing))
451  }
452
453  fn as_rant_params() -> Vec<Parameter> {
454    let varity = if T::is_optional_param_type() {
455      Varity::Optional
456    } else {
457      Varity::Required
458    };
459
460    let param = Parameter {
461      name: Identifier::new(InternalString::from("arg0")),
462      varity,
463      default_value_expr: None,
464    };
465
466    vec![param]
467  }
468}
469
470/// Semantic wrapper around a `Vec<T>`.
471/// 
472/// Use this type to add an optional variadic (`*`) parameter to native functions.
473pub struct VarArgs<T: TryFromRant>(Vec<T>);
474
475impl<T: TryFromRant> VarArgs<T> {
476  pub fn new(args: Vec<T>) -> Self {
477    Self(args)
478  }
479}
480
481impl<T: TryFromRant> Deref for VarArgs<T> {
482  type Target = Vec<T>;
483  fn deref(&self) -> &Self::Target {
484    &self.0
485  }
486}
487
488impl<T: TryFromRant> DerefMut for VarArgs<T> {
489  fn deref_mut(&mut self) -> &mut Self::Target {
490    &mut self.0
491  }
492}
493
494impl<T: TryFromRant> VarArgs<T> {
495  #[inline]
496  pub fn into_vec(self) -> Vec<T> {
497    self.0
498  }
499}
500
501/// Semantic wrapper around a `Vec<T>`.
502/// 
503/// Use this type to add a required variadic (`+`) parameter to native functions.
504pub struct RequiredVarArgs<T: TryFromRant>(Vec<T>);
505
506impl<T: TryFromRant> RequiredVarArgs<T> {
507  pub fn new(args: Vec<T>) -> Self {
508    Self(args)
509  }
510}
511
512impl<T: TryFromRant> Deref for RequiredVarArgs<T> {
513  type Target = Vec<T>;
514  fn deref(&self) -> &Self::Target {
515    &self.0
516  }
517}
518
519impl<T: TryFromRant> DerefMut for RequiredVarArgs<T> {
520  fn deref_mut(&mut self) -> &mut Self::Target {
521    &mut self.0
522  }
523}
524
525macro_rules! impl_from_rant_args {
526  ($($generic_types:ident),*) => {
527    // Non-variadic implementation
528    impl<$($generic_types: TryFromRant,)*> FromRantArgs for ($($generic_types,)*) {
529      fn from_rant_args(args: Vec<RantValue>) -> ValueResult<Self> {
530        let mut args = args.into_iter();
531        Ok(($($generic_types::try_from_rant(args.next().unwrap_or(RantValue::Nothing))?,)*))
532      }
533
534      fn as_rant_params() -> Vec<Parameter> {
535        let mut i: usize = 0;
536        vec![$(Parameter { 
537          name: Identifier::new(InternalString::from(format!("arg{}", inc(&mut i)))),
538          varity: as_varity::<$generic_types>(),
539          default_value_expr: None,
540        },)*]
541      }
542    }
543    
544    // Variadic* implementation
545    impl<$($generic_types: TryFromRant,)* VarArgItem: TryFromRant> FromRantArgs for ($($generic_types,)* VarArgs<VarArgItem>) {
546      fn from_rant_args(mut args: Vec<RantValue>) -> ValueResult<Self> {
547        let mut args = args.drain(..);
548        Ok(
549          ($($generic_types::try_from_rant(args.next().unwrap_or(RantValue::Nothing))?,)*
550          VarArgs::new(args
551            .map(VarArgItem::try_from_rant)
552            .collect::<ValueResult<Vec<VarArgItem>>>()?
553          )
554        ))
555      }
556
557      fn as_rant_params() -> Vec<Parameter> {
558        let mut i: usize = 0;
559        vec![$(Parameter { 
560          name: Identifier::new(InternalString::from(format!("arg{}", inc(&mut i)))),
561          varity: as_varity::<$generic_types>(),
562          default_value_expr: None,
563        },)*
564        Parameter {
565          name: Identifier::new(InternalString::from(format!("arg{}", inc(&mut i)))),
566          varity: Varity::VariadicStar,
567          default_value_expr: None,
568        }]
569      }
570    }
571
572    // Variadic+ implementation
573    impl<$($generic_types: TryFromRant,)* VarArgItem: TryFromRant> FromRantArgs for ($($generic_types,)* RequiredVarArgs<VarArgItem>) {
574      fn from_rant_args(mut args: Vec<RantValue>) -> ValueResult<Self> {
575        let mut args = args.drain(..);
576        Ok(
577          ($($generic_types::try_from_rant(args.next().unwrap_or(RantValue::Nothing))?,)*
578          RequiredVarArgs::new(args
579            .map(VarArgItem::try_from_rant)
580            .collect::<ValueResult<Vec<VarArgItem>>>()?
581          )
582        ))
583      }
584
585      fn as_rant_params() -> Vec<Parameter> {
586        let mut i: usize = 0;
587        vec![$(Parameter { 
588          name: Identifier::new(InternalString::from(format!("arg{}", inc(&mut i)))),
589          varity: as_varity::<$generic_types>(),
590          default_value_expr: None,
591        },)*
592        Parameter {
593          name: Identifier::new(InternalString::from(format!("arg{}", inc(&mut i)))),
594          varity: Varity::VariadicPlus,
595          default_value_expr: None,
596        }]
597      }
598    }
599  }
600}
601
602impl_from_rant_args!();
603impl_from_rant_args!(A);
604impl_from_rant_args!(A, B);
605impl_from_rant_args!(A, B, C);
606impl_from_rant_args!(A, B, C, D);
607impl_from_rant_args!(A, B, C, D, E);
608impl_from_rant_args!(A, B, C, D, E, F);
609impl_from_rant_args!(A, B, C, D, E, F, G);
610impl_from_rant_args!(A, B, C, D, E, F, G, H);
611impl_from_rant_args!(A, B, C, D, E, F, G, H, I);
612impl_from_rant_args!(A, B, C, D, E, F, G, H, I, J);
613impl_from_rant_args!(A, B, C, D, E, F, G, H, I, J, K);
614//impl_from_rant_args!(A, B, C, D, E, F, G, H, I, J, K, L);
615
616/// Trait for converting something to a Rant function.
617pub trait IntoRantFunction<Params: FromRantArgs> {
618  /// Performs the conversion.
619  fn into_rant_func(self) -> RantFunction;
620}
621
622impl<Params: FromRantArgs, Function: 'static + Fn(&mut VM, Params) -> RantStdResult> IntoRantFunction<Params> for Function {
623  fn into_rant_func(self) -> RantFunction {
624    let body = RantFunctionInterface::Foreign(Rc::new(move |vm, args| {
625      self(vm, Params::from_rant_args(args).into_runtime_result()?)
626    }));
627
628    let params = Rc::new(Params::as_rant_params());
629
630    RantFunction {
631      body,
632      captured_vars: vec![],
633      min_arg_count: params.iter().take_while(|p| p.is_required()).count(),
634      vararg_start_index: params.iter()
635      .enumerate()
636      .find_map(|(i, p)| if p.varity.is_variadic() { Some(i) } else { None })
637      .unwrap_or_else(|| params.len()),
638      params,
639      flavor: None,
640    }
641  }
642}