From bed5091ecd7e0cabf0fa1a83646fc8ac9bf363c7 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Sat, 10 Feb 2024 17:04:09 -0500 Subject: [PATCH] Implement all methods for controlling the Lua GC, and some code cleanup --- src/lib.rs | 65 -------------------------- src/state.rs | 96 +++++++++++++++++++++++++++++++++++--- src/userdata/borrow.rs | 6 +-- src/userdata/borrow_mut.rs | 4 +- 4 files changed, 94 insertions(+), 77 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3a395df..92ac9d5 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,71 +33,6 @@ use lref::*; #[cfg(test)] pub mod tests; -/* fn main() -> Result<()> { - let lua = State::new(); - lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]); - - let globals = lua.globals()?; - - let v1 = RefCell::new(Vec2 { x: 50.0, y: 5.0 }); - let ud = lua.create_userdata(UserdataRef::from(v1.borrow()))?; - globals.set("v1", ud)?; - - let v2 = Vec2 { x: 10.0, y: 15.0 }; - let ud = lua.create_userdata(UserdataRef::from(&v2))?; - globals.set("v2", ud)?; - - //lua.gc_stop()?; - let chunk = lua.load( - "text.lua", - r#" - require "util" - - --if vec2 ~= nil then - print("v1: (" .. v1.x .. ", " .. v1.y .. ")") - --print("v2: (" .. v2.x .. ", " .. v2.y .. ")") - --end - - --print("vec2.x = " .. vec2.x) - --print("vec2.y = " .. vec2.y) - "#, - )?; - - const MAX_RUNS: i32 = 400; - for i in 0..MAX_RUNS { - // I don't care about the result of this execution, so I set the result as a - // Value which can be anything - // - // Chunks can also be executed with: `chunk.execute(())?;` - let res = lua.execute_chunk::<_, Value>(&chunk, ()); - - // if unwrapped, the new lines in the message would be escaped making - // the traceback in the error difficult to read. - if let Err(e) = res { - panic!("{}", e); - } - - //print_refs(&lua).unwrap(); - println!("i = {}", i); - globals.set("v1", Value::Nil)?; - lua.gc_collect()?; - - let mut t = v1.borrow_mut(); - t.x += 50.0; - t.y += 5.0; - drop(t); - - let ud = lua.create_userdata(UserdataRef::from(v1.borrow()))?; - globals.raw_set("v1", ud)?; - } - - unsafe { - assert_eq!(lua::lua_gettop(lua.state_ptr()), 0); // ensure that nothing is left on the stack - } - - Ok(()) -} */ - pub trait PushToLuaStack<'a> { unsafe fn push_to_lua_stack(&self, state: &'a State) -> Result<()>; } diff --git a/src/state.rs b/src/state.rs index 8395f93..c390506 100755 --- a/src/state.rs +++ b/src/state.rs @@ -4,7 +4,7 @@ use std::{alloc::{self, Layout}, any::TypeId, cell::RefCell, collections::HashMa use lua::lua_gc; use mlua_sys as lua; -use crate::{lua_error_guard, AnyUserdata, AsLua, Chunk, Error, FromLua, FromLuaStack, FromLuaVec, Function, IntoChunkData, IntoLuaVec, LuaRef, MetaMethod, PushToLuaStack, Result, StackGuard, Table, Userdata, UserdataBuilder, Value, ValueVec}; +use crate::{lua_error_guard, proxy::UserdataProxy, AnyUserdata, AsLua, Chunk, Error, FromLua, FromLuaStack, FromLuaVec, Function, IntoChunkData, IntoLuaVec, LuaRef, MetaMethod, PushToLuaStack, Result, StackGuard, Table, Userdata, UserdataBuilder, Value, ValueVec}; pub fn ptr_to_string(ptr: *const i8) -> std::result::Result { let c = unsafe { CStr::from_ptr(ptr) }; @@ -522,6 +522,13 @@ impl State { Ok(mt) } + /// Creates a userdata proxy. This proxy has the same metatable as `T`, but has no default value. + /// This eliminates the need for `T` to have a default value. + pub fn create_proxy(&self) -> Result { + self.create_userdata(UserdataProxy::::new()) + } + + /// Retrieves the debug info from the Lua stack. pub(crate) unsafe fn debug_info(&self) -> Box { let s = self.state_ptr(); @@ -535,6 +542,7 @@ impl State { Box::from_raw(ar) } + /// Retrieves the current line of the script pub fn current_line(&self) -> usize { unsafe { let ar = self.debug_info(); @@ -542,6 +550,7 @@ impl State { } } + /// Retrieves a traceback of the Lua stack, optionally prepends the traceback string with `msg` pub fn traceback(&self, msg: Option<&str>) -> Result { unsafe { let _g = StackGuard::new(self); @@ -589,24 +598,97 @@ impl State { } /// Triggers a full garbage-collection cycle. - pub fn gc_collect(&self) -> Result<()> { + pub fn gc_collect(&self) { unsafe { let s = self.state_ptr(); lua_gc(s, lua::LUA_GCCOLLECT); } - - Ok(()) } /// Disable the garbage collector - pub fn gc_stop(&self) -> Result<()> { + pub fn gc_stop(&self) { unsafe { let s = self.state_ptr(); lua_gc(s, lua::LUA_GCSTOP); } - - Ok(()) } + + /// Restarts the garbage collector + pub fn gc_restart(&self) { + unsafe { + let s = self.state_ptr(); + + lua_gc(s, lua::LUA_GCRESTART); + } + } + + /// Returns the current amount of memory used by Lua in kilabytes + pub fn memory_usage(&self) -> u32 { + unsafe { + let s = self.state_ptr(); + + lua_gc(s, lua::LUA_GCCOUNT) as u32 + } + } + + /// Returns the remainder of dividing the current amount of bytes of memory in use by Lua by 1024. + pub fn memory_usage_rem(&self) -> u32 { + unsafe { + let s = self.state_ptr(); + + lua_gc(s, lua::LUA_GCCOUNTB) as u32 + } + } + + /// Trigger a step of the garbage collector + /// + /// Lua docs: + /// > Performs an incremental step of garbage collection, corresponding to the allocation + /// of stepsize Kbytes. + pub fn gc_step(&self, step_size: i32) { + unsafe { + let s = self.state_ptr(); + + lua_gc(s, lua::LUA_GCSTEP, step_size); + } + } + + /// Changes the collector to incremental mode with the given parameters + /// (see [Incremental Garbage Collection](https://www.lua.org/manual/5.4/manual.html#2.5.1)). + /// Returns the previous mode. + pub fn gc_set_incremental(&self, pause: i32, step_mul: i32, step_size: i32) -> GcMode { + unsafe { + let s = self.state_ptr(); + + let mode = lua_gc(s, lua::LUA_GCINC, pause, step_mul, step_size); + if mode == lua::LUA_GCGEN { + GcMode::Generational + } else { + GcMode::Incremental + } + } + } + + /// Changes the collector to generational mode with the given parameters + /// (see [Generational Garbage Collection](https://www.lua.org/manual/5.4/manual.html#2.5.2)). + /// Returns the previous mode. + pub fn gc_set_generational(&self, minor_mul: i32, major_mul: i32)-> GcMode { + unsafe { + let s = self.state_ptr(); + + let mode = lua_gc(s, lua::LUA_GCGEN, minor_mul, major_mul); + if mode == lua::LUA_GCGEN { + GcMode::Generational + } else { + GcMode::Incremental + } + } + } +} + +pub enum GcMode { + Incremental, + Generational, } \ No newline at end of file diff --git a/src/userdata/borrow.rs b/src/userdata/borrow.rs index f2cc063..d08d1e6 100755 --- a/src/userdata/borrow.rs +++ b/src/userdata/borrow.rs @@ -87,9 +87,9 @@ impl<'a, T: Userdata + 'static> Userdata for UserdataRef<'a, T> { #[cfg(test)] mod tests { - use std::{borrow::Borrow, cell::{Ref, RefCell}}; + use std::cell::{Ref, RefCell}; - use crate::{tests::Vec2, AnyUserdata, State, StdLibrary, Value}; + use crate::{tests::Vec2, State, StdLibrary, Value}; use super::UserdataRef; @@ -120,7 +120,7 @@ mod tests { //println!("i = {}", i); globals.set("v1", Value::Nil)?; - lua.gc_collect()?; // must collect here to drop the Ref + lua.gc_collect(); // must collect here to drop the Ref let mut t = v1.borrow_mut(); t.x += 50.0; diff --git a/src/userdata/borrow_mut.rs b/src/userdata/borrow_mut.rs index d76490c..9d438eb 100755 --- a/src/userdata/borrow_mut.rs +++ b/src/userdata/borrow_mut.rs @@ -141,7 +141,7 @@ mod tests { //println!("i = {}", i); globals.set("v1", Value::Nil)?; - lua.gc_collect()?; // must collect here to drop the RefMut + lua.gc_collect(); // must collect here to drop the RefMut x += 50.0; y += 5.0; @@ -184,7 +184,7 @@ mod tests { } globals.set("v1", Value::Nil)?; - lua.gc_collect()?; // must collect here to drop the RefMut + lua.gc_collect(); // must collect here to drop the RefMut let t = v1.borrow(); assert_eq!(100.0, t.x);