From 0f008081464562ef5bd27f6afe02f79461a00a56 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Fri, 8 Nov 2024 21:29:46 +0800 Subject: [PATCH] Manually manage the lifecycle of scope userdata through `Scope::add_destructor()` and `UserData::destroy()` --- yazi-fm/src/lives/config.rs | 4 ++-- yazi-fm/src/lives/file.rs | 4 ++-- yazi-fm/src/lives/files.rs | 4 ++-- yazi-fm/src/lives/filter.rs | 4 ++-- yazi-fm/src/lives/finder.rs | 4 ++-- yazi-fm/src/lives/folder.rs | 4 ++-- yazi-fm/src/lives/iter.rs | 4 ++-- yazi-fm/src/lives/lives.rs | 28 +++++++++++++++++++--------- yazi-fm/src/lives/mode.rs | 4 ++-- yazi-fm/src/lives/preview.rs | 4 ++-- yazi-fm/src/lives/selected.rs | 5 ++--- yazi-fm/src/lives/tab.rs | 4 ++-- yazi-fm/src/lives/tabs.rs | 4 ++-- yazi-fm/src/lives/tasks.rs | 4 ++-- yazi-fm/src/lives/yanked.rs | 5 ++--- yazi-shared/src/ro_cell.rs | 3 +++ 16 files changed, 50 insertions(+), 39 deletions(-) diff --git a/yazi-fm/src/lives/config.rs b/yazi-fm/src/lives/config.rs index 1d9f75ba..6761ddf1 100644 --- a/yazi-fm/src/lives/config.rs +++ b/yazi-fm/src/lives/config.rs @@ -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 { - SCOPE.create_userdata(Self { inner }) + Lives::scoped_userdata(Self { inner }) } } diff --git a/yazi-fm/src/lives/file.rs b/yazi-fm/src/lives/file.rs index bc25c0ae..fa062da7 100644 --- a/yazi-fm/src/lives/file.rs +++ b/yazi-fm/src/lives/file.rs @@ -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 { - SCOPE.create_userdata(Self { idx, folder, tab }) + Lives::scoped_userdata(Self { idx, folder, tab }) } #[inline] diff --git a/yazi-fm/src/lives/files.rs b/yazi-fm/src/lives/files.rs index 976a1c1b..af747a1d 100644 --- a/yazi-fm/src/lives/files.rs +++ b/yazi-fm/src/lives/files.rs @@ -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, @@ -23,7 +23,7 @@ impl Files { folder: &yazi_fs::Folder, tab: &yazi_core::tab::Tab, ) -> mlua::Result { - SCOPE.create_userdata(Self { window, folder, tab }) + Lives::scoped_userdata(Self { window, folder, tab }) } #[inline] diff --git a/yazi-fm/src/lives/filter.rs b/yazi-fm/src/lives/filter.rs index 60c72801..4c6a6813 100644 --- a/yazi-fm/src/lives/filter.rs +++ b/yazi-fm/src/lives/filter.rs @@ -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 { - SCOPE.create_userdata(Self { inner }) + Lives::scoped_userdata(Self { inner }) } } diff --git a/yazi-fm/src/lives/finder.rs b/yazi-fm/src/lives/finder.rs index 1c11a5f2..2b53d9cf 100644 --- a/yazi-fm/src/lives/finder.rs +++ b/yazi-fm/src/lives/finder.rs @@ -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 { - SCOPE.create_userdata(Self { inner }) + Lives::scoped_userdata(Self { inner }) } } diff --git a/yazi-fm/src/lives/folder.rs b/yazi-fm/src/lives/folder.rs index 96fa5257..3c13ca5c 100644 --- a/yazi-fm/src/lives/folder.rs +++ b/yazi-fm/src/lives/folder.rs @@ -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, @@ -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<()> { diff --git a/yazi-fm/src/lives/iter.rs b/yazi-fm/src/lives/iter.rs index 13e3b19a..845a8e30 100644 --- a/yazi-fm/src/lives/iter.rs +++ b/yazi-fm/src/lives/iter.rs @@ -1,6 +1,6 @@ use mlua::{AnyUserData, UserData}; -use super::SCOPE; +use super::Lives; pub(super) struct Iter, T> { inner: I, @@ -10,7 +10,7 @@ pub(super) struct Iter, T> { impl + 'static, T: 'static> Iter { #[inline] pub(super) fn make(inner: I) -> mlua::Result { - SCOPE.create_userdata(Self { inner, count: 0 }) + Lives::scoped_userdata(Self { inner, count: 0 }) } } diff --git a/yazi-fm/src/lives/lives.rs b/yazi-fm/src/lives/lives.rs index 4f39522d..7ffd4d80 100644 --- a/yazi-fm/src/lives/lives.rs +++ b/yazi-fm/src/lives/lives.rs @@ -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>> = RoCell::new_const(RefCell::new(Vec::new())); pub(crate) struct Lives; @@ -20,14 +20,14 @@ impl Lives { pub(crate) fn scope(cx: &Ctx, f: impl FnOnce() -> mlua::Result) -> mlua::Result { 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(data: T) -> mlua::Result + where + T: UserData + 'static, + { + let ud = LUA.create_userdata(data)?; + TO_DESTROY.borrow_mut().push(ud.clone()); + Ok(ud) + } } diff --git a/yazi-fm/src/lives/mode.rs b/yazi-fm/src/lives/mode.rs index 88522dda..902bd991 100644 --- a/yazi-fm/src/lives/mode.rs +++ b/yazi-fm/src/lives/mode.rs @@ -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 { - SCOPE.create_userdata(Self { inner }) + Lives::scoped_userdata(Self { inner }) } } diff --git a/yazi-fm/src/lives/preview.rs b/yazi-fm/src/lives/preview.rs index 609a6e8b..cdc85d94 100644 --- a/yazi-fm/src/lives/preview.rs +++ b/yazi-fm/src/lives/preview.rs @@ -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 { - SCOPE.create_userdata(Self { tab }) + Lives::scoped_userdata(Self { tab }) } #[inline] diff --git a/yazi-fm/src/lives/selected.rs b/yazi-fm/src/lives/selected.rs index 0b7c9939..d2de2a38 100644 --- a/yazi-fm/src/lives/selected.rs +++ b/yazi-fm/src/lives/selected.rs @@ -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) -> mlua::Result { - 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, _>>| { if let Some(next) = iter.next() { (next.0, Url::cast(lua, next.1.clone())?).into_lua_multi(lua) diff --git a/yazi-fm/src/lives/tab.rs b/yazi-fm/src/lives/tab.rs index 144b2193..c0ebaa13 100644 --- a/yazi-fm/src/lives/tab.rs +++ b/yazi-fm/src/lives/tab.rs @@ -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 { - SCOPE.create_userdata(Self { inner }) + Lives::scoped_userdata(Self { inner }) } } diff --git a/yazi-fm/src/lives/tabs.rs b/yazi-fm/src/lives/tabs.rs index 5fd8d2ae..dc3a2b66 100644 --- a/yazi-fm/src/lives/tabs.rs +++ b/yazi-fm/src/lives/tabs.rs @@ -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 { - SCOPE.create_userdata(Self { inner }) + Lives::scoped_userdata(Self { inner }) } } diff --git a/yazi-fm/src/lives/tasks.rs b/yazi-fm/src/lives/tasks.rs index c78ac06d..60aac480 100644 --- a/yazi-fm/src/lives/tasks.rs +++ b/yazi-fm/src/lives/tasks.rs @@ -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 { - SCOPE.create_userdata(Self { inner }) + Lives::scoped_userdata(Self { inner }) } } diff --git a/yazi-fm/src/lives/yanked.rs b/yazi-fm/src/lives/yanked.rs index 6a002d82..0ca5262e 100644 --- a/yazi-fm/src/lives/yanked.rs +++ b/yazi-fm/src/lives/yanked.rs @@ -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 { - 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, _>>| { if let Some(next) = iter.next() { (next.0, Url::cast(lua, next.1.clone())?).into_lua_multi(lua) diff --git a/yazi-shared/src/ro_cell.rs b/yazi-shared/src/ro_cell.rs index e5c830fd..2667355b 100644 --- a/yazi-shared/src/ro_cell.rs +++ b/yazi-shared/src/ro_cell.rs @@ -11,6 +11,9 @@ impl RoCell { #[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());