perf: use AnyUserData::type_id() to reduce stack pushes (#2834)

This commit is contained in:
三咲雅 misaki masa 2025-06-03 23:40:23 +08:00 committed by GitHub
parent d5038eeed5
commit 2d95221f59
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 68 additions and 102 deletions

4
Cargo.lock generated
View file

@ -407,9 +407,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_complete" name = "clap_complete"
version = "4.5.51" version = "4.5.52"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d2267df7f3c8e74e38268887ea5235d4dfadd39bfff2d56ab82d61776be355e" checksum = "1a554639e42d0c838336fc4fbedb9e2df3ad1fa4acda149f9126b4ccfcd7900f"
dependencies = [ dependencies = [
"clap", "clap",
] ]

View file

@ -62,7 +62,7 @@ Yazi is currently in heavy development, expect breaking changes.
| [Ghostty](https://github.com/ghostty-org/ghostty) | [Kitty unicode placeholders][kgp] | ✅ Built-in | | [Ghostty](https://github.com/ghostty-org/ghostty) | [Kitty unicode placeholders][kgp] | ✅ Built-in |
| [Windows Terminal](https://github.com/microsoft/terminal) (>= v1.22.10352.0) | [Sixel graphics format][sixel] | ✅ Built-in | | [Windows Terminal](https://github.com/microsoft/terminal) (>= v1.22.10352.0) | [Sixel graphics format][sixel] | ✅ Built-in |
| [st with Sixel patch](https://github.com/bakkeby/st-flexipatch) | [Sixel graphics format][sixel] | ✅ Built-in | | [st with Sixel patch](https://github.com/bakkeby/st-flexipatch) | [Sixel graphics format][sixel] | ✅ Built-in |
| [Warp](https://www.warp.dev) | [Inline images protocol][iip] | ✅ Built-in | | [Warp](https://www.warp.dev) (macOS/Linux only) | [Inline images protocol][iip] | ✅ Built-in |
| [Tabby](https://github.com/Eugeny/tabby) | [Inline images protocol][iip] | ✅ Built-in | | [Tabby](https://github.com/Eugeny/tabby) | [Inline images protocol][iip] | ✅ Built-in |
| [VSCode](https://github.com/microsoft/vscode) | [Inline images protocol][iip] | ✅ Built-in | | [VSCode](https://github.com/microsoft/vscode) | [Inline images protocol][iip] | ✅ Built-in |
| [Rio](https://github.com/raphamorim/rio) | [Inline images protocol][iip] | ❌ Rio doesn't correctly clear images [#709][rio-bug] | | [Rio](https://github.com/raphamorim/rio) | [Inline images protocol][iip] | ❌ Rio doesn't correctly clear images [#709][rio-bug] |

View file

@ -25,7 +25,7 @@ yazi-shared = { path = "../yazi-shared", version = "25.5.31" }
# External dependencies # External dependencies
clap = { workspace = true } clap = { workspace = true }
clap_complete = "4.5.51" clap_complete = "4.5.52"
clap_complete_fig = "4.5.2" clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.6" clap_complete_nushell = "4.5.6"
vergen-gitcl = { version = "1.0.8", features = [ "build", "rustc" ] } vergen-gitcl = { version = "1.0.8", features = [ "build", "rustc" ] }

View file

@ -31,7 +31,7 @@ yazi-shared = { path = "../yazi-shared", version = "25.5.31" }
# External build dependencies # External build dependencies
anyhow = { workspace = true } anyhow = { workspace = true }
clap = { workspace = true } clap = { workspace = true }
clap_complete = "4.5.51" clap_complete = "4.5.52"
clap_complete_fig = "4.5.2" clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.6" clap_complete_nushell = "4.5.6"
serde_json = { workspace = true } serde_json = { workspace = true }

View file

@ -1,4 +1,4 @@
use std::{borrow::Cow, collections::HashMap}; use std::{any::TypeId, borrow::Cow, collections::HashMap};
use mlua::{ExternalError, IntoLua, Lua, MultiValue, Table, Value}; use mlua::{ExternalError, IntoLua, Lua, MultiValue, Table, Value};
use yazi_shared::{OrderedFloat, event::{Data, DataKey}, replace_cow}; use yazi_shared::{OrderedFloat, event::{Data, DataKey}, replace_cow};
@ -40,21 +40,24 @@ impl Sendable {
} }
Value::Function(_) => Err("function is not supported".into_lua_err())?, Value::Function(_) => Err("function is not supported".into_lua_err())?,
Value::Thread(_) => Err("thread is not supported".into_lua_err())?, Value::Thread(_) => Err("thread is not supported".into_lua_err())?,
Value::UserData(ud) => { Value::UserData(ud) => match ud.type_id() {
if let Ok(t) = ud.take::<yazi_binding::Url>() { Some(t) if t == TypeId::of::<yazi_binding::Url>() => {
Data::Url(t.into()) Data::Url(ud.take::<yazi_binding::Url>()?.into())
} else if let Ok(t) = ud.take::<yazi_binding::Urn>() {
Data::Urn(t.into())
} else if let Ok(t) = ud.borrow::<yazi_binding::Id>() {
Data::Id(**t)
} else if let Ok(t) = ud.take::<yazi_fs::FilesOp>() {
Data::Any(Box::new(t))
} else if let Ok(t) = ud.take::<super::body::BodyYankIter>() {
Data::Any(Box::new(t))
} else {
Err(format!("unsupported userdata included: {ud:?}").into_lua_err())?
} }
} Some(t) if t == TypeId::of::<yazi_binding::Urn>() => {
Data::Urn(ud.take::<yazi_binding::Urn>()?.into())
}
Some(t) if t == TypeId::of::<yazi_binding::Id>() => {
Data::Id(**ud.borrow::<yazi_binding::Id>()?)
}
Some(t) if t == TypeId::of::<yazi_fs::FilesOp>() => {
Data::Any(Box::new(ud.take::<yazi_fs::FilesOp>()?))
}
Some(t) if t == TypeId::of::<super::body::BodyYankIter>() => {
Data::Any(Box::new(ud.take::<super::body::BodyYankIter>()?))
}
_ => Err(format!("unsupported userdata included: {ud:?}").into_lua_err())?,
},
Value::Error(_) => Err("error is not supported".into_lua_err())?, Value::Error(_) => Err("error is not supported".into_lua_err())?,
Value::Other(..) => Err("unknown data is not supported".into_lua_err())?, Value::Other(..) => Err("unknown data is not supported".into_lua_err())?,
}) })
@ -195,17 +198,18 @@ impl Sendable {
Value::Table(_) => Err("table is not supported".into_lua_err())?, Value::Table(_) => Err("table is not supported".into_lua_err())?,
Value::Function(_) => Err("function is not supported".into_lua_err())?, Value::Function(_) => Err("function is not supported".into_lua_err())?,
Value::Thread(_) => Err("thread is not supported".into_lua_err())?, Value::Thread(_) => Err("thread is not supported".into_lua_err())?,
Value::UserData(ud) => { Value::UserData(ud) => match ud.type_id() {
if let Ok(t) = ud.take::<yazi_binding::Url>() { Some(t) if t == TypeId::of::<yazi_binding::Url>() => {
DataKey::Url(t.into()) DataKey::Url(ud.take::<yazi_binding::Url>()?.into())
} else if let Ok(t) = ud.take::<yazi_binding::Urn>() {
DataKey::Urn(t.into())
} else if let Ok(t) = ud.borrow::<yazi_binding::Id>() {
DataKey::Id(**t)
} else {
Err(format!("unsupported userdata included: {ud:?}").into_lua_err())?
} }
} Some(t) if t == TypeId::of::<yazi_binding::Urn>() => {
DataKey::Urn(ud.take::<yazi_binding::Urn>()?.into())
}
Some(t) if t == TypeId::of::<yazi_binding::Id>() => {
DataKey::Id(**ud.borrow::<yazi_binding::Id>()?)
}
_ => Err(format!("unsupported userdata included: {ud:?}").into_lua_err())?,
},
Value::Error(_) => Err("error is not supported".into_lua_err())?, Value::Error(_) => Err("error is not supported".into_lua_err())?,
Value::Other(..) => Err("unknown data is not supported".into_lua_err())?, Value::Other(..) => Err("unknown data is not supported".into_lua_err())?,
}) })

