gproxy_protocol/transform/
error.rs1use std::{error::Error, fmt};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
6pub enum TransformErrorKind {
7 InvalidInput,
8 InvalidResult,
9 Unsupported,
10 MissingMetadata,
11 MissingState,
12 Conflict,
13 Limit,
14 Host,
15}
16
17#[derive(Debug)]
19pub struct TransformError {
20 kind: TransformErrorKind,
21 context: String,
22 detail: String,
23 source: Option<Box<dyn Error + Send + Sync + 'static>>,
24}
25
26impl TransformError {
27 pub fn new(
28 kind: TransformErrorKind,
29 context: impl Into<String>,
30 detail: impl Into<String>,
31 ) -> Self {
32 Self {
33 kind,
34 context: context.into(),
35 detail: detail.into(),
36 source: None,
37 }
38 }
39
40 pub fn with_source(
41 kind: TransformErrorKind,
42 context: impl Into<String>,
43 detail: impl Into<String>,
44 source: impl Into<Box<dyn Error + Send + Sync + 'static>>,
45 ) -> Self {
46 Self {
47 kind,
48 context: context.into(),
49 detail: detail.into(),
50 source: Some(source.into()),
51 }
52 }
53
54 pub fn shape(context: impl Into<String>, detail: impl Into<String>) -> Self {
55 Self::new(TransformErrorKind::InvalidInput, context, detail)
56 }
57
58 pub fn unsupported(context: impl Into<String>, detail: impl Into<String>) -> Self {
59 Self::new(TransformErrorKind::Unsupported, context, detail)
60 }
61
62 pub fn invalid_result(context: impl Into<String>, detail: impl Into<String>) -> Self {
63 Self::new(TransformErrorKind::InvalidResult, context, detail)
64 }
65
66 pub fn missing_metadata(field: impl Into<String>) -> Self {
67 Self::new(
68 TransformErrorKind::MissingMetadata,
69 field,
70 "required factual metadata is unavailable",
71 )
72 }
73
74 pub fn kind(&self) -> TransformErrorKind {
75 self.kind
76 }
77 pub fn context(&self) -> &str {
78 &self.context
79 }
80 pub fn detail(&self) -> &str {
81 &self.detail
82 }
83}
84
85impl fmt::Display for TransformError {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 write!(f, "{}: {}", self.context, self.detail)
88 }
89}
90
91impl Error for TransformError {
92 fn source(&self) -> Option<&(dyn Error + 'static)> {
93 self.source
94 .as_deref()
95 .map(|source| source as &(dyn Error + 'static))
96 }
97}
98
99impl From<serde_json::Error> for TransformError {
100 fn from(error: serde_json::Error) -> Self {
101 let message = error.to_string();
102 Self::with_source(TransformErrorKind::InvalidInput, "JSON", message, error)
103 }
104}
105
106impl From<crate::capability::CapabilityError> for TransformError {
107 fn from(error: crate::capability::CapabilityError) -> Self {
108 use crate::capability::CapabilityErrorKind;
109 let kind = match error.kind() {
110 CapabilityErrorKind::Unsupported => TransformErrorKind::Unsupported,
111 CapabilityErrorKind::NotFound | CapabilityErrorKind::Expired => {
112 TransformErrorKind::Host
113 }
114 CapabilityErrorKind::Conflict => TransformErrorKind::Conflict,
115 CapabilityErrorKind::Limit => TransformErrorKind::Limit,
116 CapabilityErrorKind::Invalid => TransformErrorKind::InvalidInput,
117 CapabilityErrorKind::Transport | CapabilityErrorKind::Storage => {
118 TransformErrorKind::Host
119 }
120 };
121 let message = error.to_string();
122 Self::with_source(kind, "host capability", message, error)
123 }
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
129pub enum DiagnosticKind {
130 OmittedOptional,
133 RepresentationChanged,
134}
135
136#[derive(Debug, Clone, PartialEq, Eq)]
137pub struct Diagnostic {
138 pub field: String,
139 pub kind: DiagnosticKind,
140 pub message: String,
141}
142
143#[derive(Debug, Default, Clone, PartialEq, Eq)]
145pub struct Report {
146 pub diagnostics: Vec<Diagnostic>,
147}
148
149impl Report {
150 pub fn omitted(&mut self, field: impl Into<String>, message: impl Into<String>) {
151 self.diagnostics.push(Diagnostic {
152 field: field.into(),
153 kind: DiagnosticKind::OmittedOptional,
154 message: message.into(),
155 });
156 }
157
158 pub fn changed(&mut self, field: impl Into<String>, message: impl Into<String>) {
159 self.diagnostics.push(Diagnostic {
160 field: field.into(),
161 kind: DiagnosticKind::RepresentationChanged,
162 message: message.into(),
163 });
164 }
165}