Skip to main content

cloud_sdk/operation/permit/fingerprint/
error.rs

1//! Payload-redacting plan-confirm construction errors.
2
3use core::fmt;
4
5use crate::operation::PermitContextError;
6
7/// Plan-confirm construction failure.
8#[derive(Clone, Copy)]
9pub enum PlanFingerprintBuildError<E> {
10    /// Read-only requests do not accept state-change permits.
11    ReadOnlyOperation,
12    /// The prepared request has no provider operation identifier.
13    MissingOperationId,
14    /// The endpoint is outside the provider-owned trust policy.
15    EndpointNotAdmitted,
16    /// Caller marked the plan as an ineffective no-op.
17    NoOp,
18    /// An account, tenant, or context value is invalid.
19    Context(PermitContextError),
20    /// Cost metadata is required by operation policy.
21    MissingCost,
22    /// Cost metadata was supplied for a no-known-cost operation.
23    UnexpectedCost,
24    /// Single-attempt policy must have an exact budget of one.
25    InvalidSingleAttemptBudget,
26    /// Reconciliation policy requires an idempotency identity.
27    MissingIdempotency,
28    /// Identity is forbidden when reconciliation is not admitted.
29    UnexpectedIdempotency,
30    /// Canonical length arithmetic overflowed or exceeded the hard bound.
31    InputTooLarge,
32    /// Caller output cannot hold the complete canonical input or digest.
33    OutputTooSmall,
34    /// Caller-provided collision-resistant hashing failed.
35    Hasher(E),
36    /// Hasher output length differs from its admitted algorithm.
37    InvalidDigestLength,
38}
39
40impl<E> fmt::Debug for PlanFingerprintBuildError<E> {
41    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
42        formatter.write_str(match self {
43            Self::ReadOnlyOperation => "PlanFingerprintBuildError::ReadOnlyOperation",
44            Self::MissingOperationId => "PlanFingerprintBuildError::MissingOperationId",
45            Self::EndpointNotAdmitted => "PlanFingerprintBuildError::EndpointNotAdmitted",
46            Self::NoOp => "PlanFingerprintBuildError::NoOp",
47            Self::Context(_) => "PlanFingerprintBuildError::Context",
48            Self::MissingCost => "PlanFingerprintBuildError::MissingCost",
49            Self::UnexpectedCost => "PlanFingerprintBuildError::UnexpectedCost",
50            Self::InvalidSingleAttemptBudget => {
51                "PlanFingerprintBuildError::InvalidSingleAttemptBudget"
52            }
53            Self::MissingIdempotency => "PlanFingerprintBuildError::MissingIdempotency",
54            Self::UnexpectedIdempotency => "PlanFingerprintBuildError::UnexpectedIdempotency",
55            Self::InputTooLarge => "PlanFingerprintBuildError::InputTooLarge",
56            Self::OutputTooSmall => "PlanFingerprintBuildError::OutputTooSmall",
57            Self::Hasher(_) => "PlanFingerprintBuildError::Hasher([redacted])",
58            Self::InvalidDigestLength => "PlanFingerprintBuildError::InvalidDigestLength",
59        })
60    }
61}
62
63impl<E> fmt::Display for PlanFingerprintBuildError<E> {
64    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
65        formatter.write_str(match self {
66            Self::ReadOnlyOperation => "read-only operation does not accept an execution permit",
67            Self::MissingOperationId => "plan confirmation requires an operation identifier",
68            Self::EndpointNotAdmitted => "plan confirmation endpoint is not admitted",
69            Self::NoOp => "no-op plan cannot receive execution authority",
70            Self::Context(_) => "plan confirmation context is invalid",
71            Self::MissingCost => "cost-bearing plan requires price confirmation",
72            Self::UnexpectedCost => "no-known-cost plan cannot include price authority",
73            Self::InvalidSingleAttemptBudget => "single-attempt plan must authorize one attempt",
74            Self::MissingIdempotency => "reconciliation replay requires idempotency identity",
75            Self::UnexpectedIdempotency => "idempotency identity requires reconciliation replay",
76            Self::InputTooLarge => "canonical plan confirmation exceeds its size limit",
77            Self::OutputTooSmall => "plan confirmation output is too small",
78            Self::Hasher(_) => "plan confirmation hashing failed",
79            Self::InvalidDigestLength => "plan confirmation digest length is invalid",
80        })
81    }
82}
83
84impl<E: core::error::Error + 'static> core::error::Error for PlanFingerprintBuildError<E> {
85    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
86        match self {
87            Self::Context(error) => Some(error),
88            Self::Hasher(error) => Some(error),
89            _ => None,
90        }
91    }
92}
93
94pub(super) fn map_infallible<E>(
95    error: PlanFingerprintBuildError<core::convert::Infallible>,
96) -> PlanFingerprintBuildError<E> {
97    match error {
98        PlanFingerprintBuildError::ReadOnlyOperation => {
99            PlanFingerprintBuildError::ReadOnlyOperation
100        }
101        PlanFingerprintBuildError::MissingOperationId => {
102            PlanFingerprintBuildError::MissingOperationId
103        }
104        PlanFingerprintBuildError::EndpointNotAdmitted => {
105            PlanFingerprintBuildError::EndpointNotAdmitted
106        }
107        PlanFingerprintBuildError::NoOp => PlanFingerprintBuildError::NoOp,
108        PlanFingerprintBuildError::Context(error) => PlanFingerprintBuildError::Context(error),
109        PlanFingerprintBuildError::MissingCost => PlanFingerprintBuildError::MissingCost,
110        PlanFingerprintBuildError::UnexpectedCost => PlanFingerprintBuildError::UnexpectedCost,
111        PlanFingerprintBuildError::InvalidSingleAttemptBudget => {
112            PlanFingerprintBuildError::InvalidSingleAttemptBudget
113        }
114        PlanFingerprintBuildError::MissingIdempotency => {
115            PlanFingerprintBuildError::MissingIdempotency
116        }
117        PlanFingerprintBuildError::UnexpectedIdempotency => {
118            PlanFingerprintBuildError::UnexpectedIdempotency
119        }
120        PlanFingerprintBuildError::InputTooLarge => PlanFingerprintBuildError::InputTooLarge,
121        PlanFingerprintBuildError::OutputTooSmall => PlanFingerprintBuildError::OutputTooSmall,
122        PlanFingerprintBuildError::InvalidDigestLength => {
123            PlanFingerprintBuildError::InvalidDigestLength
124        }
125        PlanFingerprintBuildError::Hasher(never) => match never {},
126    }
127}