View file

@ -40,6 +40,7 @@ mlua = { workspace = true }
paste = { workspace = true } paste = { workspace = true }
ratatui = { workspace = true } ratatui = { workspace = true }
scopeguard = { workspace = true } scopeguard = { workspace = true }
textwrap = "0.16.2"
tokio = { workspace = true } tokio = { workspace = true }
tokio-stream = { workspace = true } tokio-stream = { workspace = true }
@ -47,7 +48,6 @@ tokio-stream = { workspace = true }
tracing = { workspace = true } tracing = { workspace = true }
tracing-appender = "0.2.3" tracing-appender = "0.2.3"
tracing-subscriber = { version = "0.3.19", features = [ "env-filter" ] } tracing-subscriber = { version = "0.3.19", features = [ "env-filter" ] }
textwrap = "0.16.2"
[target."cfg(unix)".dependencies] [target."cfg(unix)".dependencies]
libc = { workspace = true } libc = { workspace = true }

View file

@ -17,16 +17,7 @@ impl Bar {
let new = let new =
lua.create_function(|_, (_, edge): (Table, Edge)| Ok(Self { edge, ..Default::default() }))?; lua.create_function(|_, (_, edge): (Table, Edge)| Ok(Self { edge, ..Default::default() }))?;
let bar = lua.create_table_from([ let bar = lua.create_table()?;
// TODO: remove these constants
("NONE", Borders::NONE.bits()),
("TOP", Borders::TOP.bits()),
("RIGHT", Borders::RIGHT.bits()),
("BOTTOM", Borders::BOTTOM.bits()),
("LEFT", Borders::LEFT.bits()),
("ALL", Borders::ALL.bits()),
])?;
bar.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?)); bar.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
bar.into_lua(lua) bar.into_lua(lua)
} }

