use std::any::Any;
use std::fmt;
use crate::lua_vm::CFunction;
pub enum UdValue {
Nil,
Boolean(bool),
Integer(i64),
Number(f64),
Str(String),
Function(CFunction),
UserdataRef(*const dyn Any),
UserdataOwned(Box<dyn UserDataTrait>),
}
impl Clone for UdValue {
fn clone(&self) -> Self {
match self {
UdValue::Nil => UdValue::Nil,
UdValue::Boolean(b) => UdValue::Boolean(*b),
UdValue::Integer(i) => UdValue::Integer(*i),
UdValue::Number(n) => UdValue::Number(*n),
UdValue::Str(s) => UdValue::Str(s.clone()),
UdValue::Function(f) => UdValue::Function(*f),
UdValue::UserdataRef(p) => UdValue::UserdataRef(*p),
UdValue::UserdataOwned(_) => {
UdValue::Nil
}
}
}
}
impl UdValue {
#[inline]
pub fn is_nil(&self) -> bool {
matches!(self, UdValue::Nil)
}
#[inline]
pub fn as_userdata_ref<T: 'static>(&self) -> Option<&T> {
match self {
UdValue::UserdataRef(ptr) => {
let any_ref: &dyn Any = unsafe { &**ptr };
any_ref.downcast_ref::<T>()
}
_ => None,
}
}
#[inline]
pub fn from_userdata<T: UserDataTrait>(value: T) -> Self {
UdValue::UserdataOwned(Box::new(value))
}
}
pub trait UserDataTrait: 'static {
fn type_name(&self) -> &'static str;
fn get_field(&self, _key: &str) -> Option<UdValue> {
None
}
fn set_field(&mut self, _key: &str, _value: UdValue) -> Option<Result<(), String>> {
None
}
fn lua_tostring(&self) -> Option<String> {
None
}
fn lua_eq(&self, _other: &dyn UserDataTrait) -> Option<bool> {
None
}
fn lua_lt(&self, _other: &dyn UserDataTrait) -> Option<bool> {
None
}
fn lua_le(&self, _other: &dyn UserDataTrait) -> Option<bool> {
None
}
fn lua_len(&self) -> Option<UdValue> {
None
}
fn lua_unm(&self) -> Option<UdValue> {
None
}
fn lua_add(&self, _other: &UdValue) -> Option<UdValue> {
None
}
fn lua_sub(&self, _other: &UdValue) -> Option<UdValue> {
None
}
fn lua_mul(&self, _other: &UdValue) -> Option<UdValue> {
None
}
fn lua_div(&self, _other: &UdValue) -> Option<UdValue> {
None
}
fn lua_mod(&self, _other: &UdValue) -> Option<UdValue> {
None
}
fn lua_concat(&self, _other: &UdValue) -> Option<UdValue> {
None
}
fn lua_gc(&mut self) {}
fn lua_close(&mut self) {}
fn lua_call(&self) -> Option<crate::lua_vm::CFunction> {
None
}
fn lua_next(&self, _control: &UdValue) -> Option<(UdValue, UdValue)> {
None
}
fn field_names(&self) -> &'static [&'static str] {
&[]
}
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl From<bool> for UdValue {
fn from(b: bool) -> Self {
UdValue::Boolean(b)
}
}
impl From<i64> for UdValue {
fn from(i: i64) -> Self {
UdValue::Integer(i)
}
}
impl From<i32> for UdValue {
fn from(i: i32) -> Self {
UdValue::Integer(i as i64)
}
}
impl From<f64> for UdValue {
fn from(n: f64) -> Self {
UdValue::Number(n)
}
}
impl From<f32> for UdValue {
fn from(n: f32) -> Self {
UdValue::Number(n as f64)
}
}
impl From<String> for UdValue {
fn from(s: String) -> Self {
UdValue::Str(s)
}
}
impl From<&str> for UdValue {
fn from(s: &str) -> Self {
UdValue::Str(s.to_owned())
}
}
impl<T: Into<UdValue>> From<Option<T>> for UdValue {
fn from(opt: Option<T>) -> Self {
match opt {
Some(v) => v.into(),
None => UdValue::Nil,
}
}
}
impl UdValue {
pub fn to_bool(&self) -> bool {
match self {
UdValue::Nil => false,
UdValue::Boolean(b) => *b,
_ => true,
}
}
pub fn to_integer(&self) -> Option<i64> {
match self {
UdValue::Integer(i) => Some(*i),
UdValue::Number(n) => {
let i = *n as i64;
if (i as f64) == *n { Some(i) } else { None }
}
_ => None,
}
}
pub fn to_number(&self) -> Option<f64> {
match self {
UdValue::Number(n) => Some(*n),
UdValue::Integer(i) => Some(*i as f64),
_ => None,
}
}
pub fn to_str(&self) -> Option<&str> {
match self {
UdValue::Str(s) => Some(s.as_str()),
_ => None,
}
}
}
impl fmt::Debug for UdValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UdValue::Nil => write!(f, "Nil"),
UdValue::Boolean(b) => write!(f, "Boolean({})", b),
UdValue::Integer(i) => write!(f, "Integer({})", i),
UdValue::Number(n) => write!(f, "Number({})", n),
UdValue::Str(s) => write!(f, "Str({:?})", s),
UdValue::Function(_) => write!(f, "Function(<cfunction>)"),
UdValue::UserdataRef(_) => write!(f, "UserdataRef(<ptr>)"),
UdValue::UserdataOwned(ud) => write!(f, "UserdataOwned({})", ud.type_name()),
}
}
}
impl fmt::Display for UdValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UdValue::Nil => write!(f, "nil"),
UdValue::Boolean(b) => write!(f, "{}", b),
UdValue::Integer(i) => write!(f, "{}", i),
UdValue::Number(n) => write!(f, "{}", n),
UdValue::Str(s) => write!(f, "{}", s),
UdValue::Function(_) => write!(f, "function"),
UdValue::UserdataRef(_) => write!(f, "userdata"),
UdValue::UserdataOwned(ud) => write!(f, "{}", ud.type_name()),
}
}
}
pub fn udvalue_to_lua_value(
lua_state: &mut crate::lua_vm::LuaState,
udv: UdValue,
) -> crate::lua_vm::LuaResult<crate::lua_value::LuaValue> {
use crate::lua_value::LuaValue;
match udv {
UdValue::Nil => Ok(LuaValue::nil()),
UdValue::Boolean(b) => Ok(LuaValue::boolean(b)),
UdValue::Integer(i) => Ok(LuaValue::integer(i)),
UdValue::Number(n) => Ok(LuaValue::float(n)),
UdValue::Str(s) => lua_state.create_string(&s),
UdValue::Function(f) => Ok(LuaValue::cfunction(f)),
UdValue::UserdataRef(_) => Ok(LuaValue::nil()), UdValue::UserdataOwned(ud) => {
use crate::lua_value::LuaUserdata;
let userdata = LuaUserdata::from_boxed(ud);
lua_state.create_userdata(userdata)
}
}
}
pub fn lua_value_to_udvalue(value: &crate::lua_value::LuaValue) -> UdValue {
if value.is_nil() {
UdValue::Nil
} else if let Some(b) = value.as_boolean() {
UdValue::Boolean(b)
} else if let Some(i) = value.as_integer() {
UdValue::Integer(i)
} else if let Some(n) = value.as_float() {
UdValue::Number(n)
} else if let Some(s) = value.as_str() {
UdValue::Str(s.to_owned())
} else if let Some(ud) = value.as_userdata_mut() {
UdValue::UserdataRef(ud.get_trait().as_any() as *const dyn Any)
} else {
UdValue::Nil
}
}
#[macro_export]
macro_rules! impl_simple_userdata {
($ty:ty, $name:expr) => {
impl $crate::lua_value::userdata_trait::UserDataTrait for $ty {
fn type_name(&self) -> &'static str {
$name
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}
};
}
pub trait LuaMethodProvider {
fn __lua_lookup_method(_key: &str) -> Option<CFunction> {
None
}
}
impl<T> LuaMethodProvider for T {}
pub trait LuaStaticMethodProvider {
fn __lua_static_methods() -> &'static [(&'static str, CFunction)] {
&[]
}
}
impl<T> LuaStaticMethodProvider for T {}
pub trait LuaRegistrable {
fn lua_static_methods() -> &'static [(&'static str, CFunction)];
}
pub trait LuaEnum {
fn variants() -> &'static [(&'static str, i64)];
fn enum_name() -> &'static str;
}
pub struct OpaqueUserData<T: 'static> {
value: T,
}
impl<T: 'static> OpaqueUserData<T> {
pub fn new(value: T) -> Self {
OpaqueUserData { value }
}
pub fn inner(&self) -> &T {
&self.value
}
pub fn inner_mut(&mut self) -> &mut T {
&mut self.value
}
}
impl<T: 'static> UserDataTrait for OpaqueUserData<T> {
fn type_name(&self) -> &'static str {
std::any::type_name::<T>()
}
fn as_any(&self) -> &dyn Any {
&self.value
}
fn as_any_mut(&mut self) -> &mut dyn Any {
&mut self.value
}
}
pub struct RefUserData<T: UserDataTrait> {
ptr: *mut T,
}
impl<T: UserDataTrait> RefUserData<T> {
#[inline]
pub unsafe fn new(reference: &mut T) -> Self {
RefUserData {
ptr: reference as *mut T,
}
}
#[inline]
pub unsafe fn from_raw(ptr: *mut T) -> Self {
RefUserData { ptr }
}
#[inline]
fn inner(&self) -> &T {
unsafe { &*self.ptr }
}
#[inline]
fn inner_mut(&mut self) -> &mut T {
unsafe { &mut *self.ptr }
}
}
impl<T: UserDataTrait> UserDataTrait for RefUserData<T> {
#[inline]
fn type_name(&self) -> &'static str {
self.inner().type_name()
}
#[inline]
fn get_field(&self, key: &str) -> Option<UdValue> {
self.inner().get_field(key)
}
#[inline]
fn set_field(&mut self, key: &str, value: UdValue) -> Option<Result<(), String>> {
self.inner_mut().set_field(key, value)
}
fn lua_tostring(&self) -> Option<String> {
self.inner().lua_tostring()
}
fn lua_eq(&self, other: &dyn UserDataTrait) -> Option<bool> {
self.inner().lua_eq(other)
}
fn lua_lt(&self, other: &dyn UserDataTrait) -> Option<bool> {
self.inner().lua_lt(other)
}
fn lua_le(&self, other: &dyn UserDataTrait) -> Option<bool> {
self.inner().lua_le(other)
}
fn lua_len(&self) -> Option<UdValue> {
self.inner().lua_len()
}
fn lua_unm(&self) -> Option<UdValue> {
self.inner().lua_unm()
}
fn lua_add(&self, other: &UdValue) -> Option<UdValue> {
self.inner().lua_add(other)
}
fn lua_sub(&self, other: &UdValue) -> Option<UdValue> {
self.inner().lua_sub(other)
}
fn lua_mul(&self, other: &UdValue) -> Option<UdValue> {
self.inner().lua_mul(other)
}
fn lua_div(&self, other: &UdValue) -> Option<UdValue> {
self.inner().lua_div(other)
}
fn lua_mod(&self, other: &UdValue) -> Option<UdValue> {
self.inner().lua_mod(other)
}
fn lua_concat(&self, other: &UdValue) -> Option<UdValue> {
self.inner().lua_concat(other)
}
fn lua_gc(&mut self) {
}
fn lua_close(&mut self) {
}
fn field_names(&self) -> &'static [&'static str] {
self.inner().field_names()
}
fn as_any(&self) -> &dyn Any {
self.inner().as_any()
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self.inner_mut().as_any_mut()
}
}