Skip to main content

gestalt/
rpc_support.rs

1// Code generated by sdkgen. DO NOT EDIT.
2
3//! Shared generated runtime for sdkgen clients: the canonical error model.
4
5/// Canonical SDK error codes, drawn from the standard gRPC status codes.
6pub mod gestalt_error_code {
7    /// The operation was cancelled.
8    pub const CANCELLED: i32 = 1;
9    /// The cause of the error is unknown.
10    pub const UNKNOWN: i32 = 2;
11    /// The client specified an invalid argument.
12    pub const INVALID_ARGUMENT: i32 = 3;
13    /// The deadline expired before the operation could complete.
14    pub const DEADLINE_EXCEEDED: i32 = 4;
15    /// The requested entity was not found.
16    pub const NOT_FOUND: i32 = 5;
17    /// The entity the client attempted to create already exists.
18    pub const ALREADY_EXISTS: i32 = 6;
19    /// The caller does not have permission to execute the operation.
20    pub const PERMISSION_DENIED: i32 = 7;
21    /// A resource has been exhausted.
22    pub const RESOURCE_EXHAUSTED: i32 = 8;
23    /// The system is not in a state required for the operation.
24    pub const FAILED_PRECONDITION: i32 = 9;
25    /// The operation was aborted.
26    pub const ABORTED: i32 = 10;
27    /// The operation was attempted past the valid range.
28    pub const OUT_OF_RANGE: i32 = 11;
29    /// The operation is not implemented or supported.
30    pub const UNIMPLEMENTED: i32 = 12;
31    /// An internal error occurred.
32    pub const INTERNAL: i32 = 13;
33    /// The service is currently unavailable.
34    pub const UNAVAILABLE: i32 = 14;
35    /// Unrecoverable data loss or corruption.
36    pub const DATA_LOSS: i32 = 15;
37    /// The request lacks valid authentication credentials.
38    pub const UNAUTHENTICATED: i32 = 16;
39}
40
41/// Canonical SDK error: one numeric status code and a human-readable message.
42/// Concrete transport adapters map their native errors into this type.
43#[derive(Debug, thiserror::Error)]
44#[error("{message}")]
45pub struct GestaltError {
46    /// Numeric status code, one of the gestalt_error_code constants.
47    pub code: i32,
48    /// Human-readable error message.
49    pub message: String,
50}
51
52impl GestaltError {
53    /// Creates an error with the given code and message.
54    pub fn new(code: i32, message: impl Into<String>) -> Self {
55        Self {
56            code,
57            message: message.into(),
58        }
59    }
60}
61
62/// Maps an HTTP status code to the canonical Gestalt gRPC error code.
63pub fn http_status_to_gestalt_code(status: i32) -> i32 {
64    match status {
65        400 => gestalt_error_code::INVALID_ARGUMENT,
66        401 => gestalt_error_code::UNAUTHENTICATED,
67        403 => gestalt_error_code::PERMISSION_DENIED,
68        404 => gestalt_error_code::NOT_FOUND,
69        409 => gestalt_error_code::ALREADY_EXISTS,
70        412 => gestalt_error_code::FAILED_PRECONDITION,
71        429 => gestalt_error_code::RESOURCE_EXHAUSTED,
72        499 => gestalt_error_code::CANCELLED,
73        500 => gestalt_error_code::INTERNAL,
74        501 => gestalt_error_code::UNIMPLEMENTED,
75        503 => gestalt_error_code::UNAVAILABLE,
76        504 => gestalt_error_code::DEADLINE_EXCEEDED,
77        _ => gestalt_error_code::UNKNOWN,
78    }
79}
80
81// Provider-only extensions to the shared generated error model.
82
83/// Native representation of google.rpc.Status carried in response payloads,
84/// mirroring the canonical error model.
85#[derive(Clone, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
86pub struct RpcStatus {
87    /// Numeric gRPC status code, one of the gestalt_error_code constants.
88    pub code: i32,
89    /// Human-readable error message.
90    pub message: String,
91}
92
93impl From<tonic::Status> for GestaltError {
94    fn from(status: tonic::Status) -> Self {
95        // tonic reports an expired grpc-timeout as CANCELLED carrying the
96        // TimeoutExpired message; the gRPC spec assigns deadline expiry
97        // DEADLINE_EXCEEDED, so the canonical code is restored here.
98        let timeout_expired = tonic::TimeoutExpired(()).to_string();
99        let code = if status.code() == tonic::Code::Cancelled && status.message() == timeout_expired
100        {
101            gestalt_error_code::DEADLINE_EXCEEDED
102        } else {
103            status.code() as i32
104        };
105        Self {
106            code,
107            message: status.message().to_string(),
108        }
109    }
110}