aboutsummaryrefslogtreecommitdiffstats
path: root/rust/fatcat-openapi/src/header.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/fatcat-openapi/src/header.rs')
-rw-r--r--rust/fatcat-openapi/src/header.rs197
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 00000000..7589ab08
--- /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
+ )),
+ }
+ }
+}