Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/gfx/wgpu_bindings/src/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 27 kB image not shown  

SSL error.rs   Sprache: unbekannt

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Types needed to marshal [`server`](crate::server) errors back to C++ in Firefox. The main type
//! of this module is [`ErrorBuffer`](crate::server::ErrorBuffer).

use std::{
    error::Error,
    fmt::{self, Display, Formatter},
    os::raw::c_char,
    ptr,
};

use serde::{Deserialize, Serialize};

/// A non-owning representation of `mozilla::webgpu::ErrorBuffer` in C++, passed as an argument to
/// other functions in [this module](self).
///
/// C++ callers of Rust functions (presumably in `WebGPUParent.cpp`) that expect one of these
/// structs can create a `mozilla::webgpu::ErrorBuffer` object, and call its `ToFFI` method to
/// construct a value of this type, available to C++ as `mozilla::webgpu::ffi::WGPUErrorBuffer`. If
/// we catch a `Result::Err` in other functions of [this module](self), the error is converted to
/// this type.
#[repr(C)]
pub struct ErrorBuffer {
    /// The type of error that `string` is associated with. If this location is set to
    /// [`ErrorBufferType::None`] after being passed as an argument to a function in [this module](self),
    /// then the remaining fields are guaranteed to not have been altered by that function from
    /// their original state.
    r#type: *mut ErrorBufferType,
    /// The (potentially truncated) message associated with this error. A fixed-capacity,
    /// null-terminated UTF-8 string buffer owned by C++.
    ///
    /// When we convert WGPU errors to this type, we render the error as a string, copying into
    /// `message` up to `capacity - 1`, and null-terminate it.
    message: *mut c_char,
    message_capacity: usize,
}

impl ErrorBuffer {
    /// Fill this buffer with the textual representation of `error`.
    ///
    /// If the error message is too long, truncate it to `self.capacity`. In either case, the error
    /// message is always terminated by a zero byte.
    ///
    /// Note that there is no explicit indication of the message's length, only the terminating zero
    /// byte. If the textual form of `error` itself includes a zero byte (as Rust strings can), then
    /// the C++ code receiving this error message has no way to distinguish that from the
    /// terminating zero byte, and will see the message as shorter than it is.
    pub(crate) fn init(&mut self, error: impl HasErrorBufferType) {
        use std::fmt::Write;

        let mut message = format!("{}", error);
        let mut e = error.source();
        while let Some(source) = e {
            write!(message, ", caused by: {}", source).unwrap();
            e = source.source();
        }

        let err_ty = error.error_type();
        // SAFETY: We presume the pointer provided by the caller is safe to write to.
        unsafe { *self.r#type = err_ty };

        if matches!(err_ty, ErrorBufferType::None) {
            log::warn!("{message}");
            return;
        }

        assert_ne!(self.message_capacity, 0);
        // Since we need to store a nul terminator after the content, the
        // content length must always be strictly less than the buffer's
        // capacity.
        let length = if message.len() >= self.message_capacity {
            // Thanks to the structure of UTF-8, `std::is_char_boundary` is
            // O(1), so this should examine a few bytes at most.
            //
            // The largest value in this range is `self.message_capacity - 1`,
            // which is a safe length.
            let truncated_length = (0..self.message_capacity)
                .rfind(|&offset| message.is_char_boundary(offset))
                .unwrap_or(0);
            log::warn!(
                "Error message's length {} reached capacity {}, truncating to {}",
                message.len(),
                self.message_capacity,
                truncated_length,
            );
            truncated_length
        } else {
            message.len()
        };
        unsafe {
            ptr::copy_nonoverlapping(message.as_ptr(), self.message as *mut u8, length);
            *self.message.add(length) = 0;
        }
    }
}

/// Corresponds to an optional discriminant of [`GPUError`] type in the WebGPU API. Strongly
/// correlates to [`GPUErrorFilter`]s.
///
/// [`GPUError`]: https://gpuweb.github.io/gpuweb/#gpuerror
/// [`GPUErrorFilter`]: https://gpuweb.github.io/gpuweb/#enumdef-gpuerrorfilter
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub(crate) enum ErrorBufferType {
    None = 0,
    DeviceLost = 1,
    Internal = 2,
    OutOfMemory = 3,
    Validation = 4,
}

/// A trait for querying the [`ErrorBufferType`] classification of an error. Used by
/// [`ErrorBuffer::init`](crate::server::ErrorBuffer::init).
pub(crate) trait HasErrorBufferType: Error {
    fn error_type(&self) -> ErrorBufferType;
}

/// Representation an error whose error message is already rendered as a [`&str`], and has no error
/// sources. Used for convenience in [`server`](crate::server) code.
#[derive(Clone, Debug)]
pub(crate) struct ErrMsg<'a> {
    pub(crate) message: &'a str,
    pub(crate) r#type: ErrorBufferType,
}

