rune/runtime/
from_value.rs1use core::cmp::Ordering;
2
3use crate::alloc::{self, String};
4use crate::any::AnyMarker;
5use crate::hash::Hash;
6
7use super::{Mut, RawAnyGuard, Ref, RuntimeError, Value};
8
9pub use rune_macros::FromValue;
85
86pub trait IntoValue {
88 #[doc(hidden)]
90 fn into_value(self) -> Value;
91}
92
93impl IntoValue for Value {
94 #[inline]
95 fn into_value(self) -> Value {
96 self
97 }
98}
99
100impl IntoValue for &Value {
101 #[inline]
102 fn into_value(self) -> Value {
103 self.clone()
104 }
105}
106
107pub fn from_value<T>(value: impl IntoValue) -> Result<T, RuntimeError>
139where
140 T: FromValue,
141{
142 T::from_value(value.into_value())
143}
144
145#[diagnostic::on_unimplemented(
177 message = "FromValue is not implemented for `{Self}`",
178 label = "FromValue is not implemented for `{Self}`",
179 note = "This probably means that `{Self}` hasn't derived rune::Any"
180)]
181pub trait FromValue: 'static + Sized {
182 fn from_value(value: Value) -> Result<Self, RuntimeError>;
184}
185
186pub trait UnsafeToMut {
188 type Guard: 'static;
193
194 unsafe fn unsafe_to_mut<'a>(value: Value) -> Result<(&'a mut Self, Self::Guard), RuntimeError>;
199}
200
201pub trait UnsafeToRef {
203 type Guard: 'static;
208
209 unsafe fn unsafe_to_ref<'a>(value: Value) -> Result<(&'a Self, Self::Guard), RuntimeError>;
214}
215
216impl<T> FromValue for T
217where
218 T: AnyMarker,
219{
220 #[inline]
221 fn from_value(value: Value) -> Result<Self, RuntimeError> {
222 value.downcast()
223 }
224}
225
226impl FromValue for Value {
227 #[inline]
228 fn from_value(value: Value) -> Result<Self, RuntimeError> {
229 Ok(value)
230 }
231}
232
233impl<T> FromValue for Option<T>
236where
237 T: FromValue,
238{
239 #[inline]
240 fn from_value(value: Value) -> Result<Self, RuntimeError> {
241 Ok(match value.downcast::<Option<Value>>()? {
242 Some(some) => Some(T::from_value(some.clone())?),
243 None => None,
244 })
245 }
246}
247
248impl FromValue for rust_alloc::string::String {
249 #[inline]
250 fn from_value(value: Value) -> Result<Self, RuntimeError> {
251 let string = String::from_value(value)?;
252 let string = rust_alloc::string::String::from(string);
253 Ok(string)
254 }
255}
256
257impl FromValue for alloc::Box<str> {
258 #[inline]
259 fn from_value(value: Value) -> Result<Self, RuntimeError> {
260 let string = value.borrow_string_ref()?;
261 let string = alloc::Box::try_from(string.as_ref())?;
262 Ok(string)
263 }
264}
265
266impl FromValue for rust_alloc::boxed::Box<str> {
267 #[inline]
268 fn from_value(value: Value) -> Result<Self, RuntimeError> {
269 let string = value.borrow_string_ref()?;
270 let string = rust_alloc::boxed::Box::<str>::from(string.as_ref());
271 Ok(string)
272 }
273}
274
275impl FromValue for Ref<str> {
276 #[inline]
277 fn from_value(value: Value) -> Result<Self, RuntimeError> {
278 Ok(Ref::map(Ref::<String>::from_value(value)?, String::as_str))
279 }
280}
281
282impl UnsafeToRef for str {
283 type Guard = RawAnyGuard;
284
285 #[inline]
286 unsafe fn unsafe_to_ref<'a>(value: Value) -> Result<(&'a Self, Self::Guard), RuntimeError> {
287 let string = value.into_ref::<String>()?;
288 let (string, guard) = Ref::into_raw(string);
289 Ok((string.as_ref().as_str(), guard))
290 }
291}
292
293impl UnsafeToMut for str {
294 type Guard = RawAnyGuard;
295
296 #[inline]
297 unsafe fn unsafe_to_mut<'a>(value: Value) -> Result<(&'a mut Self, Self::Guard), RuntimeError> {
298 let string = value.into_mut::<String>()?;
299 let (mut string, guard) = Mut::into_raw(string);
300 Ok((string.as_mut().as_mut_str(), guard))
301 }
302}
303
304impl<T, E> FromValue for Result<T, E>
305where
306 T: FromValue,
307 E: FromValue,
308{
309 #[inline]
310 fn from_value(value: Value) -> Result<Self, RuntimeError> {
311 Ok(match value.downcast::<Result<Value, Value>>()? {
312 Ok(ok) => Result::Ok(T::from_value(ok.clone())?),
313 Err(err) => Result::Err(E::from_value(err.clone())?),
314 })
315 }
316}
317
318impl FromValue for bool {
319 #[inline]
320 fn from_value(value: Value) -> Result<Self, RuntimeError> {
321 value.as_bool()
322 }
323}
324
325impl FromValue for char {
326 #[inline]
327 fn from_value(value: Value) -> Result<Self, RuntimeError> {
328 value.as_char()
329 }
330}
331
332macro_rules! impl_integer {
333 ($($ty:ty),* $(,)?) => {
334 $(
335 impl FromValue for $ty {
336 #[inline]
337 fn from_value(value: Value) -> Result<Self, RuntimeError> {
338 value.as_integer()
339 }
340 }
341 )*
342 };
343}
344
345impl_integer!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
346
347impl FromValue for f64 {
348 #[inline]
349 fn from_value(value: Value) -> Result<Self, RuntimeError> {
350 value.as_float()
351 }
352}
353
354impl FromValue for f32 {
355 #[inline]
356 fn from_value(value: Value) -> Result<Self, RuntimeError> {
357 Ok(value.as_float()? as f32)
358 }
359}
360
361cfg_std! {
362 macro_rules! impl_map {
363 ($ty:ty, $key:ty) => {
364 impl<T> FromValue for $ty
365 where
366 T: FromValue,
367 {
368 fn from_value(value: Value) -> Result<Self, RuntimeError> {
369 let object = value.downcast::<$crate::runtime::Object>()?;
370
371 let mut output = <$ty>::with_capacity(object.len());
372
373 for (key, value) in object {
374 let key = <$key>::try_from(key)?;
375 let value = <T>::from_value(value)?;
376 output.insert(key, value);
377 }
378
379 Ok(output)
380 }
381 }
382 };
383 }
384
385 impl_map!(::std::collections::HashMap<String, T>, String);
386 impl_map!(::std::collections::HashMap<rust_alloc::string::String, T>, rust_alloc::string::String);
387}
388
389macro_rules! impl_try_map {
390 ($ty:ty, $key:ty) => {
391 impl<T> FromValue for $ty
392 where
393 T: FromValue,
394 {
395 fn from_value(value: Value) -> Result<Self, RuntimeError> {
396 let object = value.downcast::<$crate::runtime::Object>()?;
397
398 let mut output = <$ty>::try_with_capacity(object.len())?;
399
400 for (key, value) in object {
401 let key = <$key>::try_from(key)?;
402 let value = <T>::from_value(value)?;
403 output.try_insert(key, value)?;
404 }
405
406 Ok(output)
407 }
408 }
409 };
410}
411
412impl_try_map!(alloc::HashMap<String, T>, String);
413impl_try_map!(alloc::HashMap<rust_alloc::string::String, T>, rust_alloc::string::String);
414
415impl FromValue for Ordering {
416 #[inline]
417 fn from_value(value: Value) -> Result<Self, RuntimeError> {
418 value.as_ordering()
419 }
420}
421
422impl FromValue for Hash {
423 #[inline]
424 fn from_value(value: Value) -> Result<Self, RuntimeError> {
425 value.as_hash()
426 }
427}