Add UserData generic everywhere

This commit is contained in:
Sofia 2026-03-21 20:16:00 +02:00
parent d717718a9c
commit 641aa878bb
4 changed files with 167 additions and 119 deletions

View File

@ -1,14 +1,22 @@
use ferrite_lua::{
compile,
vm::{RuntimeError, VirtualMachine, value},
vm::{
RuntimeError, VirtualMachine,
value::{self, AsValue},
},
};
static TEST: &str = include_str!("../examples/test.lua");
type UserData = ();
#[derive(Debug, PartialEq, Eq)]
pub struct Max;
impl value::RustFunction for Max {
fn execute(&self, parameters: Vec<value::Value>) -> Result<Vec<value::Value>, RuntimeError> {
impl value::RustFunction<UserData> for Max {
fn execute(
&self,
parameters: Vec<value::Value<UserData>>,
) -> Result<Vec<value::Value<UserData>>, RuntimeError<UserData>> {
let lhs = parameters.get(0).cloned().unwrap_or(value::Value::Nil);
let rhs = parameters.get(1).cloned().unwrap_or(value::Value::Nil);
match lhs.lt(&rhs)? {
@ -23,8 +31,11 @@ impl value::RustFunction for Max {
}
#[derive(Debug, PartialEq, Eq)]
pub struct Print;
impl value::RustFunction for Print {
fn execute(&self, parameters: Vec<value::Value>) -> Result<Vec<value::Value>, RuntimeError> {
impl value::RustFunction<UserData> for Print {
fn execute(
&self,
parameters: Vec<value::Value<UserData>>,
) -> Result<Vec<value::Value<UserData>>, RuntimeError<UserData>> {
println!(
"{}",
parameters
@ -46,8 +57,8 @@ fn main() {
let mut vm = VirtualMachine::default();
vm.set_global("max".into(), Max.into()).unwrap();
vm.set_global("print".into(), Print.into()).unwrap();
vm.set_global("max".into(), Max.as_value()).unwrap();
vm.set_global("print".into(), Print.as_value()).unwrap();
dbg!(&compilation_unit);

View File

@ -1,11 +1,13 @@
//! Usage example:
//! ```rust
//! use ferrite_lua::{compile, vm::{self, value}};
//! use ferrite_lua::{compile, vm::{self, value::{self, AsValue}}};
//!
//! type UserData = ();
//!
//! #[derive(Debug, PartialEq, Eq)]
//! pub struct Print;
//! impl value::RustFunction for Print {
//! fn execute(&self, parameters: Vec<value::Value>) -> Result<Vec<value::Value>, vm::RuntimeError> {
//! impl value::RustFunction<UserData> for Print {
//! fn execute(&self, parameters: Vec<value::Value<UserData>>) -> Result<Vec<value::Value<UserData>>, vm::RuntimeError<UserData>> {
//! println!("{:?}", parameters);
//! Ok(Vec::new())
//! }
@ -18,7 +20,7 @@
//! let compilation_unit = compile("print(\"hello\")", None).unwrap();
//!
//! let mut vm = vm::VirtualMachine::default();
//! vm.set_global("print".into(), Print.into()).unwrap();
//! vm.set_global("print".into(), Print.as_value()).unwrap();
//!
//! let mut runner = compilation_unit.with_virtual_machine(&mut vm).execute();
//!
@ -70,7 +72,10 @@ impl Debug for CompilationUnit {
}
impl CompilationUnit {
pub fn with_virtual_machine<'a>(&self, vm: &'a mut VirtualMachine) -> ExecutionUnit<'a> {
pub fn with_virtual_machine<'a, UserData: Clone>(
&self,
vm: &'a mut VirtualMachine<UserData>,
) -> ExecutionUnit<'a, UserData> {
let chunk_id = vm.new_prototype(vm::Prototype {
instructions: self.instructions.clone(),
parameters: 0,
@ -85,13 +90,13 @@ impl CompilationUnit {
}
}
pub struct ExecutionUnit<'a> {
pub struct ExecutionUnit<'a, UserData: Clone> {
chunk_id: u32,
vm: &'a mut VirtualMachine,
vm: &'a mut VirtualMachine<UserData>,
}
impl<'a> ExecutionUnit<'a> {
pub fn execute(self) -> ClosureRunner {
impl<'a, UserData: Clone> ExecutionUnit<'a, UserData> {
pub fn execute(self) -> ClosureRunner<UserData> {
let closure = self.vm.create_closure(self.chunk_id);
closure.run(Vec::new())
}

View File

@ -12,8 +12,11 @@ pub mod value;
#[derive(Debug)]
pub struct SetMetatable;
impl RustFunction for SetMetatable {
fn execute(&self, parameters: Vec<Value>) -> Result<Vec<Value>, RuntimeError> {
impl<UserData: Clone> RustFunction<UserData> for SetMetatable {
fn execute(
&self,
parameters: Vec<Value<UserData>>,
) -> Result<Vec<Value<UserData>>, RuntimeError<UserData>> {
let table = parameters
.get(0)
.ok_or(RuntimeError::NotTable(Value::Nil))?;
@ -215,35 +218,35 @@ impl Debug for Instruction {
}
#[derive(Error, Debug)]
pub enum RuntimeError {
pub enum RuntimeError<UserData: Clone> {
#[error("Unable to perform {0:?} operator between {1:?} and {2:?}")]
InvalidOperands(BinaryOperator, Value, Value),
InvalidOperands(BinaryOperator, Value<UserData>, Value<UserData>),
#[error("Unable to call metamethod {0} for values {1:?} and {2:?}")]
InvalidBinop(String, Value, Value),
InvalidBinop(String, Value<UserData>, Value<UserData>),
#[error("Unable to call metamethod {0} for value {1:?}")]
InvalidUnop(String, Value),
InvalidUnop(String, Value<UserData>),
#[error("Metatable is not a table: {0:?}")]
MetatableNotTable(Value),
MetatableNotTable(Value<UserData>),
#[error("Metafunction not found: {0} for {1:?}")]
MetafunctionNotFound(String, Value),
MetafunctionNotFound(String, Value<UserData>),
#[error("Metafunction is not callable: {0:?}")]
MetafunctionNotCallable(Value),
MetafunctionNotCallable(Value<UserData>),
#[error("Unable to perform {0:?} operator to {1:?}")]
InvalidOperand(UnaryOperator, Value),
InvalidOperand(UnaryOperator, Value<UserData>),
#[error("Tried calling a non-function: {0:?}")]
TriedCallingNonFunction(Value),
TriedCallingNonFunction(Value<UserData>),
#[error("Global not found: {0:?}")]
GlobalNotFound(Option<Constant>),
#[error("Unable to index tables with {0:?}")]
InvalidTableIndex(Value),
InvalidTableIndex(Value<UserData>),
#[error("Value is not a table: {0:?}")]
NotTable(Value),
NotTable(Value<UserData>),
#[error("Value is not coercable to a float: {0:?}")]
NotFloatable(Value),
NotFloatable(Value<UserData>),
#[error("Value is not coercable to bits: {0:?}")]
NotBittable(Value),
NotBittable(Value<UserData>),
#[error("Value does not have a length: {0:?}")]
NotLengthable(Value),
NotLengthable(Value<UserData>),
#[error("{0}")]
Custom(String),
}
@ -255,19 +258,19 @@ pub struct Prototype {
}
#[derive(Debug, Clone)]
pub struct VirtualMachine {
pub(super) environment: Table,
pub struct VirtualMachine<UserData: Clone> {
pub(super) environment: Table<UserData>,
pub(super) constants: Vec<Constant>,
pub(super) prototypes: HashMap<u32, Prototype>,
pub(super) proto_counter: u32,
}
impl Default for VirtualMachine {
impl<UserData: Clone> Default for VirtualMachine<UserData> {
fn default() -> Self {
let environment: Table = Default::default();
let environment: Table<UserData> = Default::default();
environment.borrow_mut().insert(
IndexableValue::String("SETMETATABLE".into()),
SetMetatable.into(),
Value::RustFunction(Rc::new(RefCell::new(SetMetatable))),
);
Self {
environment,
@ -278,7 +281,7 @@ impl Default for VirtualMachine {
}
}
impl VirtualMachine {
impl<UserData: Clone> VirtualMachine<UserData> {
pub fn new_prototype(&mut self, instructions: Prototype) -> u32 {
let proto_id = self.proto_counter;
self.proto_counter += 1;
@ -286,7 +289,7 @@ impl VirtualMachine {
proto_id
}
pub(crate) fn create_closure(&self, prototype: u32) -> Closure {
pub(crate) fn create_closure(&self, prototype: u32) -> Closure<UserData> {
Closure {
vm: self.clone(),
prototype,
@ -295,14 +298,18 @@ impl VirtualMachine {
}
}
pub fn set_global(&mut self, key: Value, value: Value) -> Result<(), RuntimeError> {
pub fn set_global(
&mut self,
key: Value<UserData>,
value: Value<UserData>,
) -> Result<(), RuntimeError<UserData>> {
self.environment
.borrow_mut()
.insert(key.as_indexable()?, value);
Ok(())
}
pub fn get_globals(&self) -> HashMap<IndexableValue, Value> {
pub fn get_globals(&self) -> HashMap<IndexableValue, Value<UserData>> {
let mut values = HashMap::new();
for (key, value) in self.environment.borrow().iter() {
values.insert(key.clone(), value.clone());
@ -313,15 +320,15 @@ impl VirtualMachine {
}
#[derive(Debug, Clone)]
pub struct Closure {
vm: VirtualMachine,
pub struct Closure<UserData: Clone> {
vm: VirtualMachine<UserData>,
pub(crate) prototype: u32,
environment: Table,
upvalues: HashMap<u16, Rc<RefCell<Value>>>,
environment: Table<UserData>,
upvalues: HashMap<u16, Rc<RefCell<Value<UserData>>>>,
}
impl Closure {
pub fn run(&self, params: Vec<Value>) -> ClosureRunner {
impl<UserData: Clone> Closure<UserData> {
pub fn run(&self, params: Vec<Value<UserData>>) -> ClosureRunner<UserData> {
let mut stack = HashMap::new();
for (i, param) in params.iter().enumerate() {
stack.insert(i as u16, Rc::new(RefCell::new(param.clone())));
@ -340,7 +347,7 @@ impl Closure {
}
}
fn get_upvalue(&mut self, idx: u16) -> StackValue {
fn get_upvalue(&mut self, idx: u16) -> StackValue<UserData> {
let value = self.upvalues.get(&idx);
if let Some(value) = value {
match &*value.borrow() {
@ -352,25 +359,25 @@ impl Closure {
}
}
pub struct ClosureRunner {
closure: Closure,
pub struct ClosureRunner<UserData: Clone> {
closure: Closure<UserData>,
program_counter: usize,
stack: HashMap<u16, Rc<RefCell<Value>>>,
inner: Option<Box<ClosureRunner>>,
stack: HashMap<u16, Rc<RefCell<Value<UserData>>>>,
inner: Option<Box<ClosureRunner<UserData>>>,
function_register: u16,
return_registers: Vec<u16>,
top: u16,
parameters: Vec<Value>,
parameters: Vec<Value<UserData>>,
to_close_upvalues: u16,
}
#[derive(Clone, Debug)]
enum StackValue {
Value(Value),
enum StackValue<UserData: Clone> {
Value(Value<UserData>),
}
impl ClosureRunner {
fn set_stack(&mut self, idx: u16, value: StackValue) {
impl<UserData: Clone> ClosureRunner<UserData> {
fn set_stack(&mut self, idx: u16, value: StackValue<UserData>) {
if let Some(stack_slot) = self.stack.get_mut(&idx) {
match value {
StackValue::Value(value) => {
@ -386,7 +393,7 @@ impl ClosureRunner {
}
}
fn get_stack(&mut self, idx: u16) -> StackValue {
fn get_stack(&mut self, idx: u16) -> StackValue<UserData> {
let value = self.stack.get(&idx);
if let Some(value) = value {
match &*value.borrow() {
@ -397,7 +404,7 @@ impl ClosureRunner {
}
}
fn close_upvalues(&self) -> HashMap<u16, Rc<RefCell<Value>>> {
fn close_upvalues(&self) -> HashMap<u16, Rc<RefCell<Value<UserData>>>> {
let highest_upvalue = self
.closure
.upvalues
@ -417,7 +424,7 @@ impl ClosureRunner {
upvalues
}
pub fn execute(&mut self, unit: &CompilationUnit) -> ClosureRunner {
pub fn execute(&mut self, unit: &CompilationUnit) -> ClosureRunner<UserData> {
let mut vm = self.closure.vm.clone();
vm.constants = unit.constants.clone();
let proto_id = vm.new_prototype(Prototype {
@ -437,7 +444,7 @@ impl ClosureRunner {
closure.run(Vec::new())
}
pub fn next(&mut self) -> Result<Option<Vec<Value>>, RuntimeError> {
pub fn next(&mut self) -> Result<Option<Vec<Value<UserData>>>, RuntimeError<UserData>> {
if let Some(inner) = &mut self.inner {
match inner.next() {
Ok(ret_values) => {
@ -815,7 +822,7 @@ impl ClosureRunner {
Value::Table { metatable, .. } => {
let mut metamethod_params = vec![value.clone()];
metamethod_params.extend(params);
let ret_values =
let ret_values: Vec<Value<UserData>> =
self.call_metamethod(&metatable, "__call", metamethod_params)??;
if *ret_len != 0 {
@ -1195,10 +1202,10 @@ impl ClosureRunner {
fn result_or_metamethod_unop(
&self,
value: Result<Value, RuntimeError>,
value: Result<Value<UserData>, RuntimeError<UserData>>,
metamethod: &str,
param: Value,
) -> Result<Value, RuntimeError> {
param: Value<UserData>,
) -> Result<Value<UserData>, RuntimeError<UserData>> {
let metatable = extract_metatable(&param);
if let Some(metatable) = metatable {
@ -1213,11 +1220,11 @@ impl ClosureRunner {
fn result_or_metamethod_binop(
&self,
value: Result<Value, RuntimeError>,
value: Result<Value<UserData>, RuntimeError<UserData>>,
metamethod: &str,
lhs: Value,
rhs: Value,
) -> Result<Value, RuntimeError> {
lhs: Value<UserData>,
rhs: Value<UserData>,
) -> Result<Value<UserData>, RuntimeError<UserData>> {
let metatable = extract_metatable(&lhs).or(extract_metatable(&rhs));
if let Some(metatable) = metatable {
@ -1232,10 +1239,10 @@ impl ClosureRunner {
fn call_metamethod(
&self,
metatable: &Table,
metatable: &Table<UserData>,
metamethod: &str,
params: Vec<Value>,
) -> Result<Result<Vec<Value>, RuntimeError>, RuntimeError> {
params: Vec<Value<UserData>>,
) -> Result<Result<Vec<Value<UserData>>, RuntimeError<UserData>>, RuntimeError<UserData>> {
if let Some(value) = metatable
.borrow()
.get(&IndexableValue::String(metamethod.to_owned()))
@ -1268,7 +1275,7 @@ impl ClosureRunner {
}
}
fn lhs_and_rhs(&self, lhs: &u16, rhs: &u16) -> (Value, Value) {
fn lhs_and_rhs(&self, lhs: &u16, rhs: &u16) -> (Value<UserData>, Value<UserData>) {
(
self.stack
.get(lhs)
@ -1282,13 +1289,15 @@ impl ClosureRunner {
}
}
fn extract_metatable(value: &Value) -> Option<&Table> {
fn extract_metatable<UserData: Clone>(value: &Value<UserData>) -> Option<&Table<UserData>> {
match value {
Value::Table { metatable, .. } => Some(metatable),
_ => None,
}
}
fn extract_ret_value(values: Result<Vec<Value>, RuntimeError>) -> Result<Value, RuntimeError> {
fn extract_ret_value<UserData: Clone>(
values: Result<Vec<Value<UserData>>, RuntimeError<UserData>>,
) -> Result<Value<UserData>, RuntimeError<UserData>> {
values.map(|v| v.into_iter().next().unwrap())
}

View File

@ -82,16 +82,24 @@ impl From<&LuaBool> for LuaInteger {
}
}
pub trait RustFunction: Debug {
fn execute(&self, parameters: Vec<Value>) -> Result<Vec<Value>, RuntimeError>;
pub trait RustFunction<UserData: Clone>: Debug {
fn execute(
&self,
parameters: Vec<Value<UserData>>,
) -> Result<Vec<Value<UserData>>, RuntimeError<UserData>>;
fn as_indexable(&self) -> String;
}
impl<T: RustFunction + 'static> From<T> for Value {
fn from(value: T) -> Self {
Self::RustFunction(Rc::new(RefCell::new(value)))
pub trait AsValue<UserData: Clone> {
fn as_value(self) -> Value<UserData>;
}
impl<UserData: Clone, T: RustFunction<UserData> + 'static> AsValue<UserData> for T {
fn as_value(self) -> Value<UserData> {
Value::RustFunction(Rc::new(RefCell::new(self)))
}
}
#[derive(Clone, Hash, PartialEq, Eq)]
pub enum Constant {
String(String),
@ -102,7 +110,7 @@ pub enum Constant {
}
impl Constant {
pub fn as_value(self) -> Value {
pub fn as_value<UserData: Clone>(self) -> Value<UserData> {
match self {
Constant::String(value) => Value::String(value),
Constant::Float(vmfloat) => Value::Float(vmfloat),
@ -125,23 +133,26 @@ impl Debug for Constant {
}
}
pub type Table = Rc<RefCell<TableMap>>;
pub type TableMap = HashMap<IndexableValue, Value>;
pub type Table<UserData: Clone> = Rc<RefCell<TableMap<UserData>>>;
pub type TableMap<UserData: Clone> = HashMap<IndexableValue, Value<UserData>>;
#[derive(Clone)]
pub enum Value {
pub enum Value<UserData: Clone> {
String(String),
Float(VMFloat),
Integer(LuaInteger),
Boolean(LuaBool),
RustFunction(Rc<RefCell<dyn RustFunction>>),
Function(Closure),
RustFunction(Rc<RefCell<dyn RustFunction<UserData>>>),
Function(Closure<UserData>),
Nil,
Table { contents: Table, metatable: Table },
Table {
contents: Table<UserData>,
metatable: Table<UserData>,
},
}
impl Value {
pub fn as_indexable(self) -> Result<IndexableValue, RuntimeError> {
impl<UserData: Clone> Value<UserData> {
pub fn as_indexable(self) -> Result<IndexableValue, RuntimeError<UserData>> {
match self {
Value::String(value) => Ok(IndexableValue::String(value)),
Value::Float(value) => Ok(IndexableValue::Float(value)),
@ -152,11 +163,11 @@ impl Value {
}
Value::Function(closure) => Ok(IndexableValue::Function(closure.prototype)),
Value::Nil => Err(RuntimeError::InvalidTableIndex(self)),
Value::Table { contents, .. } => Ok(IndexableValue::Table(contents.as_ptr())),
Value::Table { contents, .. } => Ok(IndexableValue::Table(contents.as_ptr() as u64)),
}
}
pub fn as_float(&self) -> Result<LuaFloat, RuntimeError> {
pub fn as_float(&self) -> Result<LuaFloat, RuntimeError<UserData>> {
match self {
Value::Float(vmfloat) => Ok(vmfloat.lua_number()),
Value::Integer(lua_integer) => Ok(lua_integer.into()),
@ -165,7 +176,7 @@ impl Value {
}
}
pub fn as_integer(&self) -> Result<LuaInteger, RuntimeError> {
pub fn as_integer(&self) -> Result<LuaInteger, RuntimeError<UserData>> {
match self {
Value::Integer(lua_integer) => Ok(*lua_integer),
Value::Boolean(lua_boolean) => Ok(LuaInteger(lua_boolean.0 as i64)),
@ -173,7 +184,7 @@ impl Value {
}
}
pub fn as_bits(&self) -> Result<LuaInteger, RuntimeError> {
pub fn as_bits(&self) -> Result<LuaInteger, RuntimeError<UserData>> {
match self {
Value::Float(vmfloat) => Ok(LuaInteger(vmfloat.lua_number().0 as i64)),
Value::Integer(lua_integer) => Ok(LuaInteger(lua_integer.0 as i64)),
@ -184,13 +195,13 @@ impl Value {
}
}
impl From<&str> for Value {
impl<UserData: Clone> From<&str> for Value<UserData> {
fn from(value: &str) -> Self {
Value::String(value.to_owned())
}
}
impl Display for Value {
impl<UserData: Clone> Display for Value<UserData> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::String(value) => Display::fmt(value, f),
@ -207,8 +218,11 @@ impl Display for Value {
}
}
impl Value {
pub fn concat(&self, other: &Value) -> Result<Value, RuntimeError> {
impl<UserData: Clone> Value<UserData> {
pub fn concat(
&self,
other: &Value<UserData>,
) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(
Value::String(_) | Value::Integer(_) | Value::Boolean(_),
@ -229,7 +243,7 @@ impl Value {
}
}
pub fn add(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn add(&self, other: &Value<UserData>) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
let res = LuaInteger(self.as_integer()?.0 + other.as_integer()?.0);
@ -250,7 +264,7 @@ impl Value {
}
}
pub fn mult(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn mult(&self, other: &Value<UserData>) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
let res = LuaInteger(self.as_integer()?.0 * other.as_integer()?.0);
@ -271,7 +285,7 @@ impl Value {
}
}
pub fn div(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn div(&self, other: &Value<UserData>) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
let res = LuaFloat(self.as_integer()?.0 as f64 / other.as_integer()?.0 as f64);
@ -292,7 +306,7 @@ impl Value {
}
}
pub fn idiv(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn idiv(&self, other: &Value<UserData>) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
let res = LuaInteger(self.as_integer()?.0 / other.as_integer()?.0);
@ -313,7 +327,10 @@ impl Value {
}
}
pub fn r#mod(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn r#mod(
&self,
other: &Value<UserData>,
) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
let res = LuaInteger(self.as_integer()?.0 % other.as_integer()?.0);
@ -334,7 +351,7 @@ impl Value {
}
}
pub fn exp(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn exp(&self, other: &Value<UserData>) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
let res = LuaInteger(self.as_integer()?.0.pow(other.as_integer()?.0 as u32));
@ -355,7 +372,7 @@ impl Value {
}
}
pub fn band(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn band(&self, other: &Value<UserData>) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
@ -372,7 +389,7 @@ impl Value {
}
}
pub fn bor(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn bor(&self, other: &Value<UserData>) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
@ -389,7 +406,7 @@ impl Value {
}
}
pub fn bxor(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn bxor(&self, other: &Value<UserData>) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
@ -406,7 +423,10 @@ impl Value {
}
}
pub fn bsleft(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn bsleft(
&self,
other: &Value<UserData>,
) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
@ -423,7 +443,10 @@ impl Value {
}
}
pub fn bsright(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn bsright(
&self,
other: &Value<UserData>,
) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
@ -440,7 +463,7 @@ impl Value {
}
}
pub fn eq(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn eq(&self, other: &Value<UserData>) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(Value::Integer(lhs), Value::Integer(rhs)) => {
Ok(Value::Boolean(LuaBool(lhs.0 == rhs.0)))
@ -457,7 +480,7 @@ impl Value {
}
}
pub fn lt(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn lt(&self, other: &Value<UserData>) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(Value::Integer(lhs), Value::Integer(rhs)) => {
Ok(Value::Boolean(LuaBool(lhs.0 < rhs.0)))
@ -474,7 +497,7 @@ impl Value {
}
}
pub fn lte(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn lte(&self, other: &Value<UserData>) -> Result<Value<UserData>, RuntimeError<UserData>> {
match (self, other) {
(Value::Integer(lhs), Value::Integer(rhs)) => {
Ok(Value::Boolean(LuaBool(lhs.0 <= rhs.0)))
@ -491,7 +514,7 @@ impl Value {
}
}
pub fn unm(&self) -> Result<Value, RuntimeError> {
pub fn unm(&self) -> Result<Value<UserData>, RuntimeError<UserData>> {
match self {
Value::Integer(lhs) => {
let res = LuaInteger(-lhs.0);
@ -512,7 +535,7 @@ impl Value {
}
}
pub fn len(&self) -> Result<Value, RuntimeError> {
pub fn len(&self) -> Result<Value<UserData>, RuntimeError<UserData>> {
match self {
Value::String(value) => Ok(Self::Integer(LuaInteger(value.len() as i64))),
Value::Table { contents, .. } => {
@ -553,7 +576,7 @@ impl Value {
}
}
pub fn and(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn and(&self, other: &Value<UserData>) -> Result<Value<UserData>, RuntimeError<UserData>> {
if self.is_truthy() {
Ok(self.clone())
} else {
@ -561,7 +584,7 @@ impl Value {
}
}
pub fn or(&self, other: &Value) -> Result<Value, RuntimeError> {
pub fn or(&self, other: &Value<UserData>) -> Result<Value<UserData>, RuntimeError<UserData>> {
if self.is_truthy() {
Ok(self.clone())
} else {
@ -569,7 +592,7 @@ impl Value {
}
}
pub fn not(&self) -> Result<Value, RuntimeError> {
pub fn not(&self) -> Result<Value<UserData>, RuntimeError<UserData>> {
if self.is_truthy() {
Ok(Value::Boolean(LuaBool(false)))
} else {
@ -591,7 +614,7 @@ impl Value {
}
}
impl Debug for Value {
impl<UserData: Clone> Debug for Value<UserData> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::Float(arg0) => f.debug_tuple("Float").field(&arg0.lua_number()).finish(),
@ -622,11 +645,11 @@ pub enum IndexableValue {
Bool(LuaBool),
RustFunction(String),
Function(u32),
Table(*mut TableMap),
Table(u64),
}
impl From<&str> for IndexableValue {
fn from(value: &str) -> Self {
Value::from(value).as_indexable().unwrap()
Value::<()>::from(value).as_indexable().unwrap()
}
}