1use core::fmt;
2use std::error::Error;
3
4use crate::{gfx_select, global::Global, identity::IdentityManagerFactory};
5
6pub struct ErrorFormatter<'a> {
7 writer: &'a mut dyn fmt::Write,
8 global: &'a Global<IdentityManagerFactory>,
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: &str) {
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 global = self.global;
28 let label: String = gfx_select!(id => global.bind_group_label(*id));
29 self.label("bind group", &label);
30 }
31
32 pub fn bind_group_layout_label(&mut self, id: &crate::id::BindGroupLayoutId) {
33 let global = self.global;
34 let label: String = gfx_select!(id => global.bind_group_layout_label(*id));
35 self.label("bind group layout", &label);
36 }
37
38 pub fn render_pipeline_label(&mut self, id: &crate::id::RenderPipelineId) {
39 let global = self.global;
40 let label: String = gfx_select!(id => global.render_pipeline_label(*id));
41 self.label("render pipeline", &label);
42 }
43
44 pub fn compute_pipeline_label(&mut self, id: &crate::id::ComputePipelineId) {
45 let global = self.global;
46 let label: String = gfx_select!(id => global.compute_pipeline_label(*id));
47 self.label("compute pipeline", &label);
48 }
49
50 pub fn buffer_label_with_key(&mut self, id: &crate::id::BufferId, key: &str) {
51 let global = self.global;
52 let label: String = gfx_select!(id => global.buffer_label(*id));
53 self.label(key, &label);
54 }
55
56 pub fn buffer_label(&mut self, id: &crate::id::BufferId) {
57 self.buffer_label_with_key(id, "buffer");
58 }
59
60 pub fn texture_label_with_key(&mut self, id: &crate::id::TextureId, key: &str) {
61 let global = self.global;
62 let label: String = gfx_select!(id => global.texture_label(*id));
63 self.label(key, &label);
64 }
65
66 pub fn texture_label(&mut self, id: &crate::id::TextureId) {
67 self.texture_label_with_key(id, "texture");
68 }
69
70 pub fn texture_view_label_with_key(&mut self, id: &crate::id::TextureViewId, key: &str) {
71 let global = self.global;
72 let label: String = gfx_select!(id => global.texture_view_label(*id));
73 self.label(key, &label);
74 }
75
76 pub fn texture_view_label(&mut self, id: &crate::id::TextureViewId) {
77 self.texture_view_label_with_key(id, "texture view");
78 }
79
80 pub fn sampler_label(&mut self, id: &crate::id::SamplerId) {
81 let global = self.global;
82 let label: String = gfx_select!(id => global.sampler_label(*id));
83 self.label("sampler", &label);
84 }
85
86 pub fn command_buffer_label(&mut self, id: &crate::id::CommandBufferId) {
87 let global = self.global;
88 let label: String = gfx_select!(id => global.command_buffer_label(*id));
89 self.label("command buffer", &label);
90 }
91
92 pub fn query_set_label(&mut self, id: &crate::id::QuerySetId) {
93 let global = self.global;
94 let label: String = gfx_select!(id => global.query_set_label(*id));
95 self.label("query set", &label);
96 }
97}
98
99pub trait PrettyError: Error + Sized {
100 fn fmt_pretty(&self, fmt: &mut ErrorFormatter) {
101 fmt.error(self);
102 }
103}
104
105pub fn format_pretty_any(
106 writer: &mut dyn fmt::Write,
107 global: &Global<IdentityManagerFactory>,
108 error: &(dyn Error + 'static),
109) {
110 let mut fmt = ErrorFormatter { writer, global };
111
112 if let Some(pretty_err) = error.downcast_ref::<ContextError>() {
113 return pretty_err.fmt_pretty(&mut fmt);
114 }
115
116 if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderCommandError>() {
117 return pretty_err.fmt_pretty(&mut fmt);
118 }
119 if let Some(pretty_err) = error.downcast_ref::<crate::binding_model::CreateBindGroupError>() {
120 return pretty_err.fmt_pretty(&mut fmt);
121 }
122 if let Some(pretty_err) =
123 error.downcast_ref::<crate::binding_model::CreatePipelineLayoutError>()
124 {
125 return pretty_err.fmt_pretty(&mut fmt);
126 }
127 if let Some(pretty_err) = error.downcast_ref::<crate::command::ExecutionError>() {
128 return pretty_err.fmt_pretty(&mut fmt);
129 }
130 if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderPassErrorInner>() {
131 return pretty_err.fmt_pretty(&mut fmt);
132 }
133 if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderPassError>() {
134 return pretty_err.fmt_pretty(&mut fmt);
135 }
136 if let Some(pretty_err) = error.downcast_ref::<crate::command::ComputePassErrorInner>() {
137 return pretty_err.fmt_pretty(&mut fmt);
138 }
139 if let Some(pretty_err) = error.downcast_ref::<crate::command::ComputePassError>() {
140 return pretty_err.fmt_pretty(&mut fmt);
141 }
142 if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderBundleError>() {
143 return pretty_err.fmt_pretty(&mut fmt);
144 }
145 if let Some(pretty_err) = error.downcast_ref::<crate::command::TransferError>() {
146 return pretty_err.fmt_pretty(&mut fmt);
147 }
148 if let Some(pretty_err) = error.downcast_ref::<crate::command::PassErrorScope>() {
149 return pretty_err.fmt_pretty(&mut fmt);
150 }
151 if let Some(pretty_err) = error.downcast_ref::<crate::track::UsageConflict>() {
152 return pretty_err.fmt_pretty(&mut fmt);
153 }
154 if let Some(pretty_err) = error.downcast_ref::<crate::command::QueryError>() {
155 return pretty_err.fmt_pretty(&mut fmt);
156 }
157
158 fmt.error(error)
160}
161
162#[derive(Debug)]
163pub struct ContextError {
164 pub string: &'static str,
165 #[cfg(any(
166 not(target_arch = "wasm32"),
167 all(
168 feature = "fragile-send-sync-non-atomic-wasm",
169 not(target_feature = "atomics")
170 )
171 ))]
172 pub cause: Box<dyn Error + Send + Sync + 'static>,
173 #[cfg(not(any(
174 not(target_arch = "wasm32"),
175 all(
176 feature = "fragile-send-sync-non-atomic-wasm",
177 not(target_feature = "atomics")
178 )
179 )))]
180 pub cause: Box<dyn Error + 'static>,
181 pub label_key: &'static str,
182 pub label: String,
183}
184
185impl PrettyError for ContextError {
186 fn fmt_pretty(&self, fmt: &mut ErrorFormatter) {
187 fmt.error(self);
188 fmt.label(self.label_key, &self.label);
189 }
190}
191
192impl fmt::Display for ContextError {
193 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194 write!(f, "In {}", self.string)
195 }
196}
197
198impl Error for ContextError {
199 fn source(&self) -> Option<&(dyn Error + 'static)> {
200 Some(self.cause.as_ref())
201 }
202}