Skip to content

Commit

Permalink
Merge pull request #1219 from fitzgen/UnwrapThrowExt
Browse files Browse the repository at this point in the history
Add the `UnwrapThrowExt<T>` trait
  • Loading branch information
alexcrichton committed Feb 1, 2019
2 parents 2e80313 + 0e11e4a commit 9f00664
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 1 deletion.
72 changes: 71 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ macro_rules! if_std {
/// use wasm_bindgen::prelude::*;
/// ```
pub mod prelude {
pub use wasm_bindgen_macro::wasm_bindgen;
#[doc(hidden)]
pub use wasm_bindgen_macro::__wasm_bindgen_class_marker;
pub use wasm_bindgen_macro::wasm_bindgen;
pub use JsValue;
pub use UnwrapThrowExt;

if_std! {
pub use closure::Closure;
Expand Down Expand Up @@ -640,6 +641,75 @@ pub fn throw_val(s: JsValue) -> ! {
}
}

/// An extension trait for `Option<T>` and `Result<T, E>` for unwraping the `T`
/// value, or throwing a JS error if it is not available.
///
/// These methods should have a smaller code size footprint than the normal
/// `Option::unwrap` and `Option::expect` methods, but they are specific to
/// working with wasm and JS.
///
/// On non-wasm32 targets, defaults to the normal unwrap/expect calls.
///
/// # Example
///
/// ```no_run
/// // If the value is `Option::Some` or `Result::Ok`, then we just get the
/// // contained `T` value.
/// let x = Some(42);
/// assert_eq!(x.unwrap_throw(), 42);
///
/// let y: Option<i32> = None;
///
/// // This call would throw an error to JS!
/// //
/// // y.unwrap_throw()
/// //
/// // And this call would throw an error to JS with a custom error message!
/// //
/// // y.expect_throw("woopsie daisy!")
/// ```
pub trait UnwrapThrowExt<T>: Sized {
/// Unwrap this `Option` or `Result`, but instead of panicking on failure,
/// throw an exception to JavaScript.
fn unwrap_throw(self) -> T {
self.expect_throw("`unwrap_throw` failed")
}

/// Unwrap this container's `T` value, or throw an error to JS with the
/// given message if the `T` value is unavailable (e.g. an `Option<T>` is
/// `None`).
fn expect_throw(self, message: &str) -> T;
}

impl<T> UnwrapThrowExt<T> for Option<T> {
fn expect_throw(self, message: &str) -> T {
if cfg!(all(target_arch = "wasm32", not(target_os = "emscripten"))) {
match self {
Some(val) => val,
None => throw_str(message),
}
} else {
self.expect(message)
}
}
}

impl<T, E> UnwrapThrowExt<T> for Result<T, E>
where
E: core::fmt::Debug,
{
fn expect_throw(self, message: &str) -> T {
if cfg!(all(target_arch = "wasm32", not(target_os = "emscripten"))) {
match self {
Ok(val) => val,
Err(_) => throw_str(message),
}
} else {
self.expect(message)
}
}
}

/// Returns a handle to this wasm instance's `WebAssembly.Module`
///
/// Note that this is only available when the final wasm app is built with
Expand Down
23 changes: 23 additions & 0 deletions tests/unwrap_throw.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

#[test]
fn unwrap_throw_ok() {
assert_eq!(Some(42).unwrap_throw(), 42);
let x: Result<i32, ()> = Ok(42);
assert_eq!(x.unwrap_throw(), 42);
}

#[test]
#[should_panic]
fn unwrap_throw_none() {
let x: Option<i32> = None;
x.unwrap_throw();
}

#[test]
#[should_panic]
fn unwrap_throw_err() {
let x: Result<i32, ()> = Err(());
x.unwrap_throw();
}

0 comments on commit 9f00664

Please sign in to comment.