1mod percent_encoding;
55mod templatevar;
56
57use crate::percent_encoding::{encode_reserved, encode_unreserved};
58use std::collections::HashMap;
59use std::str::FromStr;
60
61pub use crate::templatevar::{IntoTemplateVar, TemplateVar};
62
63enum VarSpecType {
64 Raw,
65 Prefixed(u16),
66 Exploded,
67}
68
69struct VarSpec {
70 name: String,
71 var_type: VarSpecType,
72}
73
74#[derive(PartialEq)]
75enum Operator {
76 Null,
77 Plus,
78 Dot,
79 Slash,
80 Semi,
81 Question,
82 Ampersand,
83 Hash,
84}
85
86enum TemplateComponent {
87 Literal(String),
88 VarList(Operator, Vec<VarSpec>),
89}
90
91pub struct UriTemplate {
93 components: Vec<TemplateComponent>,
94 vars: HashMap<String, TemplateVar>,
95}
96
97fn prefixed(s: &str, prefix: u16) -> String {
98 let prefix = prefix as usize;
99 if prefix >= s.len() {
100 s.to_string()
101 } else {
102 s[0..prefix].to_string()
103 }
104}
105
106fn parse_varlist(varlist: &str) -> TemplateComponent {
107 let mut varlist = varlist.to_string();
108 let operator = match varlist.chars().nth(0) {
109 Some(ch) => ch,
110 None => {
111 return TemplateComponent::VarList(Operator::Null, Vec::new());
112 }
113 };
114 let operator = match operator {
115 '+' => Operator::Plus,
116 '.' => Operator::Dot,
117 '/' => Operator::Slash,
118 ';' => Operator::Semi,
119 '?' => Operator::Question,
120 '&' => Operator::Ampersand,
121 '#' => Operator::Hash,
122 _ => Operator::Null,
123 };
124 if operator != Operator::Null {
125 varlist.remove(0);
126 }
127 let varspecs = varlist.split(",");
128 let mut varspec_list = Vec::new();
129 for varspec in varspecs {
130 let mut varspec = varspec.to_string();
131 let len = varspec.len();
132 if len >= 1 && varspec.chars().nth(len - 1).unwrap() == '*' {
133 varspec.pop();
134 varspec_list.push(VarSpec {
135 name: varspec,
136 var_type: VarSpecType::Exploded,
137 });
138 continue;
139 }
140 if varspec.contains(":") {
141 let parts: Vec<_> = varspec.splitn(2, ":").collect();
142 let prefix = u16::from_str(parts[1]).ok();
143 let prefix = match prefix {
144 Some(p) => p,
145 None => 9999u16,
146 };
147 varspec_list.push(VarSpec {
148 name: parts[0].to_string(),
149 var_type: VarSpecType::Prefixed(prefix),
150 });
151 continue;
152 }
153 varspec_list.push(VarSpec {
154 name: varspec,
155 var_type: VarSpecType::Raw,
156 });
157 }
158
159 TemplateComponent::VarList(operator, varspec_list)
160}
161
162fn encode_vec<E>(v: &Vec<String>, encoder: E) -> Vec<String>
163where
164 E: Fn(&str) -> String,
165{
166 v.iter().map(|s| encoder(&s)).collect()
167}
168
169impl UriTemplate {
170 pub fn new(template: &str) -> UriTemplate {
178 let mut components = Vec::new();
179 let mut buf = String::new();
180 let mut in_varlist = false;
181
182 for ch in template.chars() {
183 if in_varlist && ch == '}' {
184 components.push(parse_varlist(&buf));
185 buf = String::new();
186 in_varlist = false;
187 continue;
188 }
189 if !in_varlist && ch == '{' {
190 if buf.len() > 0 {
191 components.push(TemplateComponent::Literal(buf));
192 buf = String::new();
193 }
194 in_varlist = true;
195 continue;
196 }
197 buf.push(ch);
198 }
199
200 if buf.len() > 0 {
201 components.push(TemplateComponent::Literal(buf));
202 }
203
204 UriTemplate {
205 components: components,
206 vars: HashMap::new(),
207 }
208 }
209
210 pub fn set<I: IntoTemplateVar>(&mut self, varname: &str, var: I) -> &mut UriTemplate {
230 self.vars
231 .insert(varname.to_string(), var.into_template_var());
232 self
233 }
234
235 pub fn delete(&mut self, varname: &str) -> bool {
247 match self.vars.remove(varname) {
248 Some(_) => true,
249 None => false,
250 }
251 }
252
253 pub fn delete_all(&mut self) {
255 self.vars.clear();
256 }
257
258 fn build_varspec<E>(
259 &self,
260 v: &VarSpec,
261 sep: &str,
262 named: bool,
263 ifemp: &str,
264 encoder: E,
265 ) -> Option<String>
266 where
267 E: Fn(&str) -> String,
268 {
269 let mut res = String::new();
270
271 let var = match self.vars.get(&v.name) {
272 Some(v) => v,
273 None => return None,
274 };
275
276 match *var {
277 TemplateVar::Scalar(ref s) => {
278 if named {
279 res.push_str(&encode_reserved(&v.name));
280 if s == "" {
281 res.push_str(ifemp);
282 return Some(res);
283 }
284 res.push('=');
285 }
286 match v.var_type {
287 VarSpecType::Raw | VarSpecType::Exploded => {
288 res.push_str(&encoder(s));
289 }
290 VarSpecType::Prefixed(p) => {
291 res.push_str(&encoder(&prefixed(s, p)));
292 }
293 };
294 }
295 TemplateVar::List(ref l) => {
296 if l.len() == 0 {
297 return None;
298 }
299 match v.var_type {
300 VarSpecType::Raw | VarSpecType::Prefixed(_) => {
301 if named {
302 res.push_str(&encode_reserved(&v.name));
303 if l.join("").len() == 0 {
304 res.push_str(ifemp);
305 return Some(res);
306 }
307 res.push('=');
308 }
309 res.push_str(&encode_vec(l, encoder).join(","));
310 }
311 VarSpecType::Exploded => {
312 if named {
313 let pairs: Vec<String> = l
314 .iter()
315 .map(|x| {
316 let val: String = if x == "" {
317 format!("{}{}", &encode_reserved(&v.name), ifemp)
318 } else {
319 format!("{}={}", &encode_reserved(&v.name), &encoder(x))
320 };
321 val
322 })
323 .collect();
324 res.push_str(&pairs.join(sep));
325 } else {
326 res.push_str(&encode_vec(&l, encoder).join(sep));
327 }
328 }
329 }
330 }
331 TemplateVar::AssociativeArray(ref a) => {
332 if a.len() == 0 {
333 return None;
334 }
335 match v.var_type {
336 VarSpecType::Raw | VarSpecType::Prefixed(_) => {
337 if named {
338 res.push_str(&encode_reserved(&v.name));
339 res.push('=');
340 }
341 let pairs: Vec<String> = a
342 .iter()
343 .map(|&(ref k, ref v)| {
344 format!("{},{}", &encode_reserved(k), &encoder(v))
345 })
346 .collect();
347 res.push_str(&pairs.join(","));
348 }
349 VarSpecType::Exploded => {
350 if named {
351 let pairs: Vec<String> = a
352 .iter()
353 .map(|&(ref k, ref v)| {
354 let val: String = if v == "" {
355 format!("{}{}", &encode_reserved(k), ifemp)
356 } else {
357 format!("{}={}", &encode_reserved(k), &encoder(v))
358 };
359 val
360 })
361 .collect();
362 res.push_str(&pairs.join(sep));
363 } else {
364 let pairs: Vec<String> = a
365 .iter()
366 .map(|&(ref k, ref v)| {
367 format!("{}={}", &encode_reserved(k), &encoder(v))
368 })
369 .collect();
370 res.push_str(&pairs.join(sep));
371 }
372 }
373 }
374 }
375 }
376
377 Some(res)
378 }
379
380 fn build_varlist(&self, operator: &Operator, varlist: &Vec<VarSpec>) -> String {
381 let mut values: Vec<String> = Vec::new();
382 let (first, sep, named, ifemp, allow_reserved) = match *operator {
383 Operator::Null => ("", ",", false, "", false),
384 Operator::Plus => ("", ",", false, "", true),
385 Operator::Dot => (".", ".", false, "", false),
386 Operator::Slash => ("/", "/", false, "", false),
387 Operator::Semi => (";", ";", true, "", false),
388 Operator::Question => ("?", "&", true, "=", false),
389 Operator::Ampersand => ("&", "&", true, "=", false),
390 Operator::Hash => ("#", ",", false, "", true),
391 };
392
393 for varspec in varlist {
394 let built = if allow_reserved {
395 self.build_varspec(varspec, sep, named, ifemp, encode_reserved)
396 } else {
397 self.build_varspec(varspec, sep, named, ifemp, encode_unreserved)
398 };
399 match built {
400 Some(s) => values.push(s),
401 None => {}
402 }
403 }
404
405 let mut res = String::new();
406 if values.len() != 0 {
407 res.push_str(first);
408 res.push_str(&values.join(sep));
409 }
410
411 res
412 }
413
414 pub fn build(&self) -> String {
426 let mut res = String::new();
427 for component in &self.components {
428 let next = match *component {
429 TemplateComponent::Literal(ref s) => encode_reserved(s),
430 TemplateComponent::VarList(ref op, ref varlist) => self.build_varlist(op, varlist),
431 };
432 res.push_str(&next);
433 }
434 res
435 }
436}