use crate::alloc::prelude::*;
use crate::alloc::{self, HashMap};
use crate::any::AnyMarker;
use super::{AnyObj, Object, RuntimeError, Value, VmResult};
pub use rune_macros::ToValue;
pub fn to_value(value: impl ToValue) -> Result<Value, RuntimeError> {
value.to_value()
}
#[diagnostic::on_unimplemented(
message = "ToValue is not implemented for `{Self}`",
label = "ToValue is not implemented for `{Self}`",
note = "This probably means that `{Self}` hasn't derived rune::Any"
)]
pub trait ToValue: Sized {
fn to_value(self) -> Result<Value, RuntimeError>;
}
pub trait ToReturn: Sized {
fn to_return(self) -> VmResult<Value>;
}
impl<T> ToReturn for VmResult<T>
where
T: ToValue,
{
#[inline]
fn to_return(self) -> VmResult<Value> {
match self {
VmResult::Ok(value) => VmResult::Ok(vm_try!(value.to_value())),
VmResult::Err(error) => VmResult::Err(error),
}
}
}
impl<T> ToReturn for T
where
T: ToValue,
{
#[inline]
fn to_return(self) -> VmResult<Value> {
VmResult::Ok(vm_try!(T::to_value(self)))
}
}
impl ToValue for Value {
#[inline]
fn to_value(self) -> Result<Value, RuntimeError> {
Ok(self)
}
}
pub trait UnsafeToValue: Sized {
type Guard: 'static;
unsafe fn unsafe_to_value(self) -> Result<(Value, Self::Guard), RuntimeError>;
}
impl<T> ToValue for T
where
T: AnyMarker,
{
#[inline]
fn to_value(self) -> Result<Value, RuntimeError> {
Ok(Value::from(AnyObj::new(self)?))
}
}
impl<T> UnsafeToValue for T
where
T: ToValue,
{
type Guard = ();
#[inline]
unsafe fn unsafe_to_value(self) -> Result<(Value, Self::Guard), RuntimeError> {
Ok((self.to_value()?, ()))
}
}
impl ToValue for &Value {
#[inline]
fn to_value(self) -> Result<Value, RuntimeError> {
Ok(self.clone())
}
}
impl<T> ToValue for Option<T>
where
T: ToValue,
{
#[inline]
fn to_value(self) -> Result<Value, RuntimeError> {
let option = match self {
Some(some) => Some(some.to_value()?),
None => None,
};
Ok(Value::try_from(option)?)
}
}
impl ToValue for alloc::Box<str> {
#[inline]
fn to_value(self) -> Result<Value, RuntimeError> {
let this = alloc::String::from(self);
Ok(Value::new(this)?)
}
}
impl ToValue for &str {
#[inline]
fn to_value(self) -> Result<Value, RuntimeError> {
let this = alloc::String::try_from(self)?;
Ok(Value::new(this)?)
}
}
#[cfg(feature = "alloc")]
impl ToValue for ::rust_alloc::boxed::Box<str> {
#[inline]
fn to_value(self) -> Result<Value, RuntimeError> {
let this = self.try_to_string()?;
Ok(Value::new(this)?)
}
}
#[cfg(feature = "alloc")]
impl ToValue for ::rust_alloc::string::String {
#[inline]
fn to_value(self) -> Result<Value, RuntimeError> {
let string = alloc::String::try_from(self)?;
Ok(Value::new(string)?)
}
}
impl<T, E> ToValue for Result<T, E>
where
T: ToValue,
E: ToValue,
{
fn to_value(self) -> Result<Value, RuntimeError> {
let result = match self {
Ok(ok) => Ok(ok.to_value()?),
Err(err) => Err(err.to_value()?),
};
Ok(Value::try_from(result)?)
}
}
macro_rules! impl_map {
($ty:ty) => {
impl<T> ToValue for $ty
where
T: ToValue,
{
fn to_value(self) -> Result<Value, RuntimeError> {
let mut output = Object::with_capacity(self.len())?;
for (key, value) in self {
let key = alloc::String::try_from(key)?;
let value = value.to_value()?;
output.insert(key, value)?;
}
Ok(Value::try_from(output)?)
}
}
};
}
impl_map!(HashMap<::rust_alloc::string::String, T>);
impl_map!(HashMap<alloc::String, T>);
cfg_std! {
impl_map!(::std::collections::HashMap<::rust_alloc::string::String, T>);
impl_map!(::std::collections::HashMap<alloc::String, T>);
}