diff options
Diffstat (limited to 'rust/fatcat-openapi/src/header.rs')
-rw-r--r-- | rust/fatcat-openapi/src/header.rs | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/rust/fatcat-openapi/src/header.rs b/rust/fatcat-openapi/src/header.rs new file mode 100644 index 0000000..7589ab0 --- /dev/null +++ b/rust/fatcat-openapi/src/header.rs @@ -0,0 +1,197 @@ +use chrono::{DateTime, Utc}; +use hyper::header::HeaderValue; +use std::convert::TryFrom; +use std::fmt; +use std::ops::Deref; + +/// A struct to allow homogeneous conversion into a HeaderValue. We can't +/// implement the From/Into trait on HeaderValue because we don't own +/// either of the types. +#[derive(Debug, Clone)] +pub(crate) struct IntoHeaderValue<T>(pub T); + +// Generic implementations + +impl<T> Deref for IntoHeaderValue<T> { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +// Derive for each TryFrom<T> in hyper::header::HeaderValue + +macro_rules! ihv_generate { + ($t:ident) => { + impl TryFrom<HeaderValue> for IntoHeaderValue<$t> { + type Error = String; + + fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> { + match hdr_value.to_str() { + Ok(hdr_value) => match hdr_value.parse::<$t>() { + Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), + Err(e) => Err(format!( + "Unable to parse {} as a string: {}", + stringify!($t), + e + )), + }, + Err(e) => Err(format!( + "Unable to parse header {:?} as a string - {}", + hdr_value, e + )), + } + } + } + + impl TryFrom<IntoHeaderValue<$t>> for HeaderValue { + type Error = String; + + fn try_from(hdr_value: IntoHeaderValue<$t>) -> Result<Self, Self::Error> { + Ok(hdr_value.0.into()) + } + } + }; +} + +ihv_generate!(u64); +ihv_generate!(i64); +ihv_generate!(i16); +ihv_generate!(u16); +ihv_generate!(u32); +ihv_generate!(usize); +ihv_generate!(isize); +ihv_generate!(i32); + +// Custom derivations + +// Vec<String> + +impl TryFrom<HeaderValue> for IntoHeaderValue<Vec<String>> { + type Error = String; + + fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> { + match hdr_value.to_str() { + Ok(hdr_value) => Ok(IntoHeaderValue( + hdr_value + .split(',') + .filter_map(|x| match x.trim() { + "" => None, + y => Some(y.to_string()), + }) + .collect(), + )), + Err(e) => Err(format!( + "Unable to parse header: {:?} as a string - {}", + hdr_value, e + )), + } + } +} + +impl TryFrom<IntoHeaderValue<Vec<String>>> for HeaderValue { + type Error = String; + + fn try_from(hdr_value: IntoHeaderValue<Vec<String>>) -> Result<Self, Self::Error> { + match HeaderValue::from_str(&hdr_value.0.join(", ")) { + Ok(hdr_value) => Ok(hdr_value), + Err(e) => Err(format!( + "Unable to convert {:?} into a header - {}", + hdr_value, e + )), + } + } +} + +// String + +impl TryFrom<HeaderValue> for IntoHeaderValue<String> { + type Error = String; + + fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> { + match hdr_value.to_str() { + Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())), + Err(e) => Err(format!("Unable to convert header {:?} to {}", hdr_value, e)), + } + } +} + +impl TryFrom<IntoHeaderValue<String>> for HeaderValue { + type Error = String; + + fn try_from(hdr_value: IntoHeaderValue<String>) -> Result<Self, Self::Error> { + match HeaderValue::from_str(&hdr_value.0) { + Ok(hdr_value) => Ok(hdr_value), + Err(e) => Err(format!( + "Unable to convert {:?} from a header {}", + hdr_value, e + )), + } + } +} + +// bool +impl TryFrom<HeaderValue> for IntoHeaderValue<bool> { + type Error = String; + + fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> { + match hdr_value.to_str() { + Ok(hdr_value) => match hdr_value.parse() { + Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), + Err(e) => Err(format!("Unable to parse bool from {} - {}", hdr_value, e)), + }, + Err(e) => Err(format!( + "Unable to convert {:?} from a header {}", + hdr_value, e + )), + } + } +} + +impl TryFrom<IntoHeaderValue<bool>> for HeaderValue { + type Error = String; + + fn try_from(hdr_value: IntoHeaderValue<bool>) -> Result<Self, Self::Error> { + match HeaderValue::from_str(&hdr_value.0.to_string()) { + Ok(hdr_value) => Ok(hdr_value), + Err(e) => Err(format!( + "Unable to convert: {:?} into a header: {}", + hdr_value, e + )), + } + } +} + +// DateTime + +impl TryFrom<HeaderValue> for IntoHeaderValue<DateTime<Utc>> { + type Error = String; + + fn try_from(hdr_value: HeaderValue) -> Result<Self, Self::Error> { + match hdr_value.to_str() { + Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) { + Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))), + Err(e) => Err(format!("Unable to parse: {} as date - {}", hdr_value, e)), + }, + Err(e) => Err(format!( + "Unable to convert header {:?} to string {}", + hdr_value, e + )), + } + } +} + +impl TryFrom<IntoHeaderValue<DateTime<Utc>>> for HeaderValue { + type Error = String; + + fn try_from(hdr_value: IntoHeaderValue<DateTime<Utc>>) -> Result<Self, Self::Error> { + match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) { + Ok(hdr_value) => Ok(hdr_value), + Err(e) => Err(format!( + "Unable to convert {:?} to a header: {}", + hdr_value, e + )), + } + } +} |