From 623547f4244cf02e1f1016044981cf34649d8127 Mon Sep 17 00:00:00 2001 From: Pauan Date: Mon, 25 Jul 2022 23:19:15 -0700 Subject: [PATCH] Improving error messages --- examples/async/src/lib.rs | 2 +- examples/async/src/util.rs | 4 +- examples/todomvc/src/app.rs | 9 ++-- examples/todomvc/src/todo.rs | 3 +- examples/todomvc/src/util.rs | 3 +- src/animation.rs | 5 +- src/bindings.rs | 69 ++++++++++++++++++---------- src/dom.rs | 88 ++++++++++++++++++++++++++++++++++-- src/events.rs | 5 +- src/routing.rs | 1 + src/utils.rs | 54 +++++++++++++++++++++- 11 files changed, 200 insertions(+), 43 deletions(-) diff --git a/examples/async/src/lib.rs b/examples/async/src/lib.rs index 8d1f486..f0b6f02 100644 --- a/examples/async/src/lib.rs +++ b/examples/async/src/lib.rs @@ -49,7 +49,7 @@ struct User { impl User { async fn fetch(user: &str) -> Result { let user = fetch_github(&format!("https://api.github.com/users/{}", user)).await?; - Ok(serde_json::from_str::(&user).unwrap_throw()) + Ok(serde_json::from_str::(&user).unwrap()) } } diff --git a/examples/async/src/util.rs b/examples/async/src/util.rs index 1ea1dff..d1ec2f3 100644 --- a/examples/async/src/util.rs +++ b/examples/async/src/util.rs @@ -112,7 +112,7 @@ pub async fn fetch_github(url: &str) -> Result { headers.set("Accept", "application/vnd.github.v3+json")?; let future = window() - .unwrap_throw() + .unwrap() .fetch_with_str_and_init( url, RequestInit::new() @@ -131,7 +131,7 @@ pub async fn fetch_github(url: &str) -> Result { let value = JsFuture::from(response.text()?) .await? .as_string() - .unwrap_throw(); + .unwrap(); Ok(value) } diff --git a/examples/todomvc/src/app.rs b/examples/todomvc/src/app.rs index 0675707..6b38eb3 100644 --- a/examples/todomvc/src/app.rs +++ b/examples/todomvc/src/app.rs @@ -1,6 +1,5 @@ use std::sync::Arc; use std::cell::Cell; -use wasm_bindgen::prelude::*; use web_sys::{Url, HtmlInputElement}; use serde_derive::{Serialize, Deserialize}; use futures_signals::signal::{Signal, SignalExt, Mutable}; @@ -21,7 +20,7 @@ pub enum Route { impl Route { // This could use more advanced URL parsing, but it isn't needed pub fn from_url(url: &str) -> Self { - let url = Url::new(&url).unwrap_throw(); + let url = Url::new(&url).unwrap(); match url.hash().as_str() { "#/active" => Route::Active, "#/completed" => Route::Completed, @@ -72,7 +71,7 @@ impl App { pub fn deserialize() -> Arc { local_storage() .get_item("todos-rust-dominator") - .unwrap_throw() + .unwrap() .and_then(|state_json| { serde_json::from_str(state_json.as_str()).ok() }) @@ -80,11 +79,11 @@ impl App { } pub fn serialize(&self) { - let state_json = serde_json::to_string(self).unwrap_throw(); + let state_json = serde_json::to_string(self).unwrap(); local_storage() .set_item("todos-rust-dominator", state_json.as_str()) - .unwrap_throw(); + .unwrap(); } pub fn route(&self) -> impl Signal { diff --git a/examples/todomvc/src/todo.rs b/examples/todomvc/src/todo.rs index 91a51d9..08786e6 100644 --- a/examples/todomvc/src/todo.rs +++ b/examples/todomvc/src/todo.rs @@ -1,5 +1,4 @@ use std::sync::Arc; -use wasm_bindgen::prelude::*; use serde_derive::{Serialize, Deserialize}; use futures_signals::map_ref; use futures_signals::signal::{Signal, SignalExt, Mutable}; @@ -126,7 +125,7 @@ impl Todo { .event(clone!(todo => move |event: events::KeyDown| { match event.key().as_str() { "Enter" => { - element.blur().unwrap_throw(); + element.blur().unwrap(); }, "Escape" => { todo.cancel_editing(); diff --git a/examples/todomvc/src/util.rs b/examples/todomvc/src/util.rs index 1b2bd27..6b493a1 100644 --- a/examples/todomvc/src/util.rs +++ b/examples/todomvc/src/util.rs @@ -1,9 +1,8 @@ -use wasm_bindgen::prelude::*; use web_sys::{window, Storage}; pub fn local_storage() -> Storage { - window().unwrap_throw().local_storage().unwrap_throw().unwrap_throw() + window().unwrap().local_storage().unwrap().unwrap() } #[inline] diff --git a/src/animation.rs b/src/animation.rs index 8c339f8..ff13532 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -16,6 +16,7 @@ use wasm_bindgen::closure::Closure; use web_sys::window; use crate::operations::spawn_future; +use crate::utils::UnwrapJsExt; struct RafState { @@ -37,7 +38,7 @@ impl Raf { window() .unwrap_throw() .request_animation_frame(callback.as_ref().unchecked_ref()) - .unwrap_throw() + .unwrap_js() } let closure = { @@ -71,7 +72,7 @@ impl Drop for Raf { window() .unwrap_throw() .cancel_animation_frame(state.id) - .unwrap_throw(); + .unwrap_js(); } } diff --git a/src/bindings.rs b/src/bindings.rs index 4d50635..70b7617 100644 --- a/src/bindings.rs +++ b/src/bindings.rs @@ -2,19 +2,21 @@ use wasm_bindgen::prelude::*; use wasm_bindgen::{JsCast, intern}; use js_sys::Reflect; use web_sys::{HtmlElement, Element, Node, Window, History, Document, Text, Comment, DomTokenList, CssStyleSheet, CssStyleDeclaration, HtmlStyleElement, CssStyleRule, EventTarget}; +use crate::utils::UnwrapJsExt; // TODO move this into wasm-bindgen or gloo or something // TODO maybe use Object for obj ? +#[track_caller] pub(crate) fn set_property(obj: &JsValue, name: &str, value: &JsValue) { - Reflect::set(obj, &JsValue::from(name), value).unwrap_throw(); + Reflect::set(obj, &JsValue::from(name), value).unwrap_js(); } thread_local! { static WINDOW: Window = web_sys::window().unwrap_throw(); static DOCUMENT: Document = WINDOW.with(|w| w.document().unwrap_throw()); - static HISTORY: History = WINDOW.with(|w| w.history().unwrap_throw()); + static HISTORY: History = WINDOW.with(|w| w.history().unwrap_js()); } pub(crate) fn window_event_target() -> EventTarget { @@ -30,21 +32,24 @@ pub(crate) fn ready_state() -> String { DOCUMENT.with(|d| d.ready_state()) } +#[track_caller] pub(crate) fn current_url() -> String { - WINDOW.with(|w| w.location().href().unwrap_throw()) + WINDOW.with(|w| w.location().href().unwrap_js()) } +#[track_caller] pub(crate) fn go_to_url(url: &str) { HISTORY.with(|h| { - h.push_state_with_url(&JsValue::NULL, "", Some(url)).unwrap_throw(); + h.push_state_with_url(&JsValue::NULL, "", Some(url)).unwrap_js(); }); } +#[track_caller] pub(crate) fn create_stylesheet() -> CssStyleSheet { DOCUMENT.with(|document| { // TODO use createElementNS ? // TODO use dyn_into ? - let e: HtmlStyleElement = document.create_element("style").unwrap_throw().unchecked_into(); + let e: HtmlStyleElement = document.create_element("style").unwrap_js().unchecked_into(); e.set_type("text/css"); append_child(&document.head().unwrap_throw(), &e); // TODO use dyn_into ? @@ -52,8 +57,9 @@ pub(crate) fn create_stylesheet() -> CssStyleSheet { }) } +#[track_caller] pub(crate) fn make_style_rule(sheet: &CssStyleSheet, selector: &str) -> Result { - let rules = sheet.css_rules().unwrap_throw(); + let rules = sheet.css_rules().unwrap_js(); let length = rules.length(); // TODO don't return u32 ? sheet.insert_rule_with_index(&format!("{}{{}}", selector), length)?; @@ -66,12 +72,14 @@ pub(crate) fn get_element_by_id(id: &str) -> Element { DOCUMENT.with(|d| d.get_element_by_id(id).unwrap_throw()) } +#[track_caller] pub(crate) fn create_element(name: &str) -> Element { - DOCUMENT.with(|d| d.create_element(name).unwrap_throw()) + DOCUMENT.with(|d| d.create_element(name).unwrap_js()) } +#[track_caller] pub(crate) fn create_element_ns(namespace: &str, name: &str) -> Element { - DOCUMENT.with(|d| d.create_element_ns(Some(namespace), name).unwrap_throw()) + DOCUMENT.with(|d| d.create_element_ns(Some(namespace), name).unwrap_js()) } pub(crate) fn create_text_node(value: &str) -> Text { @@ -94,68 +102,83 @@ pub(crate) fn create_empty_node() -> Node { } // TODO check that the attribute *actually* was changed +#[track_caller] pub(crate) fn set_attribute(elem: &Element, key: &str, value: &str) { - elem.set_attribute(key, value).unwrap_throw(); + elem.set_attribute(key, value).unwrap_js(); } +#[track_caller] pub(crate) fn set_attribute_ns(elem: &Element, namespace: &str, key: &str, value: &str) { - elem.set_attribute_ns(Some(namespace), key, value).unwrap_throw(); + elem.set_attribute_ns(Some(namespace), key, value).unwrap_js(); } +#[track_caller] pub(crate) fn remove_attribute(elem: &Element, key: &str) { - elem.remove_attribute(key).unwrap_throw(); + elem.remove_attribute(key).unwrap_js(); } +#[track_caller] pub(crate) fn remove_attribute_ns(elem: &Element, namespace: &str, key: &str) { - elem.remove_attribute_ns(Some(namespace), key).unwrap_throw(); + elem.remove_attribute_ns(Some(namespace), key).unwrap_js(); } +#[track_caller] pub(crate) fn add_class(classes: &DomTokenList, value: &str) { - classes.add_1(value).unwrap_throw(); + classes.add_1(value).unwrap_js(); } +#[track_caller] pub(crate) fn remove_class(classes: &DomTokenList, value: &str) { - classes.remove_1(value).unwrap_throw(); + classes.remove_1(value).unwrap_js(); } +#[track_caller] pub(crate) fn get_style(style: &CssStyleDeclaration, name: &str) -> String { - style.get_property_value(name).unwrap_throw() + style.get_property_value(name).unwrap_js() } +#[track_caller] pub(crate) fn remove_style(style: &CssStyleDeclaration, name: &str) { // TODO don't return String ? - style.remove_property(name).unwrap_throw(); + style.remove_property(name).unwrap_js(); } +#[track_caller] pub(crate) fn set_style(style: &CssStyleDeclaration, name: &str, value: &str, important: bool) { let priority = if important { intern("important") } else { intern("") }; - style.set_property_with_priority(name, value, priority).unwrap_throw(); + style.set_property_with_priority(name, value, priority).unwrap_js(); } +#[track_caller] pub(crate) fn insert_child_before(parent: &Node, child: &Node, other: &Node) { // TODO don't return Node ? - parent.insert_before(child, Some(other)).unwrap_throw(); + parent.insert_before(child, Some(other)).unwrap_js(); } +#[track_caller] pub(crate) fn replace_child(parent: &Node, child: &Node, other: &Node) { // TODO don't return Node ? - parent.replace_child(child, other).unwrap_throw(); + parent.replace_child(child, other).unwrap_js(); } +#[track_caller] pub(crate) fn append_child(parent: &Node, child: &Node) { // TODO don't return Node ? - parent.append_child(child).unwrap_throw(); + parent.append_child(child).unwrap_js(); } +#[track_caller] pub(crate) fn remove_child(parent: &Node, child: &Node) { // TODO don't return Node ? - parent.remove_child(child).unwrap_throw(); + parent.remove_child(child).unwrap_js(); } +#[track_caller] pub(crate) fn focus(elem: &HtmlElement) { - elem.focus().unwrap_throw(); + elem.focus().unwrap_js(); } +#[track_caller] pub(crate) fn blur(elem: &HtmlElement) { - elem.blur().unwrap_throw(); + elem.blur().unwrap_js(); } diff --git a/src/dom.rs b/src/dom.rs index 1cad472..204898b 100644 --- a/src/dom.rs +++ b/src/dom.rs @@ -18,7 +18,7 @@ use crate::callbacks::Callbacks; use crate::traits::*; use crate::operations; use crate::operations::{for_each, spawn_future}; -use crate::utils::{EventListener, on, ValueDiscard, FnDiscard}; +use crate::utils::{EventListener, on, UnwrapJsExt, ValueDiscard, FnDiscard}; pub struct RefFn where B: ?Sized, C: Fn(&A) -> &B { @@ -101,6 +101,7 @@ pub struct DomHandle { impl Discard for DomHandle { #[inline] + #[track_caller] fn discard(self) { bindings::remove_child(&self.parent, &self.dom.element); self.dom.callbacks.discard(); @@ -108,6 +109,7 @@ impl Discard for DomHandle { } #[inline] +#[track_caller] pub fn append_dom(parent: &Node, mut dom: Dom) -> DomHandle { bindings::append_child(&parent, &dom.element); @@ -242,6 +244,7 @@ impl Dom { } #[inline] + #[track_caller] pub fn empty() -> Self { Self::new(bindings::create_empty_node()) } @@ -262,15 +265,23 @@ impl Dom { #[inline] +#[track_caller] fn create_element(name: &str) -> A where A: JsCast { // TODO use unchecked_into in release mode ? - bindings::create_element(intern(name)).dyn_into().unwrap_throw() + crate::__unwrap!( + bindings::create_element(intern(name)).dyn_into(), + e => panic!("Invalid DOM type: \"{}\" => {:?}", name, JsValue::as_ref(&e)), + ) } #[inline] +#[track_caller] fn create_element_ns(name: &str, namespace: &str) -> A where A: JsCast { // TODO use unchecked_into in release mode ? - bindings::create_element_ns(intern(namespace), intern(name)).dyn_into().unwrap_throw() + crate::__unwrap!( + bindings::create_element_ns(intern(namespace), intern(name)).dyn_into(), + e => panic!("Invalid DOM type: \"{}\" => {:?}", name, JsValue::as_ref(&e)), + ) } @@ -301,6 +312,7 @@ fn set_option(element: A, callbacks: &mut Callbacks, value: D, mu } // TODO should this inline ? +// TODO track_caller fn set_style(style: &CssStyleDeclaration, name: &A, value: B, important: bool) where A: MultiStr, B: MultiStr { @@ -308,6 +320,7 @@ fn set_style(style: &CssStyleDeclaration, name: &A, value: B, important: b let mut names = vec![]; let mut values = vec![]; + // TODO track_caller fn try_set_style(style: &CssStyleDeclaration, names: &mut Vec, values: &mut Vec, name: &str, value: &str, important: bool) -> Option<()> { assert!(value != ""); @@ -346,6 +359,7 @@ fn set_style(style: &CssStyleDeclaration, name: &A, value: B, important: b } // TODO should this inline ? +// TODO track_caller fn set_style_signal(style: CssStyleDeclaration, callbacks: &mut Callbacks, name: A, value: D, important: bool) where A: MultiStr + 'static, B: MultiStr, @@ -369,6 +383,7 @@ fn set_style_signal(style: CssStyleDeclaration, callbacks: &mut Call } // TODO should this inline ? +// TODO track_caller fn set_style_unchecked_signal(style: CssStyleDeclaration, callbacks: &mut Callbacks, name: A, value: D, important: bool) where A: AsStr + 'static, B: AsStr, @@ -398,6 +413,7 @@ fn set_style_unchecked_signal(style: CssStyleDeclaration, callbacks: // TODO check that the property *actually* was changed ? // TODO maybe use AsRef ? // TODO should this inline ? +#[track_caller] fn set_property(element: &A, name: &B, value: C) where A: AsRef, B: MultiStr, C: Into { let element = element.as_ref(); let value = value.into(); @@ -459,11 +475,13 @@ pub struct DomBuilder { } impl DomBuilder where A: JsCast { + #[track_caller] #[inline] pub fn new_html(name: &str) -> Self { Self::new(create_element(name)) } + #[track_caller] #[inline] pub fn new_svg(name: &str) -> Self { Self::new(create_element_ns(name, SVG_NAMESPACE)) @@ -488,6 +506,7 @@ impl DomBuilder { } #[inline] + #[track_caller] fn _event(callbacks: &mut Callbacks, element: &EventTarget, options: &EventOptions, listener: F) where T: StaticEvent, F: FnMut(T) + 'static { @@ -496,6 +515,7 @@ impl DomBuilder { // TODO add this to the StylesheetBuilder and ClassBuilder too #[inline] + #[track_caller] pub fn global_event_with_options(mut self, options: &EventOptions, listener: F) -> Self where T: StaticEvent, F: FnMut(T) + 'static { @@ -505,6 +525,7 @@ impl DomBuilder { // TODO add this to the StylesheetBuilder and ClassBuilder too #[inline] + #[track_caller] pub fn global_event(self, listener: F) -> Self where T: StaticEvent, F: FnMut(T) + 'static { @@ -513,6 +534,7 @@ impl DomBuilder { #[deprecated(since = "0.5.21", note = "Use global_event_with_options instead")] #[inline] + #[track_caller] pub fn global_event_preventable(self, listener: F) -> Self where T: StaticEvent, F: FnMut(T) + 'static { @@ -593,6 +615,7 @@ impl DomBuilder where A: Into { impl DomBuilder where A: AsRef { #[inline] + #[track_caller] pub fn prop(self, name: B, value: C) -> Self where B: MultiStr, C: Into { set_property(&self.element, &name, value); self @@ -600,6 +623,7 @@ impl DomBuilder where A: AsRef { #[deprecated(since = "0.5.24", note = "Use the `prop` method instead")] #[inline] + #[track_caller] pub fn property(self, name: B, value: C) -> Self where B: MultiStr, C: Into { self.prop(name, value) } @@ -607,6 +631,7 @@ impl DomBuilder where A: AsRef { impl DomBuilder where A: AsRef { // TODO should this inline ? + // TODO track_caller fn set_property_signal(&mut self, name: B, value: D) where B: MultiStr + 'static, C: Into, @@ -620,6 +645,7 @@ impl DomBuilder where A: AsRef { } #[inline] + #[track_caller] pub fn prop_signal(mut self, name: B, value: D) -> Self where B: MultiStr + 'static, C: Into, @@ -631,6 +657,7 @@ impl DomBuilder where A: AsRef { #[deprecated(since = "0.5.24", note = "Use the `prop_signal` method instead")] #[inline] + #[track_caller] pub fn property_signal(self, name: B, value: D) -> Self where B: MultiStr + 'static, C: Into, @@ -642,6 +669,7 @@ impl DomBuilder where A: AsRef { impl DomBuilder where A: AsRef { #[inline] + #[track_caller] pub fn event_with_options(mut self, options: &EventOptions, listener: F) -> Self where T: StaticEvent, F: FnMut(T) + 'static { @@ -650,6 +678,7 @@ impl DomBuilder where A: AsRef { } #[inline] + #[track_caller] pub fn event(self, listener: F) -> Self where T: StaticEvent, F: FnMut(T) + 'static { @@ -658,6 +687,7 @@ impl DomBuilder where A: AsRef { #[deprecated(since = "0.5.21", note = "Use event_with_options instead")] #[inline] + #[track_caller] pub fn event_preventable(self, listener: F) -> Self where T: StaticEvent, F: FnMut(T) + 'static { @@ -667,6 +697,7 @@ impl DomBuilder where A: AsRef { impl DomBuilder where A: AsRef { #[inline] + #[track_caller] pub fn text(self, value: &str) -> Self { // TODO should this intern ? bindings::append_child(self.element.as_ref(), &bindings::create_text_node(value)); @@ -674,6 +705,7 @@ impl DomBuilder where A: AsRef { } #[inline] + #[track_caller] pub fn text_signal(mut self, value: C) -> Self where B: AsStr, C: Signal + 'static { @@ -684,12 +716,14 @@ impl DomBuilder where A: AsRef { } #[inline] + #[track_caller] pub fn child>(mut self, mut child: B) -> Self { operations::insert_children_one(self.element.as_ref(), &mut self.callbacks, child.borrow_mut()); self } #[inline] + #[track_caller] pub fn child_signal(mut self, child: B) -> Self where B: Signal> + 'static { @@ -699,12 +733,14 @@ impl DomBuilder where A: AsRef { // TODO figure out how to make this owned rather than &mut #[inline] + #[track_caller] pub fn children, C: IntoIterator>(mut self, children: C) -> Self { operations::insert_children_iter(self.element.as_ref(), &mut self.callbacks, children); self } #[inline] + #[track_caller] pub fn children_signal_vec(mut self, children: B) -> Self where B: SignalVec + 'static { @@ -716,12 +752,14 @@ impl DomBuilder where A: AsRef { impl DomBuilder where A: AsRef { #[inline] #[doc(hidden)] + #[track_caller] pub fn __internal_shadow_root(&self, mode: ShadowRootMode) -> DomBuilder { - let shadow = self.element.as_ref().attach_shadow(&ShadowRootInit::new(mode)).unwrap_throw(); + let shadow = self.element.as_ref().attach_shadow(&ShadowRootInit::new(mode)).unwrap_js(); DomBuilder::new(shadow) } #[inline] + #[track_caller] pub fn attr(self, name: B, value: &str) -> Self where B: MultiStr { let element = self.element.as_ref(); @@ -734,11 +772,13 @@ impl DomBuilder where A: AsRef { #[deprecated(since = "0.5.24", note = "Use the `attr` method instead")] #[inline] + #[track_caller] pub fn attribute(self, name: B, value: &str) -> Self where B: MultiStr { self.attr(name, value) } #[inline] + #[track_caller] pub fn attr_ns(self, namespace: &str, name: B, value: &str) -> Self where B: MultiStr { let element = self.element.as_ref(); let namespace: &str = intern(namespace); @@ -752,11 +792,13 @@ impl DomBuilder where A: AsRef { #[deprecated(since = "0.5.24", note = "Use the `attr_ns` method instead")] #[inline] + #[track_caller] pub fn attribute_namespace(self, namespace: &str, name: B, value: &str) -> Self where B: MultiStr { self.attr_ns(namespace, name, value) } #[inline] + #[track_caller] pub fn class(self, name: B) -> Self where B: MultiStr { let classes = self.element.as_ref().class_list(); @@ -769,6 +811,7 @@ impl DomBuilder where A: AsRef { // TODO make this more efficient ? #[inline] + #[track_caller] pub fn visible(self, value: bool) -> Self { if value { // TODO remove the class somehow ? @@ -782,6 +825,7 @@ impl DomBuilder where A: AsRef { impl DomBuilder where A: AsRef { // TODO should this inline ? + // TODO track_caller fn set_attribute_signal(&mut self, name: B, value: E) where B: MultiStr + 'static, C: AsStr, @@ -807,6 +851,7 @@ impl DomBuilder where A: AsRef { } #[inline] + #[track_caller] pub fn attr_signal(mut self, name: B, value: E) -> Self where B: MultiStr + 'static, C: AsStr, @@ -819,6 +864,7 @@ impl DomBuilder where A: AsRef { #[deprecated(since = "0.5.24", note = "Use the `attr_signal` method instead")] #[inline] + #[track_caller] pub fn attribute_signal(self, name: B, value: E) -> Self where B: MultiStr + 'static, C: AsStr, @@ -830,6 +876,7 @@ impl DomBuilder where A: AsRef { // TODO should this inline ? + // TODO track_caller fn set_attribute_namespace_signal(&mut self, namespace: &str, name: B, value: E) where B: MultiStr + 'static, C: AsStr, @@ -859,6 +906,7 @@ impl DomBuilder where A: AsRef { } #[inline] + #[track_caller] pub fn attr_ns_signal(mut self, namespace: &str, name: B, value: E) -> Self where B: MultiStr + 'static, C: AsStr, @@ -871,6 +919,7 @@ impl DomBuilder where A: AsRef { #[deprecated(since = "0.5.24", note = "Use the `attr_ns_signal` method instead")] #[inline] + #[track_caller] pub fn attribute_namespace_signal(self, namespace: &str, name: B, value: E) -> Self where B: MultiStr + 'static, C: AsStr, @@ -882,6 +931,7 @@ impl DomBuilder where A: AsRef { // TODO should this inline ? + // TODO track_caller fn set_class_signal(&mut self, name: B, value: C) where B: MultiStr + 'static, C: Signal + 'static { @@ -913,6 +963,7 @@ impl DomBuilder where A: AsRef { } #[inline] + #[track_caller] pub fn class_signal(mut self, name: B, value: C) -> Self where B: MultiStr + 'static, C: Signal + 'static { @@ -923,6 +974,7 @@ impl DomBuilder where A: AsRef { // TODO make this more efficient ? #[inline] + #[track_caller] pub fn visible_signal(self, value: B) -> Self where B: Signal + 'static { self.class_signal(&*HIDDEN_CLASS, not(value)) } @@ -930,6 +982,7 @@ impl DomBuilder where A: AsRef { // TODO use OptionStr ? // TODO should this inline ? + // TODO track_caller fn set_scroll_signal(&mut self, signal: B, mut f: F) where B: Signal> + 'static, F: FnMut(&Element, i32) + 'static { @@ -948,6 +1001,7 @@ impl DomBuilder where A: AsRef { // TODO rename to scroll_x_signal ? #[inline] + #[track_caller] pub fn scroll_left_signal(mut self, signal: B) -> Self where B: Signal> + 'static { // TODO bindings function for this ? self.set_scroll_signal(signal, Element::set_scroll_left); @@ -956,6 +1010,7 @@ impl DomBuilder where A: AsRef { // TODO rename to scroll_y_signal ? #[inline] + #[track_caller] pub fn scroll_top_signal(mut self, signal: B) -> Self where B: Signal> + 'static { // TODO bindings function for this ? self.set_scroll_signal(signal, Element::set_scroll_top); @@ -965,6 +1020,7 @@ impl DomBuilder where A: AsRef { impl DomBuilder where A: AsRef { #[inline] + #[track_caller] pub fn style(self, name: B, value: C) -> Self where B: MultiStr, C: MultiStr { @@ -973,6 +1029,7 @@ impl DomBuilder where A: AsRef { } #[inline] + #[track_caller] pub fn style_important(self, name: B, value: C) -> Self where B: MultiStr, C: MultiStr { @@ -981,6 +1038,7 @@ impl DomBuilder where A: AsRef { } #[inline] + #[track_caller] pub fn style_unchecked(self, name: B, value: C) -> Self where B: AsStr, C: AsStr { @@ -995,6 +1053,7 @@ impl DomBuilder where A: AsRef { impl DomBuilder where A: AsRef { #[inline] + #[track_caller] pub fn style_signal(mut self, name: B, value: E) -> Self where B: MultiStr + 'static, C: MultiStr, @@ -1006,6 +1065,7 @@ impl DomBuilder where A: AsRef { } #[inline] + #[track_caller] pub fn style_important_signal(mut self, name: B, value: E) -> Self where B: MultiStr + 'static, C: MultiStr, @@ -1017,6 +1077,7 @@ impl DomBuilder where A: AsRef { } #[inline] + #[track_caller] pub fn style_unchecked_signal(mut self, name: B, value: E) -> Self where B: AsStr + 'static, C: AsStr, @@ -1030,6 +1091,7 @@ impl DomBuilder where A: AsRef { // TODO remove the `value` argument ? #[inline] + #[track_caller] pub fn focused(mut self, value: bool) -> Self { let element = self.element.as_ref().clone(); @@ -1049,6 +1111,7 @@ impl DomBuilder where A: AsRef { // TODO should this inline ? + // TODO track_caller fn set_focused_signal(&mut self, value: B) where B: Signal + 'static { @@ -1070,6 +1133,7 @@ impl DomBuilder where A: AsRef { } #[inline] + #[track_caller] pub fn focused_signal(mut self, value: B) -> Self where B: Signal + 'static { @@ -1132,6 +1196,7 @@ impl StylesheetBuilder { } #[inline] + #[track_caller] pub fn style(self, name: B, value: C) -> Self where B: MultiStr, C: MultiStr { @@ -1140,6 +1205,7 @@ impl StylesheetBuilder { } #[inline] + #[track_caller] pub fn style_important(self, name: B, value: C) -> Self where B: MultiStr, C: MultiStr { @@ -1148,6 +1214,7 @@ impl StylesheetBuilder { } #[inline] + #[track_caller] pub fn style_unchecked(self, name: B, value: C) -> Self where B: AsStr, C: AsStr { @@ -1160,6 +1227,7 @@ impl StylesheetBuilder { } #[inline] + #[track_caller] pub fn style_signal(mut self, name: B, value: E) -> Self where B: MultiStr + 'static, C: MultiStr, @@ -1171,6 +1239,7 @@ impl StylesheetBuilder { } #[inline] + #[track_caller] pub fn style_important_signal(mut self, name: B, value: E) -> Self where B: MultiStr + 'static, C: MultiStr, @@ -1182,6 +1251,7 @@ impl StylesheetBuilder { } #[inline] + #[track_caller] pub fn style_unchecked_signal(mut self, name: B, value: E) -> Self where B: AsStr + 'static, C: AsStr, @@ -1194,6 +1264,7 @@ impl StylesheetBuilder { // TODO return a Handle #[inline] + #[track_caller] #[doc(hidden)] pub fn __internal_done(mut self) { self.callbacks.trigger_after_insert(); @@ -1214,6 +1285,7 @@ pub struct ClassBuilder { impl ClassBuilder { #[doc(hidden)] #[inline] + #[track_caller] pub fn __internal_new() -> Self { let class_name = __internal::make_class_id(); @@ -1226,11 +1298,13 @@ impl ClassBuilder { #[doc(hidden)] #[inline] + #[track_caller] pub fn __internal_class_name(&self) -> &str { &self.class_name } #[inline] + #[track_caller] pub fn style(mut self, name: B, value: C) -> Self where B: MultiStr, C: MultiStr { @@ -1239,6 +1313,7 @@ impl ClassBuilder { } #[inline] + #[track_caller] pub fn style_important(mut self, name: B, value: C) -> Self where B: MultiStr, C: MultiStr { @@ -1247,6 +1322,7 @@ impl ClassBuilder { } #[inline] + #[track_caller] pub fn style_unchecked(mut self, name: B, value: C) -> Self where B: AsStr, C: AsStr { @@ -1255,6 +1331,7 @@ impl ClassBuilder { } #[inline] + #[track_caller] pub fn style_signal(mut self, name: B, value: E) -> Self where B: MultiStr + 'static, C: MultiStr, @@ -1266,6 +1343,7 @@ impl ClassBuilder { } #[inline] + #[track_caller] pub fn style_important_signal(mut self, name: B, value: E) -> Self where B: MultiStr + 'static, C: MultiStr, @@ -1277,6 +1355,7 @@ impl ClassBuilder { } #[inline] + #[track_caller] pub fn style_unchecked_signal(mut self, name: B, value: E) -> Self where B: AsStr + 'static, C: AsStr, @@ -1290,6 +1369,7 @@ impl ClassBuilder { // TODO return a Handle ? #[doc(hidden)] #[inline] + #[track_caller] pub fn __internal_done(self) -> String { self.stylesheet.__internal_done(); self.class_name diff --git a/src/events.rs b/src/events.rs index 003be58..5a299ee 100644 --- a/src/events.rs +++ b/src/events.rs @@ -17,7 +17,10 @@ impl StaticEvent for Event where T: JsCast fn unchecked_from_event(event: web_sys::Event) -> Self { Self { // TODO use unchecked_into in release mode ? - event: event.dyn_into().unwrap(), + event: crate::__unwrap!( + event.dyn_into(), + e => panic!("Invalid event type: {:?}", wasm_bindgen::JsValue::as_ref(&e)), + ), } } } diff --git a/src/routing.rs b/src/routing.rs index e082490..f78531f 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -59,6 +59,7 @@ pub fn url() -> ReadOnlyMutable { // TODO if URL hasn't been created yet, don't create it #[inline] +#[track_caller] pub fn go_to_url(new_url: &str) { // TODO intern ? bindings::go_to_url(new_url); diff --git a/src/utils.rs b/src/utils.rs index 5c7a367..5dd5884 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::mem::ManuallyDrop; -use wasm_bindgen::{UnwrapThrowExt, intern}; +use wasm_bindgen::{JsValue, UnwrapThrowExt, intern}; use discard::Discard; use web_sys::{EventTarget, Event}; @@ -125,3 +125,55 @@ impl Discard for FnDiscard where A: FnOnce() { self.0(); } } + + +pub(crate) trait UnwrapJsExt { + fn unwrap_js(self) -> T; +} + +#[cfg(debug_assertions)] +impl UnwrapJsExt for Result { + #[inline] + #[track_caller] + fn unwrap_js(self) -> T { + match self { + Ok(value) => value, + Err(e) => { + use wasm_bindgen::JsCast; + + match e.dyn_ref::() { + Some(e) => { + panic!("{}", e.message()); + }, + None => { + panic!("{:?}", e); + }, + } + }, + } + } +} + +#[cfg(not(debug_assertions))] +impl UnwrapJsExt for Result { + #[inline] + fn unwrap_js(self) -> T { + self.unwrap_or_else(|e| wasm_bindgen::throw_val(e)) + } +} + + +#[doc(hidden)] +#[macro_export] +macro_rules! __unwrap { + ($value:expr, $var:ident => $error:expr,) => {{ + #[cfg(debug_assertions)] + match $value { + Ok(value) => value, + Err($var) => $error, + } + + #[cfg(not(debug_assertions))] + $value.unwrap_throw() + }}; +}