pub struct Scope<'scope> { /* private fields */ }Expand description
Handle passed to the closure body of Lua::scope.
Scope::create_userdata produces an AnyUserData whose backing storage
is a borrow you provide; when the scope drops every cell it created is
invalidated. Any later Lua call that reaches one of those userdatas fails
with a clean error rather than touching freed memory.
Implementations§
Source§impl<'scope> Scope<'scope>
impl<'scope> Scope<'scope>
Sourcepub fn create_userdata_ref_mut<T>(
&self,
lua: &Lua,
data: &'scope mut T,
) -> Result<AnyUserData>where
T: UserData,
pub fn create_userdata_ref_mut<T>(
&self,
lua: &Lua,
data: &'scope mut T,
) -> Result<AnyUserData>where
T: UserData,
Wrap a &mut T borrow as a Lua userdata that lives for the duration of
this scope. Any call from Lua to the returned userdata after the scope
ends fails with a clean Lua runtime error instead of touching the
freed borrow.
Naming mirrors mlua’s Scope::create_userdata_ref_mut. The bare
create_userdata name on Scope is intentionally reserved for the
future by-value, non-'static constructor (mlua’s
Scope::create_userdata<T: UserData + 'env>(T)), tracked as a
follow-up to lua-rs#27.
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_function<A, R, F>(&self, lua: &Lua, func: F) -> Result<Function>
pub fn create_function<A, R, F>(&self, lua: &Lua, func: F) -> Result<Function>
Build a Lua Function from a non-'static Rust closure. The closure
is owned by a [ScopedFnCell] that the scope holds; once the scope
drops, the cell drops the closure and any later Lua call that reaches
the returned function fails cleanly with “no longer valid” instead of
touching the released captures.
This is the function counterpart to [Self::create_userdata] — pair
them when you want to hand Lua a &mut World plus a few closures that
also borrow from the same stack frame.
Sourcepub fn create_function_mut<A, R, F>(
&self,
lua: &Lua,
func: F,
) -> Result<Function>where
A: FromLuaMulti + 'static,
R: IntoLuaMulti + 'static,
F: FnMut(&Lua, A) -> Result<R> + 'scope,
pub fn create_function_mut<A, R, F>(
&self,
lua: &Lua,
func: F,
) -> Result<Function>where
A: FromLuaMulti + 'static,
R: IntoLuaMulti + 'static,
F: FnMut(&Lua, A) -> Result<R> + 'scope,
Like Self::create_function but accepts an FnMut. Mirrors
Lua::create_function_mut: re-entrant calls into the same closure
are rejected with an “already borrowed” runtime error rather than
producing aliasing &mut captures.