Skip to main content

cloud_sdk/authentication/
generation.rs

1/// Monotonic generation of one credential state.
2#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
3pub struct CredentialGeneration(u64);
4
5impl CredentialGeneration {
6    /// Initial generation assigned to a newly admitted credential.
7    pub const INITIAL: Self = Self(1);
8
9    /// Returns the generation as a nonzero integer.
10    #[must_use]
11    pub const fn get(self) -> u64 {
12        self.0
13    }
14
15    /// Creates an executor-neutral handoff for compare-and-swap refresh.
16    #[must_use]
17    pub const fn refresh_handoff(self) -> RefreshHandoff {
18        RefreshHandoff { expected: self }
19    }
20
21    /// Advances the generation without wrapping.
22    pub fn checked_next(self) -> Result<Self, CredentialGenerationError> {
23        self.0
24            .checked_add(1)
25            .map(Self)
26            .ok_or(CredentialGenerationError::Exhausted)
27    }
28
29    #[cfg(test)]
30    pub(super) const fn from_raw_for_test(value: u64) -> Self {
31        Self(value)
32    }
33}
34
35/// Opaque generation captured before an external refresh operation begins.
36///
37/// The handoff owns no credential, clock, future, executor, or secret-store
38/// handle. A credential store uses it to reject stale refresh completion.
39#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
40pub struct RefreshHandoff {
41    expected: CredentialGeneration,
42}
43
44impl RefreshHandoff {
45    /// Returns the generation that must still be current.
46    #[must_use]
47    pub const fn expected_generation(self) -> CredentialGeneration {
48        self.expected
49    }
50}
51
52/// Credential-generation transition error.
53#[derive(Clone, Copy, Debug, Eq, PartialEq)]
54pub enum CredentialGenerationError {
55    /// The monotonic generation cannot advance without wrapping.
56    Exhausted,
57}
58
59impl_static_error!(CredentialGenerationError,
60    Self::Exhausted => "credential generation is exhausted",
61);