#![allow(clippy::missing_errors_doc)] use std::{any::type_name, cell::RefCell, fmt, ops}; use mlua::prelude::*; // Utility functions type ListWriter = dyn Fn(&mut fmt::Formatter<'_>, bool, &str) -> fmt::Result; #[must_use] pub fn make_list_writer() -> Box { let first = RefCell::new(true); Box::new(move |f, flag, literal| { if flag { if first.take() { write!(f, "{literal}")?; } else { write!(f, ", {literal}")?; } } Ok::<_, fmt::Error>(()) }) } /** Userdata metamethod implementations Note that many of these return [`LuaResult`] even though they don't return any errors - this is for consistency reasons and to make it easier to add these blanket implementations to [`LuaUserData`] impls. */ pub fn userdata_impl_to_string(_: &Lua, datatype: &D, _: ()) -> LuaResult where D: LuaUserData + ToString + 'static, { Ok(datatype.to_string()) } pub fn userdata_impl_eq(_: &Lua, datatype: &D, value: LuaValue) -> LuaResult where D: LuaUserData + PartialEq + 'static, { if let LuaValue::UserData(ud) = value { if let Ok(value_as_datatype) = ud.borrow::() { Ok(*datatype == *value_as_datatype) } else { Ok(false) } } else { Ok(false) } } pub fn userdata_impl_unm(_: &Lua, datatype: &D, _: ()) -> LuaResult where D: LuaUserData + ops::Neg + Copy, { Ok(-*datatype) } pub fn userdata_impl_add(_: &Lua, datatype: &D, value: LuaUserDataRef) -> LuaResult where D: LuaUserData + ops::Add + Copy, { Ok(*datatype + *value) } pub fn userdata_impl_sub(_: &Lua, datatype: &D, value: LuaUserDataRef) -> LuaResult where D: LuaUserData + ops::Sub + Copy, { Ok(*datatype - *value) } pub fn userdata_impl_mul_f32(_: &Lua, datatype: &D, rhs: LuaValue) -> LuaResult where D: LuaUserData + ops::Mul + ops::Mul + Copy + 'static, { match &rhs { LuaValue::Number(n) => return Ok(*datatype * *n as f32), LuaValue::Integer(i) => return Ok(*datatype * *i as f32), LuaValue::UserData(ud) => { if let Ok(vec) = ud.borrow::() { return Ok(*datatype * *vec); } } _ => {} }; Err(LuaError::FromLuaConversionError { from: rhs.type_name(), to: type_name::(), message: Some(format!( "Expected {} or number, got {}", type_name::(), rhs.type_name() )), }) } pub fn userdata_impl_mul_i32(_: &Lua, datatype: &D, rhs: LuaValue) -> LuaResult where D: LuaUserData + ops::Mul + ops::Mul + Copy + 'static, { match &rhs { LuaValue::Number(n) => return Ok(*datatype * *n as i32), LuaValue::Integer(i) => return Ok(*datatype * *i), LuaValue::UserData(ud) => { if let Ok(vec) = ud.borrow::() { return Ok(*datatype * *vec); } } _ => {} }; Err(LuaError::FromLuaConversionError { from: rhs.type_name(), to: type_name::(), message: Some(format!( "Expected {} or number, got {}", type_name::(), rhs.type_name() )), }) } pub fn userdata_impl_div_f32(_: &Lua, datatype: &D, rhs: LuaValue) -> LuaResult where D: LuaUserData + ops::Div + ops::Div + Copy + 'static, { match &rhs { LuaValue::Number(n) => return Ok(*datatype / *n as f32), LuaValue::Integer(i) => return Ok(*datatype / *i as f32), LuaValue::UserData(ud) => { if let Ok(vec) = ud.borrow::() { return Ok(*datatype / *vec); } } _ => {} }; Err(LuaError::FromLuaConversionError { from: rhs.type_name(), to: type_name::(), message: Some(format!( "Expected {} or number, got {}", type_name::(), rhs.type_name() )), }) } pub fn userdata_impl_div_i32(_: &Lua, datatype: &D, rhs: LuaValue) -> LuaResult where D: LuaUserData + ops::Div + ops::Div + Copy + 'static, { match &rhs { LuaValue::Number(n) => return Ok(*datatype / *n as i32), LuaValue::Integer(i) => return Ok(*datatype / *i), LuaValue::UserData(ud) => { if let Ok(vec) = ud.borrow::() { return Ok(*datatype / *vec); } } _ => {} }; Err(LuaError::FromLuaConversionError { from: rhs.type_name(), to: type_name::(), message: Some(format!( "Expected {} or number, got {}", type_name::(), rhs.type_name() )), }) }