1use std::{cell::RefCell, rc::Rc};
2
3#[cfg(feature = "url")]
4use url_pkg::Url;
5
6use crate::router::ResourceDef;
7use crate::util::HashMap;
8#[cfg(feature = "url")]
9use crate::web::httprequest::HttpRequest;
10
11#[derive(Clone, Debug)]
12pub struct ResourceMap {
13 #[allow(dead_code)]
14 root: ResourceDef,
15 parent: RefCell<Option<Rc<ResourceMap>>>,
16 named: HashMap<String, ResourceDef>,
17 patterns: Vec<(ResourceDef, Option<Rc<ResourceMap>>)>,
18}
19
20impl ResourceMap {
21 pub fn new(root: ResourceDef) -> Self {
22 ResourceMap {
23 root,
24 parent: RefCell::new(None),
25 named: HashMap::default(),
26 patterns: Vec::new(),
27 }
28 }
29
30 pub fn add(&mut self, pattern: &mut ResourceDef, nested: Option<Rc<ResourceMap>>) {
31 pattern.set_id(self.patterns.len() as u16);
32 self.patterns.push((pattern.clone(), nested));
33 if !pattern.name().is_empty() {
34 self.named
35 .insert(pattern.name().to_string(), pattern.clone());
36 }
37 }
38
39 pub(crate) fn finish(&self, current: Rc<ResourceMap>) {
40 for (_, nested) in &self.patterns {
41 if let Some(ref nested) = nested {
42 *nested.parent.borrow_mut() = Some(current.clone());
43 nested.finish(nested.clone());
44 }
45 }
46 }
47}
48
49#[cfg(feature = "url")]
50impl ResourceMap {
51 pub fn url_for<U, I>(
56 &self,
57 req: &HttpRequest,
58 name: &str,
59 elements: U,
60 ) -> Result<Url, super::error::UrlGenerationError>
61 where
62 U: IntoIterator<Item = I>,
63 I: AsRef<str>,
64 {
65 let mut path = String::new();
66 let mut elements = elements.into_iter();
67
68 if self.patterns_for(name, &mut path, &mut elements)?.is_some() {
69 if path.starts_with('/') {
70 let conn = req.connection_info();
71 Ok(Url::parse(&format!(
72 "{}://{}{}",
73 conn.scheme(),
74 conn.host(),
75 path
76 ))?)
77 } else {
78 Ok(Url::parse(&path)?)
79 }
80 } else {
81 Err(super::error::UrlGenerationError::ResourceNotFound)
82 }
83 }
84
85 fn patterns_for<U, I>(
101 &self,
102 name: &str,
103 path: &mut String,
104 elements: &mut U,
105 ) -> Result<Option<()>, super::error::UrlGenerationError>
106 where
107 U: Iterator<Item = I>,
108 I: AsRef<str>,
109 {
110 if self.pattern_for(name, path, elements)?.is_some() {
111 Ok(Some(()))
112 } else {
113 self.parent_pattern_for(name, path, elements)
114 }
115 }
116
117 fn pattern_for<U, I>(
118 &self,
119 name: &str,
120 path: &mut String,
121 elements: &mut U,
122 ) -> Result<Option<()>, super::error::UrlGenerationError>
123 where
124 U: Iterator<Item = I>,
125 I: AsRef<str>,
126 {
127 if let Some(pattern) = self.named.get(name) {
128 if pattern.pattern().starts_with('/') {
129 self.fill_root(path, elements)?;
130 }
131 if pattern.resource_path(path, elements) {
132 Ok(Some(()))
133 } else {
134 Err(super::error::UrlGenerationError::NotEnoughElements)
135 }
136 } else {
137 for (_, rmap) in &self.patterns {
138 if let Some(ref rmap) = rmap {
139 if rmap.pattern_for(name, path, elements)?.is_some() {
140 return Ok(Some(()));
141 }
142 }
143 }
144 Ok(None)
145 }
146 }
147
148 fn fill_root<U, I>(
149 &self,
150 path: &mut String,
151 elements: &mut U,
152 ) -> Result<(), super::error::UrlGenerationError>
153 where
154 U: Iterator<Item = I>,
155 I: AsRef<str>,
156 {
157 if let Some(ref parent) = *self.parent.borrow() {
158 parent.fill_root(path, elements)?;
159 }
160 if self.root.resource_path(path, elements) {
161 Ok(())
162 } else {
163 Err(super::error::UrlGenerationError::NotEnoughElements)
164 }
165 }
166
167 fn parent_pattern_for<U, I>(
168 &self,
169 name: &str,
170 path: &mut String,
171 elements: &mut U,
172 ) -> Result<Option<()>, super::error::UrlGenerationError>
173 where
174 U: Iterator<Item = I>,
175 I: AsRef<str>,
176 {
177 if let Some(ref parent) = *self.parent.borrow() {
178 if let Some(pattern) = parent.named.get(name) {
179 self.fill_root(path, elements)?;
180 if pattern.resource_path(path, elements) {
181 Ok(Some(()))
182 } else {
183 Err(super::error::UrlGenerationError::NotEnoughElements)
184 }
185 } else {
186 parent.parent_pattern_for(name, path, elements)
187 }
188 } else {
189 Ok(None)
190 }
191 }
192}