perf(core): cache ribbon_groups() with OnceLock, avoid per-frame tree allocations

Change CadModule::ribbon_groups() from -> Vec<RibbonGroup> to -> &[RibbonGroup],
backed by a per-module OnceLock cache. The ribbon group tree is static data
(&'static str, Copy enums) that was being fully reconstructed — Vecs, String
clones, enum discriminants — on every call, including all three per-frame
call sites (view(), dropdown_overlay(), style_combo_overlay()).

- 7 built-in modules + 2 plugin templates cache via function-local OnceLock.
  Safe because each is a unit struct with exactly one instance per process
  (plugins run in isolated child processes; see PluginProcess::spawn()).
- SharedCadModule avoids the static pattern entirely, storing groups in an
  instance field (owned.rs).
- IPC runner converts &RibbonGroup -> OwnedRibbonGroup directly via new
  From<&T> impls, avoiding an intermediate clone.
- render_small/render_large and the two make_tool_row closures now borrow
  (&RibbonItem, &[ToolDef]) instead of taking ownership, so the view loop
  doesn't need to clone items to satisfy the old by-value signatures.
- Various match-ergonomics deref fixes (*id, *default, *icon, etc.) from
  the &RibbonItem pattern change.
This commit is contained in:
Karim Jerbi committed 2026-07-02 21:00:57 +01:00
1 parent 8164e14a19
commit 73b05e1dec
14 files changed
+947 -690

No files matched your search

+6 -6
View File
@@ -409,7 +409,7 @@ impl Ribbon {
let mut items_row: Vec<Element<Message>> = Vec::new();
let mut small_buf: Vec<Element<Message>> = Vec::new();
for item in group.tools {
for item in &group.tools {
let is_large = matches!(
&item,
RibbonItem::LargeTool(_)
@@ -587,18 +587,18 @@ impl Ribbon {
let mut dd_default = "";
let mut dd_id: &'static str = "";
'outer: for group in &groups {
'outer: for group in groups {
for item in &group.tools {
let (id, items, default) = match item {
RibbonItem::Dropdown {
id, items, default, ..
} => (id, items, default),
} => (*id, items, *default),
RibbonItem::LargeDropdown {
id, items, default, ..
} => (id, items, default),
} => (*id, items, *default),
_ => continue,
};
if *id == open_id {
if id == open_id {
items_list = Some(items.clone());
dd_default = default;
dd_id = id;
@@ -820,7 +820,7 @@ impl Ribbon {
// Locate the open style combo; capture its style key + manager command.
let mut found: Option<(crate::modules::StyleKey, Option<&'static str>)> = None;
'outer: for group in &groups {
'outer: for group in groups {
for item in &group.tools {
if let RibbonItem::StyleComboGroup {
style_key,