pub struct CandidateStore { /* private fields */ }Expand description
What:
Everything one invocation needs to list and read candidates.
Option<ObjectReader> is “a running reader or nothing”;
u64 is an unsigned
64-bit counter (siblings u32,
usize).
Why:
The reader is started only when something needs it,
so an invocation that
reads no object starts no reader.
u64 cannot run out within a process.
In TS you’d write (pseudocode):
class CandidateStore { #reader?: ObjectReader; #generation = 0n; #versions: [CandidateSource, CandidateVersion][] = [] }Implementations§
Source§impl CandidateStore
What:
impl CandidateStore { ... } attaches the store’s operations,
like class methods.
Why:
The store is the only place that starts Git for candidates,
which is what
keeps the process count bounded.
impl CandidateStore
What:
impl CandidateStore { ... } attaches the store’s operations,
like class methods.
Why:
The store is the only place that starts Git for candidates,
which is what
keeps the process count bounded.
In TS you’d write (pseudocode):
class CandidateStore { version(source) {} bytes(candidate) {} invalidate() {} }Sourcepub fn new(
real_git: &Path,
global_prefix: &[OsString],
overlay: &[(OsString, OsString)],
) -> CandidateStore
pub fn new( real_git: &Path, global_prefix: &[OsString], overlay: &[(OsString, OsString)], ) -> CandidateStore
What:
Create a store without starting any process.
&[OsString] borrows the global arguments;
&[(OsString, OsString)] borrows
environment pairs;
.to_vec() and .to_path_buf() copy them into owned storage.
Why:
The store outlives the caller’s borrowed arguments,
and commands that
never ask for candidates pay nothing.
In TS you’d write (pseudocode):
constructor(realGit: string, globalPrefix: string[], overlay: [string, string][])Sourcepub fn with_baseline(self, baseline: Option<ObjectId>) -> CandidateStore
pub fn with_baseline(self, baseline: Option<ObjectId>) -> CandidateStore
What:
Compare every “against HEAD” listing with a recorded base instead of the live HEAD.
Why:
A commit transaction reads its candidates against the base it recorded at invocation,
because another landing may have moved HEAD since.
In TS you’d write (pseudocode):
listChangedIndexPaths({ baseRevision }) // never live HEADSourcepub fn version(
&mut self,
source: &CandidateSource,
) -> Result<Rc<CandidateVersion>, CandidateError>
pub fn version( &mut self, source: &CandidateSource, ) -> Result<Rc<CandidateVersion>, CandidateError>
What:
The version of one source,
listed once per generation and shared afterwards.
Rc::clone(..) makes another handle to the same version without copying it.
Why:
Every policy of a pass sees the same paths,
and asking again costs no process.
In TS you’d write (pseudocode):
async version(source: CandidateSource): Promise<CandidateVersion>Sourcepub fn stage_records(
&mut self,
pathspecs: &[OsString],
) -> Result<Vec<StageRecord>, CandidateError>
pub fn stage_records( &mut self, pathspecs: &[OsString], ) -> Result<Vec<StageRecord>, CandidateError>
What:
The index entries pathspecs select,
every conflict stage included,
with
repository-relative pathnames.
Why:
ls-files --stage reads only the index,
so comparing two of these listings
shows exactly which entries an operation on that index changed.
--full-name
keeps pathnames repository-relative from any directory.
In TS you’d write (pseudocode):
async stageRecords(pathspecs: string[]): Promise<StageRecord[]>Sourcepub fn head_records(
&mut self,
pathspecs: &[OsString],
) -> Result<Vec<CandidateRecord>, CandidateError>
pub fn head_records( &mut self, pathspecs: &[OsString], ) -> Result<Vec<CandidateRecord>, CandidateError>
What:
The changed-path records of the index against HEAD,
limited to pathspecs;
against the empty tree when no commit exists yet.
Why:
Which selected paths HEAD lacks makes them additions,
and which removed
paths it has makes them deletions.
The limit keeps a conflict elsewhere in the
index out of the listing.
In TS you’d write (pseudocode):
async headRecords(pathspecs: string[]): Promise<CandidateRecord[]>Sourcepub fn head_tree_records(&mut self) -> Result<Vec<TreeRecord>, CandidateError>
pub fn head_tree_records(&mut self) -> Result<Vec<TreeRecord>, CandidateError>
What: Every file of the HEAD commit with its mode and object; nothing when the
branch has no commit yet.
Why: A policy that compares the candidate state with HEAD reads HEAD’s copy of
a file without naming the path in an object request, and learns its mode.
--full-tree lists from the top level whatever directory Git runs in.
In TS you’d write (pseudocode):
async headTreeRecords(): Promise<TreeRecord[]>Sourcepub fn commit_tree_records(
&mut self,
commit: &ObjectId,
) -> Result<Vec<TreeRecord>, CandidateError>
pub fn commit_tree_records( &mut self, commit: &ObjectId, ) -> Result<Vec<TreeRecord>, CandidateError>
What: Every file of one commit with its mode and object.
Why: Policies that compare candidates with the parents of a commit read each parent’s files
the way they read HEAD’s. --full-tree lists from the top level whatever directory
Git runs in.
In TS you’d write (pseudocode):
async commitTreeRecords(commit: ObjectId): Promise<TreeRecord[]>Sourcepub fn baseline_reference(&mut self) -> Result<Option<ObjectId>, CandidateError>
pub fn baseline_reference(&mut self) -> Result<Option<ObjectId>, CandidateError>
What: The commit the “against HEAD” listings compare with: the recorded base or the commit
HEAD names now; nothing when the branch has no commit yet.
Why: A policy that skips content the baseline already holds names the commit in its log
record and lists its files through commit_tree_records.
In TS you’d write (pseudocode):
async baselineReference(): Promise<ObjectId | undefined>Sourcepub fn parents_outside(
&mut self,
commits: &[ObjectId],
) -> Result<Vec<ObjectId>, CandidateError>
pub fn parents_outside( &mut self, commits: &[ObjectId], ) -> Result<Vec<ObjectId>, CandidateError>
What: The parents of these commits that are not among the commits themselves, each once, in
the order of the commits and then of their parents.
Why: A pushed commit’s parent that is also pushed is new to the remote, so only the parents
outside the given commits count as already published. One rev-list answers 2,048
commits, so the process count does not grow with the commits.
In TS you’d write (pseudocode):
async parentsOutside(commits: ObjectId[]): Promise<ObjectId[]>Sourcepub fn derived_version(
&mut self,
records: Vec<CandidateRecord>,
) -> Rc<CandidateVersion>
pub fn derived_version( &mut self, records: Vec<CandidateRecord>, ) -> Rc<CandidateVersion>
What: A version of the current generation built from records the caller derived.
Vec<CandidateRecord> is taken by value: the records move into the version.
Why: A predicted staging operation has no single listing command; its candidates
come from comparing index states. The version is not remembered by source,
because no source names it.
In TS you’d write (pseudocode):
derivedVersion(records: CandidateRecord[]): CandidateVersionSourcepub fn committed_records(
&mut self,
commit: &ObjectId,
) -> Result<Vec<CandidateRecord>, CandidateError>
pub fn committed_records( &mut self, commit: &ObjectId, ) -> Result<Vec<CandidateRecord>, CandidateError>
What: The records of one commit’s own delta, each against every parent (or the empty tree for a root commit). Why: A pushed commit’s changes are the content a manual-push scan reads; the listing is the one the landed-delta source already uses.
In TS you’d write (pseudocode):
committedRecords(commit: ObjectId): CandidateRecord[]Sourcepub fn tree_records(
&mut self,
tree: &ObjectId,
) -> Result<Vec<CandidateRecord>, CandidateError>
pub fn tree_records( &mut self, tree: &ObjectId, ) -> Result<Vec<CandidateRecord>, CandidateError>
What: Every blob entry of one tree, as records that add each path. Why: A push with no known published base scans the pushed tip’s whole tree. Submodule entries are not listed: their content is a commit name, which no content policy reads.
In TS you’d write (pseudocode):
treeRecords(tree: ObjectId): CandidateRecord[] // ls-tree -r, every blob as addedSourcepub fn bytes(
&mut self,
candidate: &Candidate,
) -> Result<Rc<[u8]>, CandidateError>
pub fn bytes( &mut self, candidate: &Candidate, ) -> Result<Rc<[u8]>, CandidateError>
What:
The exact bytes a candidate holds in its version.
Rc<[u8]> is a shared read-only byte list.
Why:
Bytes come from the object the listing named,
so an edit to the worktree
file after staging is invisible here.
A deleted path has no bytes.
A
gitlink has no blob in this repository,
so its bytes are the submodule
commit’s name,
as in the TypeScript wrapper.
A candidate of a retired
version is refused instead of answered with bytes that may be outdated.
In TS you’d write (pseudocode):
async bytes(candidate: Candidate): Promise<Uint8Array>Sourcepub fn invalidate(&mut self)
pub fn invalidate(&mut self)
What:
Retire every version listed so far.
+= 1 advances the generation.
Why:
A fix or replay rewrites index entries,
so earlier listings no longer
describe what would be committed.
Blob bytes stay remembered in the
reader:
an object name always denotes the same bytes.
In TS you’d write (pseudocode):
invalidate(): void { this.#versions = []; this.#generation += 1n; }Trait Implementations§
Source§impl CandidateBytes for CandidateStore
What:
impl CandidateBytes for CandidateStore reads through the store itself.
Why:
Without corrections the store’s objects are the bytes to scan.
impl CandidateBytes for CandidateStore
What:
impl CandidateBytes for CandidateStore reads through the store itself.
Why:
Without corrections the store’s objects are the bytes to scan.
In TS you’d write (pseudocode):
class CandidateStore implements CandidateBytes {}Source§fn candidate_bytes(
&mut self,
candidate: &Candidate,
) -> Result<Rc<[u8]>, CandidateError>
fn candidate_bytes( &mut self, candidate: &Candidate, ) -> Result<Rc<[u8]>, CandidateError>
What:
The store’s bytes for the candidate.
Why:
CandidateStore::bytes is the read.
In TS you’d write (pseudocode):
bytes(candidate) { return this.read(candidate); }Auto Trait Implementations§
impl !RefUnwindSafe for CandidateStore
impl !Send for CandidateStore
impl !Sync for CandidateStore
impl !UnwindSafe for CandidateStore
impl Freeze for CandidateStore
impl Unpin for CandidateStore
impl UnsafeUnpin for CandidateStore
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more