impl Display for ErrMsg<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let Self { message, r#type: _ } = self;
        write!(f, "{message}")
    }
}

impl Error for ErrMsg<'_> {}

impl HasErrorBufferType for ErrMsg<'_> {
    fn error_type(&self) -> ErrorBufferType {
        self.r#type
    }
}

/// Encapsulates implementations of [`HasErrorType`] for [`wgpu_core`] types.
mod foreign {
    use wgc::{
        binding_model::{
            CreateBindGroupError, CreateBindGroupLayoutError, CreatePipelineLayoutError,
            GetBindGroupLayoutError,
        },
        command::{
            ClearError, CommandEncoderError, ComputePassError, CopyError, CreateRenderBundleError,
            QueryError, QueryUseError, RenderBundleError, RenderPassError, ResolveError,
            TransferError,
        },
        device::{
            queue::{QueueSubmitError, QueueWriteError},
            DeviceError,
        },
        instance::{RequestAdapterError, RequestDeviceError},
        pipeline::{
            CreateComputePipelineError, CreateRenderPipelineError, CreateShaderModuleError,
        },
        resource::{
            BufferAccessError, CreateBufferError, CreateQuerySetError, CreateSamplerError,
            CreateTextureError, CreateTextureViewError, DestroyError,
        },
    };

    use super::{ErrorBufferType, HasErrorBufferType};

    impl HasErrorBufferType for RequestAdapterError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                RequestAdapterError::NotFound => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for RequestDeviceError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                RequestDeviceError::Device(e) => e.error_type(),

                RequestDeviceError::UnsupportedFeature(_)
                | RequestDeviceError::LimitsExceeded(_) => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for CreateBufferError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                CreateBufferError::Device(e) => e.error_type(),
                CreateBufferError::AccessError(e) => e.error_type(),

                CreateBufferError::UnalignedSize
                | CreateBufferError::InvalidUsage(_)
                | CreateBufferError::UsageMismatch(_)
                | CreateBufferError::MaxBufferSize { .. }
                | CreateBufferError::MissingDownlevelFlags(_) => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for BufferAccessError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                BufferAccessError::Device(e) => e.error_type(),

                BufferAccessError::Failed
                | BufferAccessError::InvalidResource(_)
                | BufferAccessError::DestroyedResource(_)
                | BufferAccessError::AlreadyMapped
                | BufferAccessError::MapAlreadyPending
                | BufferAccessError::MissingBufferUsage(_)
                | BufferAccessError::NotMapped
                | BufferAccessError::UnalignedRange
                | BufferAccessError::UnalignedOffset { .. }
                | BufferAccessError::UnalignedRangeSize { .. }
                | BufferAccessError::OutOfBoundsUnderrun { .. }
                | BufferAccessError::OutOfBoundsOverrun { .. }
                | BufferAccessError::NegativeRange { .. }
                | BufferAccessError::MapAborted => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for CreateTextureError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                CreateTextureError::Device(e) => e.error_type(),

                CreateTextureError::InvalidUsage(_)
                | CreateTextureError::InvalidDimension(_)
                | CreateTextureError::InvalidDepthDimension(_, _)
                | CreateTextureError::InvalidCompressedDimension(_, _)
                | CreateTextureError::InvalidMipLevelCount { .. }
                | CreateTextureError::InvalidFormatUsages(_, _, _)
                | CreateTextureError::InvalidViewFormat(_, _)
                | CreateTextureError::InvalidDimensionUsages(_, _)
                | CreateTextureError::InvalidMultisampledStorageBinding
                | CreateTextureError::InvalidMultisampledFormat(_)
                | CreateTextureError::InvalidSampleCount(..)
                | CreateTextureError::MultisampledNotRenderAttachment
                | CreateTextureError::MissingFeatures(_, _)
                | CreateTextureError::MissingDownlevelFlags(_) => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for CreateSamplerError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                CreateSamplerError::Device(e) => e.error_type(),

