Skip to main content

modkit_canonical_errors/
lib.rs

1extern crate self as modkit_canonical_errors;
2
3pub mod builder;
4pub mod context;
5pub mod error;
6mod gts_validation;
7pub mod problem;
8
9#[doc(hidden)]
10pub use gts_validation::validate_gts_resource_type;
11
12pub use builder::{ResourceErrorBuilder, ServiceUnavailableBuilder};
13pub use context::{
14    Aborted, AbortedV1, AlreadyExists, AlreadyExistsV1, Cancelled, CancelledV1, DataLoss,
15    DataLossV1, DeadlineExceeded, DeadlineExceededV1, FailedPrecondition, FailedPreconditionV1,
16    FieldViolation, FieldViolationV1, Internal, InternalV1, InvalidArgument, InvalidArgumentV1,
17    NotFound, NotFoundV1, OutOfRange, OutOfRangeV1, PermissionDenied, PermissionDeniedV1,
18    PreconditionViolation, PreconditionViolationV1, QuotaViolation, QuotaViolationV1,
19    ResourceExhausted, ResourceExhaustedV1, ServiceUnavailable, ServiceUnavailableV1,
20    Unauthenticated, UnauthenticatedV1, Unimplemented, UnimplementedV1, Unknown, UnknownV1,
21};
22pub use error::CanonicalError;
23pub use problem::Problem;
24
25/// Generates a resource error type with builder-returning constructors for the 13 canonical
26/// error categories that carry a `resource_type`.
27///
28/// Generated constructors either accept a detail string or are zero-argument
29/// (using a default message). Each returns a `ResourceErrorBuilder` with
30/// typestate enforcement — required fields must be set via builder methods
31/// (e.g. `.with_resource(...)`, `.with_reason(...)`) before `.create()`
32/// compiles.
33///
34/// Categories where `resource_type` is absent (`internal`,
35/// `service_unavailable`, `unauthenticated`) are **not** generated — use
36/// `CanonicalError::*()` directly for those.
37///
38/// The GTS type literal is validated at compile time.
39///
40/// # Example
41///
42/// ```ignore
43/// resource_error!(TenantResourceError, "gts.cf.core.tenants.tenant.v1~");
44///
45/// let err = TenantResourceError::not_found("tenant not found")
46///     .with_resource("tenant-123")
47///     .create();
48/// assert_eq!(err.resource_type(), Some("gts.cf.core.tenants.tenant.v1~"));
49/// ```
50#[macro_export]
51macro_rules! resource_error {
52    ($vis:vis $name:ident, $gts_type:literal) => {
53        const _: () = $crate::validate_gts_resource_type($gts_type);
54
55        $vis struct $name;
56
57        impl $name {
58            // --- resource_name required ---
59
60            $vis fn not_found(detail: impl Into<String>)
61                -> $crate::ResourceErrorBuilder<
62                    $crate::builder::ResourceMissing,
63                    $crate::builder::NoContext,
64                >
65            {
66                $crate::ResourceErrorBuilder::__not_found($gts_type, detail)
67            }
68
69            $vis fn already_exists(detail: impl Into<String>)
70                -> $crate::ResourceErrorBuilder<
71                    $crate::builder::ResourceMissing,
72                    $crate::builder::NoContext,
73                >
74            {
75                $crate::ResourceErrorBuilder::__already_exists($gts_type, detail)
76            }
77
78            $vis fn data_loss(detail: impl Into<String>)
79                -> $crate::ResourceErrorBuilder<
80                    $crate::builder::ResourceMissing,
81                    $crate::builder::NoContext,
82                >
83            {
84                $crate::ResourceErrorBuilder::__data_loss($gts_type, detail)
85            }
86
87            // --- resource_name optional ---
88
89            $vis fn aborted(detail: impl Into<String>)
90                -> $crate::ResourceErrorBuilder<
91                    $crate::builder::ResourceOptional,
92                    $crate::builder::NeedsReason,
93                >
94            {
95                $crate::ResourceErrorBuilder::__aborted($gts_type, detail)
96            }
97
98            $vis fn unknown(detail: impl Into<String>)
99                -> $crate::ResourceErrorBuilder<
100                    $crate::builder::ResourceOptional,
101                    $crate::builder::NoContext,
102                >
103            {
104                $crate::ResourceErrorBuilder::__unknown($gts_type, detail)
105            }
106
107            $vis fn deadline_exceeded(detail: impl Into<String>)
108                -> $crate::ResourceErrorBuilder<
109                    $crate::builder::ResourceOptional,
110                    $crate::builder::NoContext,
111                >
112            {
113                $crate::ResourceErrorBuilder::__deadline_exceeded($gts_type, detail)
114            }
115
116            // --- resource_name absent ---
117
118            $vis fn permission_denied()
119                -> $crate::ResourceErrorBuilder<
120                    $crate::builder::ResourceAbsent,
121                    $crate::builder::NeedsReason,
122                >
123            {
124                $crate::ResourceErrorBuilder::__permission_denied($gts_type, "You do not have permission to perform this operation")
125            }
126
127            $vis fn unimplemented(detail: impl Into<String>)
128                -> $crate::ResourceErrorBuilder<
129                    $crate::builder::ResourceOptional,
130                    $crate::builder::NoContext,
131                >
132            {
133                $crate::ResourceErrorBuilder::__unimplemented($gts_type, detail)
134            }
135
136            $vis fn cancelled()
137                -> $crate::ResourceErrorBuilder<
138                    $crate::builder::ResourceAbsent,
139                    $crate::builder::NoContext,
140                >
141            {
142                $crate::ResourceErrorBuilder::__cancelled($gts_type, "Operation cancelled by the client")
143            }
144
145            // --- resource_name optional, needs field violations ---
146
147            $vis fn invalid_argument()
148                -> $crate::ResourceErrorBuilder<
149                    $crate::builder::ResourceOptional,
150                    $crate::builder::NeedsFieldViolation,
151                >
152            {
153                $crate::ResourceErrorBuilder::__invalid_argument($gts_type, "Request validation failed")
154            }
155
156            $vis fn out_of_range(detail: impl Into<String>)
157                -> $crate::ResourceErrorBuilder<
158                    $crate::builder::ResourceOptional,
159                    $crate::builder::NeedsFieldViolation,
160                >
161            {
162                $crate::ResourceErrorBuilder::__out_of_range($gts_type, detail)
163            }
164
165            // --- resource_name optional, needs quota violations ---
166
167            $vis fn resource_exhausted(detail: impl Into<String>)
168                -> $crate::ResourceErrorBuilder<
169                    $crate::builder::ResourceOptional,
170                    $crate::builder::NeedsQuotaViolation,
171                >
172            {
173                $crate::ResourceErrorBuilder::__resource_exhausted($gts_type, detail)
174            }
175
176            // --- resource_name optional, needs precondition violations ---
177
178            $vis fn failed_precondition()
179                -> $crate::ResourceErrorBuilder<
180                    $crate::builder::ResourceOptional,
181                    $crate::builder::NeedsPreconditionViolation,
182                >
183            {
184                $crate::ResourceErrorBuilder::__failed_precondition($gts_type, "Operation precondition not met")
185            }
186        }
187    };
188}