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}