Skip to main content

git_zero_core/validation/revision/
state.rs

1//! Caller-owned revision flags and independent shallow-boundary changes.
2use super::{ObjectId, ValidationMetadata};
3
4pub(super) const EXCLUDED: u8 = 1;
5pub(super) const CANDIDATE: u8 = 2;
6pub(super) const PENDING: u8 = 4;
7pub(super) const DONE: u8 = 8;
8pub(super) const BORDER: u8 = 16;
9pub(super) const UNSHALLOW: u8 = 32;
10pub(super) const CLIENT_SHALLOW: u8 = 64;
11
12/// Additional limits for an explicitly enabled revision-history request.
13#[derive(Clone, Copy, Debug)]
14pub struct RevisionLimits {
15    /// Maximum exclusion arguments, counting duplicate arguments too.
16    pub max_exclusions: usize,
17}
18
19/// Revision history, separate from absolute/relative depth. Zero is an active
20/// unrestricted revision walk. HTTP resolves exclusion refs to the iterator
21/// passed to `select_revision_fetch`; non-commit endpoints have no ancestry effect.
22#[derive(Clone, Copy, Debug, Default)]
23pub struct RevisionOptions {
24    pub since: Option<u64>,
25}
26
27#[derive(Clone, Copy, Debug, Eq, PartialEq)]
28pub enum ShallowChange {
29    Shallow(ObjectId),
30    Unshallow(ObjectId),
31}
32
33/// One caller-owned byte per repository object. Existing metadata/storage layouts
34/// remain unchanged. Recreate this descriptor for every request/retry; arrays are
35/// reset by selection, and failures invalidate all results.
36pub struct RevisionState<'a> {
37    pub(super) states: &'a mut [u8],
38    pub(super) limits: RevisionLimits,
39    pub(super) count: usize,
40}
41
42impl<'a> RevisionState<'a> {
43    pub fn new(states: &'a mut [u8], limits: RevisionLimits) -> Self {
44        Self {
45            states,
46            limits,
47            count: 0,
48        }
49    }
50
51    pub fn max_exclusions(&self) -> usize {
52        self.limits.max_exclusions
53    }
54
55    /// Changes may include commits absent from the returned PACK. Pass the same
56    /// metadata work array used by the successful selection, without modifying it.
57    pub fn changes<'b>(
58        &'b self,
59        objects: &'b [Option<ValidationMetadata>],
60    ) -> impl Iterator<Item = ShallowChange> + 'b {
61        self.states
62            .iter()
63            .zip(objects)
64            .take(self.count)
65            .filter_map(|(&state, object)| revision_change(state, object.as_ref()?.id))
66    }
67}
68
69fn revision_change(state: u8, id: ObjectId) -> Option<ShallowChange> {
70    if state & (BORDER | CLIENT_SHALLOW) == BORDER {
71        Some(ShallowChange::Shallow(id))
72    } else if state & UNSHALLOW != 0 {
73        Some(ShallowChange::Unshallow(id))
74    } else {
75        None
76    }
77}
78
79// Candidate membership is frozen before this pure transition classifies which
80// existing client boundaries now have their parents available.
81pub(super) fn mark_unshallow(states: &mut [u8]) {
82    for state in states {
83        if *state & (CLIENT_SHALLOW | CANDIDATE | BORDER) == (CLIENT_SHALLOW | CANDIDATE) {
84            *state |= UNSHALLOW;
85        }
86    }
87}