use std::collections::HashMap;
use crate::headers::AcceptHeader;
use crate::headers::AcceptHeaderItem;
use crate::templating::HumusApiFormat;
use crate::templating::HumusFormatIdentifier;
use crate::templating::TemplatesManifest;
#[derive(Debug, Clone)]
pub struct FormatChooser {
accept_header_items: HashMap<AcceptHeaderItem, HumusFormatIdentifier>,
user_agent_prefixes: Vec<(String, HumusFormatIdentifier)>,
}
impl FormatChooser {
pub fn new<ApiFormat>(manifest: &TemplatesManifest) -> Self
where
ApiFormat: HumusApiFormat,
{
let mut accept_header_items: HashMap<AcceptHeaderItem, HumusFormatIdentifier> =
HashMap::new();
for (id, format_description) in &manifest.format {
if ApiFormat::from_name(id).is_some() {
continue;
}
accept_header_items.insert(
AcceptHeaderItem::MediaType(
format_description.media_type.essence_str().to_string(),
),
*id,
);
accept_header_items.insert(
AcceptHeaderItem::PartialWildcard(
format_description.media_type.type_().to_string(),
),
*id,
);
}
for api_format in ApiFormat::get_all() {
let id = api_format.get_name();
let media_type = api_format.get_media_type();
accept_header_items.insert(
AcceptHeaderItem::MediaType(media_type.essence_str().to_string()),
id,
);
accept_header_items.insert(
AcceptHeaderItem::PartialWildcard(media_type.type_().to_string()),
id,
);
}
for (item, id) in &manifest.media_type_aliases {
accept_header_items.insert(item.clone(), *id);
}
let mut user_agent_prefixes: Vec<(String, HumusFormatIdentifier)> = manifest
.format_by_user_agent_prefix
.iter()
.map(|(prefix, format)| (prefix.clone(), *format))
.collect();
user_agent_prefixes.sort_by_key(|(prefix_a, _)| std::cmp::Reverse(prefix_a.len()));
Self {
accept_header_items,
user_agent_prefixes,
}
}
pub fn choose_from_accept_header(
&self,
header: &AcceptHeader,
) -> Option<HumusFormatIdentifier> {
for (item, _) in &header.items {
if matches!(item, AcceptHeaderItem::Wildcard) {
return None;
}
if let Some(format) = self.accept_header_items.get(item) {
return Some(*format);
}
}
None
}
pub fn choose_from_user_agent(&self, user_agent: &str) -> Option<HumusFormatIdentifier> {
for (prefix, format) in &self.user_agent_prefixes {
if user_agent.starts_with(prefix) {
return Some(*format);
}
}
None
}
}