1#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
5pub enum OperationImpact {
6 ReadOnly,
8 Mutation,
10 Destructive,
12}
13
14#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
16pub enum RequestSemantics {
17 Safe,
19 Idempotent,
21 NonIdempotent,
23}
24
25#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
27pub enum RetryEligibility {
28 Never,
30 ExplicitPolicy,
32}
33
34#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
36pub enum CostIntent {
37 NoKnownCost,
39 MayIncurCost,
41}
42
43#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
45pub enum RequestIdPolicy {
46 Retain,
48 Protected,
50 Discard,
52}
53
54#[derive(Clone, Copy, Debug, Eq, PartialEq)]
56pub enum OperationMetadataError {
57 ReadOnlyMustBeSafe,
59 StateChangeCannotBeSafe,
61 NonIdempotentRetry,
63}
64
65impl_static_error!(OperationMetadataError,
66 Self::ReadOnlyMustBeSafe => "read-only operation must use safe semantics",
67 Self::StateChangeCannotBeSafe => "state-changing operation cannot use safe semantics",
68 Self::NonIdempotentRetry => "non-idempotent operation cannot be retry eligible",
69);
70
71#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
79pub struct OperationMetadata {
80 impact: OperationImpact,
81 semantics: RequestSemantics,
82 retry: RetryEligibility,
83 cost: CostIntent,
84 request_id: RequestIdPolicy,
85}
86
87impl OperationMetadata {
88 pub const fn new(
90 impact: OperationImpact,
91 semantics: RequestSemantics,
92 retry: RetryEligibility,
93 cost: CostIntent,
94 request_id: RequestIdPolicy,
95 ) -> Result<Self, OperationMetadataError> {
96 match (impact, semantics, retry) {
97 (OperationImpact::ReadOnly, semantics, _)
98 if !matches!(semantics, RequestSemantics::Safe) =>
99 {
100 return Err(OperationMetadataError::ReadOnlyMustBeSafe);
101 }
102 (
103 OperationImpact::Mutation | OperationImpact::Destructive,
104 RequestSemantics::Safe,
105 _,
106 ) => {
107 return Err(OperationMetadataError::StateChangeCannotBeSafe);
108 }
109 (_, RequestSemantics::NonIdempotent, RetryEligibility::ExplicitPolicy) => {
110 return Err(OperationMetadataError::NonIdempotentRetry);
111 }
112 _ => {}
113 }
114 Ok(Self {
115 impact,
116 semantics,
117 retry,
118 cost,
119 request_id,
120 })
121 }
122
123 #[must_use]
125 pub const fn impact(self) -> OperationImpact {
126 self.impact
127 }
128
129 #[must_use]
131 pub const fn semantics(self) -> RequestSemantics {
132 self.semantics
133 }
134
135 #[must_use]
137 pub const fn retry_eligibility(self) -> RetryEligibility {
138 self.retry
139 }
140
141 #[must_use]
143 pub const fn cost_intent(self) -> CostIntent {
144 self.cost
145 }
146
147 #[must_use]
149 pub const fn request_id_policy(self) -> RequestIdPolicy {
150 self.request_id
151 }
152}