neon/result/
mod.rs

1//! Represents JavaScript exceptions as a Rust [`Result`](std::result) type.
2//!
3//! Most interactions with the JavaScript engine can throw a JavaScript exception. Neon APIs
4//! that can throw an exception are called _throwing APIs_ and return the type
5//! [`NeonResult`] (or its shorthand [`JsResult`]).
6//!
7//! When a throwing API triggers a JavaScript exception, it returns an [Err]
8//! result. This indicates that the thread associated with the [`Context`]
9//! is now throwing, and allows Rust code to perform any cleanup. See the
10//! [`neon::context`](crate::context) module documentation for more about
11//! [contexts and exceptions](crate::context#throwing-exceptions).
12//!
13//! Typically, Neon code can manage JavaScript exceptions correctly and conveniently by
14//! using Rust's [question mark (`?`)][question-mark] operator. This ensures that Rust code
15//! "short-circuits" when an exception is thrown and returns back to JavaScript without
16//! calling any throwing APIs.
17//!
18//! ## Example
19//!
20//! Neon functions typically use [`JsResult`] for their return type. This
21//! example defines a function that extracts a property called `"message"` from an object,
22//! throwing an exception if the argument is not of the right type or extracting the property
23//! fails:
24//!
25//! ```
26//! # use neon::prelude::*;
27//! fn get_message(mut cx: FunctionContext) -> JsResult<JsValue> {
28//!     let obj: Handle<JsObject> = cx.argument(0)?;
29//!     obj.prop(&mut cx, "message").get()
30//! }
31//! ```
32//!
33//! [question-mark]: https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.html
34
35use std::{
36    fmt::{Display, Formatter, Result as FmtResult},
37    marker::PhantomData,
38};
39
40use crate::{context::Context, handle::Handle, types::Value};
41
42/// A [unit type][unit] indicating that the JavaScript thread is throwing an exception.
43///
44/// `Throw` deliberately does not implement [`std::error::Error`]. It's
45/// not recommended to chain JavaScript exceptions with other kinds of Rust errors,
46/// since throwing means that the JavaScript thread is unavailable until the exception
47/// is handled.
48///
49/// [unit]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#unit-like-structs-without-any-fields
50#[derive(Debug)]
51pub struct Throw(PhantomData<*mut ()>); // *mut is !Send + !Sync, making it harder to accidentally store
52
53impl Throw {
54    #[cfg(feature = "sys")]
55    /// Creates a `Throw` struct representing a JavaScript exception
56    /// state.
57    ///
58    /// # Safety
59    ///
60    /// `Throw` should *only* be constructed when the JavaScript VM is in a
61    /// throwing state. I.e., when [`Status::PendingException`](crate::sys::bindings::Status::PendingException)
62    /// is returned.
63    pub unsafe fn new() -> Self {
64        Self(PhantomData)
65    }
66
67    #[cfg(not(feature = "sys"))]
68    pub(crate) unsafe fn new() -> Self {
69        Self(PhantomData)
70    }
71}
72
73impl Display for Throw {
74    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
75        fmt.write_str("JavaScript Error")
76    }
77}
78
79/// The result type for throwing APIs.
80pub type NeonResult<T> = Result<T, Throw>;
81
82/// Shorthand for a [`NeonResult`] that produces JavaScript values.
83pub type JsResult<'b, T> = NeonResult<Handle<'b, T>>;
84
85/// Extension trait for converting Rust [`Result`] values
86/// into [`NeonResult`] values by throwing JavaScript exceptions.
87pub trait ResultExt<T> {
88    fn or_throw<'a, C: Context<'a>>(self, cx: &mut C) -> NeonResult<T>;
89}
90
91impl<'a, 'b, T, E> ResultExt<Handle<'a, T>> for Result<Handle<'a, T>, Handle<'b, E>>
92where
93    T: Value,
94    E: Value,
95{
96    fn or_throw<'cx, C: Context<'cx>>(self, cx: &mut C) -> JsResult<'a, T> {
97        self.or_else(|err| cx.throw(err))
98    }
99}