uri_rs/ast/
uri.rs

1use std::fmt::Formatter;
2
3use crate::ast::authority::Authority;
4use crate::ast::path::Path;
5use crate::ast::query::Query;
6use crate::ast::scheme::Scheme;
7use crate::parser::parsers::{Elms, uri_parsers, UriParseError};
8
9pub type Fragment = String;
10
11#[derive(Debug, Clone, PartialEq, Hash)]
12pub struct Uri {
13  schema: Scheme,
14  authority: Option<Authority>,
15  path: Path,
16  query: Option<Query>,
17  fragment: Option<String>,
18}
19
20impl Default for Uri {
21  fn default() -> Self {
22    Uri {
23      schema: Scheme::default(),
24      authority: Option::default(),
25      path: Path::default(),
26      query: Option::default(),
27      fragment: Option::default(),
28    }
29  }
30}
31
32impl std::fmt::Display for Uri {
33  fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
34    write!(
35      f,
36      "{}:{}{}{}{}",
37      self.schema.to_string(),
38      self
39        .authority
40        .as_ref()
41        .map(|a| format!("//{}", a.to_string()))
42        .unwrap_or("".to_string()),
43      self.path.to_string(),
44      self
45        .query
46        .as_ref()
47        .map(|q| format!("?{}", q.to_string()))
48        .unwrap_or("".to_string()),
49      self
50        .fragment
51        .as_ref()
52        .map(|s| format!("#{}", s))
53        .unwrap_or("".to_string())
54    )
55  }
56}
57
58impl Uri {
59  pub fn parse(text: &str) -> Result<Uri, nom::Err<UriParseError>> {
60    uri_parsers::uri(Elms::new(text.as_bytes())).map(|(_, v)| v)
61  }
62
63  pub fn new(
64    schema: Scheme,
65    authority: Option<Authority>,
66    path: Path,
67    query: Option<Query>,
68    fragment: Option<Fragment>,
69  ) -> Self {
70    Self {
71      schema,
72      authority,
73      path,
74      query,
75      fragment,
76    }
77  }
78
79  pub fn schema(&self) -> &Scheme {
80    &self.schema
81  }
82
83  pub fn authority(&self) -> Option<&Authority> {
84    self.authority.as_ref()
85  }
86
87  pub fn path(&self) -> &Path {
88    &self.path
89  }
90
91  pub fn path_as_opt(&self) -> Option<&Path> {
92    if self.path.is_empty() {
93      None
94    } else {
95      Some(&self.path)
96    }
97  }
98
99  pub fn query(&self) -> Option<&Query> {
100    self.query.as_ref()
101  }
102
103  pub fn fragment(&self) -> Option<&Fragment> {
104    self.fragment.as_ref()
105  }
106}
107
108#[cfg(test)]
109mod test {
110  use std::env;
111
112  use crate::{Uri};
113
114  fn init() {
115    env::set_var("RUST_LOG", "debug");
116    let _ = env_logger::builder().is_test(true).try_init();
117  }
118
119  #[test]
120  fn test_parse() {
121    init();
122    let s = "http://user1:pass1@localhost:8080/example?key1=value1&key2=value2&key1=value2#f1";
123    match Uri::parse(s) {
124      Ok(uri) => println!("{:?}", uri),
125      Err(e) => println!("{:?}", e),
126    }
127  }
128}