mapf/domain/
connectable.rs

1/*
2 * Copyright (C) 2023 Open Source Robotics Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16*/
17
18use super::*;
19use crate::error::NoError;
20
21/// Create actions that connect a state to a target. May produce multiple
22/// actions, each of which represents a valid connection. If no actions are
23/// produced, then a connection was not possible.
24///
25/// See also: [`Extrapolator`]
26pub trait Connectable<State, Action, Target> {
27    /// What kind of error can happen during connection
28    type ConnectionError;
29
30    type Connections<'a>: IntoIterator<Item = Result<(Action, State), Self::ConnectionError>> + 'a
31    where
32        Self: 'a,
33        Self::ConnectionError: 'a,
34        State: 'a,
35        Action: 'a,
36        Target: 'a;
37
38    fn connect<'a>(&'a self, from_state: State, to_target: &'a Target) -> Self::Connections<'a>
39    where
40        Self: 'a,
41        Self::ConnectionError: 'a,
42        State: 'a,
43        Action: 'a,
44        Target: 'a;
45}
46
47// Allow an empty tuple to implement the Connectable trait by never attempting
48// any connection.
49impl<State, Action, Target> Connectable<State, Action, Target> for () {
50    type ConnectionError = NoError;
51    type Connections<'a>
52        = [Result<(Action, State), NoError>; 0]
53    where
54        Action: 'a,
55        State: 'a,
56        Target: 'a;
57
58    fn connect<'a>(&'a self, _: State, _: &'a Target) -> Self::Connections<'a>
59    where
60        Self: 'a,
61        Self::ConnectionError: 'a,
62        State: 'a,
63        Action: 'a,
64        Target: 'a,
65    {
66        []
67    }
68}
69
70impl<Base, Prop, State, Action, Target> Connectable<State, Action, Target> for Chained<Base, Prop>
71where
72    Base: Connectable<State, Action, Target>,
73    Base::ConnectionError: Into<Prop::ConnectionError>,
74    Prop: Connectable<State, Action, Target>,
75    State: Clone,
76{
77    type ConnectionError = Prop::ConnectionError;
78    type Connections<'a>
79        = ChainedConnections<'a, Base, Prop, State, Action, Target>
80    where
81        Self: 'a,
82        Self::ConnectionError: 'a,
83        State: 'a,
84        Action: 'a,
85        Target: 'a;
86
87    fn connect<'a>(&'a self, from_state: State, to_target: &'a Target) -> Self::Connections<'a>
88    where
89        Self: 'a,
90        Self::ConnectionError: 'a,
91        State: 'a,
92        Action: 'a,
93        Target: 'a,
94    {
95        ChainedConnections::<Base, Prop, State, Action, Target> {
96            base_connections: self.base.connect(from_state.clone(), to_target).into_iter(),
97            prop_connections: self.prop.connect(from_state, to_target).into_iter(),
98        }
99    }
100}
101
102pub struct ChainedConnections<'a, Base, Prop, State, Action, Target>
103where
104    Base: Connectable<State, Action, Target> + 'a,
105    Prop: Connectable<State, Action, Target> + 'a,
106    Base::ConnectionError: 'a,
107    State: 'a,
108    Action: 'a,
109    Target: 'a,
110{
111    base_connections: <Base::Connections<'a> as IntoIterator>::IntoIter,
112    prop_connections: <Prop::Connections<'a> as IntoIterator>::IntoIter,
113}
114
115impl<'a, Base, Prop, State, Action, Target> Iterator
116    for ChainedConnections<'a, Base, Prop, State, Action, Target>
117where
118    Base: Connectable<State, Action, Target> + 'a,
119    Prop: Connectable<State, Action, Target> + 'a,
120    Base::ConnectionError: 'a + Into<Prop::ConnectionError>,
121    State: 'a,
122    Action: 'a,
123    Target: 'a,
124{
125    type Item = Result<(Action, State), Prop::ConnectionError>;
126    fn next(&mut self) -> Option<Self::Item> {
127        if let Some(next) = self.base_connections.next() {
128            let next = next.map_err(Into::into);
129            return Some(next);
130        }
131
132        self.prop_connections.next()
133    }
134}