pub struct PublishCache {
pub panes: Option<(u64, Arc<PanesRenderState>)>,
pub modes: Option<(u64, Arc<ModesRenderState>)>,
pub buffer_locals: Option<(u64, Arc<BufferLocalsRenderState>)>,
pub resolved_opts: Option<(u64, Arc<ResolvedOptionsRenderState>)>,
pub buffers: Option<(u64, Arc<BuffersRenderState>)>,
pub tabs: Option<(u64, Arc<TabsRenderState>)>,
pub publish_batch_depth: u32,
pub publish_pending: bool,
pub last_paint_revision: u64,
}Expand description
Perf plan B.4: identity-preserving sub-state cache.
Editor::build_render_state rebuilds every sub-state Arc
from scratch on every publish today. Most publishes don’t
touch most sub-states (cursor moves, scroll, etc. only update
active_document), so the inner allocations and deep clones
for the rest are wasted.
This struct lives behind Editor::publish_cache (a
std::sync::Mutex<PublishCache> because Editor is shared as
Arc<Editor> and therefore must be Sync). The mutex is
uncontested in practice — only build_render_state takes the
lock, and only the actor thread calls it.
Each slot pairs a u64 version (captured from the
corresponding Versioned<T> field on Editor at the moment
the cached Arc was built) with the cached Arc<SubState>.
On the next publish, if the field’s current version matches
the cached version, the cached Arc is reused (same Arc
identity preserved across the publish — Arc::ptr_eq returns
true). Otherwise the slot is rebuilt and the new
(version, Arc) pair is stored.
Targeted sub-states:
B.4.a (5 subs):
panes— full sub-state Arc. Mutates onpane_tree.split_active/close_active/set_active/ tab swap; otherwise stable.modes— full sub-state Arc. Mutates onactivate_mode/deactivate_mode; otherwise stable.buffer_locals— full sub-state Arc. Mutates on the fewbuffer_locals.entry(...).or_default()/.insert/.removesites; otherwise stable. Largest savings because the per-entry clone deep-walks the typed-map.
(ML.3c retired the lsp_progress inner-Arc cache with
RenderState.lsp.progress; DR.2 retired the sibling
pane_highlights_map cache.)
B.4.b (3 subs):
buffers— fullArc<BuffersRenderState>. Keyed onbuffer_uris.version()alone. The innerregistryfield isArc<Mutex<...>>-backed so the SAME registry handle inside a reused Arc still sees current state — no version dependency on registry mutations needed for this sub-state’s cache hit/miss decision. Saves thebuffer_uris.clone()HashMap allocation per no-op publish.tabs— fullArc<TabsRenderState>. Composite key overtabs.version()(tab list shape) +active_tab(per-publish read) +pane_tree.version()(active pane’s buffer) +buffers.version()(label-resolving names). Saves thebuild_tabs_render_statewalk per no-op publish.
Fields§
§panes: Option<(u64, Arc<PanesRenderState>)>§modes: Option<(u64, Arc<ModesRenderState>)>§buffer_locals: Option<(u64, Arc<BufferLocalsRenderState>)>§resolved_opts: Option<(u64, Arc<ResolvedOptionsRenderState>)>PI.4: keyed on Editor::resolved_options_version.
buffers: Option<(u64, Arc<BuffersRenderState>)>Perf plan B.4.b: keyed on buffer_uris.version() only.
tabs: Option<(u64, Arc<TabsRenderState>)>Perf plan B.4.b: keyed on a composite of tabs.version(),
active_tab, pane_tree.version(), buffers.version().
The composite is encoded into one u64 via a small fold so
the cache slot shape stays uniform with the other entries.
publish_batch_depth: u32Slice I.4 (publish coalescing): depth of the in-flight
dispatch / handle_effect batch. While > 0, intermediate
publish_render_state() calls (from chained setters,
ensure_cursor_visible, maybe_reparse_syntax, …) suppress
their build/store/wake and instead set publish_pending; the
single real publish fires once when the outermost batch
unwinds. Collapses ~6 whole-world publishes per keystroke to 1
(and 12 worker wakes to 2). Lives here (not on Editor) because
PublishCache is Default-derived and already the actor’s
single publish-side lock — no new Editor construction churn,
and build_render_state already takes this lock.
publish_pending: boolA suppressed publish occurred during the current batch; flushed once when the batch depth returns to 0.
last_paint_revision: u64§12 paint gate: the RenderState::paint_revision of the last
real (un-suppressed) publish. publish_render_state compares the
freshly-built revision against this; a change means a
render-visible non-cell surface moved off-keystroke, so the actor
fires paint_request. Lives here (not on Editor) for the same
reason as the cache slots: PublishCache is Default-derived and
already the actor’s single publish-side lock, so no Editor
construction churn. u64::MAX would be a valid revision, so this
starts at 0 and the first publish (revision rarely 0) paints — a
harmless extra first frame.
Implementations§
Source§impl PublishCache
impl PublishCache
Trait Implementations§
Source§impl Debug for PublishCache
impl Debug for PublishCache
Source§impl Default for PublishCache
impl Default for PublishCache
Source§fn default() -> PublishCache
fn default() -> PublishCache
Auto Trait Implementations§
impl !RefUnwindSafe for PublishCache
impl !UnwindSafe for PublishCache
impl Freeze for PublishCache
impl Send for PublishCache
impl Sync for PublishCache
impl Unpin for PublishCache
impl UnsafeUnpin for PublishCache
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more