From 3d4b68143f05eb6f9d08b501e88dca59036308c4 Mon Sep 17 00:00:00 2001 From: Nicolas Guichard Date: Sat, 16 Nov 2024 01:39:46 +0100 Subject: [PATCH 1/3] Change NoCustomError to be an empty enum Contrary to an empty struct, which has exactly 1 possible value, an empty enum has 0 possible values: it can't even be constructed. Fixes #3154 --- server_fn/src/error.rs | 51 +++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/server_fn/src/error.rs b/server_fn/src/error.rs index c139dde062..13215a5b52 100644 --- a/server_fn/src/error.rs +++ b/server_fn/src/error.rs @@ -31,24 +31,50 @@ impl From for Error { Clone, Copy, )] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -pub struct NoCustomError; +pub enum NoCustomError {} + +#[cfg(feature = "rkyv")] +impl rkyv::Archive for NoCustomError { + const COPY_OPTIMIZATION: rkyv::traits::CopyOptimization = + rkyv::traits::CopyOptimization::disable(); + type Archived = (); + type Resolver = (); + fn resolve(&self, _: Self::Resolver, _: rkyv::Place) { + match *self {} + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Deserialize + for NoCustomError +{ + fn deserialize(&self, _: &mut D) -> Result { + match *self {} + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Serialize for NoCustomError { + fn serialize( + &self, + _: &mut S, + ) -> Result::Error> { + match *self {} + } +} // Implement `Display` for `NoCustomError` impl fmt::Display for NoCustomError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Unit Type Displayed") + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + match *self {} } } impl FromStr for NoCustomError { type Err = (); - fn from_str(_s: &str) -> Result { - Ok(NoCustomError) + fn from_str(_: &str) -> Result { + Err(()) } } @@ -94,13 +120,6 @@ pub(crate) trait ServerFnErrorKind {} impl ServerFnErrorKind for ServerFnError {} -// This impl should catch passing () or nothing to server_fn_error -impl ViaError for &&&WrapError<()> { - fn to_server_error(&self) -> ServerFnError { - ServerFnError::WrappedServerError(NoCustomError) - } -} - // This impl will catch any type that implements any type that impls // Error and Clone, so that it can be wrapped into ServerFnError impl ViaError for &&WrapError { From a9ad221d99bc6f35074d93d648459662f2bb9cbe Mon Sep 17 00:00:00 2001 From: Nicolas Guichard Date: Sat, 16 Nov 2024 03:16:03 +0100 Subject: [PATCH 2/3] Provide conversion utilities around Result> This adds 3 new traits: - `ConvertServerFnResult` provides easy conversion from `Result>` to `Result>` when `TargetCustError` implements `From` - `ConvertDefaultServerFnResult` provides easy conversion from `Result` to `Result>` - `IntoServerFnResult` provides easy conversion from `Result` to `Result` when `E` implements `std::error::Error` Fixes #3153 and #3155 --- server_fn/src/error.rs | 189 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/server_fn/src/error.rs b/server_fn/src/error.rs index 13215a5b52..63d73b9005 100644 --- a/server_fn/src/error.rs +++ b/server_fn/src/error.rs @@ -200,6 +200,195 @@ impl From for ServerFnError { } } +/// Helper trait to convert from `Result>` to `Result>` +/// +/// This is meant to ease the use of the `?` operator: +/// ``` +/// use server_fn::{error::ConvertServerFnResult, ServerFnError}; +/// +/// enum Helper1Error { +/// ErrorCase1, +/// } +/// fn helper1() -> Result> { +/// Err(ServerFnError::WrappedServerError(Helper1Error::ErrorCase1)) +/// } +/// +/// enum Helper2Error { +/// ErrorCase2, +/// } +/// fn helper2() -> Result> { +/// Err(ServerFnError::WrappedServerError(Helper2Error::ErrorCase2)) +/// } +/// +/// enum FnError { +/// ErrorCase1, +/// ErrorCase2, +/// } +/// fn server_fn() -> Result> { +/// Ok(helper1().convert_custom_error()? +/// + helper2().convert_custom_error()?) +/// } +/// +/// impl From for FnError { +/// fn from(e: Helper1Error) -> Self { +/// match e { +/// Helper1Error::ErrorCase1 => Self::ErrorCase1, +/// } +/// } +/// } +/// +/// impl From for FnError { +/// fn from(e: Helper2Error) -> Self { +/// match e { +/// Helper2Error::ErrorCase2 => Self::ErrorCase2, +/// } +/// } +/// } +/// ``` +/// +/// See also [`ConvertDefaultServerFnResult`] for conversion from the default [`ServerFnError`] +/// and [`ConvertServerFnResult`] for conversion between different custom error types. +pub trait ConvertServerFnResult { + /// Converts a `Result>` into a `Result>`. + /// + /// `FromCustErr` must implement `Into`. + /// + /// See the [trait-level documentation](ConvertServerFnResult) for usage examples. + fn convert_custom_error(self) -> Result>; +} + +impl ConvertServerFnResult + for Result> +where + FromCustErr: Into, +{ + fn convert_custom_error(self) -> Result> { + self.map_err(|err| match err { + ServerFnError::::MissingArg(s) => { + ServerFnError::::MissingArg(s) + } + ServerFnError::::Args(s) => { + ServerFnError::::Args(s) + } + ServerFnError::::Serialization(s) => { + ServerFnError::::Serialization(s) + } + ServerFnError::::ServerError(s) => { + ServerFnError::::ServerError(s) + } + ServerFnError::::Response(s) => { + ServerFnError::::Response(s) + } + ServerFnError::::Registration(s) => { + ServerFnError::::Registration(s) + } + ServerFnError::::Request(s) => { + ServerFnError::::Request(s) + } + ServerFnError::::Deserialization(s) => { + ServerFnError::::Deserialization(s) + } + ServerFnError::::WrappedServerError(o) => { + ServerFnError::::WrappedServerError(o.into()) + } + }) + } +} + +/// Helper trait to convert from `Result` to `Result>` +/// +/// This is meant to ease the use of the `?` operator: +/// ``` +/// use server_fn::{error::ConvertDefaultServerFnResult, ServerFnError}; +/// +/// fn helper() -> Result { +/// Err(ServerFnError::ServerError(String::from("Server error"))) +/// } +/// +/// enum FnError { +/// TypedError, +/// } +/// fn server_fn() -> Result> { +/// Ok(helper().convert_custom_error()?) +/// } +/// ``` +/// +/// See also [`ConvertServerFnResult`] for conversion between different custom error types +/// and [`IntoServerFnResult`] for string-based conversion from any [`std::error::Error`]. +pub trait ConvertDefaultServerFnResult { + /// Converts a `Result` into a `Result>`. + /// + /// See the [trait-level documentation](ConvertDefaultServerFnResult) for usage examples. + fn convert_custom_error(self) -> Result>; +} +impl ConvertDefaultServerFnResult + for Result +{ + fn convert_custom_error(self) -> Result> { + self.map_err(|err| match err { + ServerFnError::MissingArg(s) => { + ServerFnError::::MissingArg(s) + } + ServerFnError::Args(s) => ServerFnError::::Args(s), + ServerFnError::Serialization(s) => { + ServerFnError::::Serialization(s) + } + ServerFnError::ServerError(s) => { + ServerFnError::::ServerError(s) + } + ServerFnError::Response(s) => ServerFnError::::Response(s), + ServerFnError::Registration(s) => { + ServerFnError::::Registration(s) + } + ServerFnError::Request(s) => ServerFnError::::Request(s), + ServerFnError::Deserialization(s) => { + ServerFnError::::Deserialization(s) + } + }) + } +} + +/// Helper trait to convert from `Result` to `Result>` +/// +/// This is meant to ease the use of the `?` operator: +/// ``` +/// use server_fn::{error::IntoServerFnResult, ServerFnError}; +/// +/// fn helper() -> Result { +/// "3".parse() +/// } +/// +/// enum FnError { +/// ErrorCase1, +/// } +/// fn server_fn() -> Result> { +/// Ok(helper().into_server_fn_result()?) +/// } +/// ``` +/// +/// See also [`ConvertDefaultServerFnResult`] for conversion from the default [`ServerFnError`] +/// and [`ConvertServerFnResult`] for conversion between different custom error types. +pub trait IntoServerFnResult { + /// Converts a `Result` into a `Result>`. + /// + /// Maps the error to [`ServerFnError::ServerError()`] using [`Error::to_string()`]. + /// + /// When using the default [`NoCustomError`], one can directly use [`Into`] instead. + /// + /// See the [trait-level documentation](IntoServerFnResult) for usage examples. + fn into_server_fn_result(self) -> Result>; +} + +impl IntoServerFnResult + for Result +{ + fn into_server_fn_result(self) -> Result> { + self.map_err(|err| { + ServerFnError::::ServerError(err.to_string()) + }) + } +} + impl Display for ServerFnError where CustErr: Display, From 8f2cf7a66e840deb578a2d8a3162f3d0b4035936 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 17 Nov 2024 20:44:03 +0000 Subject: [PATCH 3/3] [autofix.ci] apply automated fixes --- router/src/matching/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/router/src/matching/mod.rs b/router/src/matching/mod.rs index b5247dc315..a60102e8ae 100644 --- a/router/src/matching/mod.rs +++ b/router/src/matching/mod.rs @@ -64,10 +64,7 @@ where } else { (base.as_ref(), path) }; - match path.strip_prefix(base) { - Some(path) => path, - None => return None, - } + path.strip_prefix(base)? } };