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 mlua::{AnyUserData, UserData, UserDataFields};
use super::SCOPE; use super::Lives;
pub(super) struct Config { pub(super) struct Config {
inner: *const yazi_core::tab::Config, inner: *const yazi_core::tab::Config,
@ -17,7 +17,7 @@ impl Deref for Config {
impl Config { impl Config {
#[inline] #[inline]
pub(super) fn make(inner: &yazi_core::tab::Config) -> mlua::Result<AnyUserData> { 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_plugin::{bindings::Range, elements::Style};
use yazi_shared::MIME_DIR; use yazi_shared::MIME_DIR;
use super::SCOPE; use super::Lives;
use crate::Ctx; use crate::Ctx;
pub(super) struct File { pub(super) struct File {
@ -31,7 +31,7 @@ impl File {
folder: &yazi_fs::Folder, folder: &yazi_fs::Folder,
tab: &yazi_core::tab::Tab, tab: &yazi_core::tab::Tab,
) -> mlua::Result<AnyUserData> { ) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { idx, folder, tab }) Lives::scoped_userdata(Self { idx, folder, tab })
} }
#[inline] #[inline]

View file

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

View file

@ -2,7 +2,7 @@ use std::ops::Deref;
use mlua::{AnyUserData, MetaMethod, UserData, UserDataMethods}; use mlua::{AnyUserData, MetaMethod, UserData, UserDataMethods};
use super::SCOPE; use super::Lives;
pub(super) struct Filter { pub(super) struct Filter {
inner: *const yazi_fs::Filter, inner: *const yazi_fs::Filter,
@ -17,7 +17,7 @@ impl Deref for Filter {
impl Filter { impl Filter {
#[inline] #[inline]
pub(super) fn make(inner: &yazi_fs::Filter) -> mlua::Result<AnyUserData> { 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 mlua::{AnyUserData, MetaMethod, UserData, UserDataMethods};
use super::SCOPE; use super::Lives;
pub(super) struct Finder { pub(super) struct Finder {
inner: *const yazi_core::tab::Finder, inner: *const yazi_core::tab::Finder,
@ -17,7 +17,7 @@ impl Deref for Finder {
impl Finder { impl Finder {
#[inline] #[inline]
pub(super) fn make(inner: &yazi_core::tab::Finder) -> mlua::Result<AnyUserData> { 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_config::LAYOUT;
use yazi_plugin::{bindings::Cast, url::Url}; use yazi_plugin::{bindings::Cast, url::Url};
use super::{File, Files, SCOPE}; use super::{File, Files, Lives};
pub(super) struct Folder { pub(super) struct Folder {
window: Range<usize>, 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<()> { pub(super) fn register(lua: &Lua) -> mlua::Result<()> {

View file

@ -1,6 +1,6 @@
use mlua::{AnyUserData, UserData}; use mlua::{AnyUserData, UserData};
use super::SCOPE; use super::Lives;
pub(super) struct Iter<I: Iterator<Item = T>, T> { pub(super) struct Iter<I: Iterator<Item = T>, T> {
inner: I, 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> { impl<I: Iterator<Item = T> + 'static, T: 'static> Iter<I, T> {
#[inline] #[inline]
pub(super) fn make(inner: I) -> mlua::Result<AnyUserData> { 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 tracing::error;
use yazi_plugin::LUA; use yazi_plugin::LUA;
use yazi_shared::RoCell; use yazi_shared::RoCell;
use crate::Ctx; 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; 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> { pub(crate) fn scope<T>(cx: &Ctx, f: impl FnOnce() -> mlua::Result<T>) -> mlua::Result<T> {
let result = LUA.scope(|scope| { let result = LUA.scope(|scope| {
defer! { SCOPE.drop(); } scope.add_destructor(|| {
SCOPE.init(*unsafe { for ud in TO_DESTROY.borrow_mut().drain(..) {
mem::transmute::<&&mut mlua::Scope<'_, '_>, &&mut mlua::Scope<'static, 'static>>(&scope) ud.destroy().expect("failed to destruct scoped userdata");
}
}); });
LUA.set_named_registry_value("cx", scope.create_any_userdata_ref(cx)?)?;
let globals = LUA.globals(); LUA.set_named_registry_value("cx", scope.create_any_userdata_ref(cx)?)?;
globals.raw_set( LUA.globals().raw_set(
"cx", "cx",
LUA.create_table_from([ LUA.create_table_from([
("active", super::Tab::make(cx.manager.active())?), ("active", super::Tab::make(cx.manager.active())?),
@ -45,4 +45,14 @@ impl Lives {
} }
result 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 mlua::{AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMethods};
use super::SCOPE; use super::Lives;
pub(super) struct Mode { pub(super) struct Mode {
inner: *const yazi_core::tab::Mode, inner: *const yazi_core::tab::Mode,
@ -17,7 +17,7 @@ impl Deref for Mode {
impl Mode { impl Mode {
#[inline] #[inline]
pub(super) fn make(inner: &yazi_core::tab::Mode) -> mlua::Result<AnyUserData> { 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 mlua::{AnyUserData, UserData, UserDataFields};
use yazi_config::LAYOUT; use yazi_config::LAYOUT;
use super::{Folder, SCOPE}; use super::{Folder, Lives};
pub(super) struct Preview { pub(super) struct Preview {
tab: *const yazi_core::tab::Tab, tab: *const yazi_core::tab::Tab,
@ -18,7 +18,7 @@ impl Deref for Preview {
impl Preview { impl Preview {
#[inline] #[inline]
pub(super) fn make(tab: &yazi_core::tab::Tab) -> mlua::Result<AnyUserData> { pub(super) fn make(tab: &yazi_core::tab::Tab) -> mlua::Result<AnyUserData> {
SCOPE.create_userdata(Self { tab }) Lives::scoped_userdata(Self { tab })
} }
#[inline] #[inline]

View file

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

View file

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