                CreateSamplerError::InvalidLodMinClamp(_)
                | CreateSamplerError::InvalidLodMaxClamp { .. }
                | CreateSamplerError::InvalidAnisotropy(_)
                | CreateSamplerError::InvalidFilterModeWithAnisotropy { .. }
                | CreateSamplerError::MissingFeatures(_) => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for CreateBindGroupLayoutError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                CreateBindGroupLayoutError::Device(e) => e.error_type(),

                CreateBindGroupLayoutError::ConflictBinding(_)
                | CreateBindGroupLayoutError::Entry { .. }
                | CreateBindGroupLayoutError::TooManyBindings(_)
                | CreateBindGroupLayoutError::InvalidBindingIndex { .. }
                | CreateBindGroupLayoutError::InvalidVisibility(_) => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for CreatePipelineLayoutError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                CreatePipelineLayoutError::Device(e) => e.error_type(),

                CreatePipelineLayoutError::InvalidResource(_)
                | CreatePipelineLayoutError::MisalignedPushConstantRange { .. }
                | CreatePipelineLayoutError::MissingFeatures(_)
                | CreatePipelineLayoutError::MoreThanOnePushConstantRangePerStage { .. }
                | CreatePipelineLayoutError::PushConstantRangeTooLarge { .. }
                | CreatePipelineLayoutError::TooManyBindings(_)
                | CreatePipelineLayoutError::TooManyGroups { .. } => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for CreateBindGroupError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                CreateBindGroupError::Device(e) => e.error_type(),

                CreateBindGroupError::InvalidResource(_)
                | CreateBindGroupError::BindingArrayPartialLengthMismatch { .. }
                | CreateBindGroupError::BindingArrayLengthMismatch { .. }
                | CreateBindGroupError::BindingArrayZeroLength
                | CreateBindGroupError::BindingRangeTooLarge { .. }
                | CreateBindGroupError::BindingSizeTooSmall { .. }
                | CreateBindGroupError::BindingZeroSize(_)
                | CreateBindGroupError::BindingsNumMismatch { .. }
                | CreateBindGroupError::DuplicateBinding(_)
                | CreateBindGroupError::MissingBindingDeclaration(_)
                | CreateBindGroupError::MissingBufferUsage(_)
                | CreateBindGroupError::MissingTextureUsage(_)
                | CreateBindGroupError::SingleBindingExpected
                | CreateBindGroupError::UnalignedBufferOffset(_, _, _)
                | CreateBindGroupError::BufferRangeTooLarge { .. }
                | CreateBindGroupError::WrongBindingType { .. }
                | CreateBindGroupError::InvalidTextureMultisample { .. }
                | CreateBindGroupError::InvalidTextureSampleType { .. }
                | CreateBindGroupError::InvalidTextureDimension { .. }
                | CreateBindGroupError::InvalidStorageTextureFormat { .. }
                | CreateBindGroupError::InvalidStorageTextureMipLevelCount { .. }
                | CreateBindGroupError::WrongSamplerComparison { .. }
                | CreateBindGroupError::WrongSamplerFiltering { .. }
                | CreateBindGroupError::DepthStencilAspect
                | CreateBindGroupError::StorageReadNotSupported(_)
                | CreateBindGroupError::ResourceUsageCompatibility(_)
                | CreateBindGroupError::DestroyedResource(_) => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for CreateShaderModuleError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                CreateShaderModuleError::Device(e) => e.error_type(),

                CreateShaderModuleError::Generation => ErrorBufferType::Internal,

                CreateShaderModuleError::Parsing(_)
                | CreateShaderModuleError::Validation(_)
                | CreateShaderModuleError::MissingFeatures(_)
                | CreateShaderModuleError::InvalidGroupIndex { .. } => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for CreateComputePipelineError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                CreateComputePipelineError::Device(e) => e.error_type(),

                CreateComputePipelineError::Internal(_) => ErrorBufferType::Internal,

                CreateComputePipelineError::InvalidResource(_)
                | CreateComputePipelineError::Implicit(_)
                | CreateComputePipelineError::Stage(_)
                | CreateComputePipelineError::MissingDownlevelFlags(_) => {
                    ErrorBufferType::Validation
                }

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for CreateRenderPipelineError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                CreateRenderPipelineError::Device(e) => e.error_type(),

                CreateRenderPipelineError::Internal { .. } => ErrorBufferType::Internal,

