[rs] Add labels for some error messages

This adds transforms for the ids in the errors to a label,
and adds them to the validation error message.

This changes the formatting of the validation error to happen when
constructing the error, rather than in the unhandled error handler.
It also requires some code for all the error variants for extracting the ids.
This commit is contained in:
Mikko Lehtonen
2020-11-12 00:07:02 +02:00
parent 581674efb3
commit daa15a853f
4 changed files with 331 additions and 101 deletions

View File

@@ -1,7 +1,8 @@
use crate::{
backend::native_gpu_future, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource,
CommandEncoderDescriptor, ComputePipelineDescriptor, Features, Limits, LoadOp, MapMode,
Operations, PipelineLayoutDescriptor, RenderBundleEncoderDescriptor, RenderPipelineDescriptor,
backend::error::format_error, backend::native_gpu_future, BindGroupDescriptor,
BindGroupLayoutDescriptor, BindingResource, CommandEncoderDescriptor,
ComputePipelineDescriptor, Features, Limits, LoadOp, MapMode, Operations,
PipelineLayoutDescriptor, RenderBundleEncoderDescriptor, RenderPipelineDescriptor,
SamplerDescriptor, ShaderModuleSource, SwapChainStatus, TextureDescriptor,
TextureViewDescriptor,
};
@@ -19,6 +20,10 @@ use typed_arena::Arena;
pub struct Context(wgc::hub::Global<wgc::hub::IdentityManagerFactory>);
impl Context {
pub(crate) fn global(&self) -> &wgc::hub::Global<wgc::hub::IdentityManagerFactory> {
&self.0
}
pub fn adapter_get_info(&self, id: wgc::id::AdapterId) -> wgc::instance::AdapterInfo {
let global = &self.0;
wgc::gfx_select!(id => global.adapter_get_info(id)).unwrap_pretty()
@@ -651,9 +656,10 @@ impl crate::Context for Context {
wgc::gfx_select!(
device.id => global.device_create_shader_module(device.id, desc, PhantomData)
)
.map_err(|err| err.with_context("In Device::create_shader_module".to_string()))
.map_err(|err| err.with_context("In Device::create_shader_module", None))
.unwrap_error_sink(
&device.error_sink,
&self,
|| wgc::gfx_select!( device.id => global.shader_module_error(PhantomData)),
)
}
@@ -670,8 +676,8 @@ impl crate::Context for Context {
entries: Borrowed(desc.entries),
}, PhantomData)
)
.map_err(|err| err.with_context(format!("In Device::create_bind_group_layout with label {:?}", desc.label)))
.unwrap_error_sink(&device.error_sink, || wgc::gfx_select!( device.id => global.bind_group_layout_error(PhantomData, desc.label)))
.map_err(|err| err.with_context(&format!("In Device::create_bind_group_layout"),desc.label))
.unwrap_error_sink(&device.error_sink, &self, || wgc::gfx_select!( device.id => global.bind_group_layout_error(PhantomData, desc.label)))
}
fn device_create_bind_group(
@@ -722,14 +728,10 @@ impl crate::Context for Context {
},
PhantomData
))
.map_err(|err| {
err.with_context(format!(
"In Device::create_bind_group with label {:?}",
desc.label
))
})
.map_err(|err| err.with_context(&format!("In Device::create_bind_group"), desc.label))
.unwrap_error_sink(
&device.error_sink,
&self,
|| wgc::gfx_select!( device.id => global.bind_group_error(PhantomData, desc.label)),
)
}
@@ -767,13 +769,14 @@ impl crate::Context for Context {
PhantomData
))
.map_err(|err| {
err.with_context(format!(
"In Device::create_pipeline_layout with label {:?}",
err.with_context(&format!(
"In Device::create_pipeline_layout"),
desc.label
))
)
})
.unwrap_error_sink(
&device.error_sink,
&self,
|| wgc::gfx_select!( device.id => global.pipeline_layout_error(PhantomData, desc.label)),
)
}
@@ -841,12 +844,12 @@ impl crate::Context for Context {
implicit_pipeline_ids
))
.map_err(|err| {
err.with_context(format!(
"In Device::create_render_pipeline with label {:?}",
err.with_context(&format!(
"In Device::create_render_pipeline"),
desc.label
))
)
})
.unwrap_error_sink(&device.error_sink, || {
.unwrap_error_sink(&device.error_sink, &self, || {
let err = wgc::gfx_select!( device.id => global.render_pipeline_error(PhantomData, desc.label));
(err, 0u8)
})
@@ -883,12 +886,12 @@ impl crate::Context for Context {
implicit_pipeline_ids
))
.map_err(|err| {
err.with_context(format!(
"In Device::create_compute_pipeline with label {:?}",
err.with_context(&format!(
"In Device::create_compute_pipeline"),
desc.label
))
)
})
.unwrap_error_sink(&device.error_sink, || {
.unwrap_error_sink(&device.error_sink, &self, || {
let err = wgc::gfx_select!( device.id => global.compute_pipeline_error(PhantomData, desc.label));
(err, 0u8)
})
@@ -911,14 +914,10 @@ impl crate::Context for Context {
},
PhantomData
))
.map_err(|err| {
err.with_context(format!(
"In Device::create_buffer with label {:?}",
desc.label
))
})
.map_err(|err| err.with_context(&format!("In Device::create_buffer"), desc.label))
.unwrap_error_sink(
&device.error_sink,
&self,
|| wgc::gfx_select!( device.id => global.buffer_error(PhantomData, desc.label)),
);
Buffer {
@@ -946,14 +945,10 @@ impl crate::Context for Context {
},
PhantomData
))
.map_err(|err| {
err.with_context(format!(
"In Device::create_texture with label {:?}",
desc.label
))
})
.map_err(|err| err.with_context(&format!("In Device::create_texture"), desc.label))
.unwrap_error_sink(
&device.error_sink,
&self,
|| wgc::gfx_select!( device.id => global.texture_error(PhantomData, desc.label)),
);
Texture {
@@ -984,14 +979,10 @@ impl crate::Context for Context {
},
PhantomData
))
.map_err(|err| {
err.with_context(format!(
"In Device::create_sampler with label {:?}",
desc.label
))
})
.map_err(|err| err.with_context(&format!("In Device::create_sampler"), desc.label))
.unwrap_error_sink(
&device.error_sink,
&self,
|| wgc::gfx_select!( device.id => global.sampler_error(PhantomData, desc.label)),
)
}
@@ -1009,14 +1000,10 @@ impl crate::Context for Context {
},
PhantomData
))
.map_err(|err| {
err.with_context(format!(
"In Device::create_command_encoder with label {:?}",
desc.label
))
})
.map_err(|err| err.with_context(&format!("In Device::create_command_encoder"), desc.label))
.unwrap_error_sink(
&device.error_sink,
&self,
|| wgc::gfx_select!( device.id => global.command_encoder_error(PhantomData)),
);
CommandEncoder {
@@ -1112,8 +1099,8 @@ impl crate::Context for Context {
let global = &self.0;
wgc::gfx_select!(buffer.id => global.buffer_map_async(buffer.id, range, operation))
.map_err(|err| err.with_context("In Buffer::map_async".to_string()))
.unwrap_error_sink(&buffer.error_sink, || ());
.map_err(|err| err.with_context("In Buffer::map_async", None))
.unwrap_error_sink(&buffer.error_sink, &self, || ());
future
}
@@ -1153,8 +1140,8 @@ impl crate::Context for Context {
fn buffer_unmap(&self, buffer: &Self::BufferId) {
let global = &self.0;
wgc::gfx_select!(buffer.id => global.buffer_unmap(buffer.id))
.map_err(|err| err.with_context("In Buffer::get_mapped_range".to_string()))
.unwrap_error_sink(&buffer.error_sink, || ());
.map_err(|err| err.with_context("In Buffer::get_mapped_range", None))
.unwrap_error_sink(&buffer.error_sink, &self, || ());
}
fn swap_chain_get_current_texture_view(
@@ -1204,14 +1191,10 @@ impl crate::Context for Context {
wgc::gfx_select!(
texture.id => global.texture_create_view(texture.id, &descriptor, PhantomData)
)
.map_err(|err| {
err.with_context(format!(
"In Texture::create_view with label {:?}",
desc.label
))
})
.map_err(|err| err.with_context(&format!("In Texture::create_view"), desc.label))
.unwrap_error_sink(
&texture.error_sink,
&self,
|| wgc::gfx_select!( texture.id =>global.texture_view_error(PhantomData, desc.label)),
)
}
@@ -1318,8 +1301,8 @@ impl crate::Context for Context {
destination_offset,
copy_size
))
.map_err(|err| err.with_context("In CommandEncoder::copy_buffer_to_buffer".to_string()))
.unwrap_error_sink(&encoder.error_sink, || ());
.map_err(|err| err.with_context("In CommandEncoder::copy_buffer_to_buffer", None))
.unwrap_error_sink(&encoder.error_sink, &self, || ());
}
fn command_encoder_copy_buffer_to_texture(
@@ -1336,8 +1319,8 @@ impl crate::Context for Context {
&map_texture_copy_view(destination),
&copy_size
))
.map_err(|err| err.with_context("In CommandEncoder::copy_buffer_to_texture".to_string()))
.unwrap_error_sink(&encoder.error_sink, || ())
.map_err(|err| err.with_context("In CommandEncoder::copy_buffer_to_texture", None))
.unwrap_error_sink(&encoder.error_sink, &self, || ())
}
fn command_encoder_copy_texture_to_buffer(
@@ -1354,8 +1337,8 @@ impl crate::Context for Context {
&map_buffer_copy_view(destination),
&copy_size
))
.map_err(|err| err.with_context("In CommandEncoder::copy_texture_to_buffer".to_string()))
.unwrap_error_sink(&encoder.error_sink, || ())
.map_err(|err| err.with_context("In CommandEncoder::copy_texture_to_buffer", None))
.unwrap_error_sink(&encoder.error_sink, &self, || ())
}
fn command_encoder_copy_texture_to_texture(
@@ -1372,8 +1355,8 @@ impl crate::Context for Context {
&map_texture_copy_view(destination),
&copy_size
))
.map_err(|err| err.with_context("In CommandEncoder::copy_texture_to_texture".to_string()))
.unwrap_error_sink(&encoder.error_sink, || ())
.map_err(|err| err.with_context("In CommandEncoder::copy_texture_to_texture", None))
.unwrap_error_sink(&encoder.error_sink, &self, || ())
}
fn command_encoder_begin_compute_pass(
@@ -1392,8 +1375,8 @@ impl crate::Context for Context {
wgc::gfx_select!(
encoder.id => global.command_encoder_run_compute_pass(encoder.id, pass)
)
.map_err(|err| err.with_context("In a ComputePass".to_string()))
.unwrap_error_sink(&encoder.error_sink, || ())
.map_err(|err| err.with_context("In a ComputePass", None))
.unwrap_error_sink(&encoder.error_sink, &self, || ())
}
fn command_encoder_begin_render_pass<'a>(
@@ -1436,17 +1419,18 @@ impl crate::Context for Context {
) {
let global = &self.0;
wgc::gfx_select!(encoder.id => global.command_encoder_run_render_pass(encoder.id, pass))
.map_err(|err| err.with_context("In a RenderPass".to_string()))
.unwrap_error_sink(&encoder.error_sink, || ())
.map_err(|err| err.with_context("In a RenderPass", None))
.unwrap_error_sink(&encoder.error_sink, &self, || ())
}
fn command_encoder_finish(&self, encoder: &Self::CommandEncoderId) -> Self::CommandBufferId {
let desc = wgt::CommandBufferDescriptor::default();
let global = &self.0;
wgc::gfx_select!(encoder.id => global.command_encoder_finish(encoder.id, &desc))
.map_err(|err| err.with_context("In a CommandEncoder".to_string()))
.map_err(|err| err.with_context("In a CommandEncoder", None))
.unwrap_error_sink(
&encoder.error_sink,
&self,
|| wgc::gfx_select!( encoder.id => global.command_buffer_error(PhantomData, None)),
)
}
@@ -1454,20 +1438,20 @@ impl crate::Context for Context {
fn command_encoder_insert_debug_marker(&self, encoder: &Self::CommandEncoderId, label: &str) {
let global = &self.0;
wgc::gfx_select!(encoder.id => global.command_encoder_insert_debug_marker(encoder.id, &label))
.map_err(|err| err.with_context("In CommandEncoder::insert_debug_marker".to_string()))
.unwrap_error_sink(&encoder.error_sink, ||())
.map_err(|err| err.with_context("In CommandEncoder::insert_debug_marker", None))
.unwrap_error_sink(&encoder.error_sink,&self, ||())
}
fn command_encoder_push_debug_group(&self, encoder: &Self::CommandEncoderId, label: &str) {
let global = &self.0;
wgc::gfx_select!(encoder.id => global.command_encoder_push_debug_group(encoder.id, &label))
.map_err(|err| err.with_context("In CommandEncoder::push_debug_group".to_string()))
.unwrap_error_sink(&encoder.error_sink, || ())
.map_err(|err| err.with_context("In CommandEncoder::push_debug_group", None))
.unwrap_error_sink(&encoder.error_sink, &self, || ())
}
fn command_encoder_pop_debug_group(&self, encoder: &Self::CommandEncoderId) {
let global = &self.0;
wgc::gfx_select!(encoder.id => global.command_encoder_pop_debug_group(encoder.id))
.map_err(|err| err.with_context("In CommandEncoder::pop_debug_group".to_string()))
.unwrap_error_sink(&encoder.error_sink, || ())
.map_err(|err| err.with_context("In CommandEncoder::pop_debug_group", None))
.unwrap_error_sink(&encoder.error_sink, &self, || ())
}
fn render_bundle_encoder_finish(
@@ -1483,7 +1467,7 @@ impl crate::Context for Context {
},
PhantomData
))
.map_err(|err| err.with_context("In a RenderBundleEncoder".to_string()))
.map_err(|err| err.with_context("In a RenderBundleEncoder", None))
.unwrap_pretty()
}
@@ -1540,7 +1524,12 @@ pub(crate) struct SwapChainOutputDetail {
trait PrettyResult<T> {
fn unwrap_pretty(self) -> T;
fn unwrap_error_sink(self, error_sink: &ErrorSink, fallback: impl FnOnce() -> T) -> T;
fn unwrap_error_sink(
self,
error_sink: &ErrorSink,
context: &Context,
fallback: impl FnOnce() -> T,
) -> T;
}
impl<T, E> PrettyResult<T> for Result<T, E>
@@ -1551,7 +1540,12 @@ where
self.unwrap_or_else(|err| panic!("{}", err))
}
fn unwrap_error_sink(self, error_sink: &ErrorSink, fallback: impl FnOnce() -> T) -> T {
fn unwrap_error_sink(
self,
error_sink: &ErrorSink,
context: &Context,
fallback: impl FnOnce() -> T,
) -> T {
self.unwrap_or_else(|err| {
let error_sink = error_sink.lock();
@@ -1573,8 +1567,10 @@ where
}
// Otherwise, it is a validation error
let desc = format_error(&err, context);
error_sink.handle_error(crate::Error::ValidationError {
source: Box::new(err),
description: desc,
});
fallback()
})
@@ -1582,33 +1578,35 @@ where
}
trait WithContextError: Error + Send + Sync + 'static + Sized {
fn with_context(self, string: String) -> ContextError<Self>;
fn with_context(self, string: &str, label: Option<&str>) -> ContextError;
}
impl<E: Error + Send + Sync + 'static> WithContextError for E {
fn with_context(self, string: String) -> ContextError<Self> {
fn with_context(self, string: &str, label: Option<&str>) -> ContextError {
ContextError {
string,
cause: self,
string: string.to_string(),
cause: Box::new(self),
label: label.unwrap_or("").to_string(),
}
}
}
#[derive(Debug)]
struct ContextError<E: Error + Send + Sync + 'static> {
string: String,
cause: E,
pub(crate) struct ContextError {
pub string: String,
pub cause: Box<dyn Error + Send + Sync + 'static>,
pub label: String,
}
impl<E: Error + Send + Sync + 'static> Display for ContextError<E> {
impl Display for ContextError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.string)
}
}
impl<E: Error + Send + Sync + 'static> Error for ContextError<E> {
impl Error for ContextError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.cause)
Some(self.cause.as_ref())
}
}
@@ -1638,15 +1636,5 @@ impl Debug for ErrorSinkRaw {
fn default_error_handler(err: crate::Error) {
eprintln!("wgpu error: {}\n", err);
if err.source().is_some() {
eprintln!("Caused by:");
let mut source_opt = err.source();
while let Some(source) = source_opt {
eprintln!(" {}", source);
source_opt = source.source();
}
eprintln!();
}
panic!("Handling wgpu errors as fatal by default");
}

238
wgpu/src/backend/error.rs Normal file
View File

@@ -0,0 +1,238 @@
use std::{error::Error, fmt::Display};
use super::Context;
pub(crate) fn format_error(err: &(impl Error + 'static), context: &Context) -> String {
let mut err_descs = Vec::new();
err_descs.push(fmt_pretty_any(err, context));
let mut source_opt = err.source();
while let Some(source) = source_opt {
err_descs.push(fmt_pretty_any(source, context));
source_opt = source.source();
}
let desc = format!("Validation Error\n\nCaused by:\n{}", err_descs.join(""));
desc
}
fn fmt_pretty_any(error: &(dyn Error + 'static), context: &Context) -> String {
if let Some(pretty_err) = error.downcast_ref::<super::direct::ContextError>() {
return pretty_err.fmt_pretty(context);
}
if let Some(pretty_err) = error.downcast_ref::<wgc::command::RenderCommandError>() {
return pretty_err.fmt_pretty(context);
}
if let Some(pretty_err) = error.downcast_ref::<wgc::binding_model::CreateBindGroupError>() {
return pretty_err.fmt_pretty(context);
}
if let Some(pretty_err) = error.downcast_ref::<wgc::binding_model::CreatePipelineLayoutError>()
{
return pretty_err.fmt_pretty(context);
}
if let Some(pretty_err) = error.downcast_ref::<wgc::command::ExecutionError>() {
return pretty_err.fmt_pretty(context);
}
if let Some(pretty_err) = error.downcast_ref::<wgc::command::RenderPassErrorInner>() {
return pretty_err.fmt_pretty(context);
}
if let Some(pretty_err) = error.downcast_ref::<wgc::command::ComputePassErrorInner>() {
return pretty_err.fmt_pretty(context);
}
if let Some(pretty_err) = error.downcast_ref::<wgc::command::TransferError>() {
return pretty_err.fmt_pretty(context);
}
// default
format_error_line(error.as_display())
}
pub(crate) fn format_error_line(err: &dyn Display) -> String {
format!(" {}\n", err)
}
pub(crate) fn format_note_line(note: &dyn Display) -> String {
format!(" note: {}\n", note)
}
pub(crate) fn format_label_line(label_key: &str, label_value: &str) -> String {
if label_key.is_empty() || label_value.is_empty() {
String::new()
} else {
format_note_line(&format!("{} = `{}`", label_key, label_value))
}
}
trait AsDisplay {
fn as_display(&self) -> &dyn Display;
}
impl<T: Display> AsDisplay for T {
fn as_display(&self) -> &dyn Display {
self
}
}
pub trait PrettyError: Error {
fn fmt_pretty(&self, _context: &Context) -> String {
format_error_line(self.as_display())
}
}
impl PrettyError for super::direct::ContextError {
fn fmt_pretty(&self, _context: &Context) -> String {
format_error_line(self.as_display()) + &format_label_line("label", &self.label)
}
}
impl PrettyError for wgc::command::RenderCommandError {
fn fmt_pretty(&self, context: &Context) -> String {
let global = context.global();
let mut ret = format_error_line(self);
match *self {
Self::InvalidBindGroup(id) => {
let name = wgc::gfx_select!(id => global.bind_group_label(id));
ret.push_str(&format_label_line("bind group", &name));
}
Self::InvalidPipeline(id) => {
let name = wgc::gfx_select!(id => global.render_pipeline_label(id));
ret.push_str(&format_label_line("render pipeline", &name));
}
Self::Buffer(id, ..) | Self::DestroyedBuffer(id) => {
let name = wgc::gfx_select!(id => global.buffer_label(id));
ret.push_str(&format_label_line("buffer", &name));
}
_ => {}
};
ret
}
}
impl PrettyError for wgc::binding_model::CreateBindGroupError {
fn fmt_pretty(&self, context: &Context) -> String {
let global = context.global();
let mut ret = format_error_line(self);
match *self {
Self::InvalidBuffer(id) => {
let name = wgc::gfx_select!(id => global.buffer_label(id));
ret.push_str(&format_label_line("buffer", &name));
}
Self::InvalidTextureView(id) => {
let name = wgc::gfx_select!(id => global.texture_view_label(id));
ret.push_str(&format_label_line("texture view", &name));
}
Self::InvalidSampler(id) => {
let name = wgc::gfx_select!(id => global.sampler_label(id));
ret.push_str(&format_label_line("sampler", &name));
}
_ => {}
};
ret
}
}
impl PrettyError for wgc::binding_model::CreatePipelineLayoutError {
fn fmt_pretty(&self, context: &Context) -> String {
let global = context.global();
let mut ret = format_error_line(self);
match *self {
Self::InvalidBindGroupLayout(id) => {
let name = wgc::gfx_select!(id => global.bind_group_layout_label(id));
ret.push_str(&format_label_line("bind group layout", &name));
}
_ => {}
};
ret
}
}
impl PrettyError for wgc::command::ExecutionError {
fn fmt_pretty(&self, context: &Context) -> String {
let global = context.global();
let mut ret = format_error_line(self);
match *self {
Self::DestroyedBuffer(id) => {
let name = wgc::gfx_select!(id => global.buffer_label(id));
ret.push_str(&format_label_line("buffer", &name));
}
};
ret
}
}
impl PrettyError for wgc::command::RenderPassErrorInner {
fn fmt_pretty(&self, context: &Context) -> String {
let global = context.global();
let mut ret = format_error_line(self);
match *self {
Self::InvalidAttachment(id) => {
let name = wgc::gfx_select!(id => global.texture_view_label(id));
ret.push_str(&format_label_line("attachment", &name));
}
_ => {}
};
ret
}
}
impl PrettyError for wgc::command::ComputePassErrorInner {
fn fmt_pretty(&self, context: &Context) -> String {
let global = context.global();
let mut ret = format_error_line(self);
match *self {
Self::InvalidBindGroup(id) => {
let name = wgc::gfx_select!(id => global.bind_group_label(id));
ret.push_str(&format_label_line("bind group", &name));
}
Self::InvalidPipeline(id) => {
let name = wgc::gfx_select!(id => global.compute_pipeline_label(id));
ret.push_str(&format_label_line("pipeline", &name));
}
Self::InvalidIndirectBuffer(id) => {
let name = wgc::gfx_select!(id => global.buffer_label(id));
ret.push_str(&format_label_line("indirect buffer", &name));
}
_ => {}
};
ret
}
}
impl PrettyError for wgc::command::TransferError {
fn fmt_pretty(&self, context: &Context) -> String {
let global = context.global();
let mut ret = format_error_line(self);
match *self {
Self::InvalidBuffer(id) => {
let name = wgc::gfx_select!(id => global.buffer_label(id));
ret.push_str(&format_label_line("label", &name));
}
Self::InvalidTexture(id) => {
let name = wgc::gfx_select!(id => global.texture_label(id));
ret.push_str(&format_label_line("texture", &name));
}
// Self::MissingCopySrcUsageFlag(buf_opt, tex_opt) => {
// if let Some(buf) = buf_opt {
// let name = wgc::gfx_select!(buf => global.buffer_label(buf));
// ret.push_str(&format_label_line("source", &name));
// }
// if let Some(tex) = tex_opt {
// let name = wgc::gfx_select!(tex => global.texture_label(tex));
// ret.push_str(&format_label_line("source", &name));
// }
// }
Self::MissingCopyDstUsageFlag(buf_opt, tex_opt) => {
if let Some(buf) = buf_opt {
let name = wgc::gfx_select!(buf => global.buffer_label(buf));
ret.push_str(&format_label_line("destination", &name));
}
if let Some(tex) = tex_opt {
let name = wgc::gfx_select!(tex => global.texture_label(tex));
ret.push_str(&format_label_line("destination", &name));
}
}
_ => {}
};
ret
}
}

View File

@@ -5,6 +5,8 @@ pub(crate) use web::Context;
#[cfg(not(target_arch = "wasm32"))]
mod direct;
#[cfg(not(target_arch = "wasm32"))]
mod error;
#[cfg(not(target_arch = "wasm32"))]
pub(crate) use direct::Context;

View File

@@ -2696,6 +2696,8 @@ pub enum Error {
ValidationError {
///
source: Box<dyn error::Error + Send + Sync + 'static>,
///
description: String,
},
}
@@ -2703,7 +2705,7 @@ impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
Error::OutOfMemoryError { source } => Some(source.as_ref()),
Error::ValidationError { source } => Some(source.as_ref()),
Error::ValidationError { source, .. } => Some(source.as_ref()),
}
}
}
@@ -2712,7 +2714,7 @@ impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::OutOfMemoryError { .. } => f.write_str("Out of Memory"),
Error::ValidationError { .. } => f.write_str("Validation error"),
Error::ValidationError { description, .. } => f.write_str(description),
}
}
}