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}