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}