pub trait ModelStore {
Show 39 methods
// Required methods
fn read(&self, name: &str) -> Option<String>;
fn write(&self, name: &str, contents: &str) -> Result<(), String>;
fn mutation_generation(&self) -> u64;
// Provided methods
fn backend_label(&self) -> String { ... }
fn list(&self) -> Vec<String> { ... }
fn remove(&self, _name: &str) -> Result<(), String> { ... }
fn residency(&self, name: &str) -> Residency { ... }
fn identity(&self, identity: &str) -> DocumentIdentity { ... }
fn display_name(&self, identity: &str) -> String { ... }
fn sibling_of(&self, identity: &str, file_name: &str) -> Option<String> { ... }
fn canonical_identity(&self, name: &str) -> String { ... }
fn take_persistence_errors(&self) -> Vec<String> { ... }
fn plm_session(&self) -> Option<Session> { ... }
fn plm_client(&self) -> Option<Rc<PlmClient>> { ... }
fn plm_revision(&self, key: &str) -> Option<IndexEntry> { ... }
fn refresh_plm_index(&self, keys: &[String], stale: bool) { ... }
fn local_files(&self) -> Option<&dyn ModelStore> { ... }
fn begin_pick_file(&self) -> Result<(), String> { ... }
fn take_picked_file(&self) -> Option<ImportedFile> { ... }
fn pending_writes(&self) -> usize { ... }
fn browser_location(&self) -> String { ... }
fn browser_entries(&self, _extensions: &[&str]) -> Vec<BrowserEntry> { ... }
fn browser_enter(&self, _identity: &str) -> Result<(), String> { ... }
fn browser_up(&self) -> Result<(), String> { ... }
fn browser_home(&self) -> Result<(), String> { ... }
fn browser_root(&self) -> Result<(), String> { ... }
fn browser_navigate(&self, _location: &str) -> Result<(), String> { ... }
fn browser_places(&self) -> Vec<BrowserPlace> { ... }
fn browser_create_dir(&self, _name: &str) -> Result<(), String> { ... }
fn browser_write(
&self,
name: &str,
contents: &str,
) -> Result<String, String> { ... }
fn list_external_files(&self, _extensions: &[&str]) -> Vec<String> { ... }
fn read_external_file(&self, _name: &str) -> Option<Vec<u8>> { ... }
fn supports_file_interchange(&self) -> bool { ... }
fn export_file(
&self,
name: &str,
contents: &str,
) -> Result<Option<String>, String> { ... }
fn begin_import(&self) -> Result<(), String> { ... }
fn take_import(&self) -> Option<ImportedFile> { ... }
fn begin_import_filtered(
&self,
_filter: (&str, &[&str]),
) -> Result<(), String> { ... }
fn export_file_named(
&self,
_file_name: &str,
_contents: &str,
) -> Result<(), String> { ... }
fn export_file_named_bytes(
&self,
_file_name: &str,
_contents: &[u8],
) -> Result<(), String> { ... }
}Expand description
The application’s single persistent-storage abstraction. Reserved application
keys and named model documents are read and written through the same methods.
All methods take &self; mutable backend state lives behind interior mutability.
Required Methods§
Sourcefn read(&self, name: &str) -> Option<String>
fn read(&self, name: &str) -> Option<String>
Read a stored document by name, or None if absent/unreadable.
Sourcefn write(&self, name: &str, contents: &str) -> Result<(), String>
fn write(&self, name: &str, contents: &str) -> Result<(), String>
Create or overwrite the document name with contents. Err carries a
message the panel surfaces in its status line.
Sourcefn mutation_generation(&self) -> u64
fn mutation_generation(&self) -> u64
A monotonic count of this store’s MUTATIONS — every write, remove
and browser_write that landed, WHOEVER made it. A read never moves
it; two reads that agree mean nothing was written in between.
This is a cache-invalidation key, which is why it is REQUIRED rather
than defaulted: a default would let a new backend (the GitHub one this
trait is shaped for) compile while silently never invalidating
anything, which is the failure it exists to stop. The outdated-parts
badge (panels::update_components) used to key on the file dialog’s
own save counter, which counts Save / Save As / native Save-As and
NOTHING else — so a KiCad re-import (panels::kicad_bulk::write_part)
or the explorer’s delete row could change a part’s source under an open
assembly, move no other generation, and leave the badge dark.
Provided Methods§
Sourcefn backend_label(&self) -> String
fn backend_label(&self) -> String
A short human label of where documents persist, for the panel header
(e.g. "filesystem: ~/.config/brep-app/models" or "browser storage").
Sourcefn list(&self) -> Vec<String>
fn list(&self) -> Vec<String>
The names of the documents currently available to Open (bare names, no extension). May be empty on a backend that cannot enumerate — then the panel falls back to the name field / import.
Sourcefn remove(&self, _name: &str) -> Result<(), String>
fn remove(&self, _name: &str) -> Result<(), String>
Delete the document name (best-effort; Ok if it is already gone).
Sourcefn residency(&self, name: &str) -> Residency
fn residency(&self, name: &str) -> Residency
Whether name is absent, listed but not yet loaded, or readable now
(see Residency). The default answers from read, which is exact for
every store that holds what it lists; only an index-hydrated store
overrides it. No caller branches on OnDisk yet — it is here so one
CAN tell “not loaded yet” from “gone” without a second store API.
Sourcefn identity(&self, identity: &str) -> DocumentIdentity
fn identity(&self, identity: &str) -> DocumentIdentity
What kind of identity identity is on THIS store (see
DocumentIdentity and the enumeration above it). Every file backend
keys by path, so the default never parses: a browser folder named
part/7/rev holds a document, not a revision.
Sourcefn display_name(&self, identity: &str) -> String
fn display_name(&self, identity: &str) -> String
The name a person sees for identity: the tab title, the name field.
The default is the file rule, [model_display_name]; a PLM store knows
the part number and revision label from its index, which the key alone
does not carry.
Sourcefn sibling_of(&self, identity: &str, file_name: &str) -> Option<String>
fn sibling_of(&self, identity: &str, file_name: &str) -> Option<String>
The identity of file_name beside the document identity — or None
on a store with no folders to be beside (the PLM, where a family member
or a spun-out part is a new part instead, S7 / S9). The default is the
file rule, sibling_identity.
Sourcefn canonical_identity(&self, name: &str) -> String
fn canonical_identity(&self, name: &str) -> String
The ONE spelling of the document name resolves to, as the explorer
spells it (BrowserEntry::identity), so two names for one document
compare equal: a bare bolt and /home/u/.config/brep-app/models/bolt.nbrep
on the desktop, sub/bolt and /models/sub/bolt.nbrep in the browser.
The adoption importer (S13) needs it. An assembly’s sourceKeys are
whatever name the part was inserted by, and the importer must match
each one to the file it walked. The default is name unchanged, which
is right for a store with one spelling per document (a PLM store’s
revision keys).
Sourcefn take_persistence_errors(&self) -> Vec<String>
fn take_persistence_errors(&self) -> Vec<String>
Persistence failures that surfaced AFTER a write / remove already
returned Ok — the price of a WRITE-BEHIND backend (see
[mirror_store]). The app shell drains this once per frame into the toast
overlay, so a save that never reached storage is never silent: the
in-memory copy means nothing is lost mid-session, but the user has to know
it will not survive a reload. Empty on a backend that writes synchronously
(native files), which reports through write’s Err instead.
Sourcefn plm_session(&self) -> Option<Session>
fn plm_session(&self) -> Option<Session>
The PLM this session is on, or is configured for and not on (why, when
known): what the Settings PLM tab shows (plan S1 part 3). None is the
file-based app, and the tab is absent.
Sourcefn plm_client(&self) -> Option<Rc<PlmClient>>
fn plm_client(&self) -> Option<Rc<PlmClient>>
The signed-in PLM client of a session whose store IS the PLM, for the
calls that are not store reads and writes (Generate, spin-out, the
lifecycle verbs). None on every file store, and on a PLM configured
but not connected.
Sourcefn plm_revision(&self, key: &str) -> Option<IndexEntry>
fn plm_revision(&self, key: &str) -> Option<IndexEntry>
What the PLM’s store index says of revision key (part/…/rev/…):
its part number, label, lifecycle and lock, as the session last read
them. None on every file store and for a key the index does not list.
No request: this is the index the session already holds.
Sourcefn refresh_plm_index(&self, keys: &[String], stale: bool)
fn refresh_plm_index(&self, keys: &[String], stale: bool)
Bring the held index up to date after the change feed moved: keys
are the revisions the feed named, stale means it could not say. A
no-op on every file store.
Sourcefn local_files(&self) -> Option<&dyn ModelStore>
fn local_files(&self) -> Option<&dyn ModelStore>
This machine’s own files, browsable, for the file chooser (any file,
any folder): the native file store itself, or the file store a PLM
session keeps beside the server. None in the browser, which picks
through Self::begin_pick_file instead.
Sourcefn begin_pick_file(&self) -> Result<(), String>
fn begin_pick_file(&self) -> Result<(), String>
The browser’s file chooser for ANY file (not the model lane’s
.nbrep input): the choice arrives later through
Self::take_picked_file, under the file’s own name.
Sourcefn take_picked_file(&self) -> Option<ImportedFile>
fn take_picked_file(&self) -> Option<ImportedFile>
The file Self::begin_pick_file’s chooser delivered, once.
Sourcefn pending_writes(&self) -> usize
fn pending_writes(&self) -> usize
Writes handed to a WRITE-BEHIND backend that have not settled yet — the status bar’s working indicator reports them (“Saving to browser storage”). Always 0 on a backend that writes synchronously.
Sourcefn browser_location(&self) -> String
fn browser_location(&self) -> String
Current directory shown by the embedded explorer.
Sourcefn browser_entries(&self, _extensions: &[&str]) -> Vec<BrowserEntry>
fn browser_entries(&self, _extensions: &[&str]) -> Vec<BrowserEntry>
Directories and matching files at the current explorer location. Directories are never filtered. The default implementation presents the backend’s named model collection as a flat virtual directory.
fn browser_enter(&self, _identity: &str) -> Result<(), String>
fn browser_up(&self) -> Result<(), String>
fn browser_home(&self) -> Result<(), String>
fn browser_root(&self) -> Result<(), String>
Navigate the explorer directly to location — a value previously returned
by Self::browser_location, a BrowserPlace::location, a breadcrumb
ancestor, or a user-typed path. Err if it is not a directory this backend
can browse. Powers the breadcrumb, the sidebar, back/forward, and the
path-edit field. Default: unsupported.
Sourcefn browser_places(&self) -> Vec<BrowserPlace>
fn browser_places(&self) -> Vec<BrowserPlace>
Quick-access places for the explorer’s left sidebar (home, documents, the models root, disks…). Default: none, and the sidebar hides itself.
Sourcefn browser_create_dir(&self, _name: &str) -> Result<(), String>
fn browser_create_dir(&self, _name: &str) -> Result<(), String>
Create a child directory at the current browser location.
Sourcefn browser_write(&self, name: &str, contents: &str) -> Result<String, String>
fn browser_write(&self, name: &str, contents: &str) -> Result<String, String>
Write a filename at the current browser location and return its stable identity for subsequent plain Save operations.
Sourcefn list_external_files(&self, _extensions: &[&str]) -> Vec<String>
fn list_external_files(&self, _extensions: &[&str]) -> Vec<String>
Files available to the in-app explorer for a foreign-format import. Names retain their extension. Browser storage returns none and offers an Upload button instead; desktop enumerates its application files directory.
Sourcefn read_external_file(&self, _name: &str) -> Option<Vec<u8>>
fn read_external_file(&self, _name: &str) -> Option<Vec<u8>>
Read one entry returned by Self::list_external_files.
Sourcefn supports_file_interchange(&self) -> bool
fn supports_file_interchange(&self) -> bool
Whether this backend can exchange files with the user’s real filesystem
(browser download+upload). The panel shows the Upload affordance only when
this is true.
Sourcefn export_file(
&self,
name: &str,
contents: &str,
) -> Result<Option<String>, String>
fn export_file( &self, name: &str, contents: &str, ) -> Result<Option<String>, String>
Hand contents to the user as a file named after name (browser: a
download; native w/ dialog: a Save-As). Returns the saved document’s
identity — the full path the user chose on native (so the caller can
re-save straight to it), the bare download name on the web — or None
when the user cancelled. No-op (None) by default.
Sourcefn begin_import(&self) -> Result<(), String>
fn begin_import(&self) -> Result<(), String>
Begin importing a real file — opens the platform picker. The result is
retrieved later via Self::take_import (upload/read is async in the
browser). No-op by default.
Sourcefn take_import(&self) -> Option<ImportedFile>
fn take_import(&self) -> Option<ImportedFile>
Poll for a completed import, consuming it.
None until a begin_import finishes. Default: never any.
Sourcefn begin_import_filtered(&self, _filter: (&str, &[&str])) -> Result<(), String>
fn begin_import_filtered(&self, _filter: (&str, &[&str])) -> Result<(), String>
Begin importing a real file behind a specific picker filter (a human
label + dot-less extensions, e.g. ("STEP", &["step","stp"])). The chosen
file’s contents + its FULL name (extension preserved, so the panel can
route it) arrive via Self::take_import. Default: reuse Self::begin_import.
Sourcefn export_file_named(
&self,
_file_name: &str,
_contents: &str,
) -> Result<(), String>
fn export_file_named( &self, _file_name: &str, _contents: &str, ) -> Result<(), String>
Hand contents to the user under EXACTLY file_name (extension included,
no model-extension munging) — the Save-As / download for a foreign export
format. The file’s media type comes from its extension
(media_type). Default no-op (interchange unsupported).
Sourcefn export_file_named_bytes(
&self,
_file_name: &str,
_contents: &[u8],
) -> Result<(), String>
fn export_file_named_bytes( &self, _file_name: &str, _contents: &[u8], ) -> Result<(), String>
Self::export_file_named for a BINARY format (GLB, a sheet PDF). Every
text export could go through this one — text is bytes — but the text
method stays because the browser’s Blob takes a string directly and
routing UTF-8 through a Uint8Array for every STEP file would be a copy
for nothing. Both lanes type the file the same way, from its extension,
so which lane an export takes is a question about copies and never about
what the user receives. Default no-op, like its text sibling.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".