about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJiahao XU <Jiahao_XU@outlook.com>2022-06-22 22:43:54 +1000
committerJiahao XU <Jiahao_XU@outlook.com>2022-06-22 22:44:30 +1000
commite0ea0c25341a34bbaa96a8173096e7713d472131 (patch)
tree9ed2d0ebe234281fe8e9883f67466165d9ee9ad6
parent1713e25a411c3854e85baa5fe076d5e3e8cffe35 (diff)
downloadrust-e0ea0c25341a34bbaa96a8173096e7713d472131.tar.gz
rust-e0ea0c25341a34bbaa96a8173096e7713d472131.zip
Add new unstable API `Error::try_downgrade_inner`
Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
-rw-r--r--library/std/src/io/error.rs57
1 files changed, 57 insertions, 0 deletions
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 4a50e647c64..b1931a52290 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -795,6 +795,63 @@ impl Error {
         }
     }
 
+    /// Attempt to downgrade the inner error to `E` if any.
+    ///
+    /// If this [`Error`] was constructed via [`new`] then this function will
+    /// attempt to perform downgrade on it, otherwise it will return [`Err`].
+    ///
+    /// If downgrade succeeds, it will return [`Ok`], otherwise it will also
+    /// return [`Err`].
+    ///
+    /// [`new`]: Error::new
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(io_error_try_downcast_inner)]
+    ///
+    /// use std::fmt;
+    /// use std::io;
+    /// use std::error::Error;
+    ///
+    /// #[derive(Debug)]
+    /// enum E {
+    ///     Io(io::Error),
+    ///     SomeOtherVariant,
+    /// }
+    ///
+    /// impl fmt::Display for E {
+    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         todo!()
+    ///     }
+    /// }
+    /// impl Error for E {}
+    ///
+    /// impl From<io::Error> for E {
+    ///     fn from(err: io::Error) -> E {
+    ///         err.try_downcast_inner::<E>()
+    ///             .map(|b| *b)
+    ///             .unwrap_or_else(E::Io)
+    ///     }
+    /// }
+    /// ```
+    #[unstable(feature = "io_error_try_downcast_inner", issue = "none")]
+    pub fn try_downcast_inner<E>(self) -> result::Result<Box<E>, Self>
+    where
+        E: error::Error + Send + Sync + 'static,
+    {
+        match self.repr.into_data() {
+            ErrorData::Custom(b) if b.error.is::<E>() => {
+                let res = (*b).error.downcast::<E>();
+
+                // Safety: b.error.is::<E>() returns true,
+                // which means that res must be Ok(e).
+                Ok(unsafe { res.unwrap_unchecked() })
+            }
+            repr_data => Err(Self { repr: Repr::new(repr_data) }),
+        }
+    }
+
     /// Returns the corresponding [`ErrorKind`] for this error.
     ///
     /// # Examples