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]]
name = "clap_complete"
version = "4.5.51"
version = "4.5.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d2267df7f3c8e74e38268887ea5235d4dfadd39bfff2d56ab82d61776be355e"
checksum = "1a554639e42d0c838336fc4fbedb9e2df3ad1fa4acda149f9126b4ccfcd7900f"
dependencies = [
"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 |
| [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 |
| [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 |
| [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] |

View file

@ -25,7 +25,7 @@ yazi-shared = { path = "../yazi-shared", version = "25.5.31" }
# External dependencies
clap = { workspace = true }
clap_complete = "4.5.51"
clap_complete = "4.5.52"
clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.6"
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
anyhow = { workspace = true }
clap = { workspace = true }
clap_complete = "4.5.51"
clap_complete = "4.5.52"
clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.6"
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 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::Thread(_) => Err("thread is not supported".into_lua_err())?,
Value::UserData(ud) => {
if let Ok(t) = ud.take::<yazi_binding::Url>() {
Data::Url(t.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())?
Value::UserData(ud) => match ud.type_id() {
Some(t) if t == TypeId::of::<yazi_binding::Url>() => {
Data::Url(ud.take::<yazi_binding::Url>()?.into())
}
}
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::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::Function(_) => Err("function is not supported".into_lua_err())?,
Value::Thread(_) => Err("thread is not supported".into_lua_err())?,
Value::UserData(ud) => {
if let Ok(t) = ud.take::<yazi_binding::Url>() {
DataKey::Url(t.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())?
Value::UserData(ud) => match ud.type_id() {
Some(t) if t == TypeId::of::<yazi_binding::Url>() => {
DataKey::Url(ud.take::<yazi_binding::Url>()?.into())
}
}
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::Other(..) => Err("unknown data is not supported".into_lua_err())?,
})

View file

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

View file

@ -17,16 +17,7 @@ impl Bar {
let new =
lua.create_function(|_, (_, edge): (Table, Edge)| Ok(Self { edge, ..Default::default() }))?;
let bar = 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()),
])?;
let bar = lua.create_table()?;
bar.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
bar.into_lua(lua)
}

View file

@ -29,13 +29,6 @@ impl Border {
.create_function(|_, (_, edge): (Table, Edge)| Ok(Border { edge, ..Default::default() }))?;
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
("PLAIN", PLAIN),
("ROUNDED", ROUNDED),

View file

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

View file

@ -1,3 +1,5 @@
use std::any::TypeId;
use mlua::{AnyUserData, ExternalError};
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 {
Line(Line),
Text(Text),
List(List),
List(Box<List>),
Bar(Bar),
Clear(Clear),
Border(Border),
Gauge(Gauge),
Table(Table),
Gauge(Box<Gauge>),
Table(Box<Table>),
}
impl Renderable {
@ -37,26 +39,16 @@ impl TryFrom<AnyUserData> for Renderable {
type Error = mlua::Error;
fn try_from(ud: AnyUserData) -> Result<Self, Self::Error> {
Ok(if let Ok(c) = ud.take::<crate::elements::Line>() {
Self::Line(c)
} else if let Ok(c) = ud.take::<crate::elements::Text>() {
Self::Text(c)
} else if let Ok(c) = ud.take::<crate::elements::List>() {
Self::List(c)
} else if let Ok(c) = ud.take::<crate::elements::Bar>() {
Self::Bar(c)
} else if let Ok(c) = ud.take::<crate::elements::Clear>() {
Self::Clear(c)
} 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(),
);
Ok(match ud.type_id() {
Some(t) if t == TypeId::of::<Line>() => Self::Line(ud.take()?),
Some(t) if t == TypeId::of::<Text>() => Self::Text(ud.take()?),
Some(t) if t == TypeId::of::<List>() => Self::List(Box::new(ud.take()?)),
Some(t) if t == TypeId::of::<Bar>() => Self::Bar(ud.take()?),
Some(t) if t == TypeId::of::<Clear>() => Self::Clear(ud.take()?),
Some(t) if t == TypeId::of::<Border>() => Self::Border(ud.take()?),
Some(t) if t == TypeId::of::<Gauge>() => Self::Gauge(Box::new(ud.take()?)),
Some(t) if t == TypeId::of::<Table>() => Self::Table(Box::new(ud.take()?)),
_ => 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() })
})?;
let text = lua.create_table_from([
("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)?),
])?;
let text = lua.create_table_from([("parse", parse)])?;
text.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?));
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 tokio::process::{ChildStderr, ChildStdin, ChildStdout};
@ -118,15 +118,18 @@ impl UserData for Command {
_ => Stdio::null(),
});
}
Value::UserData(ud) => {
if let Ok(stdin) = ud.take::<ChildStdin>() {
return Ok(stdin.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()?);
Value::UserData(ud) => match ud.type_id() {
Some(t) if t == TypeId::of::<ChildStdin>() => {
return Ok(ud.take::<ChildStdin>()?.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> {
self.data.iter().rev().find_map(|r| match r {
Renderable::Table(t) => Some(t),
Renderable::Table(t) => Some(t.as_ref()),
_ => None,
})
}
pub fn table_mut(&mut self) -> Option<&mut crate::elements::Table> {
self.data.iter_mut().rev().find_map(|r| match r {
Renderable::Table(t) => Some(t),
Renderable::Table(t) => Some(t.as_mut()),
_ => None,
})
}
@ -83,7 +83,7 @@ impl Utils {
.style(THEME.spot.title),
)],
}),
Renderable::Table(table),
Renderable::Table(Box::new(table)),
];
emit!(Call(Cmd::new("mgr:update_spotted").with_any("lock", lock)));