use core::cmp::Ordering;
use crate::alloc::{self, String};
use crate::any::AnyMarker;
use crate::hash::Hash;
use super::{
AnyObj, ConstValue, FromConstValue, Mut, RawAnyGuard, Ref, RuntimeError, Value, VmResult,
};
pub use rune_macros::FromValue;
pub trait IntoValue {
#[doc(hidden)]
fn into_value(self) -> Value;
}
impl IntoValue for Value {
#[inline]
fn into_value(self) -> Value {
self
}
}
impl IntoValue for &Value {
#[inline]
fn into_value(self) -> Value {
self.clone()
}
}
pub fn from_value<T>(value: impl IntoValue) -> Result<T, RuntimeError>
where
T: FromValue,
{
T::from_value(value.into_value())
}
#[diagnostic::on_unimplemented(
message = "FromValue is not implemented for `{Self}`",
label = "FromValue is not implemented for `{Self}`",
note = "This probably means that `{Self}` hasn't derived rune::Any"
)]
pub trait FromValue: 'static + Sized {
fn from_value(value: Value) -> Result<Self, RuntimeError>;
}
pub trait UnsafeToMut {
type Guard: 'static;
unsafe fn unsafe_to_mut<'a>(value: Value) -> Result<(&'a mut Self, Self::Guard), RuntimeError>;
}
pub trait UnsafeToRef {
type Guard: 'static;
unsafe fn unsafe_to_ref<'a>(value: Value) -> Result<(&'a Self, Self::Guard), RuntimeError>;
}
#[deprecated = "Rune: Implementing this trait will no longer work. Use UnsafeToRef and UnsafeToMut instead."]
pub trait UnsafeFromValue: Sized {
type Output: 'static;
type Guard: 'static;
fn unsafe_from_value(value: Value) -> VmResult<(Self::Output, Self::Guard)>;
unsafe fn unsafe_coerce(output: Self::Output) -> Self;
}
impl<T> FromValue for T
where
T: AnyMarker,
{
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
value.downcast()
}
}
impl<T> FromValue for Mut<T>
where
T: AnyMarker,
{
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
value.into_mut()
}
}
impl<T> FromValue for Ref<T>
where
T: AnyMarker,
{
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
value.into_ref()
}
}
impl FromValue for AnyObj {
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
value.into_any_obj()
}
}
impl FromValue for Value {
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
Ok(value)
}
}
impl<T> FromValue for Option<T>
where
T: FromValue,
{
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
Ok(match value.downcast::<Option<Value>>()? {
Some(some) => Some(T::from_value(some.clone())?),
None => None,
})
}
}
impl FromValue for ::rust_alloc::string::String {
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
let string = String::from_value(value)?;
let string = ::rust_alloc::string::String::from(string);
Ok(string)
}
}
impl FromValue for alloc::Box<str> {
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
let string = value.borrow_string_ref()?;
let string = alloc::Box::try_from(string.as_ref())?;
Ok(string)
}
}
#[cfg(feature = "alloc")]
impl FromValue for ::rust_alloc::boxed::Box<str> {
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
let string = value.borrow_string_ref()?;
let string = ::rust_alloc::boxed::Box::<str>::from(string.as_ref());
Ok(string)
}
}
impl FromValue for Ref<str> {
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
Ok(Ref::map(Ref::<String>::from_value(value)?, String::as_str))
}
}
impl UnsafeToRef for str {
type Guard = RawAnyGuard;
#[inline]
unsafe fn unsafe_to_ref<'a>(value: Value) -> Result<(&'a Self, Self::Guard), RuntimeError> {
let string = value.into_ref::<String>()?;
let (string, guard) = Ref::into_raw(string);
Ok((string.as_ref().as_str(), guard))
}
}
impl UnsafeToMut for str {
type Guard = RawAnyGuard;
#[inline]
unsafe fn unsafe_to_mut<'a>(value: Value) -> Result<(&'a mut Self, Self::Guard), RuntimeError> {
let string = value.into_mut::<String>()?;
let (mut string, guard) = Mut::into_raw(string);
Ok((string.as_mut().as_mut_str(), guard))
}
}
impl<T, E> FromValue for Result<T, E>
where
T: FromValue,
E: FromValue,
{
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
Ok(match value.downcast::<Result<Value, Value>>()? {
Ok(ok) => Result::Ok(T::from_value(ok.clone())?),
Err(err) => Result::Err(E::from_value(err.clone())?),
})
}
}
impl FromValue for bool {
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
value.as_bool()
}
}
impl FromConstValue for bool {
#[inline]
fn from_const_value(value: ConstValue) -> Result<Self, RuntimeError> {
value.as_bool()
}
}
impl FromValue for char {
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
value.as_char()
}
}
impl FromConstValue for char {
#[inline]
fn from_const_value(value: ConstValue) -> Result<Self, RuntimeError> {
value.as_char()
}
}
macro_rules! impl_integer {
($($ty:ty),* $(,)?) => {
$(
impl FromValue for $ty {
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
value.as_integer()
}
}
impl FromConstValue for $ty {
#[inline]
fn from_const_value(value: ConstValue) -> Result<Self, RuntimeError> {
value.as_integer()
}
}
)*
};
}
impl_integer!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
impl FromValue for f64 {
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
value.as_float()
}
}
impl FromValue for f32 {
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
Ok(value.as_float()? as f32)
}
}
cfg_std! {
macro_rules! impl_map {
($ty:ty, $key:ty) => {
impl<T> FromValue for $ty
where
T: FromValue,
{
fn from_value(value: Value) -> Result<Self, RuntimeError> {
let object = value.downcast::<$crate::runtime::Object>()?;
let mut output = <$ty>::with_capacity(object.len());
for (key, value) in object {
let key = <$key>::try_from(key)?;
let value = <T>::from_value(value)?;
output.insert(key, value);
}
Ok(output)
}
}
};
}
impl_map!(::std::collections::HashMap<String, T>, String);
impl_map!(::std::collections::HashMap<::rust_alloc::string::String, T>, ::rust_alloc::string::String);
}
macro_rules! impl_try_map {
($ty:ty, $key:ty) => {
impl<T> FromValue for $ty
where
T: FromValue,
{
fn from_value(value: Value) -> Result<Self, RuntimeError> {
let object = value.downcast::<$crate::runtime::Object>()?;
let mut output = <$ty>::try_with_capacity(object.len())?;
for (key, value) in object {
let key = <$key>::try_from(key)?;
let value = <T>::from_value(value)?;
output.try_insert(key, value)?;
}
Ok(output)
}
}
};
}
impl_try_map!(alloc::HashMap<String, T>, String);
#[cfg(feature = "alloc")]
impl_try_map!(alloc::HashMap<::rust_alloc::string::String, T>, ::rust_alloc::string::String);
impl FromValue for Ordering {
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
value.as_ordering()
}
}
impl FromValue for Hash {
#[inline]
fn from_value(value: Value) -> Result<Self, RuntimeError> {
value.as_hash()
}
}