lib_humus/templating/
format_chooser.rs1use std::collections::HashMap;
6
7use crate::headers::AcceptHeader;
8use crate::headers::AcceptHeaderItem;
9use crate::templating::HumusApiFormat;
10use crate::templating::HumusFormatIdentifier;
11use crate::templating::TemplatesManifest;
12
13#[derive(Debug, Clone)]
15pub struct FormatChooser {
16 accept_header_items: HashMap<AcceptHeaderItem, HumusFormatIdentifier>,
18
19 user_agent_prefixes: Vec<(String, HumusFormatIdentifier)>,
21}
22
23impl FormatChooser {
24 pub fn new<ApiFormat>(manifest: &TemplatesManifest) -> Self
26 where
27 ApiFormat: HumusApiFormat,
28 {
29 let mut accept_header_items: HashMap<AcceptHeaderItem, HumusFormatIdentifier> =
30 HashMap::new();
31
32 for (id, format_description) in &manifest.format {
33 if ApiFormat::from_name(id).is_some() {
35 continue;
36 }
37
38 accept_header_items.insert(
40 AcceptHeaderItem::MediaType(
41 format_description.media_type.essence_str().to_string(),
42 ),
43 *id,
44 );
45 accept_header_items.insert(
47 AcceptHeaderItem::PartialWildcard(
48 format_description.media_type.type_().to_string(),
49 ),
50 *id,
51 );
52 }
53
54 for api_format in ApiFormat::get_all() {
55 let id = api_format.get_name();
56 let media_type = api_format.get_media_type();
57
58 accept_header_items.insert(
60 AcceptHeaderItem::MediaType(media_type.essence_str().to_string()),
61 id,
62 );
63 accept_header_items.insert(
65 AcceptHeaderItem::PartialWildcard(media_type.type_().to_string()),
66 id,
67 );
68 }
69
70 for (item, id) in &manifest.media_type_aliases {
72 accept_header_items.insert(item.clone(), *id);
73 }
74
75 let mut user_agent_prefixes: Vec<(String, HumusFormatIdentifier)> = manifest
80 .format_by_user_agent_prefix
81 .iter()
82 .map(|(prefix, format)| (prefix.clone(), *format))
83 .collect();
84
85 user_agent_prefixes.sort_by_key(|(prefix_a, _)| std::cmp::Reverse(prefix_a.len()));
87
88 Self {
89 accept_header_items,
90 user_agent_prefixes,
91 }
92 }
93
94 pub fn choose_from_accept_header(
96 &self,
97 header: &AcceptHeader,
98 ) -> Option<HumusFormatIdentifier> {
99 for (item, _) in &header.items {
100 if matches!(item, AcceptHeaderItem::Wildcard) {
101 return None;
102 }
103 if let Some(format) = self.accept_header_items.get(item) {
104 return Some(*format);
105 }
106 }
107 None
108 }
109
110 pub fn choose_from_user_agent(&self, user_agent: &str) -> Option<HumusFormatIdentifier> {
112 for (prefix, format) in &self.user_agent_prefixes {
113 if user_agent.starts_with(prefix) {
114 return Some(*format);
115 }
116 }
117 None
118 }
119}