View file

@ -29,13 +29,6 @@ impl Border {
.create_function(|_, (_, edge): (Table, Edge)| Ok(Border { edge, ..Default::default() }))?; .create_function(|_, (_, edge): (Table, Edge)| Ok(Border { edge, ..Default::default() }))?;
let border = lua.create_table_from([ let border = lua.create_table_from([
// TODO: remove these constants
("NONE", Borders::NONE.bits()),
("TOP", Borders::TOP.bits()),
("RIGHT", Borders::RIGHT.bits()),
("BOTTOM", Borders::BOTTOM.bits()),
("LEFT", Borders::LEFT.bits()),
("ALL", Borders::ALL.bits()),
// Type // Type
("PLAIN", PLAIN), ("PLAIN", PLAIN),
("ROUNDED", ROUNDED), ("ROUNDED", ROUNDED),

View file

@ -35,14 +35,7 @@ impl Line {
Ok(Line { inner: mem::take(&mut lines[0]), ..Default::default() }) Ok(Line { inner: mem::take(&mut lines[0]), ..Default::default() })
})?; })?;
let line = lua.create_table_from([ let line = lua.create_table_from([("parse", parse)])?;
("parse", parse.into_lua(lua)?),
// TODO: remove these constants
("LEFT", 0.into_lua(lua)?),
("CENTER", 1.into_lua(lua)?),
("RIGHT", 2.into_lua(lua)?),
])?;
line.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?)); line.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
line.into_lua(lua) line.into_lua(lua)
} }

View file

@ -1,3 +1,5 @@
use std::any::TypeId;
use mlua::{AnyUserData, ExternalError}; use mlua::{AnyUserData, ExternalError};
use super::{Bar, Border, Clear, Gauge, Line, List, Table, Text}; use super::{Bar, Border, Clear, Gauge, Line, List, Table, Text};
@ -6,12 +8,12 @@ use super::{Bar, Border, Clear, Gauge, Line, List, Table, Text};
pub enum Renderable { pub enum Renderable {
Line(Line), Line(Line),
Text(Text), Text(Text),
List(List), List(Box<List>),
Bar(Bar), Bar(Bar),
Clear(Clear), Clear(Clear),
Border(Border), Border(Border),
Gauge(Gauge), Gauge(Box<Gauge>),
Table(Table), Table(Box<Table>),
} }
impl Renderable { impl Renderable {
@ -37,26 +39,16 @@ impl TryFrom<AnyUserData> for Renderable {
type Error = mlua::Error; type Error = mlua::Error;
fn try_from(ud: AnyUserData) -> Result<Self, Self::Error> { fn try_from(ud: AnyUserData) -> Result<Self, Self::Error> {
Ok(if let Ok(c) = ud.take::<crate::elements::Line>() { Ok(match ud.type_id() {
Self::Line(c) Some(t) if t == TypeId::of::<Line>() => Self::Line(ud.take()?),
} else if let Ok(c) = ud.take::<crate::elements::Text>() { Some(t) if t == TypeId::of::<Text>() => Self::Text(ud.take()?),
Self::Text(c) Some(t) if t == TypeId::of::<List>() => Self::List(Box::new(ud.take()?)),
} else if let Ok(c) = ud.take::<crate::elements::List>() { Some(t) if t == TypeId::of::<Bar>() => Self::Bar(ud.take()?),
Self::List(c) Some(t) if t == TypeId::of::<Clear>() => Self::Clear(ud.take()?),
} else if let Ok(c) = ud.take::<crate::elements::Bar>() { Some(t) if t == TypeId::of::<Border>() => Self::Border(ud.take()?),
Self::Bar(c) Some(t) if t == TypeId::of::<Gauge>() => Self::Gauge(Box::new(ud.take()?)),
} else if let Ok(c) = ud.take::<crate::elements::Clear>() { Some(t) if t == TypeId::of::<Table>() => Self::Table(Box::new(ud.take()?)),
Self::Clear(c) _ => Err(format!("expected a UserData of renderable element, not: {ud:#?}").into_lua_err())?,
} else if let Ok(c) = ud.take::<crate::elements::Border>() {
Self::Border(c)
} else if let Ok(c) = ud.take::<crate::elements::Gauge>() {
Self::Gauge(c)
} else if let Ok(c) = ud.take::<crate::elements::Table>() {
Self::Table(c)
} else {
return Err(
format!("expected a UserData of renderable element, not: {ud:#?}").into_lua_err(),
);
}) })
} }
} }

View file

@ -27,17 +27,7 @@ impl Text {
Ok(Text { inner: code.as_bytes().into_text().into_lua_err()?, ..Default::default() }) Ok(Text { inner: code.as_bytes().into_text().into_lua_err()?, ..Default::default() })
})?; })?;
let text = lua.create_table_from([ let text = lua.create_table_from([("parse", parse)])?;
("parse", parse.into_lua(lua)?),
// TODO: remove these constants
("LEFT", 0.into_lua(lua)?),
("CENTER", 1.into_lua(lua)?),
("RIGHT", 2.into_lua(lua)?),
("WRAP_NO", 0.into_lua(lua)?),
("WRAP", 1.into_lua(lua)?),
("WRAP_TRIM", 2.into_lua(lua)?),
])?;
text.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?)); text.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
text.into_lua(lua) text.into_lua(lua)
} }

