Skip to main content

cloud_sdk/operation/permit/
direct.rs

1//! Single-owner execution permits.
2
3use super::state::{DirectState, PermitAttempt};
4use super::{
5    ExecutionPermitError, PermitIdempotencyKey, PermitScope, PermitState, PermitTimestamp,
6    PlanSubject, ReconciliationToken, RecoveryToken,
7};
8
9macro_rules! direct_permit {
10    ($name:ident, $scope:expr, $description:literal) => {
11        #[doc = $description]
12        ///
13        /// This authority is intentionally neither `Copy` nor `Clone`.
14        #[doc = concat!(
15                            "```compile_fail\nuse cloud_sdk::operation::", stringify!($name),
16                            ";\nfn clone_authority(value: ", stringify!($name),
17                            "<'_, '_>) { let _ = value.clone(); }\n```"
18                        )]
19        #[doc = concat!(
20                            "```compile_fail\nuse cloud_sdk::operation::", stringify!($name),
21                            ";\nfn copy_authority(value: ", stringify!($name),
22                            "<'_, '_>) { let _first = value; let _second = value; }\n```"
23                        )]
24        pub struct $name<'request, 'fingerprint> {
25            inner: DirectState<'request, 'fingerprint>,
26        }
27
28        impl<'request, 'fingerprint> $name<'request, 'fingerprint> {
29            /// Creates one direct authority for an exact confirmed plan.
30            pub fn new(
31                subject: PlanSubject<'request, 'fingerprint>,
32                now: PermitTimestamp,
33            ) -> Result<Self, ExecutionPermitError> {
34                Ok(Self {
35                    inner: DirectState::new(subject, $scope, now)?,
36                })
37            }
38
39            /// Returns the current fail-closed lifecycle state.
40            #[must_use]
41            pub const fn state(&self) -> PermitState {
42                self.inner.state()
43            }
44
45            /// Starts one attempt for the originally confirmed request.
46            pub fn begin(
47                &mut self,
48                now: PermitTimestamp,
49            ) -> Result<PermitAttempt<'_, 'request, 'fingerprint>, ExecutionPermitError> {
50                self.inner.begin(now)
51            }
52
53            /// Starts one attempt only if a supplied plan still matches exactly.
54            pub fn begin_for(
55                &mut self,
56                subject: PlanSubject<'_, '_>,
57                now: PermitTimestamp,
58            ) -> Result<PermitAttempt<'_, 'request, 'fingerprint>, ExecutionPermitError> {
59                self.inner.begin_for(subject, now)
60            }
61
62            /// Rearms authority after a generation-matched `NotSent` result.
63            pub fn recover_not_sent(
64                &mut self,
65                token: RecoveryToken,
66                now: PermitTimestamp,
67            ) -> Result<(), ExecutionPermitError> {
68                self.inner.recover_not_sent(token, now)
69            }
70
71            /// Rearms after caller-performed operation-specific reconciliation.
72            ///
73            /// Callers must invoke this only after proving that the provider did
74            /// not apply the uncertain attempt. The exact plan and idempotency
75            /// identity are rechecked before authority becomes ready.
76            pub fn reconcile_not_applied(
77                &mut self,
78                token: ReconciliationToken,
79                subject: PlanSubject<'_, '_>,
80                idempotency: PermitIdempotencyKey<'_>,
81                now: PermitTimestamp,
82            ) -> Result<(), ExecutionPermitError> {
83                self.inner
84                    .reconcile_not_applied(token, subject, idempotency, now)
85            }
86        }
87
88        impl core::fmt::Debug for $name<'_, '_> {
89            fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
90                formatter
91                    .debug_struct(stringify!($name))
92                    .field("state", &self.inner.state())
93                    .field("plan", &"[redacted]")
94                    .finish()
95            }
96        }
97    };
98}
99
100direct_permit!(
101    MutationPermit,
102    PermitScope::Mutation,
103    "Single-owner authority for one non-destructive mutation plan."
104);
105direct_permit!(
106    DestructivePermit,
107    PermitScope::Destructive,
108    "Single-owner authority for one destructive mutation plan."
109);
110direct_permit!(
111    CostPermit,
112    PermitScope::Cost,
113    "Single-owner authority for one exact price-bounded cost plan."
114);