Skip to main content

Engine

Struct Engine 

Source
pub struct Engine { /* private fields */ }
Expand description

Unified engine. Holds a list of mounted backends and routes mem-named operations to the right one.

Send so the engine can sit behind a Mutex (today’s pattern in the MCP server). The trait object’s Send + Sync bound on MemBackend keeps the inner backends thread-safe; the engine itself is single-threaded by design (the lazy memos are OnceCell, which is !Sync).

Debug is hand-written to avoid requiring Debug on the dyn MemBackend trait object — backend impls are free to stay non-Debug.

§Load-on-init

Engine::from_mounts walks each backend at construction time (list_entities + read_entity + parse) and populates a single shared Store with entities and edges from every mount. Each mount’s schema resolves from its own pin (the backend config’s schema, or the mount-record assertion as fallback) through the SchemaResolver, so schemas holds genuinely heterogeneous schemas in a multi-schema workspace. Per-file errors don’t fail construction; they collect into Engine::load_errors for the operator to inspect.

Implementations§

Source§

impl Engine

Source

pub fn apply_external_commit( &mut self, envelope: &CommitEnvelope, ) -> Result<(), EngineError>

Replay an externally-produced commit envelope into the in-memory store.

Refuses with EngineError::UnknownMem when the envelope names a mem the engine has no mount for. Parse failures on any change variant surface as EngineError::Parse and abort the apply before any store mutation lands — the post-state is either coherent at the envelope SHA or unchanged. (The store mutation loop below uses a staged scratch list precisely to preserve this all-or-nothing property; do not refactor it into per-change in-place mutations without restoring an equivalent guarantee.)

Empty changes is a valid envelope: the head cursor advances and a MemChangedEvent fires, but no store mutation happens. Lets replay drivers signal “we saw a commit, here is its SHA, no entity-level changes” — useful for empty commits (e.g. tag-only or merge commits without tree changes).

Source§

impl Engine

Source

pub fn from_archive_bytes(bytes: Vec<u8>) -> Result<Self, FromArchiveBytesError>

Hydrate an engine from sealed archive bytes (.mem).

Validates the bytes through the archive ingress validator (extract_entries), reads the embedded .memstead/config.json for mem name + schema pin, loads any embedded schema package (.memstead/schema/) into the engine’s schema catalogue, and constructs a single-mount read-only engine backed by the bytes. No temp file, no on-disk artifact — the bytes are the storage.

The resulting engine refuses mutations (memstead_create, memstead_update, memstead_delete, memstead_relate, memstead_rename) via the existing read-only-mount / sealed-backend envelope. Read operations work for the embedded mem.

Source

pub fn from_archive_bytes_with_limits( bytes: Vec<u8>, limits: &ValidatorLimits, ) -> Result<Self, FromArchiveBytesError>

Variant of Self::from_archive_bytes with caller-supplied limits. Bridge / registry deployments tune the caps; the default ladder (ValidatorLimits::DEFAULT) is what from_archive_bytes picks.

Source

pub fn export_mem_to_bytes( &self, mem_name: &str, ) -> Result<Vec<u8>, EngineError>

Export the named mem’s current state as .mem archive bytes.

Symmetric to Self::from_archive_bytes: a mem name in, a self-contained byte buffer out. The bytes validate against extract_entries standalone — any consumer of sealed archives accepts them. Feeding the bytes back into Engine::from_archive_bytes yields an engine that returns identical reads against the exported mem.

Returns EngineError::UnknownMem when the name resolves to no mount; EngineError::Backend wrapping crate::backend::BackendError::Sealed when the mem is archive-mounted (already-an-archive, no meaningful re-export); EngineError::InvalidInput when the mem has no loaded MemConfig; EngineError::MemConfigIncomplete when the loaded config is missing version. The git-branch byte-export path lifts in a follow-up; today it surfaces as EngineError::Backend wrapping the unmounted-hook message.

Source§

impl Engine

Source

pub fn from_mounts( mounts: Vec<(Mount, Box<dyn MemBackend>)>, ) -> Result<Self, EngineError>

Build an engine from (mount, backend) pairs. The backend is the implementor that will serve reads / writes for that mount’s mem.

Returns EngineError::DuplicateMem when two mounts name the same mem; that’s a configuration error the caller must fix before the engine can route deterministically. An empty mount list is allowed (returns an engine that errors UnknownMem on every read) — useful for tests; production callers will reject empty inputs at the persistence-adapter layer.

Source

pub fn from_mounts_with_schemas_dir( mounts: Vec<(Mount, Box<dyn MemBackend>)>, schemas_dir: Option<&Path>, ) -> Result<Self, EngineError>

Construct an engine from mounts plus an optional workspace schemas directory. Loads every subdirectory of schemas_dir as a workspace-authored schema and combines with the builtin catalogue for per-mem schema-pin resolution. Workspace schemas take precedence on (name, version) collision — matches full’s behaviour.

schemas_dir = None is equivalent to Self::from_mounts. Used by engine_from_workspace_root to thread the [schemas_dir] workspace-toml entry into schema resolution.

Source

pub fn from_mounts_with_schemas_dir_and_extra( mounts: Vec<(Mount, Box<dyn MemBackend>)>, schemas_dir: Option<&Path>, extra: Vec<Arc<Schema>>, ) -> Result<Self, EngineError>

Like Self::from_mounts_with_schemas_dir but layers additional, pre-loaded local-storage schemas (e.g. those a git-branch backend reads from its __MEMSTEAD:schemas/ ref via SchemaSource) on top of the folder schemas_dir set. Both are local-storage schemas — they override built-ins on (name, version) collision. The git-branch boot path uses this to make ref-installed schemas resolvable, which from_mounts_with_schemas_dir (folder only) does not.

Source

pub fn from_workspace_root(workspace_root: &Path) -> Result<Self, BootError>

Boot an engine from a workspace root using only lean-flavour backends (folder + archive). The MCP filesystem server, the CLI’s lean dispatcher, and the macOS UniFFI consumer all reach the new engine through this entry point — replacing per-flavour init code with one call.

Loads the workspace through crate::FileWorkspaceStore, instantiates each mount’s backend via crate::instantiate_lean_backend, and constructs the engine via Engine::from_mounts.

Errors:

Source§

impl Engine

Source

pub fn reload_if_stale(&mut self, mem: Option<&str>) -> Vec<WarningHint>

Reload-before-operation: before any read or write executes, check the mem ref; if it advanced past the engine’s cached last_known_head, reload the affected mem(s) and return one [WarningHint::MemReloaded] per reload so the caller can surface the drift to the agent (the response itself already carries fresh content — the warning explains why state shifted).

The ref check runs on every call — there is no throttle window. A per-operation current_head() read is microseconds, effectively free at LLM latencies, and a throttle that let an operation execute against an already-moved ref would reintroduce the exact silent-staleness this guards against. This is the correctness floor: no operation acts on a projection that is behind git truth.

mem = Some(name) scopes the probe to one mount; None scans every mount. Read handlers that target a known mem (memstead_entity derives the mem from the id; memstead_changes_since takes it as a param) and every mutation (which knows its target mem) pass a name; tools that scan multi-mem (memstead_search without a mem filter, memstead_overview, memstead_health) pass None.

Behaviour matrix per mount:

  • cached Some(old) + on-disk Some(new), old != new → reload the mem, emit MemReloaded, refresh the cached head to new.
  • cached None + on-disk Some(new) → silently capture the first observed head as the baseline (no warning — there’s no prior in-memory snapshot to be stale against).
  • cached / on-disk match, on-disk None (folder, archive, refdb hiccup), or current_head errors → no-op.

Reload errors are warn-logged and the affected mem is skipped — the caller’s response is still served from the (now stale) in-memory snapshot rather than failing the entire request. The next operation retries.

Cache invalidation rides on reload_one_mem — community and search-index memos drop when any mem reloads.

Source

pub fn take_mem_changed_notices(&mut self) -> Vec<MemChangedNotice>

Drain the reload-before-operation notices accumulated since the last drain. The response layer calls this after an operation completes to attach the structured mem_changed notice. Every handler that can trigger a reload (directly via Self::reload_if_stale or indirectly through a mutation) must drain, or an undrained notice leaks into the next operation’s response.

Source

pub fn mem_changed_notice( &self, mem: &str, from_head: &str, to_head: &str, ) -> MemChangedNotice

Build a crate::ops::MemChangedNotice describing the per-entity delta a reload applied to mem (from from_head to to_head). Derived from Self::changes_since so it carries rename detection on git-branch mounts; on any backend error (e.g. an unresolvable cursor) it falls back to an empty delta — the heads alone still tell the agent the mem moved.

Callers pair this with Self::reload_if_stale: a returned crate::ops::WarningHint::MemReloaded carries the old_head / new_head to pass here. The delta matches the transition the reload applied (changes_since walks the same from_head → current range).

Source

pub fn changes_since( &self, mem: &str, since: &str, rename_similarity: Option<f32>, ) -> Result<ChangesReport, EngineError>