View file

@ -1,4 +1,4 @@
use std::{io, process::Stdio}; use std::{any::TypeId, io, process::Stdio};
use mlua::{AnyUserData, ExternalError, IntoLuaMulti, Lua, MetaMethod, Table, UserData, Value}; use mlua::{AnyUserData, ExternalError, IntoLuaMulti, Lua, MetaMethod, Table, UserData, Value};
use tokio::process::{ChildStderr, ChildStdin, ChildStdout}; use tokio::process::{ChildStderr, ChildStdin, ChildStdout};
@ -118,15 +118,18 @@ impl UserData for Command {
_ => Stdio::null(), _ => Stdio::null(),
}); });
} }
Value::UserData(ud) => { Value::UserData(ud) => match ud.type_id() {
if let Ok(stdin) = ud.take::<ChildStdin>() { Some(t) if t == TypeId::of::<ChildStdin>() => {
return Ok(stdin.try_into()?); return Ok(ud.take::<ChildStdin>()?.try_into()?);
} else if let Ok(stdout) = ud.take::<ChildStdout>() {
return Ok(stdout.try_into()?);
} else if let Ok(stderr) = ud.take::<ChildStderr>() {
return Ok(stderr.try_into()?);
} }
} Some(t) if t == TypeId::of::<ChildStdout>() => {
return Ok(ud.take::<ChildStdout>()?.try_into()?);
}
Some(t) if t == TypeId::of::<ChildStderr>() => {
return Ok(ud.take::<ChildStderr>()?.try_into()?);
}
_ => {}
},
_ => {} _ => {}
} }

View file

@ -47,14 +47,14 @@ impl SpotLock {
pub fn table(&self) -> Option<&crate::elements::Table> { pub fn table(&self) -> Option<&crate::elements::Table> {
self.data.iter().rev().find_map(|r| match r { self.data.iter().rev().find_map(|r| match r {
Renderable::Table(t) => Some(t), Renderable::Table(t) => Some(t.as_ref()),
_ => None, _ => None,
}) })
} }
pub fn table_mut(&mut self) -> Option<&mut crate::elements::Table> { pub fn table_mut(&mut self) -> Option<&mut crate::elements::Table> {
self.data.iter_mut().rev().find_map(|r| match r { self.data.iter_mut().rev().find_map(|r| match r {
Renderable::Table(t) => Some(t), Renderable::Table(t) => Some(t.as_mut()),
_ => None, _ => None,
}) })
} }
@ -83,7 +83,7 @@ impl Utils {
.style(THEME.spot.title), .style(THEME.spot.title),
)], )],
}), }),
Renderable::Table(table), Renderable::Table(Box::new(table)),
]; ];
emit!(Call(Cmd::new("mgr:update_spotted").with_any("lock", lock))); emit!(Call(Cmd::new("mgr:update_spotted").with_any("lock", lock)));