1use core::fmt;
2use std::error::Error;
3
4use crate::{gfx_select, global::Global};
5
6pub struct ErrorFormatter<'a> {
7 writer: &'a mut dyn fmt::Write,
8 global: &'a Global,
9}
10
11impl<'a> ErrorFormatter<'a> {
12 pub fn error(&mut self, err: &dyn Error) {
13 writeln!(self.writer, " {err}").expect("Error formatting error");
14 }
15
16 pub fn note(&mut self, note: &dyn fmt::Display) {
17 writeln!(self.writer, " note: {note}").expect("Error formatting error");
18 }
19
20 pub fn label(&mut self, label_key: &str, label_value: &String) {
21 if !label_key.is_empty() && !label_value.is_empty() {
22 self.note(&format!("{label_key} = `{label_value}`"));
23 }
24 }
25
26 pub fn bind_group_label(&mut self, id: &crate::id::BindGroupId) {
27 let label: String = gfx_select!(id => self.global.bind_group_label(*id));
28 self.label("bind group", &label);
29 }
30
31 pub fn bind_group_layout_label(&mut self, id: &crate::id::BindGroupLayoutId) {
32 let label: String = gfx_select!(id => self.global.bind_group_layout_label(*id));
33 self.label("bind group layout", &label);
34 }
35
36 pub fn render_pipeline_label(&mut self, id: &crate::id::RenderPipelineId) {
37 let label: String = gfx_select!(id => self.global.render_pipeline_label(*id));
38 self.label("render pipeline", &label);
39 }
40
41 pub fn compute_pipeline_label(&mut self, id: &crate::id::ComputePipelineId) {
42 let label: String = gfx_select!(id => self.global.compute_pipeline_label(*id));
43 self.label("compute pipeline", &label);
44 }
45
46 pub fn buffer_label_with_key(&mut self, id: &crate::id::BufferId, key: &str) {
47 let label: String = gfx_select!(id => self.global.buffer_label(*id));
48 self.label(key, &label);
49 }
50
51 pub fn buffer_label(&mut self, id: &crate::id::BufferId) {
52 self.buffer_label_with_key(id, "buffer");
53 }
54
55 pub fn texture_label_with_key(&mut self, id: &crate::id::TextureId, key: &str) {
56 let label: String = gfx_select!(id => self.global.texture_label(*id));
57 self.label(key, &label);
58 }
59
60 pub fn texture_label(&mut self, id: &crate::id::TextureId) {
61 self.texture_label_with_key(id, "texture");
62 }
63
64 pub fn texture_view_label_with_key(&mut self, id: &crate::id::TextureViewId, key: &str) {
65 let label: String = gfx_select!(id => self.global.texture_view_label(*id));
66 self.label(key, &label);
67 }
68
69 pub fn texture_view_label(&mut self, id: &crate::id::TextureViewId) {
70 self.texture_view_label_with_key(id, "texture view");
71 }
72
73 pub fn sampler_label(&mut self, id: &crate::id::SamplerId) {
74 let label: String = gfx_select!(id => self.global.sampler_label(*id));
75 self.label("sampler", &label);
76 }
77
78 pub fn command_buffer_label(&mut self, id: &crate::id::CommandBufferId) {
79 let label: String = gfx_select!(id => self.global.command_buffer_label(*id));
80 self.label("command buffer", &label);
81 }
82
83 pub fn query_set_label(&mut self, id: &crate::id::QuerySetId) {
84 let label: String = gfx_select!(id => self.global.query_set_label(*id));
85 self.label("query set", &label);
86 }
87}
88
89pub trait PrettyError: Error + Sized {
90 fn fmt_pretty(&self, fmt: &mut ErrorFormatter) {
91 fmt.error(self);
92 }
93}
94
95pub fn format_pretty_any(
96 writer: &mut dyn fmt::Write,
97 global: &Global,
98 error: &(dyn Error + 'static),
99) {
100 let mut fmt = ErrorFormatter { writer, global };
101
102 if let Some(pretty_err) = error.downcast_ref::<ContextError>() {
103 return pretty_err.fmt_pretty(&mut fmt);
104 }
105
106 if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderCommandError>() {
107 return pretty_err.fmt_pretty(&mut fmt);
108 }
109 if let Some(pretty_err) = error.downcast_ref::<crate::binding_model::CreateBindGroupError>() {
110 return pretty_err.fmt_pretty(&mut fmt);
111 }
112 if let Some(pretty_err) =
113 error.downcast_ref::<crate::binding_model::CreatePipelineLayoutError>()
114 {
115 return pretty_err.fmt_pretty(&mut fmt);
116 }
117 if let Some(pretty_err) = error.downcast_ref::<crate::command::ExecutionError>() {
118 return pretty_err.fmt_pretty(&mut fmt);
119 }
120 if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderPassErrorInner>() {
121 return pretty_err.fmt_pretty(&mut fmt);
122 }
123 if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderPassError>() {
124 return pretty_err.fmt_pretty(&mut fmt);
125 }
126 if let Some(pretty_err) = error.downcast_ref::<crate::command::ComputePassErrorInner>() {
127 return pretty_err.fmt_pretty(&mut fmt);
128 }
129 if let Some(pretty_err) = error.downcast_ref::<crate::command::ComputePassError>() {
130 return pretty_err.fmt_pretty(&mut fmt);
131 }
132 if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderBundleError>() {
133 return pretty_err.fmt_pretty(&mut fmt);
134 }
135 if let Some(pretty_err) = error.downcast_ref::<crate::command::TransferError>() {
136 return pretty_err.fmt_pretty(&mut fmt);
137 }
138 if let Some(pretty_err) = error.downcast_ref::<crate::command::PassErrorScope>() {
139 return pretty_err.fmt_pretty(&mut fmt);
140 }
141 if let Some(pretty_err) = error.downcast_ref::<crate::track::UsageConflict>() {
142 return pretty_err.fmt_pretty(&mut fmt);
143 }
144 if let Some(pretty_err) = error.downcast_ref::<crate::command::QueryError>() {
145 return pretty_err.fmt_pretty(&mut fmt);
146 }
147
148 fmt.error(error)
150}
151
152#[derive(Debug)]
153pub struct ContextError {
154 pub string: &'static str,
155 #[cfg(send_sync)]
156 pub cause: Box<dyn Error + Send + Sync + 'static>,
157 #[cfg(not(send_sync))]
158 pub cause: Box<dyn Error + 'static>,
159 pub label_key: &'static str,
160 pub label: String,
161}
162
163impl PrettyError for ContextError {
164 fn fmt_pretty(&self, fmt: &mut ErrorFormatter) {
165 fmt.error(self);
166 fmt.label(self.label_key, &self.label);
167 }
168}
169
170impl fmt::Display for ContextError {
171 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172 write!(f, "In {}", self.string)
173 }
174}
175
176impl Error for ContextError {
177 fn source(&self) -> Option<&(dyn Error + 'static)> {
178 Some(self.cause.as_ref())
179 }
180}