///|
/// A single-entry, explicitly keyed view-construction memo.
///
/// The caller owns the memo and supplies a canonical `DeclarationKey` covering
/// every input read by `build`. A hit returns the previously built `View`
/// without running `build`; a miss builds and replaces the entry.
///
/// This is deliberately not dependency tracking. A key that omits a model
/// field, message payload captured by an event handler, environment value, or
/// other view input will serve a stale view. Use one memo per independently
/// invalidated subtree, and construct the key with named record fields so the
/// dependency set is reviewable at the call site.
///
/// The memo caches construction, not runtime state. Element identity,
/// reconciliation, layout, paint, and transient control state remain owned by
/// the runtime.
///
/// `ViewMemo` is a handle: copying the struct aliases the same entry. Keep one
/// owner per independently invalidated subtree rather than sharing a memo
/// across unrelated call sites.
pub struct ViewMemo[Msg] {
priv state : Ref[ViewMemoState[Msg]]
}
///|
/// A caller-readable snapshot of one memo's construction counters.
///
/// A miss is counted when a lookup is not served from the cache. A build is
/// counted after `build` returns successfully. They are normally equal, but
/// remain separate so a failed build cannot be mistaken for completed work.
#derive(Eq, Debug)
pub struct ViewMemoStats {
priv build_count : Int32
priv hit_count : Int32
priv miss_count : Int32
}
///|
pub extend ViewMemoStats with Debug::{to_repr}
///|
pub extend ViewMemoStats with Eq::{not_equal, equal}
///|
priv struct ViewMemoState[Msg] {
mut entry : ViewMemoEntry[Msg]?
mut build_count : Int32
mut hit_count : Int32
mut miss_count : Int32
}
///|
priv struct ViewMemoEntry[Msg] {
key : DeclarationKey
view : View[Msg]
}
///|
pub fn[Msg] ViewMemo::new() -> ViewMemo[Msg] {
{ state: Ref({ entry: None, build_count: 0, hit_count: 0, miss_count: 0, }), }
}
///|
pub fn ViewMemoStats::build_count(self : ViewMemoStats) -> Int32 {
self.build_count
}
///|
pub fn ViewMemoStats::hit_count(self : ViewMemoStats) -> Int32 {
self.hit_count
}
///|
pub fn ViewMemoStats::miss_count(self : ViewMemoStats) -> Int32 {
self.miss_count
}
///|
/// Return a snapshot of this memo's counters.
///
/// The counters stay inside the caller-owned memo. They are not registered
/// globally and do not appear in `RuntimeInspectorSnapshot`, which only knows
/// about runtime-owned caches.
pub fn[Msg] ViewMemo::stats(self : ViewMemo[Msg]) -> ViewMemoStats {
{
build_count: self.state.val.build_count,
hit_count: self.state.val.hit_count,
miss_count: self.state.val.miss_count,
}
}
///|
/// Return the view for `key`, running `build` only when this memo has no entry
/// for that key.
pub fn[Msg] ViewMemo::view(
self : ViewMemo[Msg],
key~ : DeclarationKey,
build~ : () -> View[Msg],
) -> View[Msg] {
match self.state.val.entry {
Some(entry) if entry.key == key => {
self.state.val.hit_count = self.state.val.hit_count + 1
entry.view
}
_ => {
self.state.val.miss_count = self.state.val.miss_count + 1
let view = build()
self.state.val.build_count = self.state.val.build_count + 1
self.state.val.entry = Some({ key, view, })
view
}
}
}