use crate::{Instance, NumCast};
use super::{Object, RbHash, RbString, Symbol, Userdata, Value};
impl Value {
#[must_use]
pub fn from_symbol(symbol: String) -> Self {
Self::Symbol(symbol.into())
}
}
impl<T> From<Option<T>> for Value
where
T: Into<Value>,
{
fn from(value: Option<T>) -> Self {
match value {
Some(v) => v.into(),
None => Self::Nil,
}
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Value::String(RbString {
data: value.into_bytes(),
})
}
}
impl From<&str> for Value {
fn from(value: &str) -> Self {
Value::String(RbString {
data: value.to_string().into_bytes(),
})
}
}
impl From<RbString> for Value {
fn from(value: RbString) -> Self {
Self::String(value)
}
}
impl From<Symbol> for Value {
fn from(value: Symbol) -> Self {
Self::Symbol(value)
}
}
impl From<bool> for Value {
fn from(value: bool) -> Self {
Self::Bool(value)
}
}
impl From<f32> for Value {
fn from(value: f32) -> Self {
Self::Float(value as _)
}
}
impl From<f64> for Value {
fn from(value: f64) -> Self {
Self::Float(value)
}
}
macro_rules! from_primitive_int_impl {
($($primitive:ty),* $(,)?) => {
$(impl From<$primitive> for Value {
fn from(value: $primitive) -> Self {
if let Some(fixnum) = NumCast::from(value) {
Self::Fixnum(fixnum)
} else {
Self::Bignum(NumCast::from(value).unwrap())
}
}
})*
};
}
from_primitive_int_impl!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
impl From<RbHash> for Value {
fn from(value: RbHash) -> Self {
Self::Hash(value)
}
}
impl<T> From<Vec<T>> for Value
where
T: Into<Value>,
{
fn from(value: Vec<T>) -> Self {
Self::Array(value.into_iter().map(Into::into).collect())
}
}
impl TryInto<String> for Value {
type Error = Self;
fn try_into(self) -> Result<String, Self::Error> {
self.into_string()
.map(|str| str.to_string_lossy().into_owned())
}
}
impl TryInto<RbString> for Value {
type Error = Self;
fn try_into(self) -> Result<RbString, Self::Error> {
self.into_string()
}
}
macro_rules! to_primitive_int_impl {
($($primitive:ty),* $(,)?) => {
$(impl TryInto<$primitive> for Value {
type Error = Self;
fn try_into(self) -> Result<$primitive, Self::Error> {
match self.into_fixnum() {
Ok(fixnum) => <$primitive as NumCast>::from(fixnum).ok_or(Value::Fixnum(fixnum)),
Err(value) => {
let bignum = value.into_bignum()?;
<$primitive as NumCast>::from(bignum.as_ref()).ok_or(Value::Bignum(bignum))
}
}
}
})*
};
}
to_primitive_int_impl!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
impl TryInto<f64> for Value {
type Error = Self;
fn try_into(self) -> Result<f64, Self::Error> {
self.into_float()
}
}
impl TryInto<Object> for Value {
type Error = Self;
fn try_into(self) -> Result<Object, Self::Error> {
self.into_object()
}
}
impl TryInto<Userdata> for Value {
type Error = Self;
fn try_into(self) -> Result<Userdata, Self::Error> {
self.into_userdata()
}
}
impl From<Value> for bool {
fn from(value: Value) -> Self {
match value {
Value::Nil => false,
Value::Bool(b) => b,
_ => true,
}
}
}
impl<T> From<Instance<T>> for Value
where
T: Into<Value>,
{
fn from(instance: Instance<T>) -> Self {
let value = Box::new(instance.value.into());
Value::Instance(Instance {
value,
fields: instance.fields,
})
}
}