azure_sdk_core 0.43.7

Rust wrappers around Microsoft Azure REST APIs - Core crate
Documentation
use bytes::{Bytes, BytesMut};
use http::{self, request::Builder};
use hyper::header::{AsHeaderName, HeaderMap, HeaderName, HeaderValue};
use std::{
    convert::TryFrom,
    fmt::Display,
    io::{self, Write},
    str::FromStr,
};

struct Writer(BytesMut);
impl io::Write for Writer {
    fn write(&mut self, src: &[u8]) -> io::Result<usize> {
        self.0.extend_from_slice(src);
        Ok(src.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

fn format_as_bytes<D: Display>(value: D) -> Bytes {
    let mut wrt = Writer(BytesMut::new());
    let _ = write!(wrt, "{}", value);
    wrt.0.freeze()
}

#[allow(dead_code)]
pub fn into_header_value<B: Into<Bytes>>(value: B) -> Result<HeaderValue, http::Error> {
    let value: &[u8] = &value.into();
    Ok(HeaderValue::try_from(value)?)
}

pub fn format_header_value<D: Display>(value: D) -> Result<HeaderValue, http::Error> {
    let value: &[u8] = &format_as_bytes(value);
    Ok(HeaderValue::try_from(value)?)
}

pub trait HeaderMapExt {
    fn get_header<K: AsHeaderName>(&self, key: K) -> Option<&HeaderValue>;

    fn get_as_str<K: AsHeaderName>(&self, key: K) -> Option<&str> {
        self.get_header(key).and_then(|v| v.to_str().ok())
    }

    fn get_as_string<K: AsHeaderName>(&self, key: K) -> Option<String> {
        self.get_as_str(key).map(|s| s.to_owned())
    }

    fn get_as_u64<K: AsHeaderName>(&self, key: K) -> Option<u64> {
        self.get_as_str(key).and_then(|s| s.parse::<u64>().ok())
    }

    fn get_as_enum<K: AsHeaderName, V: FromStr<Err = E>, E>(&self, key: K) -> Result<Option<V>, E> {
        if let Some(s) = self.get_as_str(key) {
            return Ok(Some(s.parse::<V>()?));
        }
        Ok(None)
    }
}

impl HeaderMapExt for HeaderMap {
    fn get_header<K: AsHeaderName>(&self, key: K) -> Option<&HeaderValue> {
        self.get(key)
    }
}

pub trait RequestBuilderExt {
    fn set_header<K, V>(self, key: K, value: V) -> Self
    where
        HeaderName: TryFrom<K>,
        <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
        HeaderValue: TryFrom<V>,
        <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
        Self: Sized;

    fn header_formatted<K, D: Display>(self, key: K, value: D) -> Self
    where
        HeaderName: TryFrom<K>,
        <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
        Self: Sized,
    {
        self.set_header(key, &format_as_bytes(value) as &[u8])
    }

    fn header_static<K>(self, key: K, value: &'static str) -> Self
    where
        HeaderName: TryFrom<K>,
        <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
        Self: Sized,
    {
        self.set_header(key, HeaderValue::from_static(value))
    }

    fn header_bytes<K, B: Into<Bytes>>(self, key: K, value: B) -> Self
    where
        HeaderName: TryFrom<K>,
        <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
        Self: Sized,
    {
        self.set_header(key, &value.into() as &[u8])
    }
}

impl RequestBuilderExt for Builder {
    fn set_header<K, V>(self, key: K, value: V) -> Self
    where
        HeaderName: TryFrom<K>,
        <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
        HeaderValue: TryFrom<V>,
        <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
        Self: Sized,
    {
        self.header(key, value)
    }
}