Manually manage the lifecycle of scope userdata through Scope::add_destructor() and UserData::destroy()

This commit is contained in:
sxyazi 2024-11-08 21:29:46 +08:00
parent 2ee619193e
commit 0f00808146
No known key found for this signature in database
16 changed files with 50 additions and 39 deletions

View file

@ -2,7 +2,7 @@ use std::ops::Deref;
use mlua::{AnyUserData, UserData, UserDataFields};
use super::SCOPE;
use super::Lives;
pub(super) struct Config {
inner: *const yazi_core::tab::Config,
@ -17,7 +17,7 @@ impl Deref for Config {
impl Config {
#[inline]
pub(super) fn make(inner: &yazi_core::tab::Config) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { inner })
Lives::scoped_userdata(Self { inner })
}
}

View file

@ -5,7 +5,7 @@ use yazi_config::THEME;
use yazi_plugin::{bindings::Range, elements::Style};
use yazi_shared::MIME_DIR;
use super::SCOPE;
use super::Lives;
use crate::Ctx;
pub(super) struct File {
@ -31,7 +31,7 @@ impl File {
folder: &yazi_fs::Folder,
tab: &yazi_core::tab::Tab,
) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { idx, folder, tab })
Lives::scoped_userdata(Self { idx, folder, tab })
}
#[inline]

View file

@ -2,7 +2,7 @@ use std::ops::{Deref, Range};
use mlua::{AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMethods};
use super::{File, Filter, SCOPE};
use super::{File, Filter, Lives};
pub(super) struct Files {
window: Range<usize>,
@ -23,7 +23,7 @@ impl Files {
folder: &yazi_fs::Folder,
tab: &yazi_core::tab::Tab,
) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { window, folder, tab })
Lives::scoped_userdata(Self { window, folder, tab })
}
#[inline]

View file

@ -2,7 +2,7 @@ use std::ops::Deref;
use mlua::{AnyUserData, MetaMethod, UserData, UserDataMethods};
use super::SCOPE;
use super::Lives;
pub(super) struct Filter {
inner: *const yazi_fs::Filter,
@ -17,7 +17,7 @@ impl Deref for Filter {
impl Filter {
#[inline]
pub(super) fn make(inner: &yazi_fs::Filter) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { inner })
Lives::scoped_userdata(Self { inner })
}
}

View file

@ -2,7 +2,7 @@ use std::ops::Deref;
use mlua::{AnyUserData, MetaMethod, UserData, UserDataMethods};
use super::SCOPE;
use super::Lives;
pub(super) struct Finder {
inner: *const yazi_core::tab::Finder,
@ -17,7 +17,7 @@ impl Deref for Finder {
impl Finder {
#[inline]
pub(super) fn make(inner: &yazi_core::tab::Finder) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { inner })
Lives::scoped_userdata(Self { inner })
}
}

View file