                CreateRenderPipelineError::ColorAttachment(_)
                | CreateRenderPipelineError::InvalidResource(_)
                | CreateRenderPipelineError::Implicit(_)
                | CreateRenderPipelineError::ColorState(_, _)
                | CreateRenderPipelineError::DepthStencilState(_)
                | CreateRenderPipelineError::InvalidSampleCount(_)
                | CreateRenderPipelineError::TooManyVertexBuffers { .. }
                | CreateRenderPipelineError::TooManyVertexAttributes { .. }
                | CreateRenderPipelineError::VertexStrideTooLarge { .. }
                | CreateRenderPipelineError::UnalignedVertexStride { .. }
                | CreateRenderPipelineError::InvalidVertexAttributeOffset { .. }
                | CreateRenderPipelineError::ShaderLocationClash(_)
                | CreateRenderPipelineError::StripIndexFormatForNonStripTopology { .. }
                | CreateRenderPipelineError::ConservativeRasterizationNonFillPolygonMode
                | CreateRenderPipelineError::MissingFeatures(_)
                | CreateRenderPipelineError::MissingDownlevelFlags(_)
                | CreateRenderPipelineError::Stage { .. }
                | CreateRenderPipelineError::UnalignedShader { .. } => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for RenderBundleError {
        fn error_type(&self) -> ErrorBufferType {
            // We can't classify this ourselves, because inner error classification is private. May
            // need some upstream work to do this properly.
            ErrorBufferType::Validation
        }
    }

