Skip to main content

Lua

Struct Lua 

Source
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

Source

pub fn new() -> Self

Create a Lua runtime with parser and standard libraries installed.

Examples found in repository?
examples/scope_world.rs (line 66)
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}
Source

pub fn try_new() -> Result<Self>

Fallible variant of Lua::new.

Source

pub fn with_hooks(hooks: HostHooks) -> Result<Self>

Create a Lua runtime with the supplied host capabilities.

Source

pub fn load(&self, source: impl AsRef<[u8]>) -> Chunk

Load a Lua source chunk.

Examples found in repository?
examples/scope_world.rs (lines 73-90)
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}
Source

pub fn globals(&self) -> Table

Return the global environment table.

Examples found in repository?
examples/scope_world.rs (line 71)
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}
Source

pub fn create_table(&self) -> Result<Table>

Create a new empty table.

Source

pub fn create_string(&self, bytes: impl AsRef<[u8]>) -> Result<LuaString>

Create a new Lua string from bytes.

Source

pub fn create_function<A, R, F>(&self, func: F) -> Result<Function>
where A: FromLuaMulti + 'static, R: IntoLuaMulti + 'static, F: Fn(&Lua, A) -> Result<R> + 'static,

Source

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,

Source

pub fn create_userdata<T>(&self, data: T) -> Result<AnyUserData>
where T: UserData,

Source

pub fn scope<F, R>(&self, f: F) -> Result<R>
where F: for<'scope> FnOnce(&Scope<'scope>) -> 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?
examples/scope_world.rs (lines 69-92)
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}
Source

pub fn gc_collect(&self)

Run a full garbage-collection cycle.

Source§

impl Lua

Source

pub fn sandboxed(config: SandboxConfig) -> Result<(Self, Sandbox)>

Create a Lua runtime with no host capabilities (no file, process, or dynamic-library hooks), the configured globals stripped, and an instruction/memory budget installed. Returns the runtime and a Sandbox handle for inspecting and resetting the budget.

Source

pub fn install_sandbox(&self, config: SandboxConfig) -> Result<Sandbox>

Apply sandbox limits to this runtime: strip the configured globals and, if any runtime limit is set, install the runtime-wide budget. The budget lives in the shared GlobalState and is enforced natively in the VM on every thread, so code inside coroutines is metered too. Use this when you want to grant some host capabilities (build the Lua with selected HostHooks) but still bound execution.

Trait Implementations§

Source§

impl Clone for Lua

Source§

fn clone(&self) -> Lua

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Lua

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Lua

§

impl !RefUnwindSafe for Lua

§

impl !Send for Lua

§

impl !Sync for Lua

§

impl Unpin for Lua

§

impl UnsafeUnpin for Lua

§

impl !UnwindSafe for Lua

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.