use crate::config_bag::{Storable, StoreReplace};
use crate::Document;
use std::borrow::Cow;
use std::collections::HashMap;
type MaybeStatic = Cow<'static, str>;
#[derive(Debug, Clone, PartialEq)]
pub struct EndpointAuthScheme {
name: MaybeStatic,
properties: Vec<(MaybeStatic, Document)>,
}
impl EndpointAuthScheme {
pub fn with_capacity(name: impl Into<MaybeStatic>, capacity: usize) -> Self {
Self {
name: name.into(),
properties: Vec::with_capacity(capacity),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn put(mut self, key: impl Into<MaybeStatic>, value: impl Into<Document>) -> Self {
self.properties.push((key.into(), value.into()));
self
}
pub fn get(&self, key: &str) -> Option<&Document> {
self.properties
.iter()
.find(|(k, _)| k.as_ref() == key)
.map(|(_, v)| v)
}
pub fn as_document(&self) -> Document {
let mut map = HashMap::with_capacity(self.properties.len() + 1);
map.insert("name".to_string(), Document::String(self.name.to_string()));
for (k, v) in &self.properties {
map.insert(k.to_string(), v.clone());
}
Document::Object(map)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Endpoint {
url: MaybeStatic,
headers: HashMap<MaybeStatic, Vec<MaybeStatic>>,
properties: HashMap<MaybeStatic, Document>,
auth_schemes: Vec<EndpointAuthScheme>,
}
#[allow(unused)]
impl Endpoint {
pub fn url(&self) -> &str {
&self.url
}
pub fn headers(&self) -> impl Iterator<Item = (&str, impl Iterator<Item = &str>)> {
self.headers
.iter()
.map(|(k, v)| (k.as_ref(), v.iter().map(|v| v.as_ref())))
}
pub fn properties(&self) -> &HashMap<Cow<'static, str>, Document> {
&self.properties
}
pub fn auth_schemes(&self) -> &[EndpointAuthScheme] {
&self.auth_schemes
}
pub fn into_builder(self) -> Builder {
Builder { endpoint: self }
}
pub fn builder() -> Builder {
Builder::new()
}
}
impl Storable for Endpoint {
type Storer = StoreReplace<Self>;
}
#[derive(Debug, Clone)]
pub struct Builder {
endpoint: Endpoint,
}
#[allow(unused)]
impl Builder {
pub(crate) fn new() -> Self {
Self {
endpoint: Endpoint {
url: Default::default(),
headers: HashMap::new(),
properties: HashMap::new(),
auth_schemes: Vec::new(),
},
}
}
pub fn url(mut self, url: impl Into<MaybeStatic>) -> Self {
self.endpoint.url = url.into();
self
}
pub fn header(mut self, name: impl Into<MaybeStatic>, value: impl Into<MaybeStatic>) -> Self {
self.endpoint
.headers
.entry(name.into())
.or_default()
.push(value.into());
self
}
pub fn property(mut self, key: impl Into<MaybeStatic>, value: impl Into<Document>) -> Self {
self.endpoint.properties.insert(key.into(), value.into());
self
}
pub fn auth_scheme(mut self, auth_scheme: EndpointAuthScheme) -> Self {
self.endpoint.auth_schemes.push(auth_scheme);
self
}
pub fn build(self) -> Endpoint {
assert_ne!(self.endpoint.url(), "", "URL was unset");
self.endpoint
}
}
#[cfg(test)]
mod test {
use crate::endpoint::Endpoint;
use crate::Document;
use std::borrow::Cow;
use std::collections::HashMap;
#[test]
fn endpoint_builder() {
let endpoint = Endpoint::builder()
.url("https://www.amazon.com")
.header("x-amz-test", "header-value")
.property("custom", Document::Bool(true))
.build();
assert_eq!(endpoint.url, Cow::Borrowed("https://www.amazon.com"));
assert_eq!(
endpoint.headers,
HashMap::from([(
Cow::Borrowed("x-amz-test"),
vec![Cow::Borrowed("header-value")]
)])
);
assert_eq!(
endpoint.properties,
HashMap::from([(Cow::Borrowed("custom"), Document::Bool(true))])
);
assert_eq!(endpoint.url(), "https://www.amazon.com");
assert_eq!(
endpoint
.headers()
.map(|(k, v)| (k, v.collect::<Vec<_>>()))
.collect::<Vec<_>>(),
vec![("x-amz-test", vec!["header-value"])]
);
}
#[test]
fn borrowed_values() {
fn foo(a: &str) {
let endpoint = Endpoint::builder().url(a.to_string()).build();
assert_eq!(endpoint.url(), a);
}
foo("asdf");
}
}