wgpu/api/
device.rs

1use std::{error, fmt, future::Future, sync::Arc};
2
3use parking_lot::Mutex;
4
5use crate::api::blas::{Blas, BlasGeometrySizeDescriptors, CreateBlasDescriptor};
6use crate::api::tlas::{CreateTlasDescriptor, Tlas};
7use crate::*;
8
9/// Open connection to a graphics and/or compute device.
10///
11/// Responsible for the creation of most rendering and compute resources.
12/// These are then used in commands, which are submitted to a [`Queue`].
13///
14/// A device may be requested from an adapter with [`Adapter::request_device`].
15///
16/// Corresponds to [WebGPU `GPUDevice`](https://gpuweb.github.io/gpuweb/#gpu-device).
17#[derive(Debug, Clone)]
18pub struct Device {
19    pub(crate) inner: dispatch::DispatchDevice,
20}
21#[cfg(send_sync)]
22static_assertions::assert_impl_all!(Device: Send, Sync);
23
24crate::cmp::impl_eq_ord_hash_proxy!(Device => .inner);
25
26/// Describes a [`Device`].
27///
28/// For use with [`Adapter::request_device`].
29///
30/// Corresponds to [WebGPU `GPUDeviceDescriptor`](
31/// https://gpuweb.github.io/gpuweb/#dictdef-gpudevicedescriptor).
32pub type DeviceDescriptor<'a> = wgt::DeviceDescriptor<Label<'a>>;
33static_assertions::assert_impl_all!(DeviceDescriptor<'_>: Send, Sync);
34
35impl Device {
36    /// Check for resource cleanups and mapping callbacks. Will block if [`Maintain::Wait`] is passed.
37    ///
38    /// Return `true` if the queue is empty, or `false` if there are more queue
39    /// submissions still in flight. (Note that, unless access to the [`Queue`] is
40    /// coordinated somehow, this information could be out of date by the time
41    /// the caller receives it. `Queue`s can be shared between threads, so
42    /// other threads could submit new work at any time.)
43    ///
44    /// When running on WebGPU, this is a no-op. `Device`s are automatically polled.
45    pub fn poll(&self, maintain: Maintain) -> MaintainResult {
46        self.inner.poll(maintain)
47    }
48
49    /// The features which can be used on this device.
50    ///
51    /// No additional features can be used, even if the underlying adapter can support them.
52    #[must_use]
53    pub fn features(&self) -> Features {
54        self.inner.features()
55    }
56
57    /// The limits which can be used on this device.
58    ///
59    /// No better limits can be used, even if the underlying adapter can support them.
60    #[must_use]
61    pub fn limits(&self) -> Limits {
62        self.inner.limits()
63    }
64
65    /// Creates a shader module.
66    ///
67    /// <div class="warning">
68    // NOTE: Keep this in sync with `naga::front::wgsl::parse_str`!
69    // NOTE: Keep this in sync with `wgpu_core::Global::device_create_shader_module`!
70    ///
71    /// This function may consume a lot of stack space. Compiler-enforced limits for parsing
72    /// recursion exist; if shader compilation runs into them, it will return an error gracefully.
73    /// However, on some build profiles and platforms, the default stack size for a thread may be
74    /// exceeded before this limit is reached during parsing. Callers should ensure that there is
75    /// enough stack space for this, particularly if calls to this method are exposed to user
76    /// input.
77    ///
78    /// </div>
79    #[must_use]
80    pub fn create_shader_module(&self, desc: ShaderModuleDescriptor<'_>) -> ShaderModule {
81        let module = self
82            .inner
83            .create_shader_module(desc, wgt::ShaderRuntimeChecks::checked());
84        ShaderModule { inner: module }
85    }
86
87    /// Deprecated: Use [`create_shader_module_trusted`][csmt] instead.
88    ///
89    /// # Safety
90    ///
91    /// See [`create_shader_module_trusted`][csmt].
92    ///
93    /// [csmt]: Self::create_shader_module_trusted
94    #[deprecated(
95        since = "24.0.0",
96        note = "Use `Device::create_shader_module_trusted(desc, wgpu::ShaderRuntimeChecks::unchecked())` instead."
97    )]
98    #[must_use]
99    pub unsafe fn create_shader_module_unchecked(
100        &self,
101        desc: ShaderModuleDescriptor<'_>,
102    ) -> ShaderModule {
103        unsafe { self.create_shader_module_trusted(desc, crate::ShaderRuntimeChecks::unchecked()) }
104    }
105
106    /// Creates a shader module with flags to dictate runtime checks.
107    ///
108    /// When running on WebGPU, this will merely call [`create_shader_module`][csm].
109    ///
110    /// # Safety
111    ///
112    /// In contrast with [`create_shader_module`][csm] this function
113    /// creates a shader module with user-customizable runtime checks which allows shaders to
114    /// perform operations which can lead to undefined behavior like indexing out of bounds,
115    /// thus it's the caller responsibility to pass a shader which doesn't perform any of this
116    /// operations.
117    ///
118    /// See the documentation for [`ShaderRuntimeChecks`][src] for more information about specific checks.
119    ///
120    /// [csm]: Self::create_shader_module
121    /// [src]: crate::ShaderRuntimeChecks
122    #[must_use]
123    pub unsafe fn create_shader_module_trusted(
124        &self,
125        desc: ShaderModuleDescriptor<'_>,
126        runtime_checks: crate::ShaderRuntimeChecks,
127    ) -> ShaderModule {
128        let module = self.inner.create_shader_module(desc, runtime_checks);
129        ShaderModule { inner: module }
130    }
131
132    /// Creates a shader module from SPIR-V binary directly.
133    ///
134    /// # Safety
135    ///
136    /// This function passes binary data to the backend as-is and can potentially result in a
137    /// driver crash or bogus behaviour. No attempt is made to ensure that data is valid SPIR-V.
138    ///
139    /// See also [`include_spirv_raw!`] and [`util::make_spirv_raw`].
140    #[must_use]
141    pub unsafe fn create_shader_module_spirv(
142        &self,
143        desc: &ShaderModuleDescriptorSpirV<'_>,
144    ) -> ShaderModule {
145        let module = unsafe { self.inner.create_shader_module_spirv(desc) };
146        ShaderModule { inner: module }
147    }
148
149    /// Creates an empty [`CommandEncoder`].
150    #[must_use]
151    pub fn create_command_encoder(&self, desc: &CommandEncoderDescriptor<'_>) -> CommandEncoder {
152        let encoder = self.inner.create_command_encoder(desc);
153        CommandEncoder { inner: encoder }
154    }
155
156    /// Creates an empty [`RenderBundleEncoder`].
157    #[must_use]
158    pub fn create_render_bundle_encoder<'a>(
159        &self,
160        desc: &RenderBundleEncoderDescriptor<'_>,
161    ) -> RenderBundleEncoder<'a> {
162        let encoder = self.inner.create_render_bundle_encoder(desc);
163        RenderBundleEncoder {
164            inner: encoder,
165            _p: std::marker::PhantomData,
166        }
167    }
168
169    /// Creates a new [`BindGroup`].
170    #[must_use]
171    pub fn create_bind_group(&self, desc: &BindGroupDescriptor<'_>) -> BindGroup {
172        let group = self.inner.create_bind_group(desc);
173        BindGroup { inner: group }
174    }
175
176    /// Creates a [`BindGroupLayout`].
177    #[must_use]
178    pub fn create_bind_group_layout(
179        &self,
180        desc: &BindGroupLayoutDescriptor<'_>,
181    ) -> BindGroupLayout {
182        let layout = self.inner.create_bind_group_layout(desc);
183        BindGroupLayout { inner: layout }
184    }
185
186    /// Creates a [`PipelineLayout`].
187    #[must_use]
188    pub fn create_pipeline_layout(&self, desc: &PipelineLayoutDescriptor<'_>) -> PipelineLayout {
189        let layout = self.inner.create_pipeline_layout(desc);
190        PipelineLayout { inner: layout }
191    }
192
193    /// Creates a [`RenderPipeline`].
194    #[must_use]
195    pub fn create_render_pipeline(&self, desc: &RenderPipelineDescriptor<'_>) -> RenderPipeline {
196        let pipeline = self.inner.create_render_pipeline(desc);
197        RenderPipeline { inner: pipeline }
198    }
199
200    /// Creates a [`ComputePipeline`].
201    #[must_use]
202    pub fn create_compute_pipeline(&self, desc: &ComputePipelineDescriptor<'_>) -> ComputePipeline {
203        let pipeline = self.inner.create_compute_pipeline(desc);
204        ComputePipeline { inner: pipeline }
205    }
206
207    /// Creates a [`Buffer`].
208    #[must_use]
209    pub fn create_buffer(&self, desc: &BufferDescriptor<'_>) -> Buffer {
210        let mut map_context = MapContext::new(desc.size);
211        if desc.mapped_at_creation {
212            map_context.initial_range = 0..desc.size;
213        }
214
215        let buffer = self.inner.create_buffer(desc);
216
217        Buffer {
218            inner: buffer,
219            map_context: Arc::new(Mutex::new(map_context)),
220            size: desc.size,
221            usage: desc.usage,
222        }
223    }
224
225    /// Creates a new [`Texture`].
226    ///
227    /// `desc` specifies the general format of the texture.
228    #[must_use]
229    pub fn create_texture(&self, desc: &TextureDescriptor<'_>) -> Texture {
230        let texture = self.inner.create_texture(desc);
231
232        Texture {
233            inner: texture,
234            descriptor: TextureDescriptor {
235                label: None,
236                view_formats: &[],
237                ..desc.clone()
238            },
239        }
240    }
241
242    /// Creates a [`Texture`] from a wgpu-hal Texture.
243    ///
244    /// # Safety
245    ///
246    /// - `hal_texture` must be created from this device internal handle
247    /// - `hal_texture` must be created respecting `desc`
248    /// - `hal_texture` must be initialized
249    #[cfg(wgpu_core)]
250    #[must_use]
251    pub unsafe fn create_texture_from_hal<A: wgc::hal_api::HalApi>(
252        &self,
253        hal_texture: A::Texture,
254        desc: &TextureDescriptor<'_>,
255    ) -> Texture {
256        let texture = unsafe {
257            let core_device = self.inner.as_core();
258            core_device
259                .context
260                .create_texture_from_hal::<A>(hal_texture, core_device, desc)
261        };
262        Texture {
263            inner: texture.into(),
264            descriptor: TextureDescriptor {
265                label: None,
266                view_formats: &[],
267                ..desc.clone()
268            },
269        }
270    }
271
272    /// Creates a [`Buffer`] from a wgpu-hal Buffer.
273    ///
274    /// # Safety
275    ///
276    /// - `hal_buffer` must be created from this device internal handle
277    /// - `hal_buffer` must be created respecting `desc`
278    /// - `hal_buffer` must be initialized
279    #[cfg(wgpu_core)]
280    #[must_use]
281    pub unsafe fn create_buffer_from_hal<A: wgc::hal_api::HalApi>(
282        &self,
283        hal_buffer: A::Buffer,
284        desc: &BufferDescriptor<'_>,
285    ) -> Buffer {
286        let mut map_context = MapContext::new(desc.size);
287        if desc.mapped_at_creation {
288            map_context.initial_range = 0..desc.size;
289        }
290
291        let buffer = unsafe {
292            let core_device = self.inner.as_core();
293            core_device
294                .context
295                .create_buffer_from_hal::<A>(hal_buffer, core_device, desc)
296        };
297
298        Buffer {
299            inner: buffer.into(),
300            map_context: Arc::new(Mutex::new(map_context)),
301            size: desc.size,
302            usage: desc.usage,
303        }
304    }
305
306    /// Creates a new [`Sampler`].
307    ///
308    /// `desc` specifies the behavior of the sampler.
309    #[must_use]
310    pub fn create_sampler(&self, desc: &SamplerDescriptor<'_>) -> Sampler {
311        let sampler = self.inner.create_sampler(desc);
312        Sampler { inner: sampler }
313    }
314
315    /// Creates a new [`QuerySet`].
316    #[must_use]
317    pub fn create_query_set(&self, desc: &QuerySetDescriptor<'_>) -> QuerySet {
318        let query_set = self.inner.create_query_set(desc);
319        QuerySet { inner: query_set }
320    }
321
322    /// Set a callback for errors that are not handled in error scopes.
323    pub fn on_uncaptured_error(&self, handler: Box<dyn UncapturedErrorHandler>) {
324        self.inner.on_uncaptured_error(handler)
325    }
326
327    /// Push an error scope.
328    pub fn push_error_scope(&self, filter: ErrorFilter) {
329        self.inner.push_error_scope(filter)
330    }
331
332    /// Pop an error scope.
333    pub fn pop_error_scope(&self) -> impl Future<Output = Option<Error>> + WasmNotSend {
334        self.inner.pop_error_scope()
335    }
336
337    /// Starts frame capture.
338    pub fn start_capture(&self) {
339        self.inner.start_capture()
340    }
341
342    /// Stops frame capture.
343    pub fn stop_capture(&self) {
344        self.inner.stop_capture()
345    }
346
347    /// Query internal counters from the native backend for debugging purposes.
348    ///
349    /// Some backends may not set all counters, or may not set any counter at all.
350    /// The `counters` cargo feature must be enabled for any counter to be set.
351    ///
352    /// If a counter is not set, its contains its default value (zero).
353    #[must_use]
354    pub fn get_internal_counters(&self) -> wgt::InternalCounters {
355        self.inner.get_internal_counters()
356    }
357
358    /// Generate an GPU memory allocation report if the underlying backend supports it.
359    ///
360    /// Backends that do not support producing these reports return `None`. A backend may
361    /// Support it and still return `None` if it is not using performing sub-allocation,
362    /// for example as a workaround for driver issues.
363    #[must_use]
364    pub fn generate_allocator_report(&self) -> Option<wgt::AllocatorReport> {
365        self.inner.generate_allocator_report()
366    }
367
368    /// Apply a callback to this `Device`'s underlying backend device.
369    ///
370    /// If this `Device` is implemented by the backend API given by `A` (Vulkan,
371    /// Dx12, etc.), then apply `hal_device_callback` to `Some(&device)`, where
372    /// `device` is the underlying backend device type, [`A::Device`].
373    ///
374    /// If this `Device` uses a different backend, apply `hal_device_callback`
375    /// to `None`.
376    ///
377    /// The device is locked for reading while `hal_device_callback` runs. If
378    /// the callback attempts to perform any `wgpu` operations that require
379    /// write access to the device (destroying a buffer, say), deadlock will
380    /// occur. The locks are automatically released when the callback returns.
381    ///
382    /// # Safety
383    ///
384    /// - The raw handle passed to the callback must not be manually destroyed.
385    ///
386    /// [`A::Device`]: hal::Api::Device
387    #[cfg(wgpu_core)]
388    pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Device>) -> R, R>(
389        &self,
390        hal_device_callback: F,
391    ) -> R {
392        if let Some(core_device) = self.inner.as_core_opt() {
393            unsafe {
394                core_device
395                    .context
396                    .device_as_hal::<A, F, R>(core_device, hal_device_callback)
397            }
398        } else {
399            hal_device_callback(None)
400        }
401    }
402
403    /// Destroy this device.
404    pub fn destroy(&self) {
405        self.inner.destroy()
406    }
407
408    /// Set a DeviceLostCallback on this device.
409    pub fn set_device_lost_callback(
410        &self,
411        callback: impl Fn(DeviceLostReason, String) + Send + 'static,
412    ) {
413        self.inner.set_device_lost_callback(Box::new(callback))
414    }
415
416    /// Create a [`PipelineCache`] with initial data
417    ///
418    /// This can be passed to [`Device::create_compute_pipeline`]
419    /// and [`Device::create_render_pipeline`] to either accelerate these
420    /// or add the cache results from those.
421    ///
422    /// # Safety
423    ///
424    /// If the `data` field of `desc` is set, it must have previously been returned from a call
425    /// to [`PipelineCache::get_data`][^saving]. This `data` will only be used if it came
426    /// from an adapter with the same [`util::pipeline_cache_key`].
427    /// This *is* compatible across wgpu versions, as any data format change will
428    /// be accounted for.
429    ///
430    /// It is *not* supported to bring caches from previous direct uses of backend APIs
431    /// into this method.
432    ///
433    /// # Errors
434    ///
435    /// Returns an error value if:
436    ///  * the [`PIPELINE_CACHE`](wgt::Features::PIPELINE_CACHE) feature is not enabled
437    ///  * this device is invalid; or
438    ///  * the device is out of memory
439    ///
440    /// This method also returns an error value if:
441    ///  * The `fallback` field on `desc` is false; and
442    ///  * the `data` provided would not be used[^data_not_used]
443    ///
444    /// If an error value is used in subsequent calls, default caching will be used.
445    ///
446    /// [^saving]: We do recognise that saving this data to disk means this condition
447    /// is impossible to fully prove. Consider the risks for your own application in this case.
448    ///
449    /// [^data_not_used]: This data may be not used if: the data was produced by a prior
450    /// version of wgpu; or was created for an incompatible adapter, or there was a GPU driver
451    /// update. In some cases, the data might not be used and a real value is returned,
452    /// this is left to the discretion of GPU drivers.
453    #[must_use]
454    pub unsafe fn create_pipeline_cache(
455        &self,
456        desc: &PipelineCacheDescriptor<'_>,
457    ) -> PipelineCache {
458        let cache = unsafe { self.inner.create_pipeline_cache(desc) };
459        PipelineCache { inner: cache }
460    }
461}
462
463/// [`Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE`] must be enabled on the device in order to call these functions.
464impl Device {
465    /// Create a bottom level acceleration structure, used inside a top level acceleration structure for ray tracing.
466    /// - `desc`: The descriptor of the acceleration structure.
467    /// - `sizes`: Size descriptor limiting what can be built into the acceleration structure.
468    ///
469    /// # Validation
470    /// If any of the following is not satisfied a validation error is generated
471    ///
472    /// The device ***must*** have [Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE] enabled.
473    /// if `sizes` is [BlasGeometrySizeDescriptors::Triangles] then the following must be satisfied
474    /// - For every geometry descriptor (for the purposes this is called `geo_desc`) of `sizes.descriptors` the following must be satisfied:
475    ///     - `geo_desc.vertex_format` must be within allowed formats (allowed formats for a given feature set
476    ///       may be queried with [Features::allowed_vertex_formats_for_blas]).
477    ///     - Both or neither of `geo_desc.index_format` and `geo_desc.index_count` must be provided.
478    ///
479    /// [Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE]: wgt::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE
480    /// [Features::allowed_vertex_formats_for_blas]: wgt::Features::allowed_vertex_formats_for_blas
481    #[must_use]
482    pub fn create_blas(
483        &self,
484        desc: &CreateBlasDescriptor<'_>,
485        sizes: BlasGeometrySizeDescriptors,
486    ) -> Blas {
487        let (handle, blas) = self.inner.create_blas(desc, sizes);
488
489        Blas {
490            inner: blas,
491            handle,
492        }
493    }
494
495    /// Create a top level acceleration structure, used for ray tracing.
496    /// - `desc`: The descriptor of the acceleration structure.
497    ///
498    /// # Validation
499    /// If any of the following is not satisfied a validation error is generated
500    ///
501    /// The device ***must*** have [Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE] enabled.
502    ///
503    /// [Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE]: wgt::Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE
504    #[must_use]
505    pub fn create_tlas(&self, desc: &CreateTlasDescriptor<'_>) -> Tlas {
506        let tlas = self.inner.create_tlas(desc);
507
508        Tlas {
509            shared: Arc::new(TlasShared {
510                inner: tlas,
511                max_instances: desc.max_instances,
512            }),
513        }
514    }
515}
516
517/// Requesting a device from an [`Adapter`] failed.
518#[derive(Clone, Debug)]
519pub struct RequestDeviceError {
520    pub(crate) inner: RequestDeviceErrorKind,
521}
522#[derive(Clone, Debug)]
523pub(crate) enum RequestDeviceErrorKind {
524    /// Error from [`wgpu_core`].
525    // must match dependency cfg
526    #[cfg(wgpu_core)]
527    Core(wgc::instance::RequestDeviceError),
528
529    /// Error from web API that was called by `wgpu` to request a device.
530    ///
531    /// (This is currently never used by the webgl backend, but it could be.)
532    #[cfg(webgpu)]
533    WebGpu(wasm_bindgen::JsValue),
534}
535
536#[cfg(send_sync)]
537unsafe impl Send for RequestDeviceErrorKind {}
538#[cfg(send_sync)]
539unsafe impl Sync for RequestDeviceErrorKind {}
540
541#[cfg(send_sync)]
542static_assertions::assert_impl_all!(RequestDeviceError: Send, Sync);
543
544impl fmt::Display for RequestDeviceError {
545    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
546        match &self.inner {
547            #[cfg(wgpu_core)]
548            RequestDeviceErrorKind::Core(error) => error.fmt(_f),
549            #[cfg(webgpu)]
550            RequestDeviceErrorKind::WebGpu(error_js_value) => {
551                // wasm-bindgen provides a reasonable error stringification via `Debug` impl
552                write!(_f, "{error_js_value:?}")
553            }
554            #[cfg(not(any(webgpu, wgpu_core)))]
555            _ => unimplemented!("unknown `RequestDeviceErrorKind`"),
556        }
557    }
558}
559
560impl error::Error for RequestDeviceError {
561    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
562        match &self.inner {
563            #[cfg(wgpu_core)]
564            RequestDeviceErrorKind::Core(error) => error.source(),
565            #[cfg(webgpu)]
566            RequestDeviceErrorKind::WebGpu(_) => None,
567            #[cfg(not(any(webgpu, wgpu_core)))]
568            _ => unimplemented!("unknown `RequestDeviceErrorKind`"),
569        }
570    }
571}
572
573#[cfg(wgpu_core)]
574impl From<wgc::instance::RequestDeviceError> for RequestDeviceError {
575    fn from(error: wgc::instance::RequestDeviceError) -> Self {
576        Self {
577            inner: RequestDeviceErrorKind::Core(error),
578        }
579    }
580}
581
582/// Type for the callback of uncaptured error handler
583pub trait UncapturedErrorHandler: Fn(Error) + Send + 'static {}
584impl<T> UncapturedErrorHandler for T where T: Fn(Error) + Send + 'static {}
585
586/// Filter for error scopes.
587#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd)]
588pub enum ErrorFilter {
589    /// Catch only out-of-memory errors.
590    OutOfMemory,
591    /// Catch only validation errors.
592    Validation,
593    /// Catch only internal errors.
594    Internal,
595}
596static_assertions::assert_impl_all!(ErrorFilter: Send, Sync);
597
598/// Lower level source of the error.
599///
600/// `Send + Sync` varies depending on configuration.
601#[cfg(send_sync)]
602#[cfg_attr(docsrs, doc(cfg(all())))]
603pub type ErrorSource = Box<dyn error::Error + Send + Sync + 'static>;
604/// Lower level source of the error.
605///
606/// `Send + Sync` varies depending on configuration.
607#[cfg(not(send_sync))]
608#[cfg_attr(docsrs, doc(cfg(all())))]
609pub type ErrorSource = Box<dyn error::Error + 'static>;
610
611/// Error type
612#[derive(Debug)]
613pub enum Error {
614    /// Out of memory error
615    OutOfMemory {
616        /// Lower level source of the error.
617        source: ErrorSource,
618    },
619    /// Validation error, signifying a bug in code or data
620    Validation {
621        /// Lower level source of the error.
622        source: ErrorSource,
623        /// Description of the validation error.
624        description: String,
625    },
626    /// Internal error. Used for signalling any failures not explicitly expected by WebGPU.
627    ///
628    /// These could be due to internal implementation or system limits being reached.
629    Internal {
630        /// Lower level source of the error.
631        source: ErrorSource,
632        /// Description of the internal GPU error.
633        description: String,
634    },
635}
636#[cfg(send_sync)]
637static_assertions::assert_impl_all!(Error: Send, Sync);
638
639impl error::Error for Error {
640    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
641        match self {
642            Error::OutOfMemory { source } => Some(source.as_ref()),
643            Error::Validation { source, .. } => Some(source.as_ref()),
644            Error::Internal { source, .. } => Some(source.as_ref()),
645        }
646    }
647}
648
649impl fmt::Display for Error {
650    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
651        match self {
652            Error::OutOfMemory { .. } => f.write_str("Out of Memory"),
653            Error::Validation { description, .. } => f.write_str(description),
654            Error::Internal { description, .. } => f.write_str(description),
655        }
656    }
657}