From 67c43acdd8c0df444b46404ff07d6363ad60b04a Mon Sep 17 00:00:00 2001 From: Vidhan Bhatt Date: Thu, 5 Jun 2025 14:24:32 -0400 Subject: [PATCH 1/3] [breaking] refactor location api to be more intuitive --- src/responders/location.rs | 91 ++++++++++++++------------------------ 1 file changed, 34 insertions(+), 57 deletions(-) diff --git a/src/responders/location.rs b/src/responders/location.rs index 91b20e9..b4a94bf 100644 --- a/src/responders/location.rs +++ b/src/responders/location.rs @@ -16,68 +16,66 @@ use crate::{HxError, headers}; /// See for more information. #[derive(Debug, Clone)] pub struct HxLocation { - /// Uri of the new location. - pub uri: String, + /// URI path of the new location. + pub path: String, /// Extra options. #[cfg(feature = "serde")] #[cfg_attr(feature = "unstable", doc(cfg(feature = "serde")))] - pub options: LocationOptions, + pub options: Option, } impl HxLocation { - /// Parses `uri` and sets it as location. + /// Sets `path` as the location. #[allow(clippy::should_implement_trait)] - pub fn from_str(uri: impl AsRef) -> Self { + pub fn from_path(path: impl AsRef) -> Self { Self { + path: path.as_ref().to_owned(), #[cfg(feature = "serde")] - options: LocationOptions::default(), - uri: uri.as_ref().to_string(), + options: None, } } - /// Parses `uri` and sets it as location with additional options. + /// Sets `path` as the location with additional options. #[cfg(feature = "serde")] #[cfg_attr(feature = "unstable", doc(cfg(feature = "serde")))] - pub fn from_str_with_options(uri: impl AsRef, options: LocationOptions) -> Self { + pub fn from_path_with_options(path: impl AsRef, options: LocationOptions) -> Self { Self { - options, - uri: uri.as_ref().to_string(), + path: path.as_ref().to_string(), + options: Some(options), } } - #[cfg(feature = "serde")] fn into_header_with_options(self) -> Result { - if self.options.is_default() { - return Ok(self.uri.to_string()); - } - - #[derive(::serde::Serialize)] - struct LocWithOpts { - path: String, - #[serde(flatten)] - opts: LocationOptions, + match self.options { + Some(options) => { + #[derive(serde::Serialize)] + struct FlattenedHxLocation<'a> { + path: &'a str, + #[serde(flatten)] + options: &'a LocationOptions, + } + let loc_with_opts = FlattenedHxLocation { + path: &self.path, + options: &options, + }; + Ok(serde_json::to_string(&loc_with_opts)?) + } + _ => Ok(self.path), } - - let loc_with_opts = LocWithOpts { - path: self.uri.to_string(), - opts: self.options, - }; - - Ok(serde_json::to_string(&loc_with_opts)?) } } impl<'a> From<&'a str> for HxLocation { - fn from(uri: &'a str) -> Self { - Self::from_str(uri) + fn from(path: &'a str) -> Self { + Self::from_path(path) } } #[cfg(feature = "serde")] #[cfg_attr(feature = "unstable", doc(cfg(feature = "serde")))] impl<'a> From<(&'a str, LocationOptions)> for HxLocation { - fn from((uri, options): (&'a str, LocationOptions)) -> Self { - Self::from_str_with_options(uri, options) + fn from((path, options): (&'a str, LocationOptions)) -> Self { + Self::from_path_with_options(path, options) } } @@ -88,7 +86,7 @@ impl IntoResponseParts for HxLocation { #[cfg(feature = "serde")] let header = self.into_header_with_options()?; #[cfg(not(feature = "serde"))] - let header = self.uri.to_string(); + let header = self.path.to_string(); res.headers_mut().insert( headers::HX_LOCATION, @@ -138,29 +136,8 @@ pub struct LocationOptions { // Hacky way of making this struct non-exhaustive. // See and for reasoning. #[serde(skip)] - pub non_exhaustive: (), -} - -#[cfg(feature = "serde")] -#[cfg_attr(feature = "unstable", doc(cfg(feature = "serde")))] -impl LocationOptions { - pub(super) fn is_default(&self) -> bool { - let Self { - source: None, - event: None, - handler: None, - target: None, - swap: None, - values: None, - headers: None, - non_exhaustive: (), - } = self - else { - return false; - }; - - true - } + #[doc(hidden)] + pub _non_exhaustive: (), } #[cfg(test)] @@ -175,7 +152,7 @@ mod tests { let loc = HxLocation::from("/foo"); assert_eq!(loc.into_header_with_options().unwrap(), "/foo"); - let loc = HxLocation::from_str_with_options( + let loc = HxLocation::from_path_with_options( "/foo", LocationOptions { event: Some("click".into()), From e8f32c927ca19158779299185a1edaefe072a4f4 Mon Sep 17 00:00:00 2001 From: Vidhan Bhatt Date: Thu, 5 Jun 2025 14:26:45 -0400 Subject: [PATCH 2/3] add feature flag --- src/responders/location.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/responders/location.rs b/src/responders/location.rs index b4a94bf..bcff8b7 100644 --- a/src/responders/location.rs +++ b/src/responders/location.rs @@ -45,9 +45,10 @@ impl HxLocation { } } + #[cfg(feature = "serde")] fn into_header_with_options(self) -> Result { match self.options { - Some(options) => { + Some(options) if !options.is_default() => { #[derive(serde::Serialize)] struct FlattenedHxLocation<'a> { path: &'a str, From a9c2ba5e8e04bcc7ac970982256af26cc0f555cf Mon Sep 17 00:00:00 2001 From: Vidhan Bhatt Date: Thu, 5 Jun 2025 14:27:23 -0400 Subject: [PATCH 3/3] get rid of is_default --- src/responders/location.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/responders/location.rs b/src/responders/location.rs index bcff8b7..d9c0ad8 100644 --- a/src/responders/location.rs +++ b/src/responders/location.rs @@ -48,7 +48,7 @@ impl HxLocation { #[cfg(feature = "serde")] fn into_header_with_options(self) -> Result { match self.options { - Some(options) if !options.is_default() => { + Some(options) => { #[derive(serde::Serialize)] struct FlattenedHxLocation<'a> { path: &'a str,