pub struct Lua { /* private fields */ }Expand description
Primary owned embedding handle.
Lua is intentionally cheap to clone and single-threaded. State access is
borrowed at the embedding boundary only; opcode dispatch still runs with
direct &mut LuaState access. Captured Rust callbacks will need a call-path
adapter that releases this boundary borrow before invoking user code.
Implementations§
Source§impl Lua
impl Lua
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a Lua runtime with parser and standard libraries installed.
Examples found in repository?
65fn main() -> Result<()> {
66 let lua = Lua::new();
67 let mut world = World::default();
68
69 let count: i64 = lua.scope(|s| {
70 let world_ud = s.create_userdata_ref_mut(&lua, &mut world)?;
71 lua.globals().set("world", &world_ud)?;
72
73 lua.load(
74 r#"
75 local a = world:spawn()
76 local b = world:spawn()
77
78 -- Direct mutation through a live sub-reference.
79 local pa = world:position(a)
80 pa.x, pa.y = 10, 20
81
82 local pb = world:position(b)
83 pb.x = pa.x + 5 -- reading pa here re-borrows; both are short-lived
84
85 -- Stash one to prove it dies with the scope.
86 escaped = world:position(a)
87
88 return world:count()
89 "#,
90 )
91 .eval()
92 })?;
93
94 println!("spawned {count} entities");
95 // The mutations are visible to Rust after the scope returns.
96 for (i, e) in world.entities.iter().enumerate() {
97 println!("entity {i} = ({}, {})", e.x, e.y);
98 }
99
100 // The handle the script stashed on `escaped` is now invalid. Reading a
101 // field raises a Lua error rather than touching the released `&mut World`.
102 // We surface the message through Lua's own `pcall` + `tostring`, since the
103 // error payload is a Lua value.
104 let (ok, msg): (bool, String) = lua
105 .load("local ok, e = pcall(function() return escaped.x end); return ok, tostring(e)")
106 .eval()?;
107 assert!(!ok, "stashed handle should be unusable after the scope");
108 println!("post-scope use of a stashed handle -> {msg}");
109
110 Ok(())
111}Sourcepub fn with_hooks(hooks: HostHooks) -> Result<Self>
pub fn with_hooks(hooks: HostHooks) -> Result<Self>
Create a Lua runtime with the supplied host capabilities.
Sourcepub fn load(&self, source: impl AsRef<[u8]>) -> Chunk
pub fn load(&self, source: impl AsRef<[u8]>) -> Chunk
Load a Lua source chunk.
Examples found in repository?
65fn main() -> Result<()> {
66 let lua = Lua::new();
67 let mut world = World::default();
68
69 let count: i64 = lua.scope(|s| {
70 let world_ud = s.create_userdata_ref_mut(&lua, &mut world)?;
71 lua.globals().set("world", &world_ud)?;
72
73 lua.load(
74 r#"
75 local a = world:spawn()
76 local b = world:spawn()
77
78 -- Direct mutation through a live sub-reference.
79 local pa = world:position(a)
80 pa.x, pa.y = 10, 20
81
82 local pb = world:position(b)
83 pb.x = pa.x + 5 -- reading pa here re-borrows; both are short-lived
84
85 -- Stash one to prove it dies with the scope.
86 escaped = world:position(a)
87
88 return world:count()
89 "#,
90 )
91 .eval()
92 })?;
93
94 println!("spawned {count} entities");
95 // The mutations are visible to Rust after the scope returns.
96 for (i, e) in world.entities.iter().enumerate() {
97 println!("entity {i} = ({}, {})", e.x, e.y);
98 }
99
100 // The handle the script stashed on `escaped` is now invalid. Reading a
101 // field raises a Lua error rather than touching the released `&mut World`.
102 // We surface the message through Lua's own `pcall` + `tostring`, since the
103 // error payload is a Lua value.
104 let (ok, msg): (bool, String) = lua
105 .load("local ok, e = pcall(function() return escaped.x end); return ok, tostring(e)")
106 .eval()?;
107 assert!(!ok, "stashed handle should be unusable after the scope");
108 println!("post-scope use of a stashed handle -> {msg}");
109
110 Ok(())
111}Sourcepub fn globals(&self) -> Table
pub fn globals(&self) -> Table
Return the global environment table.
Examples found in repository?
65fn main() -> Result<()> {
66 let lua = Lua::new();
67 let mut world = World::default();
68
69 let count: i64 = lua.scope(|s| {
70 let world_ud = s.create_userdata_ref_mut(&lua, &mut world)?;
71 lua.globals().set("world", &world_ud)?;
72
73 lua.load(
74 r#"
75 local a = world:spawn()
76 local b = world:spawn()
77
78 -- Direct mutation through a live sub-reference.
79 local pa = world:position(a)
80 pa.x, pa.y = 10, 20
81
82 local pb = world:position(b)
83 pb.x = pa.x + 5 -- reading pa here re-borrows; both are short-lived
84
85 -- Stash one to prove it dies with the scope.
86 escaped = world:position(a)
87
88 return world:count()
89 "#,
90 )
91 .eval()
92 })?;
93
94 println!("spawned {count} entities");
95 // The mutations are visible to Rust after the scope returns.
96 for (i, e) in world.entities.iter().enumerate() {
97 println!("entity {i} = ({}, {})", e.x, e.y);
98 }
99
100 // The handle the script stashed on `escaped` is now invalid. Reading a
101 // field raises a Lua error rather than touching the released `&mut World`.
102 // We surface the message through Lua's own `pcall` + `tostring`, since the
103 // error payload is a Lua value.
104 let (ok, msg): (bool, String) = lua
105 .load("local ok, e = pcall(function() return escaped.x end); return ok, tostring(e)")
106 .eval()?;
107 assert!(!ok, "stashed handle should be unusable after the scope");
108 println!("post-scope use of a stashed handle -> {msg}");
109
110 Ok(())
111}Sourcepub fn create_table(&self) -> Result<Table>
pub fn create_table(&self) -> Result<Table>
Create a new empty table.
Sourcepub fn create_string(&self, bytes: impl AsRef<[u8]>) -> Result<LuaString>
pub fn create_string(&self, bytes: impl AsRef<[u8]>) -> Result<LuaString>
Create a new Lua string from bytes.
pub fn create_function<A, R, F>(&self, func: F) -> Result<Function>
pub fn create_function_mut<A, R, F>(&self, func: F) -> Result<Function>where
A: FromLuaMulti + 'static,
R: IntoLuaMulti + 'static,
F: FnMut(&Lua, A) -> Result<R> + 'static,
pub fn create_userdata<T>(&self, data: T) -> Result<AnyUserData>where
T: UserData,
Sourcepub fn scope<F, R>(&self, f: F) -> Result<R>
pub fn scope<F, R>(&self, f: F) -> Result<R>
Run f with a fresh Scope; any AnyUserData created via the
scope is invalidated when f returns, so leaked references fail
cleanly instead of using-after-the-borrow-ended.
use lua_rs_runtime::{Lua, UserData, UserDataMethods};
struct Counter { value: i64 }
impl UserData for Counter {
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
methods.add_method_mut("inc", |_lua, this, delta: i64| {
this.value += delta;
Ok(this.value)
});
}
}
let lua = Lua::new();
let mut counter = Counter { value: 0 };
lua.scope(|scope| {
let ud = scope.create_userdata_ref_mut(&lua, &mut counter)?;
lua.globals().set("c", &ud)?;
lua.load("c:inc(5); c:inc(7)").exec()
}).unwrap();
assert_eq!(counter.value, 12);
// The script can stash the userdata on a global and try to use it
// later, but the call cleanly errors instead of touching the
// dropped `&mut counter`:
lua.scope(|scope| {
let ud = scope.create_userdata_ref_mut(&lua, &mut counter)?;
lua.globals().set("leaked", &ud)
}).unwrap();
assert!(lua.load("leaked:inc(1)").exec().is_err());Examples found in repository?
65fn main() -> Result<()> {
66 let lua = Lua::new();
67 let mut world = World::default();
68
69 let count: i64 = lua.scope(|s| {
70 let world_ud = s.create_userdata_ref_mut(&lua, &mut world)?;
71 lua.globals().set("world", &world_ud)?;
72
73 lua.load(
74 r#"
75 local a = world:spawn()
76 local b = world:spawn()
77
78 -- Direct mutation through a live sub-reference.
79 local pa = world:position(a)
80 pa.x, pa.y = 10, 20
81
82 local pb = world:position(b)
83 pb.x = pa.x + 5 -- reading pa here re-borrows; both are short-lived
84
85 -- Stash one to prove it dies with the scope.
86 escaped = world:position(a)
87
88 return world:count()
89 "#,
90 )
91 .eval()
92 })?;
93
94 println!("spawned {count} entities");
95 // The mutations are visible to Rust after the scope returns.
96 for (i, e) in world.entities.iter().enumerate() {
97 println!("entity {i} = ({}, {})", e.x, e.y);
98 }
99
100 // The handle the script stashed on `escaped` is now invalid. Reading a
101 // field raises a Lua error rather than touching the released `&mut World`.
102 // We surface the message through Lua's own `pcall` + `tostring`, since the
103 // error payload is a Lua value.
104 let (ok, msg): (bool, String) = lua
105 .load("local ok, e = pcall(function() return escaped.x end); return ok, tostring(e)")
106 .eval()?;
107 assert!(!ok, "stashed handle should be unusable after the scope");
108 println!("post-scope use of a stashed handle -> {msg}");
109
110 Ok(())
111}Sourcepub fn gc_collect(&self)
pub fn gc_collect(&self)
Run a full garbage-collection cycle.