Per-entity events for mem between since and the backend’s current state.

  1. Resolves the mount (returns EngineError::UnknownMem on unknown mem).
  2. Validates rename_similarity against [RENAME_SIMILARITY_MIN, RENAME_SIMILARITY_MAX]. Out-of-range values refuse with EngineError::InvalidInput carrying details.allowed_range and details.requested. None falls back to crate::ops::RENAME_SIMILARITY_DEFAULT.
  3. Dispatches on the mount’s MountStorage:
    • Folder mounts synthesize from the JSONL changelog via crate::ops::folder_changes_since.
    • Git-branch mounts call the registered [GitBranchOps::changes_since] hook (real tree-diff with rename detection); missing hook = full flavour not loaded and the report comes back empty.
    • Archive mounts return an empty report.
  4. Enriches each envelope’s title / entity_type from the in-memory store (best-effort — Removed envelopes always leave both None; missing-from-store entities also leave them None).
  5. Returns crate::ops::ChangesReport with mem, since (echoed), head (backend-resolved current cursor), enriched changes, and any clamping warnings.
Source

pub fn fetch( &self, mem: &str, remote: &str, refspecs: &[String], ) -> Result<FetchOutcome, EngineError>

Fetch updates from remote into the workspace’s mem-repo. Advances remote-tracking refs only; the local branch pointer is not moved.

refspecs is forwarded verbatim to git fetch. An empty list uses the remote’s configured defaults.

Refusal codes: UNKNOWN_MEM, UNKNOWN_REMOTE, INVALID_INPUT (folder / archive mounts).

V1 atomicity: schema-validation quarantine for fetched commits is not yet wired. The remote-tracking refs advance unconditionally on a successful fetch; downstream schema validation runs on read via the engine’s existing reload pipeline.

Source

pub fn pull( &mut self, mem: &str, remote: &str, ) -> Result<PullOutcome, EngineError>

