소스 검색

provide nicer error types

Evan Almloff 2 년 전
부모
커밋
1aad285853
2개의 변경된 파일72개의 추가작업 그리고 29개의 파일을 삭제
  1. 44 13
      packages/html/src/events/mounted.rs
  2. 28 16
      packages/html/src/web_sys_bind/events.rs

+ 44 - 13
packages/html/src/events/mounted.rs

@@ -2,30 +2,34 @@
 
 use euclid::Rect;
 
-use std::{any::Any, rc::Rc};
+use std::{
+    any::Any,
+    fmt::{Display, Formatter},
+    rc::Rc,
+};
 
 /// An Element that has been rendered and allows reading and modifying information about it.
 ///
 /// Different platforms will have different implementations and different levels of support for this trait. Renderers that do not support specific features will return `None` for those queries.
 pub trait RenderedElementBacking {
     /// Get the renderer specific element for the given id
-    fn get_raw_element(&self) -> Option<&dyn Any> {
-        None
+    fn get_raw_element(&self) -> MountedResult<&dyn Any> {
+        Err(MountedError::NotSupported)
     }
 
     /// Get the bounding rectangle of the element relative to the viewport (this does not include the scroll position)
-    fn get_client_rect(&self) -> Option<Rect<f64, f64>> {
-        None
+    fn get_client_rect(&self) -> MountedResult<Rect<f64, f64>> {
+        Err(MountedError::NotSupported)
     }
 
     /// Scroll to make the element visible
-    fn scroll_to(&self, _behavior: ScrollBehavior) -> Option<()> {
-        None
+    fn scroll_to(&self, _behavior: ScrollBehavior) -> MountedResult<()> {
+        Err(MountedError::NotSupported)
     }
 
     /// Set the focus on the element
-    fn set_focus(&self, _focus: bool) -> Option<()> {
-        None
+    fn set_focus(&self, _focus: bool) -> MountedResult<()> {
+        Err(MountedError::NotSupported)
     }
 }
 
@@ -53,22 +57,22 @@ impl MountedData {
     }
 
     /// Get the renderer specific element for the given id
-    pub fn get_raw_element(&self) -> Option<&dyn Any> {
+    pub fn get_raw_element(&self) -> MountedResult<&dyn Any> {
         self.inner.get_raw_element()
     }
 
     /// Get the bounding rectangle of the element relative to the viewport (this does not include the scroll position)
-    pub fn get_client_rect(&self) -> Option<Rect<f64, f64>> {
+    pub fn get_client_rect(&self) -> MountedResult<Rect<f64, f64>> {
         self.inner.get_client_rect()
     }
 
     /// Scroll to make the element visible
-    pub fn scroll_to(&self, behavior: ScrollBehavior) -> Option<()> {
+    pub fn scroll_to(&self, behavior: ScrollBehavior) -> MountedResult<()> {
         self.inner.scroll_to(behavior)
     }
 
     /// Set the focus on the element
-    pub fn set_focus(&self, focus: bool) -> Option<()> {
+    pub fn set_focus(&self, focus: bool) -> MountedResult<()> {
         self.inner.set_focus(focus)
     }
 }
@@ -83,3 +87,30 @@ impl_event! [
     /// mounted
     onmounted
 ];
+
+/// The MountedResult type for the MountedData
+pub type MountedResult<T> = Result<T, MountedError>;
+
+#[derive(Debug)]
+/// The error type for the MountedData
+pub enum MountedError {
+    /// The renderer does not support the requested operation
+    NotSupported,
+    /// The element was not found
+    OperationFailed(Box<dyn std::error::Error>),
+}
+
+impl Display for MountedError {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        match self {
+            MountedError::NotSupported => {
+                write!(f, "The renderer does not support the requested operation")
+            }
+            MountedError::OperationFailed(e) => {
+                write!(f, "The operation failed: {}", e)
+            }
+        }
+    }
+}
+
+impl std::error::Error for MountedError {}

+ 28 - 16
packages/html/src/web_sys_bind/events.rs

@@ -4,11 +4,13 @@ use crate::events::{
 };
 use crate::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint};
 use crate::input_data::{decode_key_location, decode_mouse_button_set, MouseButton};
-use crate::{DragData, MountedData, RenderedElementBacking, ScrollBehavior};
+use crate::{
+    DragData, MountedData, MountedError, MountedResult, RenderedElementBacking, ScrollBehavior,
+};
 use keyboard_types::{Code, Key, Modifiers};
 use std::convert::TryInto;
 use std::str::FromStr;
-use wasm_bindgen::JsCast;
+use wasm_bindgen::{JsCast, JsValue};
 use web_sys::{
     AnimationEvent, CompositionEvent, Event, KeyboardEvent, MouseEvent, PointerEvent,
     ScrollIntoViewOptions, TouchEvent, TransitionEvent, WheelEvent,
@@ -201,19 +203,19 @@ impl From<&web_sys::Element> for MountedData {
 }
 
 impl RenderedElementBacking for web_sys::Element {
-    fn get_client_rect(&self) -> Option<euclid::Rect<f64, f64>> {
+    fn get_client_rect(&self) -> MountedResult<euclid::Rect<f64, f64>> {
         let rect = self.get_bounding_client_rect();
-        Some(euclid::Rect::new(
+        Ok(euclid::Rect::new(
             euclid::Point2D::new(rect.left(), rect.top()),
             euclid::Size2D::new(rect.width(), rect.height()),
         ))
     }
 
-    fn get_raw_element(&self) -> Option<&dyn std::any::Any> {
-        Some(self)
+    fn get_raw_element(&self) -> MountedResult<&dyn std::any::Any> {
+        Ok(self)
     }
 
-    fn scroll_to(&self, behavior: ScrollBehavior) -> Option<()> {
+    fn scroll_to(&self, behavior: ScrollBehavior) -> MountedResult<()> {
         match behavior {
             ScrollBehavior::Instant => self.scroll_into_view_with_scroll_into_view_options(
                 ScrollIntoViewOptions::new().behavior(web_sys::ScrollBehavior::Instant),
@@ -223,16 +225,26 @@ impl RenderedElementBacking for web_sys::Element {
             ),
         }
 
-        Some(())
+        Ok(())
     }
 
-    fn set_focus(&self, focus: bool) -> Option<()> {
-        self.dyn_ref::<web_sys::HtmlElement>().and_then(|e| {
-            if focus {
-                e.focus().ok()
-            } else {
-                e.blur().ok()
-            }
-        })
+    fn set_focus(&self, focus: bool) -> MountedResult<()> {
+        self.dyn_ref::<web_sys::HtmlElement>()
+            .ok_or_else(|| MountedError::OperationFailed(Box::new(FocusError(self.into()))))
+            .and_then(|e| {
+                (if focus { e.focus() } else { e.blur() })
+                    .map_err(|err| MountedError::OperationFailed(Box::new(FocusError(err))))
+            })
     }
 }
+
+#[derive(Debug)]
+struct FocusError(JsValue);
+
+impl std::fmt::Display for FocusError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "failed to focus element {:?}", self.0)
+    }
+}
+
+impl std::error::Error for FocusError {}