ockam_core/routing/route.rs
1use crate::{
2 compat::{collections::VecDeque, string::String, vec::Vec},
3 serialize, Address, Encodable, Encoded, Result, RouteError, TransportType,
4};
5use core::fmt::{self, Display};
6use core::ops::{Add, AddAssign};
7use minicbor::{CborLen, Decode, Encode};
8use serde::{Deserialize, Serialize};
9
10/// A full route to a peer.
11#[derive(Serialize, Deserialize, Encode, Decode, CborLen, Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
12#[cbor(transparent)]
13#[rustfmt::skip]
14pub struct Route {
15 #[n(0)] inner: VecDeque<Address>,
16}
17
18impl Encodable for Route {
19 fn encode(self) -> Result<Encoded> {
20 serialize(self)
21 }
22}
23
24impl AddAssign for Route {
25 fn add_assign(&mut self, mut rhs: Self) {
26 self.inner.append(&mut rhs.inner);
27 }
28}
29
30impl Add for Route {
31 type Output = Route;
32
33 fn add(mut self, rhs: Self) -> Self::Output {
34 self += rhs;
35 self
36 }
37}
38
39impl Add<Route> for Address {
40 type Output = Route;
41
42 fn add(self, rhs: Route) -> Self::Output {
43 rhs.modify().prepend(self).build()
44 }
45}
46
47impl<T> AddAssign<T> for Route
48where
49 T: Into<Address>,
50{
51 fn add_assign(&mut self, rhs: T) {
52 self.inner.push_back(rhs.into());
53 }
54}
55
56impl<T> Add<T> for Route
57where
58 T: Into<Address>,
59{
60 type Output = Route;
61
62 fn add(mut self, rhs: T) -> Self::Output {
63 self += rhs;
64 self
65 }
66}
67
68impl Route {
69 /// Create an empty [`RouteBuilder`].
70 ///
71 /// # Examples
72 ///
73 /// ```
74 /// # use ockam_core::{Route, TransportType};
75 /// # pub const TCP: TransportType = TransportType::new(1);
76 /// // ["1#alice", "0#bob"]
77 /// let route: Route = Route::new()
78 /// .append_t(TCP, "alice")
79 /// .append("bob")
80 /// .into();
81 /// ```
82 ///
83 #[allow(clippy::new_ret_no_self)]
84 pub fn new() -> RouteBuilder {
85 RouteBuilder::new()
86 }
87
88 /// Create a route from a `Vec` of [`Address`].
89 ///
90 /// # Examples
91 ///
92 /// ```
93 /// # use ockam_core::{Address, route, TransportType};
94 /// # pub const TCP: TransportType = TransportType::new(1);
95 /// // ["1#alice", "0#bob"]
96 /// let route = route![
97 /// Address::new_with_string(TCP, "alice"),
98 /// "bob",
99 /// ];
100 /// ```
101 ///
102 pub fn create<T: Into<Address>>(vt: Vec<T>) -> Self {
103 let mut route = Route::new();
104 for addr in vt {
105 route = route.append(addr.into());
106 }
107 route.into()
108 }
109
110 /// Parse a route from a string.
111 ///
112 /// # Examples
113 ///
114 /// ```
115 /// # use ockam_core::Route;
116 /// if let Some(route) = Route::parse("1#alice => bob") {
117 /// // ["1#alice", "0#bob"]
118 /// route
119 /// # ;
120 /// }
121 /// ```
122 ///
123 pub fn parse<S: Into<String>>(s: S) -> Option<Route> {
124 let s = s.into();
125 if s.is_empty() {
126 return None;
127 }
128
129 let addrs = s.split("=>").collect::<Vec<_>>();
130
131 // Invalid route
132 if addrs.is_empty() {
133 return None;
134 }
135
136 Some(
137 addrs
138 .into_iter()
139 .fold(Route::new(), |r, addr| r.append(addr.trim()))
140 .into(),
141 )
142 }
143
144 /// Create a new [`RouteBuilder`] from the current `Route`.
145 ///
146 /// # Examples
147 ///
148 /// ```
149 /// # use ockam_core::{route, Route};
150 /// let mut route: Route = route!["1#alice", "bob"];
151 ///
152 /// // ["1#alice", "0#bob", "0#carol"]
153 /// let route: Route = route.modify()
154 /// .append("carol")
155 /// .into();
156 /// ```
157 ///
158 pub fn modify(self) -> RouteBuilder {
159 RouteBuilder { inner: self.inner }
160 }
161
162 /// Return the next `Address` and remove it from this route.
163 ///
164 /// # Examples
165 ///
166 /// ```
167 /// # use ockam_core::{route, Address, Result, Route};
168 /// # fn main() -> Result<()> {
169 /// let mut route: Route = route!["1#alice", "bob"];
170 ///
171 /// // "1#alice"
172 /// let next_hop: Address = route.step()?;
173 ///
174 /// // ["0#bob"]
175 /// route
176 /// # ;
177 /// # Ok(())
178 /// # }
179 /// ```
180 ///
181 #[track_caller]
182 pub fn step(&mut self) -> Result<Address> {
183 // to avoid the error being allocated when not needed
184 #[allow(clippy::unnecessary_lazy_evaluations)]
185 Ok(self
186 .inner
187 .pop_front()
188 .ok_or_else(|| RouteError::IncompleteRoute)?)
189 }
190
191 /// Return the next `Address` from this route without removing it.
192 ///
193 /// # Examples
194 ///
195 /// ```
196 /// # use ockam_core::{route, Address, Result, Route};
197 /// # fn main() -> Result<()> {
198 /// let route: Route = route!["1#alice", "bob"];
199 ///
200 /// // "1#alice"
201 /// let next_hop: &Address = route.next()?;
202 ///
203 /// // ["1#alice", "0#bob"]
204 /// route
205 /// # ;
206 /// # Ok(())
207 /// # }
208 /// ```
209 ///
210 #[track_caller]
211 pub fn next(&self) -> Result<&Address> {
212 // to avoid the error being allocated when not needed
213 #[allow(clippy::unnecessary_lazy_evaluations)]
214 Ok(self
215 .inner
216 .front()
217 .ok_or_else(|| RouteError::IncompleteRoute)?)
218 }
219
220 /// Return the final recipient address.
221 ///
222 /// # Examples
223 ///
224 /// ```
225 /// # use ockam_core::{route, Address, Result, Route};
226 /// # fn main() -> Result<()> {
227 /// let route: Route = route!["1#alice", "bob"];
228 ///
229 /// // "0#bob"
230 /// let final_hop: &Address = route.recipient()?;
231 ///
232 /// // ["1#alice", "0#bob"]
233 /// route
234 /// # ;
235 /// # Ok(())
236 /// # }
237 /// ```
238 #[track_caller]
239 pub fn recipient(&self) -> Result<&Address> {
240 // to avoid the error being allocated when not needed
241 #[allow(clippy::unnecessary_lazy_evaluations)]
242 Ok(self
243 .inner
244 .back()
245 .ok_or_else(|| RouteError::IncompleteRoute)?)
246 }
247
248 /// Iterate over all addresses of this route.
249 pub fn iter(&self) -> impl Iterator<Item = &Address> {
250 self.inner.iter()
251 }
252
253 /// Number of hops.
254 pub fn len(&self) -> usize {
255 self.inner.len()
256 }
257
258 /// Returns true if the route is empty.
259 pub fn is_empty(&self) -> bool {
260 self.inner.is_empty()
261 }
262
263 /// Returns `true` if route contains `needle`.
264 ///
265 /// Returns `Err(_)` if `needle` is an empty route.
266 ///
267 /// # Examples
268 ///
269 /// ```
270 /// # use ockam_core::{route, Route, Result};
271 /// # fn main() -> Result<()> {
272 /// let r: Route = route!["a", "b", "c", "d"];
273 ///
274 /// // true
275 /// let res = r.contains_route(&route!["b", "c"])?;
276 ///
277 /// // false
278 /// let res = r.contains_route(&route!["a", "c"])?;
279 ///
280 /// // false
281 /// let res = r.contains_route(&route!["a", "b", "c", "d", "e"])?;
282 /// # Ok(())
283 /// # }
284 /// ```
285 pub fn contains_route(&self, needle: &Route) -> Result<bool> {
286 if needle.is_empty() {
287 return Err(RouteError::IncompleteRoute)?;
288 }
289
290 let hl = self.len();
291 let nl = needle.len();
292 if nl > hl {
293 return Ok(false);
294 }
295
296 // The below uses many iterators.
297 // An alternative might be to use `VecDeque::make_contiguous()` and slices.
298 for i in 0..=(hl - nl) {
299 let tmp = self.inner.iter().skip(i).take(nl);
300 if tmp.eq(needle.iter()) {
301 return Ok(true);
302 }
303 }
304
305 Ok(false)
306 }
307
308 /// Return true if all the addresses composing that route are local addresses
309 pub fn is_local(&self) -> bool {
310 self.iter().all(|a| a.is_local())
311 }
312
313 /// Return inner VecDeque
314 pub fn inner(self) -> VecDeque<Address> {
315 self.inner
316 }
317}
318
319impl Default for Route {
320 fn default() -> Self {
321 Route::new().into()
322 }
323}
324
325impl Display for Route {
326 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
327 write!(
328 f,
329 "{}",
330 self.inner
331 .iter()
332 .map(|a| format!("{}", a))
333 .collect::<Vec<_>>()
334 .join(" => ")
335 )
336 }
337}
338
339impl From<Route> for Vec<Address> {
340 fn from(value: Route) -> Self {
341 value.inner.into()
342 }
343}
344
345/// Convert a `RouteBuilder` into a `Route`.
346impl From<RouteBuilder> for Route {
347 fn from(builder: RouteBuilder) -> Self {
348 Self {
349 inner: builder.inner,
350 }
351 }
352}
353
354/// Convert an `Address` into a `Route`.
355///
356/// A single address can represent a valid route.
357impl<T: Into<Address>> From<T> for Route {
358 fn from(addr: T) -> Self {
359 Route::create(vec![addr])
360 }
361}
362
363/// A utility type for building and manipulating routes.
364pub struct RouteBuilder {
365 inner: VecDeque<Address>,
366}
367
368impl Default for RouteBuilder {
369 fn default() -> Self {
370 Self::new()
371 }
372}
373
374impl RouteBuilder {
375 #[doc(hidden)]
376 pub fn new() -> Self {
377 Self {
378 inner: VecDeque::new(),
379 }
380 }
381
382 /// Push a new item to the back of the route.
383 ///
384 /// # Examples
385 ///
386 /// ```
387 /// # use ockam_core::{Route, RouteBuilder};
388 /// let builder: RouteBuilder = Route::new()
389 /// .append("1#alice")
390 /// .append("bob");
391 ///
392 /// // ["1#alice, "0#bob"]
393 /// let route: Route = builder.into();
394 /// ```
395 ///
396 pub fn append<A: Into<Address>>(mut self, addr: A) -> Self {
397 self.inner.push_back(addr.into());
398 self
399 }
400
401 /// Push an item with an explicit type to the back of the route.
402 ///
403 /// # Examples
404 ///
405 /// ```
406 /// # use ockam_core::{Route, RouteBuilder, TransportType, LOCAL};
407 /// # pub const TCP: TransportType = TransportType::new(1);
408 /// let builder: RouteBuilder = Route::new()
409 /// .append_t(TCP, "alice")
410 /// .append_t(LOCAL, "bob");
411 ///
412 /// // ["1#alice", "0#bob"]
413 /// let route: Route = builder.into();
414 /// ```
415 ///
416 pub fn append_t<A: Into<String>>(mut self, ty: TransportType, addr: A) -> Self {
417 self.inner.push_back(Address::from((ty, addr.into())));
418 self
419 }
420
421 /// Push a new item to the front of the route.
422 ///
423 /// # Examples
424 ///
425 /// ```
426 /// # use ockam_core::{Route, RouteBuilder};
427 /// let builder: RouteBuilder = Route::new()
428 /// .prepend("1#alice")
429 /// .prepend("0#bob");
430 ///
431 /// // ["0#bob", "1#alice"]
432 /// let route: Route = builder.into();
433 /// ```
434 ///
435 pub fn prepend<A: Into<Address>>(mut self, addr: A) -> Self {
436 self.inner.push_front(addr.into());
437 self
438 }
439
440 /// Prepend a full route to an existing route.
441 ///
442 /// # Examples
443 ///
444 /// ```
445 /// # use ockam_core::{route, Route, RouteBuilder};
446 /// let mut route_a: Route = route!["1#alice", "bob"];
447 /// let route_b: Route = route!["1#carol", "dave"];
448 ///
449 /// // ["1#carol", "0#dave", "1#alice", "0#bob"]
450 /// let route: Route = route_a.modify()
451 /// .prepend_route(route_b)
452 /// .into();
453 /// ```
454 ///
455 pub fn prepend_route(mut self, route: Route) -> Self {
456 route
457 .inner
458 .into_iter()
459 .rev()
460 .for_each(|addr| self.inner.push_front(addr));
461 self
462 }
463
464 /// Append a full route to an existing route.
465 ///
466 /// # Examples
467 ///
468 /// ```
469 /// # use ockam_core::{route, Route, RouteBuilder};
470 /// let mut route_a: Route = route!["1#alice", "bob"];
471 /// let route_b: Route = route!["1#carol", "dave"];
472 ///
473 /// // ["1#alice", "0#bob", "1#carol", "0#dave"]
474 /// let route: Route = route_a.modify()
475 /// .append_route(route_b)
476 /// .into();
477 /// ```
478 ///
479 pub fn append_route(mut self, route: impl Into<Route>) -> Self {
480 self.inner.append(&mut route.into().inner);
481 self
482 }
483
484 /// Replace the next item in the route with a new address.
485 ///
486 /// Similar to [`Self::prepend(...)`](RouteBuilder::prepend), but
487 /// drops the previous HEAD value.
488 ///
489 /// # Examples
490 ///
491 /// ```
492 /// # use ockam_core::{route, Route, RouteBuilder};
493 /// let mut route: Route = route!["1#alice", "bob"];
494 ///
495 /// // ["1#carol", "0#bob"]
496 /// let route: Route = route.modify()
497 /// .replace("1#carol")
498 /// .into();
499 /// ```
500 ///
501 pub fn replace<A: Into<Address>>(mut self, addr: A) -> Self {
502 self.inner.pop_front();
503 self.inner.push_front(addr.into());
504 self
505 }
506
507 /// Pop the front item from the route.
508 ///
509 /// # Examples
510 ///
511 /// ```
512 /// # use ockam_core::{route, Address, Route};
513 /// let mut route: Route = route!["1#alice", "bob", "carol"];
514 ///
515 /// // ["0#bob", "carol"]
516 /// let route: Route = route.modify()
517 /// .pop_front()
518 /// .into();
519 /// ```
520 ///
521 pub fn pop_front(mut self) -> Self {
522 self.inner.pop_front();
523 self
524 }
525
526 /// Pop the back item from the route.
527 ///
528 /// # Examples
529 ///
530 /// ```
531 /// # use ockam_core::{route, Address, Route};
532 /// let mut route: Route = route!["1#alice", "bob", "carol"];
533 ///
534 /// // ["1#alice", "0#bob"]
535 /// let route: Route = route.modify()
536 /// .pop_back()
537 /// .into();
538 /// ```
539 ///
540 pub fn pop_back(mut self) -> Self {
541 self.inner.pop_back();
542 self
543 }
544
545 /// Builds the route.
546 /// Same as `into()`, but without the need to specify the type.
547 ///
548 /// # Examples
549 ///
550 /// ```
551 /// # use ockam_core::{route, Route, RouteBuilder};
552 /// let route = Route::new()
553 /// .append("1#alice")
554 /// .append("bob")
555 /// .build();
556 /// ```
557 pub fn build(self) -> Route {
558 Route { inner: self.inner }
559 }
560}
561
562impl Route {
563 pub(crate) fn manual_encode(&self, buffer: &mut Vec<u8>) {
564 crate::bare::write_variable_length_integer(buffer, self.inner.len() as u64);
565 for addr in &self.inner {
566 addr.manual_encode(buffer);
567 }
568 }
569
570 pub(crate) fn encoded_size(&self) -> usize {
571 let mut size = crate::bare::size_of_variable_length(self.inner.len() as u64);
572 for addr in &self.inner {
573 size += addr.encoded_size();
574 }
575 size
576 }
577
578 pub(crate) fn manual_decode(slice: &[u8], index: &mut usize) -> Option<Route> {
579 let number_of_addresses = crate::bare::read_variable_length_integer(slice, index)?;
580 let mut addresses = VecDeque::with_capacity(number_of_addresses as usize);
581
582 for _ in 0..number_of_addresses {
583 let addr = Address::manually_decode(slice, index)?;
584 addresses.push_back(addr);
585 }
586
587 Some(Route { inner: addresses })
588 }
589}
590
591#[cfg(test)]
592mod tests {
593 use crate::{route, Address, Encodable, Error, Route};
594
595 #[test]
596 fn encode_and_manually_decode_route() {
597 let route = route!["alice", "bob"];
598 let encoded = route.clone().encode().unwrap();
599 let decoded = Route::manual_decode(&encoded, &mut 0).unwrap();
600 assert_eq!(route, decoded);
601 }
602
603 fn validate_error(_err: Error) {
604 // assert_eq!(err.domain(), RouteError::DOMAIN_NAME);
605 // assert_eq!(err.code(), RouteError::DOMAIN_CODE);
606 // ???
607 }
608
609 #[test]
610 fn test_route_macro() {
611 let address = Address::from_string("a");
612 let mut route = route![address, "b"];
613 assert_eq!(route.next().unwrap(), &Address::from_string("0#a"));
614 assert_eq!(route.next().unwrap(), &Address::from_string("0#a"));
615 assert_eq!(route.recipient().unwrap(), &Address::from_string("0#b"));
616 assert_eq!(route.step().unwrap(), Address::from_string("0#a"));
617 assert_eq!(route.step().unwrap(), Address::from_string("0#b"));
618 }
619
620 #[test]
621 fn test_route_create() {
622 let addresses = vec!["node-1", "node-2"];
623 let route = Route::create(addresses);
624 assert_eq!(
625 route.recipient().unwrap(),
626 &Address::from_string("0#node-2")
627 );
628 }
629
630 #[test]
631 fn test_route_parse_empty_string() {
632 assert_eq!(Route::parse(""), None);
633 }
634
635 #[test]
636 fn test_route_parse_valid_input() {
637 let s = " node-1 =>node-2=> node-3 ";
638 let mut route = Route::parse(s).unwrap();
639 assert_eq!(route.next().unwrap(), &Address::from_string("0#node-1"));
640 assert_eq!(
641 route.recipient().unwrap(),
642 &Address::from_string("0#node-3")
643 );
644 let _ = route.step();
645 assert_eq!(route.next().unwrap(), &Address::from_string("0#node-2"));
646 }
647
648 #[test]
649 fn test_route_accessors_error_condition() {
650 let s = "node-1";
651 let mut route = Route::parse(s).unwrap();
652 let _ = route.step();
653 validate_error(route.step().err().unwrap());
654 validate_error(route.next().err().unwrap());
655 }
656
657 #[test]
658 fn test_route_no_recipient() -> Result<(), ()> {
659 let mut route = Route::parse("node-1=>node-2").unwrap();
660 let _ = route.step();
661 let _ = route.step();
662 match route.recipient() {
663 Ok(_) => Err(()),
664 Err(_) => Ok(()),
665 }
666 }
667
668 #[test]
669 fn test_route_prepend_route() {
670 let r1 = route!["a", "b", "c"];
671 let r2 = route!["1", "2", "3"];
672
673 let r1: Route = r1.modify().prepend_route(r2).into();
674 assert_eq!(r1, route!["1", "2", "3", "a", "b", "c"]);
675 }
676
677 #[test]
678 fn test_route_contains_route() {
679 let r = route!["a", "b", "c", "d", "e"];
680
681 assert!(matches!(r.contains_route(&route!["a"]), Ok(true)));
682 assert!(matches!(r.contains_route(&route!["a", "b"]), Ok(true)));
683 assert!(matches!(r.contains_route(&route!["b", "c"]), Ok(true)));
684 assert!(matches!(r.contains_route(&route!["c", "d"]), Ok(true)));
685 assert!(matches!(r.contains_route(&route!["e"]), Ok(true)));
686
687 assert!(r.contains_route(&route![]).is_err());
688
689 assert!(matches!(
690 r.contains_route(&route!["a", "b", "c", "d", "e", "f"]),
691 Ok(false)
692 ));
693
694 assert!(matches!(r.contains_route(&route!["a", "c"]), Ok(false)));
695 assert!(matches!(r.contains_route(&route!["x"]), Ok(false)));
696 }
697}