Files
servo/components/script_bindings/error.rs
Sam d5d400c7d6 script: Use CString for Error::Type and Error::Range (#42576)
Continuation of https://github.com/servo/servo/pull/42135, switch
Error::Type and Error::Range to also use CStrings internally, as they
are converted to CString for throwing JS exceptions (other get thrown as
DomException object, which uses rust string internally).

Changes in script crate are mechanical.

Testing: Should be covered by WPT tests.
Part of #42126

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
2026-02-12 15:17:30 +00:00

145 lines
4.9 KiB
Rust

/* 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 https://mozilla.org/MPL/2.0/. */
use std::ffi::CString;
use js::error::throw_type_error;
use js::jsapi::JS_IsExceptionPending;
use crate::codegen::PrototypeList::proto_id_to_name;
use crate::num::Finite;
use crate::script_runtime::JSContext as SafeJSContext;
/// DOM exceptions that can be thrown by a native DOM method.
/// <https://webidl.spec.whatwg.org/#dfn-error-names-table>
#[derive(Clone, Debug, MallocSizeOf)]
pub enum Error {
/// IndexSizeError DOMException
IndexSize(Option<String>),
/// NotFoundError DOMException
NotFound(Option<String>),
/// HierarchyRequestError DOMException
HierarchyRequest(Option<String>),
/// WrongDocumentError DOMException
WrongDocument(Option<String>),
/// InvalidCharacterError DOMException
InvalidCharacter(Option<String>),
/// NotSupportedError DOMException
NotSupported(Option<String>),
/// InUseAttributeError DOMException
InUseAttribute(Option<String>),
/// InvalidStateError DOMException
InvalidState(Option<String>),
/// SyntaxError DOMException
Syntax(Option<String>),
/// NamespaceError DOMException
Namespace(Option<String>),
/// InvalidAccessError DOMException
InvalidAccess(Option<String>),
/// SecurityError DOMException
Security(Option<String>),
/// NetworkError DOMException
Network(Option<String>),
/// AbortError DOMException
Abort(Option<String>),
/// TimeoutError DOMException
Timeout(Option<String>),
/// InvalidNodeTypeError DOMException
InvalidNodeType(Option<String>),
/// DataCloneError DOMException
DataClone(Option<String>),
/// TransactionInactiveError DOMException
TransactionInactive(Option<String>),
/// ReadOnlyError DOMException
ReadOnly(Option<String>),
/// VersionError DOMException
Version(Option<String>),
/// NoModificationAllowedError DOMException
NoModificationAllowed(Option<String>),
/// QuotaExceededError DOMException
QuotaExceeded {
quota: Option<Finite<f64>>,
requested: Option<Finite<f64>>,
},
/// TypeMismatchError DOMException
TypeMismatch(Option<String>),
/// InvalidModificationError DOMException
InvalidModification(Option<String>),
/// NotReadableError DOMException
NotReadable(Option<String>),
/// DataError DOMException
Data(Option<String>),
/// OperationError DOMException
Operation(Option<String>),
/// NotAllowedError DOMException
NotAllowed(Option<String>),
/// EncodingError DOMException
Encoding(Option<String>),
/// ConstraintError DOMException
Constraint(Option<String>),
/// TypeError JavaScript Error
Type(CString),
/// RangeError JavaScript Error
Range(CString),
/// A JavaScript exception is already pending.
JSFailed,
}
/// The return type for IDL operations that can throw DOM exceptions.
pub type Fallible<T> = Result<T, Error>;
/// The return type for IDL operations that can throw DOM exceptions and
/// return `()`.
pub type ErrorResult = Fallible<()>;
/// Throw an exception to signal that a `JSObject` can not be converted to a
/// given DOM type.
pub fn throw_invalid_this(cx: SafeJSContext, proto_id: u16) {
debug_assert!(unsafe { !JS_IsExceptionPending(*cx) });
let mut vec = "\"this\" object does not implement interface "
.as_bytes()
.to_vec();
vec.extend_from_slice(proto_id_to_name(proto_id).as_bytes());
let error = CString::new(vec).expect("WebIDL name should not contain nul byte");
unsafe { throw_type_error(*cx, &error) };
}
pub fn throw_constructor_without_new(cx: SafeJSContext, name: &str) {
debug_assert!(unsafe { !JS_IsExceptionPending(*cx) });
let mut error = name.as_bytes().to_vec();
error.extend_from_slice(b" constructor: 'new' is required");
let error = CString::new(error).expect("WebIDL name should not contain nul byte");
unsafe { throw_type_error(*cx, &error) };
}
#[macro_export]
/// Creates a `CString` using interpolation of runtime expressions.
/// Basically a `format!` that produces a `CString`.
///
/// Because data can come from untrusted sources, it will check the interior for
/// null bytes and replace them with `\u0000`.
macro_rules! cformat {
($($arg:tt)*) => {
{
use std::io::Write;
let mut s = Vec::new();
write!(&mut s, $($arg)*).unwrap();
std::ffi::CString::new(s).or_else(|s| {
let s = s.into_vec();
let mut out = Vec::with_capacity(s.len());
for b in s {
if b == 0 {
out.extend_from_slice(b"\\u0000");
} else {
out.push(b);
}
}
std::ffi::CString::new(out)
}).expect("nul bytes should be replaced")
}
}
}