Skip to main content

FileIndex

Struct FileIndex 

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

The persistent registry: a snapshot with tombstones, living under the registry key of a workspace document — the document the root’s registry-pointer relation targets.

The host document can be either shape (MetaCarrier): a bare config file (registry.yaml, registry.figl, …) whose whole content is metadata, or a prose document (registry.md) whose fenced frontmatter carries the records. Writes splice only the registry value back through the carrier-aware editor, so the host’s other keys (title, part_of — the self-description that makes the registry a first-class node of the tree), its comments outside the records, its body, and its fence style all survive.

The rendered records are one per line (in YAML hosts), sorted by ID; a live record is id: path, a tombstone is id: null (DESIGN §5’s diff-friendly shape). This type is pure — text in (FileIndex::parse), text out (FileIndex::render) — so any storage backend can host it; the caller owns the I/O and can consult is_dirty to skip no-op writes.

Implementations§

Source§

impl FileIndex

Source

pub fn new(format: Format) -> Self

An empty registry with no host document — see the host field. Records resolve in memory; nothing is staged for writing.

Source

pub fn set_host(&mut self, path: impl Into<PathBuf>, text: &str) -> Result<()>

Give a registry a host document to persist into, adopting text as its current contents.

The bootstrap seam: a workspace that only discovers it needs a registry after a mutation has minted an ID (check --fix declines to create one until a fix actually registers something) creates the document, then hands it here so the write renders against the real host — its title, its part_of, its fence style — rather than against nothing.

This store’s records stay authoritative. Only the write target is adopted: the host’s text, carrier, and already-persisted record state, so render splices a correct diff into it. Records the host happens to carry are not merged into memory — they were not part of what this store was built from, and adopting them here would resurrect, as live records, whatever a scan or a caller had deliberately left out. They are not lost either: render only ever touches the records it knows about, so their lines survive in the document and are read back normally by the next parse.

Source

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

The document this registry persists into, if it has one.

Source

pub fn parse(path: &Path, text: &str) -> Result<Self>

Parse the registry out of its host document. path picks the carrier (a config extension means the whole file is metadata; anything else is searched for a fenced block); the records are read from the metadata’s registry key. A host with no registry key is an empty registry — the rest of its metadata is left alone.

Source

pub fn render(&mut self) -> Result<String>

Render the host document with the current records applied to its registry key. Each changed record is a scalar upsert (registry.<id> = path / null), so everything else in the host — title, part_of, comments, body, fences, existing record lines — is untouched, whatever the carrier. Records never reorder; new ones land in ID order.

Source

pub fn is_dirty(&self) -> bool

Whether the registry changed since it was parsed/created (i.e. needs a write). Cleared by mark_clean.

Source

pub fn mark_clean(&mut self)

Mark the registry as persisted.

Source

pub fn len(&self) -> usize

The number of live (resolving) IDs.

Source

pub fn is_empty(&self) -> bool

Whether the registry has no live IDs.

Source

pub fn is_tombstoned(&self, id: &Id) -> bool

Whether id is retired: known but no longer resolving.

Source

pub fn iter(&self) -> impl Iterator<Item = (&Id, &PathBuf)>

Iterate live records as (id, path), sorted by ID.

Trait Implementations§

Source§

impl Clone for FileIndex

Source§

fn clone(&self) -> FileIndex

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for FileIndex

Source§

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

Formats the value using the given formatter. Read more
Source§

impl IdIndex for FileIndex

Source§

fn is_known(&self, id: &Id) -> bool

A tombstoned id no longer resolves but stays known forever, so it can never be reminted to mean something else.

Source§

fn resolve(&self, id: &Id) -> Option<PathBuf>

Resolve an ID to its current path. None for unknown and tombstoned IDs — use is_known to tell them apart.
Source§

fn id_for_path(&self, path: &Path) -> Option<Id>

The ID currently assigned to path, if any.
Source§

impl IndexStore for FileIndex

Source§

fn register(&mut self, id: &Id, path: &Path)

Registering an id retires its tombstone, because the id is live again and a record cannot be both. This is not a hypothetical pairing: restore from the recycle bin re-registers the very id recycle tombstoned, so the sequence runs whenever a delete is undone.

render has always resolved the two in this direction — it lays the live records down over the tombstones — so without this the store disagrees with its own serialization until the process restarts, and a round trip through the registry document silently “changes” it. Nothing is lost by forgetting the tombstone: is_known stays true through resolve while the id is live, so mint-by-rejection cannot reissue it, and retiring it again tombstones it again. Registering maintains the tombstone set in both directions, which is what makes “an ID is never reissued” (DESIGN §10) true of this store rather than merely intended.

Retires whatever it displaces. Taking a path out from under the id currently carrying it evicts that id from the live map — the bijection repair InMemoryIndex::register performs and documents. Eviction alone would forget the id entirely, so is_known would go from true to false and a later mint could reissue it while the displaced document still spells it in its own frontmatter. Reaching that needs a displacement to slip past registration_conflict / move_conflict, which is precisely the case this store is the last line of defence for, so the displaced id earns a tombstone on the way out.

Un-retires what it registers. An id being registered is live, and a record cannot be both live and retired. This runs whenever a delete is undone: restore re-registers the very id recycle tombstoned. render has always resolved the pair this way — it lays the live records over the tombstones — so without this the store disagrees with its own serialization until the process restarts. Nothing is lost by forgetting the tombstone, because the id is is_known through resolve while it is live, and the clause above tombstones it again if it is ever displaced.

The two clauses only work together. Un-retiring without retiring the displaced would make the forgetting easier to reach: an id restored from the bin and then displaced would have no tombstone left to fall back on.

Source§

fn set_path(&mut self, id: &Id, new_path: &Path)

Moving an id onto a path is registering it there — the same bijection-safe eviction in both directions — so this delegates rather than restating it, exactly as InMemoryIndex::set_path delegates to its own register.

Source§

fn unregister(&mut self, id: &Id)

Retire to a tombstone: the ID stops resolving but stays known forever.

Source§

fn pending_write(&mut self) -> Result<Option<(PathBuf, String)>>

The registry’s write, rendered against its host document. None — and crucially still dirty — when there is no host to write to.

Source§

fn checkpoint(&mut self)

Snapshot the store, so a mutation that fails can put it back. Called before an op touches the index; paired with exactly one rollback or committed.
Source§

fn rollback(&mut self)

Restore the last checkpoint — the mutation failed and its writes were unwound, so the in-memory store must forget it too, or it would claim a move that never happened.
Source§

fn committed(&mut self, persisted: bool)

The mutation’s writes landed: drop the checkpoint. Read more
Source§

fn rebase(&mut self, cs: &dyn Rebase) -> Result<()>

Follow the mutation’s change set to wherever it leaves this store’s home. Read more

Auto Trait Implementations§

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.