use core::fmt;
use std::error::Error;
use crate::{
gfx_select,
hub::{Global, IdentityManagerFactory},
};
pub struct ErrorFormatter<'a> {
writer: &'a mut dyn fmt::Write,
global: &'a Global<IdentityManagerFactory>,
}
impl<'a> ErrorFormatter<'a> {
pub fn error(&mut self, err: &dyn Error) {
writeln!(self.writer, " {err}").expect("Error formatting error");
}
pub fn note(&mut self, note: &dyn fmt::Display) {
writeln!(self.writer, " note: {note}").expect("Error formatting error");
}
pub fn label(&mut self, label_key: &str, label_value: &str) {
if !label_key.is_empty() && !label_value.is_empty() {
self.note(&format!("{label_key} = `{label_value}`"));
}
}
pub fn bind_group_label(&mut self, id: &crate::id::BindGroupId) {
let global = self.global;
let label = gfx_select!(id => global.bind_group_label(*id));
self.label("bind group", &label);
}
pub fn bind_group_layout_label(&mut self, id: &crate::id::BindGroupLayoutId) {
let global = self.global;
let label = gfx_select!(id => global.bind_group_layout_label(*id));
self.label("bind group layout", &label);
}
pub fn render_pipeline_label(&mut self, id: &crate::id::RenderPipelineId) {
let global = self.global;
let label = gfx_select!(id => global.render_pipeline_label(*id));
self.label("render pipeline", &label);
}
pub fn compute_pipeline_label(&mut self, id: &crate::id::ComputePipelineId) {
let global = self.global;
let label = gfx_select!(id => global.compute_pipeline_label(*id));
self.label("compute pipeline", &label);
}
pub fn buffer_label_with_key(&mut self, id: &crate::id::BufferId, key: &str) {
let global = self.global;
let label = gfx_select!(id => global.buffer_label(*id));
self.label(key, &label);
}
pub fn buffer_label(&mut self, id: &crate::id::BufferId) {
self.buffer_label_with_key(id, "buffer");
}
pub fn texture_label_with_key(&mut self, id: &crate::id::TextureId, key: &str) {
let global = self.global;
let label = gfx_select!(id => global.texture_label(*id));
self.label(key, &label);
}
pub fn texture_label(&mut self, id: &crate::id::TextureId) {
self.texture_label_with_key(id, "texture");
}
pub fn texture_view_label_with_key(&mut self, id: &crate::id::TextureViewId, key: &str) {
let global = self.global;
let label = gfx_select!(id => global.texture_view_label(*id));
self.label(key, &label);
}
pub fn texture_view_label(&mut self, id: &crate::id::TextureViewId) {
self.texture_view_label_with_key(id, "texture view");
}
pub fn sampler_label(&mut self, id: &crate::id::SamplerId) {
let global = self.global;
let label = gfx_select!(id => global.sampler_label(*id));
self.label("sampler", &label);
}
pub fn command_buffer_label(&mut self, id: &crate::id::CommandBufferId) {
let global = self.global;
let label = gfx_select!(id => global.command_buffer_label(*id));
self.label("command buffer", &label);
}
pub fn query_set_label(&mut self, id: &crate::id::QuerySetId) {
let global = self.global;
let label = gfx_select!(id => global.query_set_label(*id));
self.label("query set", &label);
}
}
pub trait PrettyError: Error + Sized {
fn fmt_pretty(&self, fmt: &mut ErrorFormatter) {
fmt.error(self);
}
}
pub fn format_pretty_any(
writer: &mut dyn fmt::Write,
global: &Global<IdentityManagerFactory>,
error: &(dyn Error + 'static),
) {
let mut fmt = ErrorFormatter { writer, global };
if let Some(pretty_err) = error.downcast_ref::<ContextError>() {
return pretty_err.fmt_pretty(&mut fmt);
}
if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderCommandError>() {
return pretty_err.fmt_pretty(&mut fmt);
}
if let Some(pretty_err) = error.downcast_ref::<crate::binding_model::CreateBindGroupError>() {
return pretty_err.fmt_pretty(&mut fmt);
}
if let Some(pretty_err) =
error.downcast_ref::<crate::binding_model::CreatePipelineLayoutError>()
{
return pretty_err.fmt_pretty(&mut fmt);
}
if let Some(pretty_err) = error.downcast_ref::<crate::command::ExecutionError>() {
return pretty_err.fmt_pretty(&mut fmt);
}
if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderPassErrorInner>() {
return pretty_err.fmt_pretty(&mut fmt);
}
if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderPassError>() {
return pretty_err.fmt_pretty(&mut fmt);
}
if let Some(pretty_err) = error.downcast_ref::<crate::command::ComputePassErrorInner>() {
return pretty_err.fmt_pretty(&mut fmt);
}
if let Some(pretty_err) = error.downcast_ref::<crate::command::ComputePassError>() {
return pretty_err.fmt_pretty(&mut fmt);
}
if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderBundleError>() {
return pretty_err.fmt_pretty(&mut fmt);
}
if let Some(pretty_err) = error.downcast_ref::<crate::command::TransferError>() {
return pretty_err.fmt_pretty(&mut fmt);
}
if let Some(pretty_err) = error.downcast_ref::<crate::command::PassErrorScope>() {
return pretty_err.fmt_pretty(&mut fmt);
}
if let Some(pretty_err) = error.downcast_ref::<crate::track::UsageConflict>() {
return pretty_err.fmt_pretty(&mut fmt);
}
if let Some(pretty_err) = error.downcast_ref::<crate::command::QueryError>() {
return pretty_err.fmt_pretty(&mut fmt);
}
fmt.error(error)
}
#[derive(Debug)]
pub struct ContextError {
pub string: &'static str,
pub cause: Box<dyn Error + Send + Sync + 'static>,
pub label_key: &'static str,
pub label: String,
}
impl PrettyError for ContextError {
fn fmt_pretty(&self, fmt: &mut ErrorFormatter) {
fmt.error(self);
fmt.label(self.label_key, &self.label);
}
}
impl fmt::Display for ContextError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "In {}", self.string)
}
}
impl Error for ContextError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(self.cause.as_ref())
}
}