/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* 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)] pubstruct 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(&mutself, error: impl HasErrorBufferType) { use std::fmt::Write;
letmut message = format!("{}", error); letmut e = error.source(); whilelet 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 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 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 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 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
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.