    impl HasErrorBufferType for DeviceError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                DeviceError::Invalid(_) | DeviceError::DeviceMismatch(_) => {
                    ErrorBufferType::Validation
                }
                DeviceError::Lost => ErrorBufferType::DeviceLost,
                DeviceError::OutOfMemory => ErrorBufferType::OutOfMemory,
                DeviceError::ResourceCreationFailed => ErrorBufferType::Internal,
                _ => ErrorBufferType::Internal,
            }
        }
    }

    impl HasErrorBufferType for CreateTextureViewError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                CreateTextureViewError::InvalidTextureViewDimension { .. }
                | CreateTextureViewError::InvalidResource(_)
                | CreateTextureViewError::InvalidMultisampledTextureViewDimension(_)
                | CreateTextureViewError::InvalidCubemapTextureDepth { .. }
                | CreateTextureViewError::InvalidCubemapArrayTextureDepth { .. }
                | CreateTextureViewError::InvalidCubeTextureViewSize
                | CreateTextureViewError::ZeroMipLevelCount
                | CreateTextureViewError::ZeroArrayLayerCount
                | CreateTextureViewError::TooManyMipLevels { .. }
                | CreateTextureViewError::TooManyArrayLayers { .. }
                | CreateTextureViewError::InvalidArrayLayerCount { .. }
                | CreateTextureViewError::InvalidAspect { .. }
                | CreateTextureViewError::FormatReinterpretation { .. }
                | CreateTextureViewError::DestroyedResource(_) => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for CopyError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                CopyError::Encoder(e) => e.error_type(),
                CopyError::Transfer(e) => e.error_type(),

                CopyError::InvalidResource(_) => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for TransferError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                TransferError::MemoryInitFailure(e) => e.error_type(),

                TransferError::SameSourceDestinationBuffer
                | TransferError::BufferOverrun { .. }
                | TransferError::TextureOverrun { .. }
                | TransferError::InvalidTextureAspect { .. }
                | TransferError::InvalidTextureMipLevel { .. }
                | TransferError::InvalidDimensionExternal
                | TransferError::UnalignedBufferOffset(_)
                | TransferError::UnalignedCopySize(_)
                | TransferError::UnalignedCopyWidth
                | TransferError::UnalignedCopyHeight
                | TransferError::UnalignedCopyOriginX
                | TransferError::UnalignedCopyOriginY
                | TransferError::UnalignedBytesPerRow
                | TransferError::UnspecifiedBytesPerRow
                | TransferError::UnspecifiedRowsPerImage
                | TransferError::InvalidBytesPerRow
                | TransferError::InvalidRowsPerImage
                | TransferError::CopySrcMissingAspects
                | TransferError::CopyDstMissingAspects
                | TransferError::CopyAspectNotOne
                | TransferError::CopyFromForbiddenTextureFormat { .. }
                | TransferError::CopyToForbiddenTextureFormat { .. }
                | TransferError::ExternalCopyToForbiddenTextureFormat(_)
                | TransferError::TextureFormatsNotCopyCompatible { .. }
                | TransferError::MissingDownlevelFlags(_)
                | TransferError::InvalidSampleCount { .. }
                | TransferError::InvalidMipLevel { .. } => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for ComputePassError {
        fn error_type(&self) -> ErrorBufferType {
            // We can't classify this ourselves, because inner error classification is private. We
            // may need some upstream work to do this properly. For now, we trust that this opaque
            // type only ever represents `Validation`.
            ErrorBufferType::Validation
        }
    }

    impl HasErrorBufferType for QueryError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                QueryError::Encoder(e) => e.error_type(),
                QueryError::Use(e) => e.error_type(),
                QueryError::Resolve(e) => e.error_type(),

                QueryError::InvalidResource(_) => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for QueryUseError {
        fn error_type(&self) -> ErrorBufferType {
            // We can't classify this ourselves, because inner error classification is private. We
            // may need some upstream work to do this properly. For now, we trust that this opaque
            // type only ever represents `Validation`.
            ErrorBufferType::Validation
        }
    }

    impl HasErrorBufferType for ResolveError {
        fn error_type(&self) -> ErrorBufferType {
            // We can't classify this ourselves, because inner error classification is private. We
            // may need some upstream work to do this properly. For now, we trust that this opaque
            // type only ever represents `Validation`.
            ErrorBufferType::Validation
        }
    }

    impl HasErrorBufferType for RenderPassError {
        fn error_type(&self) -> ErrorBufferType {
            // TODO: This type's `inner` member has an `OutOfMemory` variant. We definitely need to
            // expose this upstream, or move this implementation upstream.
            //
            // Bug for tracking: https://bugzilla.mozilla.org/show_bug.cgi?id=1840926
            ErrorBufferType::Validation
        }
    }

    impl HasErrorBufferType for ClearError {
        fn error_type(&self) -> ErrorBufferType {
            // We can't classify this ourselves, because inner error classification is private. We
            // may need some upstream work to do this properly. For now, we trust that this opaque
            // type only ever represents `Validation`.
            ErrorBufferType::Validation
        }
    }

    impl HasErrorBufferType for CommandEncoderError {
        fn error_type(&self) -> ErrorBufferType {
            // We can't classify this ourselves, because inner error classification is private. We
            // may need some upstream work to do this properly. For now, we trust that this opaque
            // type only ever represents `Validation`.
            ErrorBufferType::Validation
        }
    }

    impl HasErrorBufferType for QueueSubmitError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                QueueSubmitError::Queue(e) => e.error_type(),
                QueueSubmitError::Unmap(e) => e.error_type(),

                QueueSubmitError::DestroyedResource(_)
                | QueueSubmitError::BufferStillMapped(_)
                | QueueSubmitError::InvalidResource(_) => ErrorBufferType::Validation,

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for QueueWriteError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                QueueWriteError::Queue(e) => e.error_type(),
                QueueWriteError::Transfer(e) => e.error_type(),
                QueueWriteError::MemoryInitFailure(e) => e.error_type(),

                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }

    impl HasErrorBufferType for GetBindGroupLayoutError {
        fn error_type(&self) -> ErrorBufferType {
            // We can't classify this ourselves, because inner error classification is private. We
            // may need some upstream work to do this properly. For now, we trust that this opaque
            // type only ever represents `Validation`.
            ErrorBufferType::Validation
        }
    }

    impl HasErrorBufferType for CreateRenderBundleError {
        fn error_type(&self) -> ErrorBufferType {
            // We can't classify this ourselves, because inner error classification is private. We
            // may need some upstream work to do this properly. For now, we trust that this opaque
            // type only ever represents `Validation`.
            ErrorBufferType::Validation
        }
    }

    impl HasErrorBufferType for DestroyError {
        fn error_type(&self) -> ErrorBufferType {
            ErrorBufferType::Validation
        }
    }

    impl HasErrorBufferType for CreateQuerySetError {
        fn error_type(&self) -> ErrorBufferType {
            match self {
                CreateQuerySetError::Device(e) => e.error_type(),
                CreateQuerySetError::ZeroCount
                | CreateQuerySetError::TooManyQueries { .. }
                | CreateQuerySetError::MissingFeatures(..) => ErrorBufferType::Validation,
                // N.B: forced non-exhaustiveness
                _ => ErrorBufferType::Validation,
            }
        }
    }
}

[ Verzeichnis aufwärts0.51unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]