lucia-lang 0.2.0

Lucia programming language
Documentation
use crate::{
    errors::{Error, ErrorKind},
    objects::{
        AnyCallback, Closure, Function, GcError, Str, Table, TableEntries, TableState, Value,
        ValueType,
    },
    Context,
};

impl<'gc> From<bool> for Value<'gc> {
    fn from(v: bool) -> Value<'gc> {
        Value::Bool(v)
    }
}

impl<'gc> From<i64> for Value<'gc> {
    fn from(v: i64) -> Value<'gc> {
        Value::Int(v)
    }
}

impl<'gc> From<f64> for Value<'gc> {
    fn from(v: f64) -> Value<'gc> {
        Value::Float(v)
    }
}

impl<'gc> From<Str<'gc>> for Value<'gc> {
    fn from(v: Str<'gc>) -> Value<'gc> {
        Value::Str(v)
    }
}

impl<'gc> From<Table<'gc>> for Value<'gc> {
    fn from(v: Table<'gc>) -> Value<'gc> {
        Value::Table(v)
    }
}

impl<'gc> From<Function<'gc>> for Value<'gc> {
    fn from(v: Function<'gc>) -> Value<'gc> {
        Value::Function(v)
    }
}

impl<'gc> From<Closure<'gc>> for Value<'gc> {
    fn from(v: Closure<'gc>) -> Value<'gc> {
        Value::Function(Function::Closure(v))
    }
}

impl<'gc> From<AnyCallback<'gc>> for Value<'gc> {
    fn from(v: AnyCallback<'gc>) -> Value<'gc> {
        Value::Function(Function::Callback(v))
    }
}

pub trait IntoValue<'gc> {
    fn into_value(self, ctx: Context<'gc>) -> Value<'gc>;
}

impl<'gc, T: Into<Value<'gc>>> IntoValue<'gc> for T {
    fn into_value(self, _ctx: Context<'gc>) -> Value<'gc> {
        self.into()
    }
}

impl<'gc> IntoValue<'gc> for &'static str {
    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
        Value::Str(Str::new(&ctx, self.to_string()))
    }
}

impl<'gc> IntoValue<'gc> for String {
    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
        Value::Str(Str::new(&ctx, self))
    }
}

impl<'gc, T: IntoValue<'gc>> IntoValue<'gc> for Option<T> {
    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
        match self {
            Some(t) => t.into_value(ctx),
            None => Value::Null,
        }
    }
}

impl<'gc> IntoValue<'gc> for TableEntries<'gc> {
    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
        Value::Table(Table::from(
            &ctx,
            TableState {
                entries: self,
                metatable: None,
            },
        ))
    }
}

impl<'gc> IntoValue<'gc> for Error<'gc> {
    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
        Value::Error(GcError::new(&ctx, self))
    }
}

impl<'gc, T: IntoValue<'gc>> IntoValue<'gc> for Vec<T> {
    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
        TableEntries::from_iter(self.into_iter().map(|x| x.into_value(ctx))).into_value(ctx)
    }
}

impl<'gc, K: IntoValue<'gc>, V: IntoValue<'gc>> IntoValue<'gc> for Vec<(K, V)> {
    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
        TableEntries::from_iter(
            self.into_iter()
                .map(|(k, v)| (k.into_value(ctx), v.into_value(ctx))),
        )
        .into_value(ctx)
    }
}

impl<'gc, const N: usize, T: IntoValue<'gc>> IntoValue<'gc> for [T; N] {
    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
        Value::Table(Table::from(
            &ctx,
            TableState {
                entries: TableEntries::from_iter(self.into_iter().map(|x| x.into_value(ctx))),
                metatable: None,
            },
        ))
    }
}

impl<'gc, const N: usize, K: IntoValue<'gc>, V: IntoValue<'gc>> IntoValue<'gc> for [(K, V); N] {
    fn into_value(self, ctx: Context<'gc>) -> Value<'gc> {
        TableEntries::from_iter(
            self.into_iter()
                .map(|(k, v)| (k.into_value(ctx), v.into_value(ctx))),
        )
        .into_value(ctx)
    }
}

macro_rules! unexpected_type_error {
    ($expected:expr, $found:expr) => {
        Error::new(ErrorKind::UnexpectedType {
            expected: $expected,
            found: $found.value_type(),
        })
    };
}

pub trait FromValue<'gc>: Sized {
    fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>>;
}

impl<'gc> FromValue<'gc> for Value<'gc> {
    fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
        Ok(value)
    }
}

impl<'gc, T: FromValue<'gc>> FromValue<'gc> for Option<T> {
    fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
        Ok(if value.is_null() {
            None
        } else {
            Some(T::from_value(value)?)
        })
    }
}

impl<'gc, T: FromValue<'gc>> FromValue<'gc> for Vec<T> {
    fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
        if let Value::Table(table) = value {
            (1..=table.len())
                .map(|i| T::from_value(table.get_index(i).map_or(Value::Null, |x| x.1)))
                .collect()
        } else {
            Err(unexpected_type_error!(ValueType::Table, value))
        }
    }
}

macro_rules! impl_int_from {
    ($($i:ty),* $(,)?) => {
        $(
            impl<'gc> FromValue<'gc> for $i {
                fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
                    if let Value::Int(i) = value {
                        if let Ok(i) = <$i>::try_from(i) {
                            Ok(i)
                        } else {
                            Err(unexpected_type_error!( ValueType::Int, value))
                        }
                    } else {
                        Err(unexpected_type_error!( ValueType::Int, value))
                    }
                }
            }
        )*
    };
}
impl_int_from!(i64, u64, i32, u32, i16, u16, i8, u8, isize, usize);

macro_rules! impl_float_from {
    ($($f:ty),* $(,)?) => {
        $(
            impl<'gc> FromValue<'gc> for $f {
                fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
                    if let Value::Float(v) = value {
                        Ok(v as $f)
                    } else {
                        Err(unexpected_type_error!(ValueType::Float, value))
                    }
                }
            }
        )*
    };
}
impl_float_from!(f32, f64);

macro_rules! impl_from {
    ($([$e:ident $t:ty]),* $(,)?) => {
        $(
            impl<'gc> FromValue<'gc> for $t {
                fn from_value( value: Value<'gc>) -> Result<Self, Error<'gc>> {
                    if let Value::$e(v) = value {
                        Ok(v)
                    } else {
                        Err(unexpected_type_error!(ValueType::$e, value))
                    }
                }
            }
        )*
    };
}
impl_from! {
    [Bool bool],
    [Str Str<'gc>],
    [Table Table<'gc>],
    [Function Function<'gc>],
}

impl<'gc> FromValue<'gc> for Closure<'gc> {
    fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
        match value {
            Value::Function(Function::Closure(c)) => Ok(c),
            _ => Err(unexpected_type_error!(ValueType::Function, value)),
        }
    }
}

impl<'gc> FromValue<'gc> for AnyCallback<'gc> {
    fn from_value(value: Value<'gc>) -> Result<Self, Error<'gc>> {
        match value {
            Value::Function(Function::Callback(c)) => Ok(c),
            _ => Err(unexpected_type_error!(ValueType::Function, value)),
        }
    }
}

impl<'gc> From<Value<'gc>> for bool {
    fn from(value: Value) -> Self {
        match value {
            Value::Null => false,
            Value::Bool(v) => v,
            Value::Int(v) => v != 0,
            Value::Float(v) => v != 0.0,
            _ => true,
        }
    }
}