mozjs/
error.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5//! Functions to throw JavaScript exceptions from Rust.
6
7#![deny(missing_docs)]
8
9use crate::jsapi::{JSContext, JSErrorFormatString, JSExnType, JS_ReportErrorNumberUTF8};
10use libc;
11use std::ffi::{CStr, CString};
12use std::{mem, os, ptr};
13
14/// Format string used to throw javascript errors.
15static ERROR_FORMAT_STRING_STRING: &CStr = c"{0}";
16
17/// Format string struct used to throw `TypeError`s.
18static mut TYPE_ERROR_FORMAT_STRING: JSErrorFormatString = JSErrorFormatString {
19    name: c"RUSTMSG_TYPE_ERROR".as_ptr(),
20    format: ERROR_FORMAT_STRING_STRING.as_ptr(),
21    argCount: 1,
22    exnType: JSExnType::JSEXN_TYPEERR as i16,
23};
24
25/// Format string struct used to throw `RangeError`s.
26static mut RANGE_ERROR_FORMAT_STRING: JSErrorFormatString = JSErrorFormatString {
27    name: c"RUSTMSG_RANGE_ERROR".as_ptr(),
28    format: ERROR_FORMAT_STRING_STRING.as_ptr(),
29    argCount: 1,
30    exnType: JSExnType::JSEXN_RANGEERR as i16,
31};
32
33/// Callback used to throw javascript errors.
34/// See throw_js_error for info about error_number.
35unsafe extern "C" fn get_error_message(
36    _user_ref: *mut os::raw::c_void,
37    error_number: libc::c_uint,
38) -> *const JSErrorFormatString {
39    let num: JSExnType = mem::transmute(error_number);
40    match num {
41        JSExnType::JSEXN_TYPEERR => &raw const TYPE_ERROR_FORMAT_STRING,
42        JSExnType::JSEXN_RANGEERR => &raw const RANGE_ERROR_FORMAT_STRING,
43        _ => panic!(
44            "Bad js error number given to get_error_message: {}",
45            error_number
46        ),
47    }
48}
49
50/// Helper fn to throw a javascript error with the given message and number.
51/// Reuse the jsapi error codes to distinguish the error_number
52/// passed back to the get_error_message callback.
53/// c_uint is u32, so this cast is safe, as is casting to/from i32 from there.
54unsafe fn throw_js_error(cx: *mut JSContext, error: &str, error_number: u32) {
55    let error = CString::new(error)
56        .or_else(|_| CString::new(error.replace("\0", "\\u0000")))
57        .unwrap();
58    JS_ReportErrorNumberUTF8(
59        cx,
60        Some(get_error_message),
61        ptr::null_mut(),
62        error_number,
63        error.as_ptr(),
64    );
65}
66
67/// Throw a `TypeError` with the given message.
68pub unsafe fn throw_type_error(cx: *mut JSContext, error: &str) {
69    throw_js_error(cx, error, JSExnType::JSEXN_TYPEERR as u32);
70}
71
72/// Throw a `RangeError` with the given message.
73pub unsafe fn throw_range_error(cx: *mut JSContext, error: &str) {
74    throw_js_error(cx, error, JSExnType::JSEXN_RANGEERR as u32);
75}
76
77/// Throw an `InternalError` with the given message.
78pub unsafe fn throw_internal_error(cx: *mut JSContext, error: &str) {
79    throw_js_error(cx, error, JSExnType::JSEXN_INTERNALERR as u32);
80}