Tightens the rustc compatibility gate so that whitespace-normalised
version strings are compared token-by-token. This prevents a corner case
where 'rustc 1.98.0' and 'rustc1.98.0' would be considered equal.
OpenCADStudio/plugins#901 (comment)
- Add BuiltinPlugin::on_load(&mut self, host: &mut dyn HostApi) with a default
no-op implementation so existing plugins remain source-compatible.
- Invoke on_load once for V4 plugins immediately after the runner connects
and before entering the request loop, giving plugins a HostApi surface to
cache plugin_request_sender() or set up worker threads before any dispatch.
- V2/V3 plugins are unchanged: HostApi is only available during dispatch.
OpenCADStudio/plugins#901 (comment)
- Add HostApi::document_path(tab_id) returning Option<PathBuf>.
- Add PluginRequest::DocumentPath and PluginResponse::DocumentPath for
out-of-process plugins.
- Implement the request in the IPC server and in both V3/V4 plugin-side
HostApi proxies.
- Implement HostSession::document_path by looking up the tab by id and
returning its current_path.
OpenCADStudio/plugins#901
- Record the host's rustc --version output in the embedded version_info.json.
- Add rustc_version/rustc_declared/rustc_compatible to plugin manifests and
release metadata, mirroring the existing acadrust gate.
- Reject API v4+ plugins whose declared rustc differs from the host, with a
clear one-line error message.
- Propagate the rustc gate through the marketplace, install flow, and UI.
- Update plugin architecture docs to describe the new ABI metadata.
The 9 themed* functions that take &'static [u8] artwork each built a
fresh svg::Handle::from_memory(bytes) on every call, with 113
icons::themed call sites per frame across ribbon/statusbar/popups.
Add a thread_local THEMED_CACHE keyed by the bytes' (address, length)
and a single themed_handle(bytes) helper; the 9 themed* functions all
go through it. The 13 wrapper functions (themed_arrow_*, themed_home,
themed_undo, themed_redo, themed_check_cell, ...) delegate to those 9
and pick up the cache transparently, so all 22 themed* functions (and
the 113 call sites) are deduped.
The cache key is (address, length) -- not pointer alone -- to match the
existing SEMANTIC_CACHE belt-and-braces pattern and guard against any
future call site that passes a sub-slice of a static (e.g. &BYTES[1..]),
which would otherwise alias the wrong handle. Every include_bytes!
produces a unique static slice today, so the length is defensive.
Construction is amortised to once per artwork per process. No semantic
change; visual output is byte-identical.
Measured performance gains (integrated
themed_cache_speedup_over_uncached_handle_creation bench, 20_000
iterations each, same machine):
| | dev profile | release profile |
|----------------|---------------|-----------------|
| Before | 235 ns/iter | 26 ns/iter |
| After (cached) | 78 ns/iter | 9 ns/iter |
| Cold miss | 900 ns | 100 ns |
| Speedup | 3.0x | 2.9x |
Release-mode warm path: 9 ns/iter. At 60 fps with up to 113 themed*
calls per frame, that is ~1 us/frame of handle work -- a rounding
error against a 16.6 ms frame budget. The cold-miss cost (one parse
+ one insert, 100 ns release) is the one-time price per new artwork
and is amortised to negligible per-frame overhead (it happens at
most once per artwork per process). The speedup is stable at ~3x
across dev and release because the ratio of work is the same:
hashmap-get + Handle clone vs. a full SVG parse + allocation.
test ui::icons::themed_cache_tests::themed_cache_returns_same_handle_for_same_bytes
test ui::icons::themed_cache_tests::themed_cache_caches_distinct_bytes_separately
test ui::icons::themed_cache_tests::themed_cache_speedup_over_uncached_handle_creation