@ -4,7 +4,7 @@ use mlua::{AnyUserData, Lua, UserData, UserDataFields};
use yazi_config::LAYOUT;
use yazi_plugin::{bindings::Cast, url::Url};
use super::{File, Files, SCOPE};
use super::{File, Files, Lives};
pub(super) struct Folder {
window: Range<usize>,
@ -33,7 +33,7 @@ impl Folder {
}
};
SCOPE.create_userdata(Self { window, inner, tab })
Lives::scoped_userdata(Self { window, inner, tab })
}
pub(super) fn register(lua: &Lua) -> mlua::Result<()> {

View file

@ -1,6 +1,6 @@
use mlua::{AnyUserData, UserData};
use super::SCOPE;
use super::Lives;
pub(super) struct Iter<I: Iterator<Item = T>, T> {
inner: I,
@ -10,7 +10,7 @@ pub(super) struct Iter<I: Iterator<Item = T>, T> {
impl<I: Iterator<Item = T> + 'static, T: 'static> Iter<I, T> {
#[inline]
pub(super) fn make(inner: I) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { inner, count: 0 })
Lives::scoped_userdata(Self { inner, count: 0 })
}
}

View file

@ -1,13 +1,13 @@
use std::mem;
use std::cell::RefCell;
use scopeguard::defer;
use mlua::{AnyUserData, UserData};
use tracing::error;
use yazi_plugin::LUA;
use yazi_shared::RoCell;
use crate::Ctx;
pub(super) static SCOPE: RoCell<&mlua::Scope> = RoCell::new();
static TO_DESTROY: RoCell<RefCell<Vec<AnyUserData>>> = RoCell::new_const(RefCell::new(Vec::new()));
pub(crate) struct Lives;
@ -20,14 +20,14 @@ impl Lives {
pub(crate) fn scope<T>(cx: &Ctx, f: impl FnOnce() -> mlua::Result<T>) -> mlua::Result<T> {
let result = LUA.scope(|scope| {
defer! { SCOPE.drop(); }
SCOPE.init(*unsafe {
mem::transmute::<&&mut mlua::Scope<'_, '_>, &&mut mlua::Scope<'static, 'static>>(&scope)
scope.add_destructor(|| {
for ud in TO_DESTROY.borrow_mut().drain(..) {
ud.destroy().expect("failed to destruct scoped userdata");
}
});
LUA.set_named_registry_value("cx", scope.create_any_userdata_ref(cx)?)?;
let globals = LUA.globals();
globals.raw_set(
LUA.set_named_registry_value("cx", scope.create_any_userdata_ref(cx)?)?;
LUA.globals().raw_set(
"cx",
LUA.create_table_from([
("active", super::Tab::make(cx.manager.active())?),
@ -45,4 +45,14 @@ impl Lives {
}
result
}
#[inline]
pub(crate) fn scoped_userdata<T>(data: T) -> mlua::Result<AnyUserData>
where
T: UserData + 'static,
{
let ud = LUA.create_userdata(data)?;
TO_DESTROY.borrow_mut().push(ud.clone());
Ok(ud)
}
}

View file

@ -2,7 +2,7 @@ use std::ops::Deref;
use mlua::{AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMethods};
use super::SCOPE;
use super::Lives;
pub(super) struct Mode {
inner: *const yazi_core::tab::Mode,
@ -17,7 +17,7 @@ impl Deref for Mode {
impl Mode {
#[inline]
pub(super) fn make(inner: &yazi_core::tab::Mode) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { inner })
Lives::scoped_userdata(Self { inner })
}
}

View file

@ -3,7 +3,7 @@ use std::ops::Deref;
use mlua::{AnyUserData, UserData, UserDataFields};
use yazi_config::LAYOUT;
use super::{Folder, SCOPE};
use super::{Folder, Lives};
pub(super) struct Preview {
tab: *const yazi_core::tab::Tab,
@ -18,7 +18,7 @@ impl Deref for Preview {
impl Preview {
#[inline]
pub(super) fn make(tab: &yazi_core::tab::Tab) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { tab })
Lives::scoped_userdata(Self { tab })
}
#[inline]

View file

@ -3,7 +3,7 @@ use std::{collections::{HashMap, hash_map}, ops::Deref};
use mlua::{AnyUserData, IntoLuaMulti, MetaMethod, UserData, UserDataMethods, UserDataRefMut};
use yazi_plugin::{bindings::Cast, url::Url};
use super::{Iter, SCOPE};
use super::{Iter, Lives};
#[derive(Clone, Copy)]
pub(super) struct Selected {
@ -19,7 +19,7 @@ impl Deref for Selected {
impl Selected {
#[inline]
pub(super) fn make(inner: &HashMap<yazi_shared::fs::Url, u64>) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { inner })
Lives::scoped_userdata(Self { inner })
}
#[inline]
@ -32,7 +32,6 @@ impl UserData for Selected {
methods.add_meta_method(MetaMethod::Pairs, |lua, me, ()| {
let iter = lua.create_function(
// FIXME: UserDataRef
|lua, mut iter: UserDataRefMut<Iter<hash_map::Keys<yazi_shared::fs::Url, u64>, _>>| {
if let Some(next) = iter.next() {
(next.0, Url::cast(lua, next.1.clone())?).into_lua_multi(lua)

View file

@ -3,7 +3,7 @@ use std::ops::Deref;
use mlua::{AnyUserData, UserData, UserDataFields, UserDataMethods};
use yazi_plugin::url::UrlRef;
use super::{Config, Finder, Folder, Mode, Preview, SCOPE, Selected};
use super::{Config, Finder, Folder, Lives, Mode, Preview, Selected};
pub(super) struct Tab {
inner: *const yazi_core::tab::Tab,
@ -18,7 +18,7 @@ impl Deref for Tab {
impl Tab {
#[inline]
pub(super) fn make(inner: &yazi_core::tab::Tab) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { inner })
Lives::scoped_userdata(Self { inner })
}
}

View file

@ -2,7 +2,7 @@ use std::ops::Deref;
use mlua::{AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMethods};
use super::{SCOPE, Tab};
use super::{Lives, Tab};
pub(super) struct Tabs {
inner: *const yazi_core::manager::Tabs,
@ -17,7 +17,7 @@ impl Deref for Tabs {
impl Tabs {
#[inline]
pub(super) fn make(inner: &yazi_core::manager::Tabs) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { inner })
Lives::scoped_userdata(Self { inner })
}
}

View file

@ -2,7 +2,7 @@ use std::ops::Deref;
use mlua::{AnyUserData, LuaSerdeExt, UserData, UserDataFields};
use super::SCOPE;
use super::Lives;
pub(super) struct Tasks {
inner: *const yazi_core::tasks::Tasks,
@ -17,7 +17,7 @@ impl Deref for Tasks {
impl Tasks {
#[inline]
pub(super) fn make(inner: &yazi_core::tasks::Tasks) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { inner })
Lives::scoped_userdata(Self { inner })
}
}

View file

@ -3,7 +3,7 @@ use std::{collections::hash_set, ops::Deref};
use mlua::{AnyUserData, IntoLuaMulti, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRefMut};
use yazi_plugin::{bindings::Cast, url::Url};
use super::{Iter, SCOPE};
use super::{Iter, Lives};
pub(super) struct Yanked {
inner: *const yazi_core::manager::Yanked,
@ -18,7 +18,7 @@ impl Deref for Yanked {
impl Yanked {
#[inline]
pub(super) fn make(inner: &yazi_core::manager::Yanked) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { inner })
Lives::scoped_userdata(Self { inner })
}
#[inline]
@ -35,7 +35,6 @@ impl UserData for Yanked {
methods.add_meta_method(MetaMethod::Pairs, |lua, me, ()| {
let iter = lua.create_function(
// FIXME: UserDataRef
|lua, mut iter: UserDataRefMut<Iter<hash_set::Iter<yazi_shared::fs::Url>, _>>| {
if let Some(next) = iter.next() {
(next.0, Url::cast(lua, next.1.clone())?).into_lua_multi(lua)

View file

@ -11,6 +11,9 @@ impl<T> RoCell<T> {
#[inline]
pub const fn new() -> Self { Self(UnsafeCell::new(None)) }
#[inline]
pub const fn new_const(value: T) -> Self { Self(UnsafeCell::new(Some(value))) }
#[inline]
pub fn init(&self, value: T) {
debug_assert!(!self.initialized());