Pull updates from remote into the named mem’s branch. Fetches into the remote-tracking ref, runs a pre-merge schema validation pass against the prospective state, then fast-forwards the local branch. Refuses with LOCAL_DIVERGENCE for diverged local branches and with SCHEMA_VIOLATION_IN_FETCH when the prospective state fails schema validation — in both refusal cases the local branch pointer is untouched (the underlying fetch has updated refs/remotes/* but the engine has not promoted the new state).

Source

pub fn push( &self, mem: &str, remote: &str, force: bool, ) -> Result<PushOutcome, EngineError>

Push the named mem’s branch to remote. Runs a pre-push schema validation pass against the local branch tree; refuses with LOCAL_INVALID_STATE when the local state fails schema validation (the remote is not contacted in that case). Refuses with NON_FAST_FORWARD when the push is not a fast-forward and force: false; with force: true runs a --force-with-lease push instead.

Source

pub fn remote_add( &self, name: &str, url: &str, ) -> Result<RemoteAddOutcome, EngineError>

Configure (or re-point) a named remote on the workspace’s mem-repo, so fetch / pull / push have somewhere to go. Upsert semantics — safe to re-run with a new URL. The mem-repo is shared by every git-branch mount, so the op is workspace-level: any git-branch mount locates it; refuses INVALID_INPUT when the workspace has none.

Source

pub fn branch_reset( &mut self, mem: &str, target_sha: &str, expected_head: Option<&str>, ) -> Result<BranchResetOutcome, EngineError>

Reset a mem’s branch pointer to target_sha. The only engine surface that moves a branch pointer over existing commits — every other mutation appends. Refuses if any commit that would be discarded by the reset is already reachable from a refs/remotes/* ref (the engine’s definition of “pushed”).

target_sha accepts anything gix::rev_parse_single admits: a SHA, an abbreviated SHA, a branch name, a tag. The branch itself (refs/heads/<mem>) must exist.

Refusal codes:

Emits a crate::engine::events::MemChangedEvent on success when the SHA actually changed; the reset’s effect is observable through the same change-event surface every commit flows through. Engine’s cached last_known_head for the affected mount is rewound to the new SHA so the next drift probe doesn’t flag the reset as a sibling-writer surprise.

Source

pub fn branch_reset_stranded_refs( &self, mem: &str, target_sha: &str, ) -> Result<Vec<StrandedCrossMemRef>, EngineError>

Cross-mem references that a reset of mem to target_sha would strand: incoming edges from entities in other mems whose target exists at the current head but would not exist at the target commit — entities created after the target, or renamed to their current id after it (the reset re-materialises the old id, so references to the new id dangle either way).

A read — computes against the live store and the commit history, moves nothing. The human surface calls this fresh at confirmation-dialog time and warns before branch_reset. Sorted (from_id, to_id, rel_type) for stable rendering.

Refusals mirror changes_since: UnknownMem, InvalidCursor for an unresolvable target_sha, InvalidInput for non-git-backed mounts.

Source

pub fn diff( &self, mem: &str, ref_a: &str, ref_b: &str, config: Option<DiffConfig>, ) -> Result<Diff, EngineError>

Two-ref structural diff. Produces a per-entity crate::ops::Diff comparing the trees at ref_a and ref_b for the named mem’s storage. Folder and archive backends carry no git refs and refuse via EngineError::InvalidInput; the git-branch backend routes through [GitBranchOps::diff] when the full flavour is loaded.

mem selects the storage context (the gitdir, for git-branch mounts). ref_a / ref_b are arbitrary refs the underlying git layer accepts — branch names, commit SHAs, tag names — so cross-mem diffs work via fully-qualified refs (refs/heads/<other-mem>) without a separate API.

Refusal codes:

Source§

impl Engine

Source

pub fn subscribe_mem_changes( &self, mem: &str, callback: EventCallback, ) -> Result<SubscriptionHandle, EngineError>

Subscribe to commit events on mem. The returned SubscriptionHandle keeps the registration alive; dropping it (or calling unsubscribe()) removes the callback.

callback runs on the engine’s mutation thread synchronously — by design, per the Core’s runtime-agnostic contract. Consumers that cannot block the writer must decouple inside the callback (channel send, dedicated thread, async runtime queue). The opt-in tokio feature lifts this into a broadcast::Receiver for tokio-resident consumers; the file-watcher feature provides a cross-process variant for readers without a writer engine.

Read-only mounts (archive or ReadOnly capability) accept the subscription but never emit — no mutations land in those mems through this engine. Unknown mems refuse with crate::EngineError::UnknownMem; the typed code is UNKNOWN_MEM.

Source§

impl Engine

Source

pub fn subscribe_mem_changes_broadcast( &self, mem: &str, ) -> Result<(SubscriptionHandle, Receiver<MemChangedEvent>), EngineError>

Tokio-broadcast convenience over the callback subscribe API. Returns a (SubscriptionHandle, broadcast::Receiver) pair: the handle keeps the registration alive (drop to unsubscribe); the receiver yields MemChangedEvents on every commit.

Backpressure follows tokio::sync::broadcast semantics: a subscriber that falls behind by more than the channel capacity (DEFAULT_BROADCAST_CAPACITY) sees RecvError::Lagged(n) on its next recv() and the channel resumes from there. Slow subscribers do not block the writer — that is the whole point of the tokio convenience over the raw callback path, where a slow callback blocks the mutation thread by design.

Use Self::subscribe_mem_changes_broadcast_with_capacity when the default capacity is too small (high-burst write loops) or too large (memory-constrained deployments).

Source

pub fn subscribe_mem_changes_broadcast_with_capacity( &self, mem: &str, capacity: usize, ) -> Result<(SubscriptionHandle, Receiver<MemChangedEvent>), EngineError>

Caller-tunable variant of Self::subscribe_mem_changes_broadcast. capacity is the tokio-broadcast channel buffer size; values below 1 panic per the tokio contract.

Source§

impl Engine

Source

pub fn set_settings(&mut self, settings: WorkspaceSettings)

Replace the workspace-level settings. Called by Self::from_workspace_root (and the full counterpart) after reading .memstead/workspace.toml. Tests / direct callers leave the default empty value in place. Cheap clone — settings carry only data shapes (raw rule lists, link policy map), no compiled matchers. Invalidates the lazy create_rule_set_memo so the next synthesis call rebuilds from the new policy.

Source

pub fn set_backend_factory(&mut self, factory: BackendFactory)

Replace the backend factory. Full consumers call this once at boot (engine_from_workspace_root) to install memstead_git_branch::storage::instantiate_full_backend so the engine can materialise git-branch backends on top of folder + archive. Lean consumers leave the default in place.

Source

pub fn set_git_branch_ops(&mut self, ops: GitBranchOps)

Install the git-branch ops bundle. Full boot (memstead_git_branch::engine_from_workspace_root) calls this once at construction. Lean consumers leave it unset and the git-branch dispatch branches collapse to typed errors / empty reports — lean has no git-branch mounts.

Source

pub fn install_schema( &self, name: &str, version: &str, files: &[(String, Vec<u8>)], ) -> Result<String, EngineError>

Install a schema package onto the workspace’s git-branch backend — the unified __MEMSTEAD:schemas/<name>@<version>/ ref. files are (relative-path, bytes) pairs (schema.yaml, types/<t>.yaml, optional mem-template.json). Returns the resulting commit sha; idempotent at the storage layer (an identical re-install produces no new commit).

Folder workspaces install schemas by writing under <workspace>/.memstead/schemas/ directly; this is the git-branch path, where the engine owns the mem-repo and the write must route through it. Errors when no git-branch ops are wired (lean flavour) or no git-branch mount exists to resolve the shared mem-repo gitdir from. The caller reloads (or restarts) to pick the new schema into the resolution catalogue.

Source

pub fn unregister_writable_mem( &mut self, mem_name: &str, ) -> Result<Option<Box<dyn MemBackend>>, EngineError>

Unregister a writable mem at runtime. Engine-level primitive that memstead_mem_delete builds on.

Removes the named mount from Self::mounts, drops the mem’s entities from the store, refreshes the [MemRouterSnapshot] via Arc::make_mut (COW swap so readers holding a pre-swap snapshot see the pre-state for their lifetime), and invalidates the community + search memos. Does NOT touch the backend’s on-disk state — the caller (delete_mem orchestrator) decides whether to remove the directory / gitdir after this returns.

Returns Ok(Some(backend)) when the mem was present and unregistered — the caller can drive any backend-specific follow-up cleanup (backend.delete_artifacts() for the mem-repo branch + __MEMSTEAD config when delete_files=true). Returns Ok(None) when no mount named the mem (idempotent — repeated calls are safe).

Source

pub fn register_writable_mem( &mut self, mount: Mount, backend: Box<dyn MemBackend>, origin: MemOrigin, ) -> Result<(), EngineError>

Register a writable mem at runtime. Engine-level primitive that memstead_mem_create builds on.

Steps:

  1. Name collision probe against the current mem_router snapshot. Writable AND read-only entries collide; the error surfaces the colliding source so the orchestrator can render a recovery hint.
  2. Schema resolution via the built-in catalogue (mirrors Self::from_mounts; workspace-authored schema resolution lifts later).
  3. Per-mem config load (folder backends only; git-branch / archive return None — same contract as Self::from_mounts).
  4. Entity load via the backend, parse, push into the engine’s store with a LoadCollector so drift warnings forward to self.load_warnings.
  5. Insert schema into Self::schemas.
  6. Push the [MountedBackend] into Self::mounts.
  7. COW snapshot swap on Self::mem_router via Arc::make_mut + add_writable(name, dir, origin, mem_path). Folder mounts surface their on-disk path; other backends register with dir: None (matches full’s contract). mem_path carries the create-time organisational path component (mirrors MemCreateParams.path) — the delete-side lifecycle composer reads it back to rebuild the <mem_path>/<name> candidate the create-side composer matched against. Caller threads None for flat-layout registrations and Some(p) for hierarchical ones.
  8. Invalidate community + search memos.

Returns Err(EngineError::MemNameCollision) when the name is already registered. Other failures (schema-not-found, backend read errors) propagate as their typed variants. On failure no engine mutation happens: every potentially- mutating step runs only after the collision probe succeeds, and intermediate failures propagate before the mount / router are touched.

Source

pub fn set_workspace_root(&mut self, root: PathBuf)

Override the workspace root after construction. The full boot helper memstead_git_branch::engine_from_workspace_root calls this so the engine knows the path even when the boot route runs through the full adapter rather than Self::from_workspace_root.

Source

pub fn persist_state(&self) -> Result<(), EngineError>

Persist the engine’s current mount list to the workspace store so a freshly-booted sibling process observes the same mem membership. Called by [crate::mem_management::create_mem] / [crate::mem_management::delete_mem] after the in-memory router mutation lands — without this, the per-mem content (branch + __MEMSTEAD config blob, or folder + .memstead/config.json) is already on disk, but the next process boot reads an empty .memstead/state/mounts.json and the engine starts with zero writable mems.

No-op when workspace_root is unset (tests / ad-hoc consumers that build the engine directly from a mount list). Production boot paths (Engine::from_workspace_root and the full counterpart) always set the root, so the engine-side fix covers every caller — including the future UniFFI binding — by construction.

Hardcoded against crate::FileWorkspaceStore because that is the only V1 adapter; a future SQLite or remote adapter would install through a setter mirroring Self::set_backend_factory.

Source

pub fn set_mem_schema( &mut self, mem: &str, target: &SchemaRef, ) -> Result<SetSchemaOutcome, EngineError>

Set a mem’s schema pin — the conformance-gated schema-migration trigger. Behaviour per the pinned contract:

  • requested == current pin → Noop, no state change.
  • requested != pin, mem integral against the target → atomic switch (schema_pin = target, migration state cleared) in one workspace-store write → Switched.
  • requested != pin, mem NOT integral → enter (or stay in) dual-pin: migration_target = target, writes validate against the target from this call on, findings carries the non-integral entities → MigrationStarted (first call) / MigrationPending (same target re-issued).
  • re-issued with the in-flight target once every entity is integral → atomic switch → Switched.

The trigger is a label change gated by the conformance check — no content hashing. The response hands the agent findings and nothing else (no migration scripts, no hints); each repair write is validated strictly against the target.

Source

pub fn export_markdown( &self, mem_filter: Option<&str>, schema_filter: Option<&str>, ) -> Result<ExportResult, EngineError>

Regenerate entity markdown files from the in-memory store.

Dispatch:

  • When mem_filter is Some(name), only that mem’s mount is considered. If its active backend doesn’t support markdown regeneration in place (today: anything other than MountStorage::Folder), the call refuses with EngineError::MarkdownExportUnsupportedBackend carrying the active backend’s id and the supported-backend list.
  • When mem_filter is None, every mount is iterated. Folder mounts regenerate as today; non-folder mounts are recorded in crate::ops::ExportResult::skipped_mounts so the caller can surface the partial-success shape.

Per-folder-mount behaviour: iterate the store, regenerate each non-stub entity belonging to the mount’s mem, compare to the on-disk file, write if changed.

schema_filter narrows the per-entity-type subset: when Some(name), only entities whose entity_type matches are regenerated. None exports every type.

Pre-fix this returned ExportResult { written: 0, unchanged: 0 } for git-branch / archive mounts — a successful-looking no-op that masked the backend-incompatibility. The typed refusal (per-mem) and the skipped_mounts channel (workspace-wide) give the caller an agent-actionable signal in one round-trip.

Source

pub fn export_mem( &self, mem_name: &str, output_path: &Path, ) -> Result<MemExportResult, EngineError>

Export a mem as a portable .mem archive.

Dispatch is internal: the engine looks up the mount whose mem name matches and branches on its MountStorage. Folder mounts produce a snapshot archive (current .md files + config); git-branch mounts invoke the registered GitBranchOps::export hook to produce a history archive (the per-mem branch tip’s tree); archive mounts reject with BackendError::Sealed (already-an-archive — no meaningful re-export).

The mem’s MemConfig is looked up via Self::mem_config_for; unloaded configs (folder mounts without a .memstead/config.json, git-branch mounts without a __MEMSTEAD:mems/<mem>/config.json) surface as EngineError::InvalidInput. Workspace-level schema dir is threaded from self.settings.schemas_dir for the schema-source resolution chain.

Source

pub fn record_pipeline_edit_provenance( &self, mem: &str, kind: &str, edits: &[(String, Option<Vec<u8>>)], note: Option<&str>, verb: &str, ) -> Result<(), BackendError>

Update a mem’s version field in its per-mem config and persist it through the backend. Backend-symmetric: folder backends rewrite .memstead/config.json; git-branch backends commit __MEMSTEAD:mems/<mem>/config.json. Archive mounts reject with BackendError::Sealed.

Returns the (mem, old_version, new_version) triple so callers can surface the change without an extra read. Reads the current value from the in-memory MemConfig and updates it on success, keeping the next call free of a stale-version read.

EngineError::UnknownMem when the name resolves to no mount; EngineError::ReadOnlyMount when the mount is sealed for writes; EngineError::InvalidInput when the mount has no loaded MemConfig (folder mount with no .memstead/config.json; the residual missing-config path is distinct from the missing-version path). F1. Record pipeline-edit provenance through mem’s backend — the bridge the pipeline-edit block (outside the engine module) uses to reach a mount’s backend. A mem that isn’t currently mounted is a successful no-op: pipeline configs may reference unmounted mems, and provenance is recorded against the mounted set.

Source

pub fn set_mem_version( &mut self, mem_name: &str, new_version: Version, note: Option<&str>, ) -> Result<SetMemVersionOutcome, EngineError>

Source

pub fn set_mem_description( &mut self, mem_name: &str, new_description: Option<String>, note: Option<&str>, ) -> Result<SetMemDescriptionOutcome, EngineError>

Update a mem’s description field in its per-mem config and persist it through the backend — the one-line text mem-archive export embeds and the registry card surfaces. None clears the field. Same backend symmetry, drift probe, and provenance-note posture as Self::set_mem_version; archive mounts reject with BackendError::Sealed.

Source

pub fn set_mem_internal( &mut self, mem_name: &str, internal: bool, note: Option<&str>, ) -> Result<bool, EngineError>

Mark (or unmark) a mem as internal — hidden from the default memstead_overview roster and public projections, while remaining a real, schema-validated, diffable mem (inspectable when explicitly scoped by name, and deletable). The ingest process-state redesign (candidate (b)) flags each ingest/<name> process mem this way so it does not clutter the roster alongside real content.

Stored as the top-level internal config field (captured by the flattened extra map). Backend-symmetric like Self::set_mem_description; EngineError::UnknownMem / ReadOnlyMount / InvalidInput on the usual failures.

Source

pub fn set_mem_sync_state( &mut self, mem_name: &str, key: &str, token: &str, note: Option<&str>, ) -> Result<SetMemSyncStateOutcome, EngineError>

Set (or clear) one opaque sync-state token in a mem’s per-mem config and persist it through the backend. The ingest layer calls this after a successful pass over a source’s changed slice to record “the source state the graph was last synced against”.

key and token are both opaque to the engine: the key is conventionally "<ingest>/<facet>" but the engine treats it as an arbitrary string; the token’s meaning belongs to the medium-type layer (git → commit id, graph → snapshot token, filesystem → a JSON-stringified stat digest). The engine never parses either. An empty token removes the key — the surface for clearing a baseline (which the next ingest pass re-seeds at the current source state).

Backend-symmetric like Self::set_mem_version: folder backends rewrite .memstead/config.json; git-branch backends commit __MEMSTEAD:mems/<mem>/config.json. Archive mounts reject with BackendError::Sealed.

Returns the (mem, key, previous-token) triple so callers can surface the change without an extra read. EngineError::UnknownMem when the name resolves to no mount; EngineError::ReadOnlyMount when the mount is sealed for writes; EngineError::InvalidInput when the mount has no loaded MemConfig.

Source

pub fn reload_one_mem(&mut self, mem: &str) -> Result<ReloadResult, EngineError>

Re-read the named mount’s backend entities and refresh the in-memory store for that mem. Returns the diff against the pre-reload snapshot — added (ids newly present), removed (ids no longer present), changed (same id, different content_hash).

Operator-triggered: useful when an external writer modified disk while this engine instance was alive (the lean flavour assumes single-writer; this primitive is the escape hatch when that assumption breaks). On the happy path the diff is empty.

Drift detection (whether disk did change) is not part of this surface — callers that want to short-circuit on “nothing changed” must compare added.is_empty() && changed.is_empty() && removed.is_empty() against the result. Backend-specific drift signals (git HEAD comparison, mtime check) live in the full-flavour engine where they have meaning.

Invalidates community + search-index memos on success.

Source

pub fn reload_one_mem_report( &mut self, mem: &str, ) -> Result<ReloadReport, EngineError>

Rich-shape variant of Self::reload_one_mem that returns a crate::ops::ReloadReport (mem + head_before + head_after + entities_loaded + changed_entity_ids) instead of the slim crate::ops::ReloadResult. Handler-facing wrapper consumed by the memstead_reload MCP tool — the rich shape is the wire contract MCP callers depend on; the slim form stays for programmatic consumers that just want the diff lists.

head_before is the engine’s prior cursor for this mem (its cached last_known_head), not the current on-disk tip: when a sibling has committed since, the tip has already advanced, so reporting it would make the advertised changes_since(since=head_before) recipe span an empty range. head_after is the freshly-peeled tip from crate::backend::MemBackend::current_head; the reload also advances the cursor to it, so a follow-up staleness probe does not re-reload the same window. Backends without history (folder, archive) carry no cursor and return Ok(None); both fields fall back to crate::ops::EMPTY_TREE_SHA for wire-shape stability.

entities_loaded is the post-reload non-stub count for the mem — same semantic as full’s report.

changed_entity_ids is the union of added ∪ changed ∪ removed from the underlying crate::ops::ReloadResult so callers don’t have to merge three lists themselves — matches full’s bundled wire shape.

Source

pub fn reload_each_writable_mem_reports( &mut self, ) -> Result<Vec<ReloadReport>, EngineError>

Batched rich-shape variant — returns one crate::ops::ReloadReport per mounted mem in declaration order. Counterpart to Self::reload_each_writable_mem (slim) that the memstead_reload MCP tool’s no-mem path consumes.

Also re-reads .memstead/workspace.toml and refreshes crate::workspace::WorkspaceSettings before sweeping the mems — this is the pairing with the CLI’s memstead workspace allow-create / grant-cross-link / set-mutations family. Without this re-read, a CLI write would land on disk but the running MCP would still serve the engine’s boot-time policy snapshot; every subsequent memstead_mem_create against the new allowlist would fail with MEM_PATH_NOT_ALLOWED until process restart. The workspace-wide form runs the heavier path; the per-mem form (reload_one_mem_report) intentionally skips the workspace re-read — content drift doesn’t imply policy drift.

Reload of workspace.toml is best-effort: a missing or unparseable file leaves the existing settings untouched. The per-mem sweep is the primary contract — settings refresh is the additive bonus.

First-error-aborts: if any mem’s reload fails, the loop stops and the error propagates. Mems reloaded before the failing one are already mutated in the store; the returned error has no rollback. Operators run the per-mem form to retry the failing mem explicitly.

Source

pub fn reload_each_writable_mem( &mut self, ) -> Result<Vec<(String, ReloadResult)>, EngineError>

Reload every mounted mem in declaration order; returns one (mem, ReloadResult) per mount.

Failure model is first-error-aborts: if any mem’s reload fails, the loop stops and the error propagates. Mems reloaded before the failing one are already mutated in the store; the returned error has no rollback. Operators run the per-mem form to retry the failing mem explicitly.

Caller-friendly batching wrapper around Self::reload_one_mem; internal cache invalidation happens once per mem (the inner call invalidates) so an N-mem batch invalidates the memos N times. That’s wasteful for large workspaces; once the memstead_reload MCP handler migrates we can tighten this to one invalidation at the end.

Source§

impl Engine

Source

pub fn create_entity( &mut self, args: CreateEntityArgs, actor: Actor, client: Option<&ClientId>, note: Option<&str>, ) -> Result<CreateEntityOutcome, EngineError>

Create a new entity in args.mem. Six concerns wired here in one shape regardless of which backend serves the mount:

  1. Capability gating — rejects mounts with ReadOnly capability before reaching the backend.
  2. Validator pipelinevalidate_section_keys + parse_metadata_value enforce the pinned schema’s strictness; typed ValidationError lifts to EngineError::Validation.
  3. Provenance — a Provenance record routes through backend.append_provenance (folder writes JSONL, git-branch no-ops since the commit subject + trailers carry the same fields).
  4. Write + commit atomicitybackend.write_entity then backend.commit with the canonical memstead: create <id> subject so the git-branch backend’s read_provenance can recover the kind.
  5. Store update — re-parse the freshly-generated markdown so the in-memory Store mirrors disk (including generator-determined content_hash).
  6. Error envelopeBackendError::Sealed lifts via the Backend variant so MCP callers see the typed payload intact; HashMismatch propagates likewise.
Source

pub fn create_entity_with_ctx( &mut self, args: CreateEntityArgs, ctx: &CommitContext<'_>, ) -> Result<CreateEntityOutcome, EngineError>

CommitContext-bundling wrapper around Self::create_entity. Destructures CommitContext into (actor, client, note) and delegates.

Source§

impl Engine

Source

pub fn classify_delete_referrers(&self, id: &EntityId) -> DeleteReferrers

Classify an entity’s incoming referrers by the source mount’s capability — the read-only core of the delete guard. Write-Mem referrers block the delete; ReadOnly referrers trigger the residual-stub demotion. Per-source dedup collapses an N-edge source into one ReferrerInfo carrying every rel-type. A referrer in an unmounted mem is treated as Write (safe-by-default: refuse rather than silently demote).

Pure read — no disk, commit, lock, or store mutation. Used by Self::delete_entity and the CLI delete --dry-run preview so both compute the same verdict from one implementation.

Source

pub fn delete_entity( &mut self, args: DeleteEntityArgs, actor: Actor, client: Option<&ClientId>, note: Option<&str>, ) -> Result<DeleteEntityOutcome, EngineError>

Delete an entity from its mount.

Binary semantics — there is no force flag. The engine partitions incoming references by the source mem’s MountCapability:

  • any Write-Mem referrers → refuse with typed EngineError::HasIncomingRefs carrying the structured referrer list;
  • only ReadOnly-mount referrers → delete the file + commit, then demote the in-memory entity to a stub at the same id so the surviving incoming edges keep a valid target. A RESIDUAL_STUB_FOR_READONLY_REFERRERS warning rides on the outcome;
  • no referrers → clean removal (file + store entry + cascading edges). Orphaned stubs whose last incoming edge was the deleted entity are GC’d.

Optimistic-locking via args.expected_hash matches update_entity. Stubs (no on-disk file) skip the backend write and commit but still log provenance.

Source

pub fn delete_entity_with_ctx( &mut self, id: &EntityId, expected_hash: &str, ctx: &CommitContext<'_>, ) -> Result<DeleteEntityOutcome, EngineError>

Positional + CommitContext wrapper around Self::delete_entity. Bundles id + expected_hash into a DeleteEntityArgs.

Source§

impl Engine

Source

pub fn apply_parse_recovery( &mut self, actor: Actor, client: Option<&ClientId>, note: Option<&str>, ) -> Result<ParseRecoveryReport, EngineError>

Walk load_warnings, dispatch the remove_explicit_relation recovery for every writable-origin PARSED_RELATION_INVALID, and report each entry on the response. Read-only-origin warnings cannot be acted on (the engine has no write access to their source markdown) and surface as outcome: "skipped" with reason: "readonly_mount".

Failure model: per-entry failures land on the response as outcome: "failed" with the underlying engine error code in reason. The bulk-fix continues past per-entry failures so a single bad source doesn’t strand the rest of the batch. Only engine-level errors (reload failure, broken workspace state) abort the call and propagate via Err.

Idempotency: after the per-source re-renders land, the method runs reload_each_writable_mem so subsequent calls to health / load_warnings reflect the post-recovery state. Re-running on an already-clean workspace returns an empty entries list with no commits.

Source§

impl Engine

Source

pub fn relate_entity( &mut self, args: RelateEntityArgs, actor: Actor, client: Option<&ClientId>, note: Option<&str>, ) -> Result<RelateEntityOutcome, EngineError>

Add or remove a typed relationship on args.source.

Cross-mem relate is policy-gated through Engine::cross_mem_link_allowed — the workspace’s [cross_mem_links] table (or per-create-rule default_cross_links synthesis) decides whether the edge is permitted. Disallowed pairings surface EngineError::CrossMemLinkNotAllowed. Cross-mem relate only writes the source entity’s markdown — the target mem is never written to. Auto-stub for absent targets works for Write target mems; ReadOnly target mems reject absent targets with EngineError::CrossMemTargetNotFound because the engine cannot persist a stub through the read-only boundary.

Schema-undeclared rel types surface either as validation errors (strict mode) or as ride-along warnings on the outcome (open mode).

Source

pub fn relate( &mut self, from: &EntityId, to: &EntityId, rel_type: &str, remove: bool, ctx: &CommitContext<'_>, ) -> Result<RelateEntityOutcome, EngineError>

Positional-args alias for Self::relate_entity. Bundles the positional inputs into a RelateEntityArgs (with expected_hash: None) and delegates to Self::relate_entity. The CommitContext is destructured into the 4-tuple (actor, client, note) the unified mutation surface accepts.

Source§

impl Engine

Source

pub fn rename_entity_with_ctx( &mut self, old_id: &EntityId, new_title: &str, expected_hash: &str, ctx: &CommitContext<'_>, ) -> Result<RenameEntityOutcome, EngineError>

Positional + CommitContext wrapper around Self::rename_entity.

Source

pub fn rename_entity( &mut self, args: RenameEntityArgs, actor: Actor, client: Option<&ClientId>, note: Option<&str>, ) -> Result<RenameEntityOutcome, EngineError>

Rename an entity by changing its title — the slug, id, and on-disk file path follow.

Same-mem referrers and self-references are rewritten atomically. The renaming entity is treated as the first referrer of itself: every entry in its own relationships list whose target equals the old id is updated to point at the new id, and every [[<old-slug>]] token in its own section bodies is rewritten to the new slug (respecting fenced-code and inline-code masking). Every other entity in the same mem that pointed at the old id (via an explicit relation or an inline body wiki-link) gets the same two- surface rewrite. All rewrites land in one per-mem commit. Cross-mem referrers and ReadOnly-mount referrers are not yet walked — those land with the multi-mem atomicity machinery and the residual-stub demotion path respectively.

Source§

impl Engine

Source

pub fn update_entity( &mut self, args: UpdateEntityArgs, actor: Actor, client: Option<&ClientId>, note: Option<&str>, ) -> Result<UpdateEntityOutcome, EngineError>

Update an entity’s sections and/or metadata.

Same six-concern shape as Engine::create_entity. Optimistic locking via args.expected_hash: when Some, must match the store’s current content_hash or returns EngineError::HashMismatch. The new engine’s MCP-facing callers should always pass the hash; None is the --force-style escape hatch.

Internally a two-step pipeline: Self::prepare_update runs all validation and computes the post-mutation markdown without committing, then Self::commit_prepared_update stages and commits the result. The split lets Self::batch_update prepare every item up front and commit the whole batch as one atomic unit.

Source

pub fn batch_update( &mut self, updates: Vec<(UpdateEntityArgs, Option<String>)>, actor: Actor, client: Option<&ClientId>, ) -> Result<BatchResult, EngineError>

Apply a batch of UpdateEntityArgs atomically — all or nothing. Surfaces BatchResult for memstead batch-update consumers.

The batch validates and prepares every item first (each with its own optimistic-lock check), then commits the whole set as one commit per mem. If any item fails — validation error, HASH_MISMATCH, entity-not-found, any per-item refusal — nothing is committed: the on-disk mem and the in-memory store are restored to exactly their pre-call state, and the result is marked applied: false with the offending item carrying a typed {code, message, details} error envelope and every other item marked "not_applied". The first failing item stops preparation (fail-fast); the caller fixes it and resubmits.

On success the returned commit_sha is the single batch commit — an honest memstead_changes_since cursor / revert handle. Each item’s per-entry note rides into its own provenance record.

Empty batches return applied: true with zero counts and no commit. A batch where every item is a no-op (content unchanged) likewise applies with an empty commit_sha.

Atomicity is per-mem: for the common single-mem batch a commit-time backend failure rolls the whole batch back. A batch spanning multiple mems commits each mem in turn; if a later mem’s commit fails, already-committed mems stay committed (true cross-mem two-phase commit is out of scope) — but the dominant failure mode, a per-item validation/hash refusal, is always fully atomic because no commit happens until every item has passed.

Source

pub fn update_entity_with_ctx( &mut self, args: UpdateEntityArgs, ctx: &CommitContext<'_>, ) -> Result<UpdateEntityOutcome, EngineError>

CommitContext-bundling wrapper around Self::update_entity. See Self::create_entity_with_ctx for the rationale.

Source§

impl Engine

Source

pub fn store(&self) -> &Store

In-memory store populated at construction time from every mount’s backend. Read-only at this point in the rebuild — mutation paths land in a later session.

Source

pub fn schemas(&self) -> &HashMap<String, Arc<Schema>>

Per-mem schema, keyed by mount’s mem name. Each entry is the schema resolved from that mount’s pin at boot, so the map holds genuinely heterogeneous schemas in a multi-schema workspace.

Source

pub fn workspace_schemas(&self) -> &[Arc<Schema>]

Workspace-authored schemas loaded from WorkspaceSettings.schemas_dir at construction. Distinct from Self::schemas (per-mem, only schemas pinned by a mount): this slice carries every workspace-loaded schema regardless of whether a mem pins it. Used by memstead_overview to enumerate schemas referenced by mem_create_rules.schemas[] but not pinned by any mem — agents see what could be pinned without looking up the workspace.toml directly.

Source

pub fn builtin_schemas(&self) -> &[Arc<Schema>]

Embedded built-in schemas loaded once at boot. Handlers resolving a schema pin by <name>@<version> (MCP’s memstead_schema, memstead_overview rendering) walk mem-pinned, workspace, and built-in catalogues in order — built-ins are the catch-all when no mem or workspace dir pins the schema. Workspace schemas shadow built-ins on (name, version) collision; resolve from workspace_schemas() first.

Source

pub fn schema_origin(&self, schema: &Arc<Schema>) -> OriginClass

Classify a schema’s trust origin — the single authority every read surface consults before serving a schema’s instruction-prose.

A schema is [OriginClass::FirstParty] iff it is an engine built-in or pinned by a writable mount in this workspace. Built-ins are compiled into the binary — unforgeable. A non-built-in schema earns first-party status only once the operator adopts it by writably mounting a mem that pins it: writing into a mem is the act that legitimately needs a schema’s authoring prose (system_message, write_rules, …), and the mount’s writable posture is set by the consumer’s own config — a publisher cannot forge it.

Everything else is [OriginClass::ThirdParty]: a schema present in the catalogue but pinned only by read-only mounts (a registry- installed read-mem or an adopted foreign folder/clone), or one the engine cannot vouch for at all. Its prose is served structural-only so a stranger’s free-text never reaches a consuming agent as instructions. This classifies by the mount graph — never by scanning the schema’s content, which a publisher controls — and ThirdParty is the safe default for any ambiguous origin.

Note a read-only mount pinning a built-in schema (e.g. a registry mem on default@1.0.0) resolves to the consumer’s own clean copy and stays first-party — the de-framing targets only foreign, non-built-in schemas that no writable mem has adopted.

Source

pub fn mem_origin_class(&self, mem: &str) -> OriginClass

Classify a mem’s data trust origin — the authority every read surface consults before serving an entity’s content (bodies, snippets, titles). A writable mount is [OriginClass::FirstParty]: its content is authored in this workspace. Anything else — a read-only mount (a registry-installed read-mem or an adopted foreign folder/clone) or an unknown mem — is [OriginClass::ThirdParty], so the consuming agent/host treats the content as quoted, untrusted data.

This reads the deployment’s declaration when one exists (see Self::declare_mem_origin), else the mount’s already-decided writable/read-only posture (fixed at adopt/mount time) — it never scans content, and both levers are consumer-side config, so a publisher cannot forge first-party. Distinct from Self::schema_origin, which governs a schema’s instruction-prose: the data channel and the instruction channel are separate vectors with separate authorities.

Source

pub fn declare_mem_origin( &mut self, mem: impl Into<String>, origin: OriginClass, )

Declare a mem’s data-trust origin as a deployment fact — the embedding process (a curated hosted read tier, an app that vouches for a bundled mem) overrides the writability inference for one mem. Composition-layer-only by design: not persisted, not reachable over MCP, never derived from mem content — the operator running the process is the only authority that can set it, so a served mem the deployment does not vouch for keeps reporting third-party on every surface. (Deliberately absent from UniFFI/CLI: those surfaces operate a workspace, not a deployment; the CLI counterpart would be a workspace-config knob no use case demands yet.)

Source

pub fn load_errors(&self) -> &[(PathBuf, String)]

Per-file errors collected during load. Non-fatal: the engine continues with whatever did parse. Empty when every backend’s content parses cleanly.

Source

pub fn settings(&self) -> &WorkspaceSettings

Workspace-level operator policy (mem create/delete rules, cross-mem links). Defaults to empty; populated via Engine::set_settings after construction. Surfaced for MCP handlers (memstead_health { include_config: true }, memstead_overview’s lifecycle-namespaces section) and other consumers that need to read workspace policy.

Source

pub fn pipeline_configs(&self) -> &PipelineConfigs

The pipeline configs (Medium / Facet / Projection / Ingest) loaded from the workspace store at boot — the read-only queryable surface the loader exposes. Empty for engines not booted from a workspace root, or for a workspace that declares no pipelines. The ingest skill, future MCP tools, and the macOS app consume this structured form rather than re-reading the JSON folders.

Source

pub fn pipeline_configs_json(&self) -> String

The pipeline configs serialized as a JSON string — the read counterpart of the add_*_json edit entry points. Serialization- boundary callers (UniFFI, where serde does not live) get the store in one call and deserialize on their side.

Shape (D14): { "mediums": [{ mem, name, config }], "facets": [...], "bindings": [{ mem, name, config }] } — the version-gated v1 binding shape (config carries the binding’s operations block). The ingests key is gone; operations are attributes of the binding, not a peer record. This reads the live binding store fresh (like the brief path) rather than the legacy in-memory snapshot, so a projection edit that preserves its operations shows them back immediately. A missing root or a legacy/unreadable store yields the fallback empty object.

Source

pub fn set_pipeline_configs(&mut self, configs: PipelineConfigs)

Overwrite the in-memory pipeline configs. The workspace-root boot paths call this after crate::pipeline_store::load_pipeline_configs; exposed so the full boot helper (a separate crate) can populate the same surface.

Source

pub fn note_missing_warning( &self, tool: &str, note: Option<&str>, ) -> Option<WarningHint>

Build a WarningHint::NoteMissing when the workspace has [mutations].require_notes = true and the caller omitted (or passed a blank/whitespace-only) note; None otherwise.

This is the single enforcement point for the require_notes provenance nudge. Every mutation that accepts a note calls it on its commit-landing path and pushes the result onto the outcome’s warnings, so both the CLI and the MCP transports inherit identical behaviour from the engine response rather than each re-deriving the policy at its own boundary (the drift that left the policy decorative on the CLI). tool becomes the warning’s details.tool — callers pass the engine-level verb (create_entity, update_entity, relate_entity, delete_entity, rename_entity, create_mem, delete_mem), matching the commit Tool: provenance trailer. The mutation still commits — the policy nudges, it never blocks.

Source

pub fn backend_factory(&self) -> BackendFactory

Backend factory currently installed on this engine. Returned by value because BackendFactory is a function pointer (Copy). Used by [crate::mem_management::create_mem] to materialise the backend for a freshly-registered mount; consumers that need to instantiate a backend ad-hoc can call this directly.

Source

pub fn git_branch_ops(&self) -> Option<GitBranchOps>

Git-branch ops bundle currently installed on this engine. None on lean-flavor engines that don’t see mem-repo mounts. Returned by value because super::GitBranchOps is Copy. create_mem reaches for the bundle to drive prune_residue against an unmounted gitdir when the ForceOverwrite recovery action is selected.

Source

pub fn get_entity(&self, id: &EntityId) -> Option<&Entity>

Convenience: look up a parsed entity by id. Returns None for unknown ids, including stub entries created for unresolved inline-link targets — callers that want to distinguish real from stub branch on Entity::stub.

Source

pub fn entity_anchors(&self, id: &EntityId) -> Vec<Anchor>

The stored provenance anchors for id, read from its mem’s anchors sidecar. Empty for an entity with none, an unknown mem, or a backend that does not persist anchors (a pre-anchor archive / any sealed read-only mount). Additive read surface (E3a): the resolution model lives in crate::anchor (crate::anchor::resolve_anchor / crate::anchor::compose_entity_anchors); the live per-anchor state (which requires observing the source artifacts through the medium/preparation pipeline) is E3b’s concern.

Source

pub fn entity_anchors_resolved(&self, id: &EntityId) -> Vec<ResolvedAnchor>

The stored anchors for id, each paired with its live resolution state when the engine could observe the source artifact this pass.

Additive over Self::entity_anchors: the durable data is unchanged; state is the crate::anchor::resolve_anchor outcome against an observation the engine produces here. It is produced only for a path-namespace, single-medium mem (codebase / filesystem) whose medium root resolves from the workspace — the engine observes working-tree existence at the current HEAD:

  • artifact absent ⇒ AnchorState::Orphaned;
  • artifact present, non-hash class (authored / informed-by) ⇒ Resolves;
  • artifact present, hash-bearing class (anchored / derived) ⇒ Recheck.

state is None (unobserved — never a fabricated state) when the mem has no single path-medium, no workspace root, or the grain/namespace is not a filesystem path. Distinguishing drifted from recheck on a present hash-bearing anchor needs the prepared-content hash the producer used — a canonical transform E3b’s verify pipeline owns — so this pass never fabricates drifted; it reports recheck and defers the hash adjudication (and non-path mediums / commit-pinned reads) to E3b.

Source

pub fn anchors_referencing_artifact( &self, artifact_path: &str, ) -> Vec<(EntityId, Anchor)>

Reverse anchor lookup: every (entity_id, anchor) across all mems whose anchor references artifact_path. This is the query the rebuilt check-realization hook consumes — given the file an agent just edited, which entities anchored to it. A span/file/tree anchor references the path when its base path (locator suffix @commit / #span stripped) equals the path, or — for a tree grain — when the path lies under the tree. Path-shaped grains only; url / entity anchors are matched by exact base equality.

Source

pub fn mem_anchors_resolved(&self, mem: &str) -> Vec<(EntityId, ResolvedAnchor)>

Every (entity_id, resolved anchor) in mem, read from its anchors sidecar once and each paired with its live resolution state (the same observation Self::entity_anchors_resolved produces per entity, computed here mem-wide in a single sidecar read). Empty for an unknown mem, a backend that persists no anchors, or a mem with none.

Additive read surface: the durable data is unchanged; state is the crate::anchor::resolve_anchor outcome against an observation the engine produces for a single path-namespace medium, or None when unobserved (never fabricated). The verify pipeline consumes it to adjudicate a mem’s anchors against the source; audit/health can reuse it.

Source

pub fn mem_names(&self) -> Vec<&str>

Mem names the engine knows about, in declaration order. Cheap; useful for callers that need to enumerate before dispatching by mem.

Source

pub fn mount(&self, mem: &str) -> Option<&Mount>

Public-shape mount record for mem, or None for an unknown mem.

Surfaces the operator-facing crate::workspace::Mount (mem name, schema pin, storage reference, capability, lifecycle, cross_linkable) so MCP / CLI handlers can branch on backend-specific shapes via crate::workspace::MountStorage when they need accessors that don’t make sense on every backend (e.g. gitdir / branch for memstead_health { include_config: true }’s git-class payload). Backends that want the equivalent of full’s engine.gitdir_for(mem) match engine.mount(mem).map(|m| &m.storage) against MountStorage::GitBranch { gitdir, branch } and walk directly — keeps the engine surface backend-neutral.

Counterpart to Self::mem_names which lists every mount.

Source

pub fn orphans_by_schema( &self, orphan_ids: &[EntityId], ) -> BTreeMap<String, usize>

Orphan count attributed to each mem’s pinned schema, over the given orphan_ids (the caller pre-filters them by any mem scope). Lets a health surface show that ingest-mem isolates (orphans by design) and code-mem debt land in different schema buckets rather than one blended, misleading total. Mems with no settled pin bucket under the empty string.

Source

pub fn communities_by_schema(&self, mems: &[String]) -> BTreeMap<String, usize>

Community count attributed to each schema across mems: a cluster counts toward every schema whose mems it touches, so these figures can sum above the global community count — the same “touches” semantic as the mem-scoped count. Per-schema dedup keeps a cluster touching two mems of one schema from being counted twice.

Source

pub fn mounts(&self) -> Vec<&Mount>

All mounts the engine knows about, in declaration order. Counterpart to Self::mem_names when the caller needs the full mount shape (e.g. to enumerate by storage variant).

Source

pub fn writable_mem_names(&self) -> Vec<&str>

Names of mems whose mount declares crate::workspace::MountCapability::Write, in declaration order. Convenience over mounts().iter().filter(...).map(...) for handlers that gate by writable status (memstead_health, memstead_overview‘s mem roster, the lifecycle tools’ candidate list). Read-only mounts (archive backends) are excluded.

Source

pub fn default_writable_mem(&self) -> Option<&str>

The default writable mem — the target a mutation lands in when it omits mem. None when no writable mem is mounted.

Defined as the first writable mount in declaration order, i.e. the seed / earliest-created writable mem. This is a stable designation, not a function of the current name set: new mems register via register_writable_mem, which pushes onto the end of the mount list (and mounts.json preserves that order across reboots), so creating an additional mem never moves the default — even one whose name sorts ahead alphabetically. Deleting the current default promotes the next-earliest writable mem; that is the only thing that shifts it. Both the MCP resolve_mem and the CLI’s omitted---mem path resolve through here so the two surfaces always agree (the pre-fix MCP path read writable_mems().iter().next() off an unordered HashSet, which silently retargeted writes when a second mem appeared).

Source

pub fn folder_path_for_mem(&self, mem: &str) -> Option<&Path>

On-disk folder path for a folder-backed mount, or None for any other backend (git-branch, archive) or unknown mem. Convenience over engine.mount(mem).map(|m| &m.storage) + matching on MountStorage::Folder { path }. Used by handlers that need a filesystem path for a folder mem (e.g. memstead_health { include_config: true }’s mems[].vcs.worktree field for folder mounts).

Source

pub fn mem_router(&self) -> &MemRouterSnapshot

Runtime snapshot of writable / visible mems. Handlers that need the writable roster (memstead_health’s writable_mems / read_mems), per-mem origin tag (include_config: true’s mems[].origin), or visibility check (memstead_overview‘s mem list, the lifecycle tools’ collision guard) consume the router here. Returned by reference — the Arc is held on the engine; callers that need a clonable handle can Arc::clone the engine’s field directly when that surface arrives.

Source

pub fn gitdir_for(&self, mem_name: &str) -> Result<PathBuf, EngineError>

Resolve the gitdir for a writable mem. Used by memstead_health { include_config: true } to surface per-mem vcs.gitdir so outer-repo auto-commit hooks can git -C <gitdir> per mem without hardcoding the layout.

  • EngineError::UnknownMem when the name does not resolve.
  • EngineError::Mem when the mount’s storage is not git-branch-backed (folder, archive — they have no gitdir).
Source

pub fn worktree_for(&self, mem_name: &str) -> Result<PathBuf, EngineError>

Resolve the worktree for a writable mem. Used by memstead_health { include_config: true } to surface per-mem vcs.worktree.

  • EngineError::UnknownMem when the name does not resolve.
  • EngineError::Mem when the mount’s backend has no worktree concept (git-branch with no working tree, archive).

Folder mounts surface their on-disk path. Git-branch mounts follow the dir: Some(...) composition pattern: when the workspace root contains a folder named after the mem with a .memstead/config.json marker, that folder is the worktree (disk-shape composition). Otherwise — pure mem-repo-backed — return Err.

Source

pub fn mem_config_for(&self, mem: &str) -> Option<&MemConfig>

Per-mem .memstead/config.json payload, when available. Used by memstead_health { include_config: true } to surface the opaque write_guidance map and the catch-all extra fields per mem.

Folder-backed mounts return Some(&MemConfig) when <path>/.memstead/config.json parsed cleanly at construction. Git-branch and archive backends return None until the read-from-storage-backend path lifts (the V1 unified engine loads configs only from folder layouts; the file lives inside the gitdir / archive for the other backends and needs a backend-level read primitive).

Unknown mem names return None (no error variant — the accessor is intentionally lenient because memstead_health emits an empty detail block per missing config rather than aborting the call).

Source

pub fn archive_provenance_for(&self, mem: &str) -> Option<&ArchiveProvenance>

The authoring-provenance payload an installed mem carries, read from the archive’s .memstead/provenance.json at construction. None when the mem carries none (a pre-provenance archive, a runtime-created mem, or a backend that does not surface one) — the read path reports provenance as absent. Unknown mem names return None.

Source

pub fn mem_configs_named(&self) -> impl Iterator<Item = (&str, &MemConfig)>

Iterate (mem_name, &MemConfig) for every mount whose mem-config payload loaded at construction. Used by callers that walk every writable mount’s config (memstead health’s per-mem dump, the workspace-dump CLI). The yielded &str is the authoritative mem leaf from the mount record.

Folder-backed mounts yield when their .memstead/config.json parsed cleanly. Git-branch and archive backends are silent in V1 (the same deferred-read-from-storage gap that Self::mem_config_for documents).

Source

pub fn schema_for(&self, mem: &str) -> Option<Arc<Schema>>

Resolved Arc<Schema> for a writable mem by name. None when the name is not a registered mount.

Cheap — Arc::clone over the per-mem schema map. Resolved schemas are stored in HashMap<String, Arc<Schema>> so the lookup is a single hash hit + clone.

Source

pub fn mem_head_sha( &self, mem_name: &str, ) -> Result<Option<String>, EngineError>

Cached current branch-tip cursor (typically a 40-char hex SHA for git-branch backends; None for fresh mems or backends that don’t track a head — folder / archive).

The value is the per-mount last_known_head, seeded at construction by backend.current_head() and refreshed by Self::reload_if_stale / mutation paths after a successful commit.

  • EngineError::UnknownMem when the name does not resolve.
Source

pub fn mem_drifted(&self, mem_name: &str) -> Result<bool, EngineError>

Whether a sibling writer has advanced this mem’s backend past the engine’s cached last_known_head — a read-only drift probe that does not reload (unlike Self::reload_if_stale). One backend.current_head() read compared against the cached cursor; the comparison clears once the engine re-reads (a reload / reload_if_stale refreshes last_known_head to the live tip).

Only git-branch backends track a head, so folder / archive / in-memory mounts always report false. A backend that errors on the probe (transient refdb hiccup) reports false rather than surfacing the error — drift is advisory, and the next real operation’s reload path is the authoritative sync.

  • EngineError::UnknownMem when the name does not resolve.
Source

pub fn workspace_root(&self) -> Option<&Path>

Workspace root the engine booted from, when one is known. None for engines built directly from a mount list (tests, ad-hoc consumers). Set by Self::from_workspace_root and the full counterpart.

Source

pub fn load_warnings(&self) -> &[WarningHint]

Typed warnings surfaced during mem load — drift findings the loader pipeline collects per entity. Empty for V1; the accessor surfaces them so handlers can merge into health summaries uniformly.

Source

pub fn communities(&self) -> &LouvainOutput

Lazy community-detection cache. First call runs Louvain against the current store using one pinned schema for community.{resolution, seed} and the per-rel weights. Subsequent calls return the cached result. Mutations invalidate the cache via Self::invalidate_communities.

One detection run per engine. The partition is workspace-global, so it needs a single source for the Louvain parameters; that source is the schema of the lexicographically-first mem name — a stable key, so the partition is deterministic across processes even when mounts pin heterogeneous schemas. For a single-schema workspace every mem’s schema is identical, so the choice of key is immaterial there.

Source

pub fn invalidate_communities(&mut self)

Drop the cached community detection result.

Source

pub fn orphans(&self) -> Vec<EntityId>

Real entities with no incoming or outgoing edges.

Source

pub fn stubs(&self) -> Vec<(EntityId, Vec<EntityId>)>

Stub entities with their referencer ids.

Source

pub fn most_connected(&self, limit: usize) -> Vec<Connectivity>

Top limit entities by total degree.

Source

pub fn missing_required_outgoing( &self, mem_filter: Option<&str>, ) -> Vec<MissingRequiredOutgoingReport>

Entities whose type’s required_outgoing blocks are not yet satisfied. mem_filter = None scans every mem; Some(v) scans only that mem.

Source

pub fn conformance_findings( &self, mem: &str, target_schema: Option<&SchemaRef>, ) -> Result<Vec<IntegrityFinding>, EngineError>

Conformance-axis integrity findings for one mem — which entities a write would refuse under the effective schema, and why. target_schema = None lints against the mem’s current pin; Some(ref) lints against that schema instead (resolved among mem-pinned, workspace, and built-in schemas).

Source

pub fn schema_pin(&self, mem: &str) -> Option<SchemaRef>

The mem’s Mount.schema expectation assertion, when set. None for unknown mems and for mems whose mount carries no assertion (the authoritative pin then lives in the backend config; the resolved active schema, not this, is the effective pin).

Source

pub fn migration_target(&self, mem: &str) -> Option<SchemaRef>

The mem’s in-flight migration target, when dual-pin state is active. None for settled or unknown mems.

Source

pub fn consistency_findings( &self, mem: &str, ) -> Result<Vec<IntegrityFinding>, EngineError>

Consistency-axis integrity findings for one mem — the pre-existing graph-coherence categories (dangling links, stubs) projected into the { id, axis, code, detail } finding shape.

Source

pub fn health(&self) -> HealthSummary

Engine-wide health summary across every mount.

Source

pub fn status(&self) -> Status

Engine-wide crate::ops::Status across every mount — the graph counts behind memstead status (renamed from stats with the command, D11; fields unchanged).

Source

pub fn context(&self, id: &EntityId) -> Option<ContextResult>

Build a ContextResult for id: the community cluster id (or None when the entity is a stub or not present), plus the outgoing + incoming neighbour lists.

Source

pub fn search_indexes(&self) -> &HashMap<String, MemIndex>

Lazily-built per-mem search index map. The map carries one entry per writable mem. Build cost scales with entity count; expect hundreds-of-ms for thousand-entity workspaces. Not available on wasm32 targets — search lives behind the bridge (see Self::search for the typed refuse).

Source

pub fn invalidate_search_indexes(&mut self)

Drop the cached per-mem search index map. No-op on wasm32 where no index exists; the method stays present so mutation hooks can call it unconditionally.

Source

pub fn list(&self, scope: &SearchScope) -> ListResult

Filter the in-memory store by metadata only (no text match).

Source

pub fn search(&self, scope: &SearchScope) -> Result<SearchResult, EngineError>

Run a search against the lazily-built index map. Returns EngineError::SearchUnavailable on wasm32 targets — browser consumers route search to the bridge; the local engine never builds a tantivy index in WASM. Native targets get the same shape as before, wrapped in Ok.

Source

pub fn list_entities(&self, mem: &str) -> Result<Vec<PathBuf>, EngineError>

All mem-relative entity paths under mem. Delegates to the backend’s list_entities. Order is backend-defined.

Source

pub fn read_entity( &self, mem: &str, rel_path: &Path, ) -> Result<Option<Vec<u8>>, EngineError>

Raw bytes for a single entity (Ok(None) if absent).

Source

pub fn read_provenance( &self, mem: &str, cursor: Option<&str>, ) -> Result<Vec<Provenance>, EngineError>

Provenance entries for mem since cursor. Cursor shape is backend-specific (RFC-3339 timestamp for folder, commit SHA for git-branch); None means “from the beginning”.

Source

pub fn capability(&self, mem: &str) -> Result<MountCapability, EngineError>

Capability declared on the mount for mem. Surfaced for callers that need to gate before dispatching a write — the engine itself does not yet enforce capability (mutation paths land in a later session).

Source

pub fn edge_is_from_readonly(&self, from: &EntityId) -> bool

Returns true when from’s source mem is mounted with crate::workspace::MountCapability::ReadOnly. Returns false for Write-Mems and for mems whose mount is absent from the router (no mount → no ReadOnly assertion can be made; the absence is treated as not-ReadOnly so consumers don’t trip on transient lookup misses).

Plan body §“Single edge source in the store” specifies this helper as the derived-on-demand alternative to adding a new field on crate::store::Edge. Strict-invariant validators and surfaces that want to highlight cross-mount references call this rather than pattern-matching on a per-edge marker. The information is fully derivable from the current mount roster, so no new state needs to live on the edge itself.

Whether a cross-mem edge from from_mem to to_mem is permitted under the current crate::WorkspaceSettings cross-mem link policy.

Resolution rules (matches full’s mem_router semantics):

  1. Same-mem edge (from_mem == to_mem) → always allowed; the policy gates cross-mem edges only.
  2. Explicit cross_mem_links[from_mem]:
    • "*" (wildcard) → allowed regardless of target.
    • ["a", ...] (allowlist) → allowed iff to_mem is in the list.
  3. Per-create-rule default_cross_links synthesis — if rule (1) didn’t grant permission and from_mem matches a [[mem_management.create]] rule whose default_cross_links is set, the synthesised value contributes:
    • "*" → allowed regardless of target.
    • ["a", ...] → allowed iff to_mem is in the list.
  4. Otherwise → denied (default-deny posture).

The synthesis layer compiles a crate::mem_management::CreateRuleSet lazily on first call and caches it; Self::set_settings invalidates the cache. Compilation failure (malformed glob in a rule) logs a warning and the synthesis layer is silently skipped — the resolver still returns true from explicit policy alone, so a half-broken config doesn’t lock out edges the operator did intend to allow. Operators who want hard validation pre-compile via crate::mem_management::CreateRuleSet::new before calling Self::set_settings.

The MCP memstead_relate handler’s cross-mem gate consumes this method directly.

Source§

impl Engine

Source

pub fn add_medium( &mut self, mem: &str, name: &str, medium: &Medium, note: Option<&str>, ) -> Result<(), PipelineEditError>

Create a medium and refresh the in-memory snapshot. See add_medium.

Source

pub fn update_medium( &mut self, mem: &str, name: &str, medium: &Medium, note: Option<&str>, ) -> Result<(), PipelineEditError>

Overwrite a medium and refresh the snapshot. See update_medium.

Source

pub fn delete_medium( &mut self, mem: &str, name: &str, note: Option<&str>, ) -> Result<(), PipelineEditError>

Delete a medium and refresh the snapshot. See delete_medium.

Source

pub fn rename_medium( &mut self, mem: &str, old: &str, new: &str, note: Option<&str>, ) -> Result<(), PipelineEditError>

Rename a medium and refresh the snapshot. See rename_medium.

Source

pub fn add_facet( &mut self, mem: &str, name: &str, facet: &Facet, note: Option<&str>, ) -> Result<(), PipelineEditError>

Create a facet and refresh the snapshot. See add_facet.

Source

pub fn update_facet( &mut self, mem: &str, name: &str, facet: &Facet, note: Option<&str>, ) -> Result<(), PipelineEditError>

Overwrite a facet and refresh the snapshot. See update_facet.

Source

pub fn delete_facet( &mut self, mem: &str, name: &str, note: Option<&str>, ) -> Result<(), PipelineEditError>

Delete a facet and refresh the snapshot. See delete_facet.

Source

pub fn rename_facet( &mut self, mem: &str, old: &str, new: &str, note: Option<&str>, ) -> Result<(), PipelineEditError>

Rename a facet and refresh the snapshot. See rename_facet.

Source

pub fn add_projection( &mut self, mem: &str, name: &str, projection: &Projection, note: Option<&str>, ) -> Result<(), PipelineEditError>

Create a projection and refresh the snapshot. See add_projection.

Source

pub fn update_projection( &mut self, mem: &str, name: &str, projection: &Projection, note: Option<&str>, ) -> Result<(), PipelineEditError>

Overwrite a projection and refresh the snapshot. See update_projection.

Source

pub fn delete_projection( &mut self, mem: &str, name: &str, note: Option<&str>, ) -> Result<(), PipelineEditError>

Delete a projection and refresh the snapshot. See delete_projection.

Source

pub fn rename_projection( &mut self, mem: &str, old: &str, new: &str, note: Option<&str>, ) -> Result<(), PipelineEditError>

Rename a projection and refresh the snapshot. See rename_projection.

Source

pub fn add_medium_json( &mut self, mem: &str, name: &str, medium_json: &str, note: Option<&str>, ) -> Result<(), PipelineEditError>

Self::add_medium from a JSON-encoded Medium.

Source

pub fn update_medium_json( &mut self, mem: &str, name: &str, medium_json: &str, note: Option<&str>, ) -> Result<(), PipelineEditError>

Self::update_medium from a JSON-encoded Medium.

Source

pub fn add_facet_json( &mut self, mem: &str, name: &str, facet_json: &str, note: Option<&str>, ) -> Result<(), PipelineEditError>

Self::add_facet from a JSON-encoded Facet.

Source

pub fn update_facet_json( &mut self, mem: &str, name: &str, facet_json: &str, note: Option<&str>, ) -> Result<(), PipelineEditError>

Self::update_facet from a JSON-encoded Facet.

Source

pub fn add_projection_json( &mut self, mem: &str, name: &str, projection_json: &str, note: Option<&str>, ) -> Result<(), PipelineEditError>

Add a projection from a JSON-encoded Projection, scaffolding a v1 [BindingV1] around it (D14). The caller supplies the projection-level fields (intent / source_facets / reference_mems / destination_mem / rules); the engine wraps them in a fresh binding with a default operations.build block (discovery / loop / batch 20) and empty deny_paths, then writes the versioned binding file. This is the projection-update path D14 routes operations-block edits through — the app edits the projection fields, the engine owns the binding shape.

Source

pub fn update_projection_json( &mut self, mem: &str, name: &str, projection_json: &str, note: Option<&str>, ) -> Result<(), PipelineEditError>

Update a projection from a JSON-encoded Projection, preserving the binding’s operations block, deny_paths, coverage_semantics, and version (D14). Reads the existing v1 binding, overlays the incoming projection-level fields, and writes it back — so a projection-field edit never silently strips the operations that make the binding runnable.

Trait Implementations§

Source§

impl Debug for Engine

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Freeze for Engine

§

impl !RefUnwindSafe for Engine

§

impl !Sync for Engine

§

impl !UnwindSafe for Engine

§

impl Send for Engine

§

impl Unpin for Engine

§

impl UnsafeUnpin for Engine

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Fruit for T
where T: Send + Downcast,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more