1#![warn(clippy::all, missing_docs)]
20
21extern crate self as conjure_error;
22
23use conjure_object::Uuid;
24use serde::{Serialize, Serializer};
25
26use crate::ser::{ParametersSerializer, StringSeed};
27
28pub use crate::error::*;
29pub use crate::types::*;
30use serde::de::DeserializeSeed;
31
32mod error;
33mod ser;
34#[allow(clippy::all, missing_docs)]
35#[rustfmt::skip]
36mod types;
37
38impl ErrorCode {
39 #[inline]
41 pub fn status_code(&self) -> u16 {
42 match self {
43 ErrorCode::PermissionDenied => 403,
44 ErrorCode::InvalidArgument => 400,
45 ErrorCode::NotFound => 404,
46 ErrorCode::Conflict => 409,
47 ErrorCode::RequestEntityTooLarge => 413,
48 ErrorCode::FailedPrecondition => 500,
49 ErrorCode::Internal => 500,
50 ErrorCode::Timeout => 500,
51 ErrorCode::CustomClient => 400,
52 ErrorCode::CustomServer => 500,
53 }
54 }
55}
56
57pub trait ErrorType {
59 fn code(&self) -> ErrorCode;
61
62 fn name(&self) -> &str;
66
67 fn instance_id(&self) -> Option<Uuid>;
72
73 fn safe_args(&self) -> &'static [&'static str];
75
76 #[inline]
78 fn with_instance_id(self, instance_id: Uuid) -> WithInstanceId<Self>
79 where
80 Self: Sized,
81 {
82 WithInstanceId {
83 error: self,
84 instance_id,
85 }
86 }
87}
88
89impl<T> ErrorType for &T
90where
91 T: ?Sized + ErrorType,
92{
93 #[inline]
94 fn code(&self) -> ErrorCode {
95 (**self).code()
96 }
97
98 #[inline]
99 fn name(&self) -> &str {
100 (**self).name()
101 }
102
103 #[inline]
104 fn instance_id(&self) -> Option<Uuid> {
105 (**self).instance_id()
106 }
107
108 #[inline]
109 fn safe_args(&self) -> &'static [&'static str] {
110 (**self).safe_args()
111 }
112}
113
114pub struct WithInstanceId<T> {
116 error: T,
117 instance_id: Uuid,
118}
119
120impl<T> ErrorType for WithInstanceId<T>
121where
122 T: ErrorType,
123{
124 fn code(&self) -> ErrorCode {
125 self.error.code()
126 }
127
128 fn name(&self) -> &str {
129 self.error.name()
130 }
131
132 fn instance_id(&self) -> Option<Uuid> {
133 Some(self.instance_id)
134 }
135
136 fn safe_args(&self) -> &'static [&'static str] {
137 self.error.safe_args()
138 }
139}
140
141impl<T> Serialize for WithInstanceId<T>
142where
143 T: Serialize,
144{
145 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
146 where
147 S: Serializer,
148 {
149 self.error.serialize(s)
150 }
151}
152
153pub fn encode<T>(error: &T) -> SerializableError
161where
162 T: ErrorType + Serialize,
163{
164 let mut builder = SerializableError::builder()
165 .error_code(error.code())
166 .error_name(error.name())
167 .error_instance_id(error.instance_id().unwrap_or_else(Uuid::new_v4));
168
169 let parameters = error
170 .serialize(ParametersSerializer)
171 .expect("failed to serialize error parameters");
172
173 for (key, value) in parameters {
174 if let Ok(value) = StringSeed.deserialize(value) {
175 builder = builder.insert_parameters(key, value);
176 }
177 }
178
179 builder.build()
180}