diff --git a/src/endpoint.rs b/src/endpoint.rs index 6dc5470..54ca0ed 100644 --- a/src/endpoint.rs +++ b/src/endpoint.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + use crate::{ geometry::{Coords, Rect}, server::Server, @@ -43,6 +45,38 @@ pub enum FitIn { Full, } +struct Smart; + +impl Display for Smart { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "smart") + } +} + +struct Filters<'a>(&'a [Filter]); + +impl<'a> Filters<'a> { + fn new(filters: &'a [Filter]) -> Option { + if filters.is_empty() { + None + } else { + Some(Self(filters)) + } + } +} + +impl Display for Filters<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let filters = self + .0 + .iter() + .map(ToString::to_string) + .collect::>() + .join(":"); + write!(f, "filters:{}", filters) + } +} + #[derive(strum::Display)] pub enum ResponseMode { /// The metadata endpoint has **ALL** the options that the image one has, diff --git a/src/endpoint/builder.rs b/src/endpoint/builder.rs index 379d4c2..40866d9 100644 --- a/src/endpoint/builder.rs +++ b/src/endpoint/builder.rs @@ -1,58 +1,29 @@ -use super::Endpoint; +use super::{Endpoint, Filters, Smart}; use crate::server::Security; use base64ct::{Base64Url, Encoding}; use hmac::Mac; impl Endpoint { - fn build_path(&self, image_uri: &str) -> String { - let mut path = vec![]; - - if let Some(resp) = &self.response { - path.push(resp.to_string()); - } - - if let Some(orientation) = &self.trim { - path.push(orientation.to_string()); - } - - if let Some(crop) = &self.crop { - path.push(crop.to_string()); - } - - if let Some(fit_in) = &self.fit_in { - path.push(fit_in.to_string()); - } - - if let Some(resize) = &self.resize { - path.push(resize.to_string()); - } - - if let Some(h_align) = &self.h_align { - path.push(h_align.to_string()); - } - - if let Some(v_align) = &self.v_align { - path.push(v_align.to_string()); - } - - if self.smart { - path.push("smart".to_string()); - } - - if !self.filters.is_empty() { - let filters = self - .filters - .iter() - .map(ToString::to_string) - .collect::>() - .join(":"); - - path.push(format!("filters:{filters}")); - } - - path.push(image_uri.to_owned()); - - path.join("/") + fn build_path(&self, image_uri: impl ToString) -> String { + let smart = self.smart.then_some(Smart); + let filters = Filters::new(&self.filters); + + [ + self.response.as_ref().map(ToString::to_string), + self.trim.as_ref().map(ToString::to_string), + self.crop.as_ref().map(ToString::to_string), + self.fit_in.as_ref().map(ToString::to_string), + self.resize.as_ref().map(ToString::to_string), + self.h_align.as_ref().map(ToString::to_string), + self.v_align.as_ref().map(ToString::to_string), + smart.as_ref().map(ToString::to_string), + filters.as_ref().map(ToString::to_string), + Some(image_uri.to_string()), + ] + .into_iter() + .flatten() + .collect::>() + .join("/") } /// ``` @@ -64,7 +35,7 @@ impl Endpoint { /// /// assert_eq!(path, "/unsafe/path/to/my/image.jpg"); /// ``` - pub fn to_path(&self, image_uri: &str) -> String { + pub fn to_path(&self, image_uri: impl ToString) -> String { let path = self.build_path(image_uri); let security = match &self.server.security { @@ -90,7 +61,7 @@ impl Endpoint { /// /// assert_eq!(path, "http://localhost:8888/unsafe/path/to/my/image.jpg"); /// ``` - pub fn to_url(&self, image_uri: &str) -> String { + pub fn to_url(&self, image_uri: impl ToString) -> String { format!("{}{}", self.server.origin, self.to_path(image_uri)) } }