runestick/
from_value.rs

1use crate::{Any, AnyObj, Mut, RawMut, RawRef, Ref, Shared, StaticString, Value, VmError};
2use std::sync::Arc;
3
4/// Trait for converting from a value.
5pub trait FromValue: 'static + Sized {
6    /// Try to convert to the given type, from the given value.
7    fn from_value(value: Value) -> Result<Self, VmError>;
8}
9
10/// A potentially unsafe conversion for value conversion.
11///
12/// This trait is used to convert values to references, which can be safely used
13/// while an external function call is used. That sort of use is safe because we
14/// hold onto the guard returned by the conversion during external function
15/// calls.
16pub trait UnsafeFromValue: Sized {
17    /// The output type from the unsafe coercion.
18    type Output: 'static;
19
20    /// The raw guard returned.
21    ///
22    /// Must only be dropped *after* the value returned from this function is
23    /// no longer live.
24    type Guard: 'static;
25
26    /// Convert the given reference using unsafe assumptions to a value.
27    ///
28    /// # Safety
29    ///
30    /// The return value of this function may only be used while a virtual
31    /// machine is not being modified.
32    ///
33    /// You must also make sure that the returned value does not outlive the
34    /// guard.
35    fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError>;
36
37    /// Coerce the output of an unsafe from value into the final output type.
38    ///
39    /// # Safety
40    ///
41    /// The return value of this function may only be used while a virtual
42    /// machine is not being modified.
43    ///
44    /// You must also make sure that the returned value does not outlive the
45    /// guard.
46    unsafe fn unsafe_coerce(output: Self::Output) -> Self;
47}
48
49impl<T> FromValue for T
50where
51    T: Any,
52{
53    fn from_value(value: Value) -> Result<Self, VmError> {
54        Ok(value.into_any()?.take_downcast()?)
55    }
56}
57
58impl<T> FromValue for Mut<T>
59where
60    T: Any,
61{
62    fn from_value(value: Value) -> Result<Self, VmError> {
63        Ok(value.into_any()?.downcast_into_mut()?)
64    }
65}
66
67impl<T> FromValue for Ref<T>
68where
69    T: Any,
70{
71    fn from_value(value: Value) -> Result<Self, VmError> {
72        Ok(value.into_any()?.downcast_into_ref()?)
73    }
74}
75
76impl FromValue for Shared<AnyObj> {
77    fn from_value(value: Value) -> Result<Self, VmError> {
78        Ok(value.into_any()?)
79    }
80}
81
82impl<T> UnsafeFromValue for T
83where
84    T: FromValue,
85{
86    type Output = T;
87    type Guard = ();
88
89    fn from_value(value: Value) -> Result<(Self, Self::Guard), VmError> {
90        Ok((T::from_value(value)?, ()))
91    }
92
93    unsafe fn unsafe_coerce(output: Self::Output) -> Self {
94        output
95    }
96}
97
98impl FromValue for Value {
99    fn from_value(value: Value) -> Result<Self, VmError> {
100        Ok(value)
101    }
102}
103
104// Option impls
105
106impl<T> FromValue for Option<T>
107where
108    T: FromValue,
109{
110    fn from_value(value: Value) -> Result<Self, VmError> {
111        Ok(match value.into_option()?.take()? {
112            Some(some) => Some(T::from_value(some)?),
113            None => None,
114        })
115    }
116}
117
118impl UnsafeFromValue for &Option<Value> {
119    type Output = *const Option<Value>;
120    type Guard = RawRef;
121
122    fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError> {
123        Ok(Ref::into_raw(value.into_option()?.into_ref()?))
124    }
125
126    unsafe fn unsafe_coerce(output: Self::Output) -> Self {
127        &*output
128    }
129}
130
131impl UnsafeFromValue for &mut Option<Value> {
132    type Output = *mut Option<Value>;
133    type Guard = RawMut;
134
135    fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError> {
136        Ok(Mut::into_raw(value.into_option()?.into_mut()?))
137    }
138
139    unsafe fn unsafe_coerce(output: Self::Output) -> Self {
140        &mut *output
141    }
142}
143
144impl UnsafeFromValue for &mut Result<Value, Value> {
145    type Output = *mut Result<Value, Value>;
146    type Guard = RawMut;
147
148    fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError> {
149        Ok(Mut::into_raw(value.into_result()?.into_mut()?))
150    }
151
152    unsafe fn unsafe_coerce(output: Self::Output) -> Self {
153        &mut *output
154    }
155}
156
157// String impls
158
159impl FromValue for String {
160    fn from_value(value: Value) -> Result<Self, VmError> {
161        match value {
162            Value::String(string) => Ok(string.borrow_ref()?.clone()),
163            Value::StaticString(string) => Ok((**string).to_owned()),
164            actual => Err(VmError::expected::<String>(actual.type_info()?)),
165        }
166    }
167}
168
169impl FromValue for Mut<String> {
170    fn from_value(value: Value) -> Result<Self, VmError> {
171        match value {
172            Value::String(string) => Ok(string.into_mut()?),
173            actual => Err(VmError::expected::<String>(actual.type_info()?)),
174        }
175    }
176}
177
178impl FromValue for Ref<String> {
179    fn from_value(value: Value) -> Result<Self, VmError> {
180        match value {
181            Value::String(string) => Ok(string.into_ref()?),
182            actual => Err(VmError::expected::<String>(actual.type_info()?)),
183        }
184    }
185}
186
187impl FromValue for Box<str> {
188    fn from_value(value: Value) -> Result<Self, VmError> {
189        let string = value.into_string()?;
190        let string = string.borrow_ref()?.clone();
191        Ok(string.into_boxed_str())
192    }
193}
194
195/// Raw guard used for `&str` references.
196///
197/// Note that we need to hold onto an instance of the static string to prevent
198/// the reference to it from being deallocated (the `StaticString` variant).
199pub enum StrGuard {
200    RawRef(RawRef),
201    StaticString(Arc<StaticString>),
202}
203
204impl UnsafeFromValue for &str {
205    type Output = *const str;
206    type Guard = StrGuard;
207
208    fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError> {
209        Ok(match value {
210            Value::String(string) => {
211                let string = string.into_ref()?;
212                let (s, guard) = Ref::into_raw(string);
213                // Safety: we're holding onto the guard for the string here, so
214                // it is live.
215                (unsafe { (*s).as_str() }, StrGuard::RawRef(guard))
216            }
217            Value::StaticString(string) => {
218                (string.as_ref().as_str(), StrGuard::StaticString(string))
219            }
220            actual => return Err(VmError::expected::<String>(actual.type_info()?)),
221        })
222    }
223
224    unsafe fn unsafe_coerce(output: Self::Output) -> Self {
225        &*output
226    }
227}
228
229impl UnsafeFromValue for &mut str {
230    type Output = *mut str;
231    type Guard = Option<RawMut>;
232
233    fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError> {
234        Ok(match value {
235            Value::String(string) => {
236                let string = string.into_mut()?;
237                let (s, guard) = Mut::into_raw(string);
238                // Safety: we're holding onto the guard for the string here, so
239                // it is live.
240                (unsafe { (*s).as_mut_str() }, Some(guard))
241            }
242            actual => {
243                return Err(VmError::expected::<String>(actual.type_info()?));
244            }
245        })
246    }
247
248    unsafe fn unsafe_coerce(output: Self::Output) -> Self {
249        &mut *output
250    }
251}
252
253impl UnsafeFromValue for &String {
254    type Output = *const String;
255    type Guard = StrGuard;
256
257    fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError> {
258        Ok(match value {
259            Value::String(string) => {
260                let string = string.into_ref()?;
261                let (s, guard) = Ref::into_raw(string);
262                (s, StrGuard::RawRef(guard))
263            }
264            Value::StaticString(string) => (&**string, StrGuard::StaticString(string)),
265            actual => {
266                return Err(VmError::expected::<String>(actual.type_info()?));
267            }
268        })
269    }
270
271    unsafe fn unsafe_coerce(output: Self::Output) -> Self {
272        &*output
273    }
274}
275
276impl UnsafeFromValue for &mut String {
277    type Output = *mut String;
278    type Guard = RawMut;
279
280    fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError> {
281        Ok(match value {
282            Value::String(string) => {
283                let string = string.into_mut()?;
284                let (s, guard) = Mut::into_raw(string);
285                (s, guard)
286            }
287            actual => {
288                return Err(VmError::expected::<String>(actual.type_info()?));
289            }
290        })
291    }
292
293    unsafe fn unsafe_coerce(output: Self::Output) -> Self {
294        &mut *output
295    }
296}
297
298// Result impls
299
300impl<T, E> FromValue for Result<T, E>
301where
302    T: FromValue,
303    E: FromValue,
304{
305    fn from_value(value: Value) -> Result<Self, VmError> {
306        Ok(match value.into_result()?.take()? {
307            Ok(ok) => Ok(T::from_value(ok)?),
308            Err(err) => Err(E::from_value(err)?),
309        })
310    }
311}
312
313impl UnsafeFromValue for &Result<Value, Value> {
314    type Output = *const Result<Value, Value>;
315    type Guard = RawRef;
316
317    fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError> {
318        let result = value.into_result()?;
319        let result = result.into_ref()?;
320        Ok(Ref::into_raw(result))
321    }
322
323    unsafe fn unsafe_coerce(output: Self::Output) -> Self {
324        &*output
325    }
326}
327
328// number impls
329
330impl FromValue for () {
331    fn from_value(value: Value) -> Result<Self, VmError> {
332        Ok(value.into_unit()?)
333    }
334}
335
336impl FromValue for u8 {
337    fn from_value(value: Value) -> Result<Self, VmError> {
338        Ok(value.into_byte()?)
339    }
340}
341
342impl FromValue for bool {
343    fn from_value(value: Value) -> Result<Self, VmError> {
344        Ok(value.into_bool()?)
345    }
346}
347
348impl FromValue for char {
349    fn from_value(value: Value) -> Result<Self, VmError> {
350        Ok(value.into_char()?)
351    }
352}
353
354impl FromValue for i64 {
355    fn from_value(value: Value) -> Result<Self, VmError> {
356        Ok(value.into_integer()?)
357    }
358}
359
360macro_rules! impl_number {
361    ($ty:ty) => {
362        impl FromValue for $ty {
363            fn from_value(value: Value) -> Result<Self, VmError> {
364                use std::convert::TryInto as _;
365                let integer = value.into_integer()?;
366
367                match integer.try_into() {
368                    Ok(number) => Ok(number),
369                    Err(..) => Err($crate::VmError::from(
370                        $crate::VmErrorKind::ValueToIntegerCoercionError {
371                            from: $crate::VmIntegerRepr::from(integer),
372                            to: std::any::type_name::<Self>(),
373                        },
374                    )),
375                }
376            }
377        }
378    };
379}
380
381impl_number!(u16);
382impl_number!(u32);
383impl_number!(u64);
384impl_number!(u128);
385impl_number!(usize);
386impl_number!(i8);
387impl_number!(i16);
388impl_number!(i32);
389impl_number!(i128);
390impl_number!(isize);
391
392impl FromValue for f64 {
393    fn from_value(value: Value) -> Result<Self, VmError> {
394        Ok(value.into_float()?)
395    }
396}
397
398impl FromValue for f32 {
399    fn from_value(value: Value) -> Result<Self, VmError> {
400        Ok(value.into_float()? as f32)
401    }
402}
403
404// map impls
405
406macro_rules! impl_map {
407    ($ty:ty) => {
408        impl<T> $crate::FromValue for $ty
409        where
410            T: $crate::FromValue,
411        {
412            fn from_value(value: $crate::Value) -> Result<Self, $crate::VmError> {
413                let object = value.into_object()?;
414                let object = object.take()?;
415
416                let mut output = <$ty>::with_capacity(object.len());
417
418                for (key, value) in object {
419                    output.insert(key, T::from_value(value)?);
420                }
421
422                Ok(output)
423            }
424        }
425    };
426}
427
428impl_map!(std::collections::HashMap<String, T>);