rosrust/api/naming/
mod.rs
1pub use self::error::{Error, ErrorKind};
2use self::mapper::Mapper;
3use self::path::Path;
4
5pub mod error;
6mod mapper;
7mod path;
8
9pub struct Resolver {
10 path: path::Buffer,
11 namespace: path::Buffer,
12 mapper: Mapper,
13}
14
15impl Resolver {
16 pub fn new(name: &str) -> Result<Resolver, Error> {
17 let path = name.parse::<path::Buffer>()?;
18 let namespace = path.parent()?.take();
19 Ok(Resolver {
20 path,
21 namespace,
22 mapper: Mapper::new(),
23 })
24 }
25
26 pub fn map(&mut self, source: &str, destination: &str) -> Result<(), Error> {
27 let source = self.resolve(source)?;
28 let destination = self.resolve(destination)?;
29 self.mapper.add(source.get(), destination);
30 Ok(())
31 }
32
33 fn resolve(&self, name: &str) -> Result<path::Buffer, Error> {
34 let first_char = *name.as_bytes().first().ok_or(ErrorKind::EmptyName)?;
35 if first_char == b'/' {
36 return name.parse();
37 }
38 Ok(if first_char == b'~' {
39 self.path.slice() + (String::from("/") + &name[1..]).parse::<path::Buffer>()?
40 } else {
41 self.namespace.slice() + (String::from("/") + name).parse::<path::Buffer>()?
42 })
43 }
44
45 pub fn translate(&self, name: &str) -> Result<String, Error> {
46 let path = self.resolve(name)?;
47 match self.mapper.translate(path.get()) {
48 Some(v) => Ok(format!("{}", v)),
49 None => Ok(format!("{}", path)),
50 }
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::path::Path;
57 use super::*;
58
59 static FAILED_TO_RESOLVE: &str = "Failed to resolve";
60
61 #[test]
62 fn constructs_from_legal_path() {
63 assert!(Resolver::new("/foo").is_ok());
64 assert!(Resolver::new("/foo/bar").is_ok());
65 assert!(Resolver::new("/f1_aA/Ba02/Xx").is_ok());
66 assert!(Resolver::new("/123/").is_ok());
67 assert!(Resolver::new("/_e").is_ok());
68
69 assert!(Resolver::new("").is_err());
70 assert!(Resolver::new("a").is_err());
71 assert!(Resolver::new("/foo$").is_err());
72 assert!(Resolver::new("/a//b").is_err());
73 }
74
75 #[test]
76 fn rejects_illegal_names() {
77 let r = Resolver::new("/some/long/path").expect(FAILED_TO_RESOLVE);
78 assert!(r.resolve("1foo/bar").is_ok());
79
80 assert!(r.resolve("/fo$o").is_err());
81 assert!(r.resolve("#f1_aA/Ba02/Xx").is_err());
82 }
83
84 #[test]
85 fn resolves_absolute_names() {
86 let r = Resolver::new("/some/long/path").expect(FAILED_TO_RESOLVE);
87 assert_eq!(
88 vec![String::from("foo")],
89 r.resolve("/foo").expect(FAILED_TO_RESOLVE).get()
90 );
91 assert_eq!(
92 vec![String::from("foo"), String::from("bar")],
93 r.resolve("/foo/bar").expect(FAILED_TO_RESOLVE).get()
94 );
95 assert_eq!(
96 vec![
97 String::from("f1_aA"),
98 String::from("Ba02"),
99 String::from("Xx"),
100 ],
101 r.resolve("/f1_aA/Ba02/Xx").expect(FAILED_TO_RESOLVE).get()
102 );
103 }
104
105 #[test]
106 fn resolves_relative_names() {
107 let r = Resolver::new("/some/long/path").expect(FAILED_TO_RESOLVE);
108 assert_eq!(
109 vec![
110 String::from("some"),
111 String::from("long"),
112 String::from("foo"),
113 ],
114 r.resolve("foo").expect(FAILED_TO_RESOLVE).get()
115 );
116 assert_eq!(
117 vec![
118 String::from("some"),
119 String::from("long"),
120 String::from("foo"),
121 String::from("bar"),
122 ],
123 r.resolve("foo/bar").expect(FAILED_TO_RESOLVE).get()
124 );
125 assert_eq!(
126 vec![
127 String::from("some"),
128 String::from("long"),
129 String::from("f1_aA"),
130 String::from("Ba02"),
131 String::from("Xx"),
132 ],
133 r.resolve("f1_aA/Ba02/Xx").expect(FAILED_TO_RESOLVE).get()
134 );
135 }
136
137 #[test]
138 fn resolves_private_names() {
139 let r = Resolver::new("/some/long/path").expect(FAILED_TO_RESOLVE);
140 assert_eq!(
141 vec![
142 String::from("some"),
143 String::from("long"),
144 String::from("path"),
145 String::from("foo"),
146 ],
147 r.resolve("~foo").expect(FAILED_TO_RESOLVE).get()
148 );
149 assert_eq!(
150 vec![
151 String::from("some"),
152 String::from("long"),
153 String::from("path"),
154 String::from("foo"),
155 String::from("bar"),
156 ],
157 r.resolve("~foo/bar").expect(FAILED_TO_RESOLVE).get()
158 );
159 assert_eq!(
160 vec![
161 String::from("some"),
162 String::from("long"),
163 String::from("path"),
164 String::from("f1_aA"),
165 String::from("Ba02"),
166 String::from("Xx"),
167 ],
168 r.resolve("~f1_aA/Ba02/Xx").expect(FAILED_TO_RESOLVE).get()
169 );
170 }
171
172 #[test]
173 fn translates_strings() {
174 let r = Resolver::new("/some/long/path").expect(FAILED_TO_RESOLVE);
175 assert_eq!(
176 String::from("/f1_aA/Ba02/Xx"),
177 r.translate("/f1_aA/Ba02/Xx").expect(FAILED_TO_RESOLVE)
178 );
179 assert_eq!(
180 String::from("/some/long/f1_aA/Ba02/Xx"),
181 r.translate("f1_aA/Ba02/Xx").expect(FAILED_TO_RESOLVE)
182 );
183 assert_eq!(
184 String::from("/some/long/path/f1_aA/Ba02/Xx"),
185 r.translate("~f1_aA/Ba02/Xx").expect(FAILED_TO_RESOLVE)
186 );
187 }
188
189 #[test]
190 fn supports_remapping() {
191 let mut r = Resolver::new("/some/long/path").expect(FAILED_TO_RESOLVE);
192 r.map("a", "/d").expect(FAILED_TO_RESOLVE);
193 r.map("~x", "/e").expect(FAILED_TO_RESOLVE);
194 r.map("/z", "/f").expect(FAILED_TO_RESOLVE);
195 r.map("/a1", "g").expect(FAILED_TO_RESOLVE);
196 r.map("a2", "~g").expect(FAILED_TO_RESOLVE);
197 assert_eq!(
198 String::from("/d"),
199 r.translate("/some/long/a").expect(FAILED_TO_RESOLVE)
200 );
201 assert_eq!(
202 String::from("/e"),
203 r.translate("path/x").expect(FAILED_TO_RESOLVE)
204 );
205 assert_eq!(
206 String::from("/f"),
207 r.translate("/z").expect(FAILED_TO_RESOLVE)
208 );
209 assert_eq!(
210 String::from("/some/long/g"),
211 r.translate("/a1").expect(FAILED_TO_RESOLVE)
212 );
213 assert_eq!(
214 String::from("/some/long/path/g"),
215 r.translate("/some/long/a2").expect(FAILED_TO_RESOLVE)
216 );
217 assert_eq!(
218 String::from("/some/long/other"),
219 r.translate("other").expect(FAILED_TO_RESOLVE)
220 );
221 }
222}