jsonschema_annotator/
error.rs1use std::borrow::Cow;
2
3#[derive(Debug)]
5pub struct Error<K> {
6 pub kind: K,
7 pub(crate) context: Vec<Cow<'static, str>>,
8 pub(crate) source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
9}
10
11impl<K> Error<K> {
12 pub fn new(kind: K) -> Self {
13 Self {
14 kind,
15 context: Vec::new(),
16 source: None,
17 }
18 }
19
20 pub fn map_kind<NK, F>(self, mapper: F) -> Error<NK>
21 where
22 F: Fn(K) -> NK,
23 {
24 Error {
25 kind: mapper(self.kind),
26 context: self.context,
27 source: self.source,
28 }
29 }
30
31 pub fn add_context(mut self, context: impl Into<Cow<'static, str>>) -> Self {
32 self.context.push(context.into());
33 self
34 }
35
36 pub fn with_source(mut self, source: impl std::error::Error + Send + Sync + 'static) -> Self {
37 self.source = Some(Box::new(source));
38 self
39 }
40
41 pub fn with_boxed_source(
42 mut self,
43 source: Box<dyn std::error::Error + Send + Sync + 'static>,
44 ) -> Self {
45 self.source = Some(source);
46 self
47 }
48}
49
50impl<K> From<K> for Error<K> {
51 fn from(value: K) -> Self {
52 Error::new(value)
53 }
54}
55
56pub trait ResultExt<T, K> {
57 fn add_context(self, context: impl Into<Cow<'static, str>>) -> Result<T, Error<K>>;
58 fn add_context_fn<C: Into<Cow<'static, str>>, F: FnOnce() -> C>(
59 self,
60 context: F,
61 ) -> Result<T, Error<K>>;
62}
63
64impl<T, K> ResultExt<T, K> for Result<T, Error<K>> {
65 fn add_context(self, context: impl Into<Cow<'static, str>>) -> Result<T, Error<K>> {
66 match self {
67 Ok(value) => Ok(value),
68 Err(error) => Err(error.add_context(context)),
69 }
70 }
71
72 fn add_context_fn<C: Into<Cow<'static, str>>, F: FnOnce() -> C>(
73 self,
74 context: F,
75 ) -> Result<T, Error<K>> {
76 match self {
77 Ok(value) => Ok(value),
78 Err(error) => Err(error.add_context(context().into())),
79 }
80 }
81}
82
83impl<K> std::fmt::Display for Error<K>
84where
85 K: std::fmt::Display,
86{
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 self.kind.fmt(f)?;
89
90 if !self.context.is_empty() {
91 write!(f, " context: [")?;
92 for (i, context) in self.context.iter().rev().enumerate() {
93 write!(f, "{}", context)?;
94 if i < self.context.len() - 1 {
95 write!(f, ", ")?;
96 }
97 }
98 write!(f, "]")?;
99 }
100
101 Ok(())
102 }
103}
104
105impl<K> std::error::Error for Error<K>
106where
107 K: std::fmt::Display + std::fmt::Debug,
108{
109 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
110 self.source.as_ref().map(|s| s.as_ref() as _)
111 }
112}
113
114#[derive(Debug)]
116pub enum SchemaErrorKind {
117 Io,
118 ValueParse,
119 InvalidSchema,
120 RefResolution,
121}
122
123impl std::fmt::Display for SchemaErrorKind {
124 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125 match self {
126 SchemaErrorKind::Io => write!(f, "I/O error"),
127 SchemaErrorKind::ValueParse => write!(f, "failed to parse value"),
128 SchemaErrorKind::InvalidSchema => write!(f, "invalid schema"),
129 SchemaErrorKind::RefResolution => write!(f, "failed to resolve $ref"),
130 }
131 }
132}
133
134#[derive(Debug)]
136pub enum AnnotatorErrorKind {
137 Parse,
138 Io,
139}
140
141impl std::fmt::Display for AnnotatorErrorKind {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 match self {
144 AnnotatorErrorKind::Parse => write!(f, "failed to parse target document"),
145 AnnotatorErrorKind::Io => write!(f, "I/O error"),
146 }
147 }
148}
149
150pub type SchemaError = Error<SchemaErrorKind>;
151pub type AnnotatorError = Error<AnnotatorErrorKind>;