1use crate::error::AvailabilityRoutingError;
6use cm_rust::{Availability, ExposeDeclCommon, ExposeSource, OfferDeclCommon, OfferSource};
7use moniker::ExtendedMoniker;
8
9pub fn advance_with_offer(
10 moniker: &ExtendedMoniker,
11 current: Availability,
12 offer: &impl OfferDeclCommon,
13) -> Result<Availability, AvailabilityRoutingError> {
14 let result = advance(moniker, current, *offer.availability());
15 if offer.source() == &OfferSource::Void
16 && result
17 == Err(AvailabilityRoutingError::TargetHasStrongerAvailability {
18 moniker: moniker.clone(),
19 })
20 {
21 return Err(AvailabilityRoutingError::OfferFromVoidToRequiredTarget {
22 moniker: moniker.clone(),
23 });
24 }
25 result
26}
27
28pub fn advance_with_expose(
29 moniker: &ExtendedMoniker,
30 current: Availability,
31 expose: &impl ExposeDeclCommon,
32) -> Result<Availability, AvailabilityRoutingError> {
33 let result = advance(moniker, current, *expose.availability());
34 if expose.source() == &ExposeSource::Void
35 && result
36 == Err(AvailabilityRoutingError::TargetHasStrongerAvailability {
37 moniker: moniker.clone(),
38 })
39 {
40 return Err(AvailabilityRoutingError::ExposeFromVoidToRequiredTarget {
41 moniker: moniker.clone(),
42 });
43 }
44 result
45}
46
47impl crate::legacy_router::OfferVisitor for Availability {
48 fn visit(
49 &mut self,
50 moniker: &ExtendedMoniker,
51 offer: &cm_rust::OfferDecl,
52 ) -> Result<(), crate::RoutingError> {
53 *self = advance_with_offer(moniker, *self, offer)?;
54 Ok(())
55 }
56}
57
58impl crate::legacy_router::ExposeVisitor for Availability {
59 fn visit(
60 &mut self,
61 moniker: &ExtendedMoniker,
62 expose: &cm_rust::ExposeDecl,
63 ) -> Result<(), crate::RoutingError> {
64 *self = advance_with_expose(moniker, *self, expose)?;
65 Ok(())
66 }
67}
68
69impl crate::legacy_router::CapabilityVisitor for Availability {
70 fn visit(
71 &mut self,
72 _: &ExtendedMoniker,
73 _: &cm_rust::CapabilityDecl,
74 ) -> Result<(), crate::RoutingError> {
75 Ok(())
76 }
77}
78
79pub fn advance(
80 moniker: &ExtendedMoniker,
81 current: Availability,
82 next_availability: Availability,
83) -> Result<Availability, AvailabilityRoutingError> {
84 let next = availability::advance(moniker, current, next_availability)?;
85 Ok(next)
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use cm_rust::{
92 DependencyType, ExposeDecl, ExposeProtocolDecl, ExposeTarget, OfferDecl, OfferProtocolDecl,
93 };
94 use cm_rust_testing::*;
95 use test_case::test_case;
96
97 fn new_offer(availability: Availability) -> OfferDecl {
98 OfferDecl::Protocol(OfferProtocolDecl {
99 source: OfferSource::Parent,
100 source_name: "fuchsia.examples.Echo".parse().unwrap(),
101 source_dictionary: Default::default(),
102 target: offer_target_static_child("echo"),
103 target_name: "fuchsia.examples.Echo".parse().unwrap(),
104 dependency_type: DependencyType::Weak,
105 availability,
106 })
107 }
108
109 fn new_void_offer() -> OfferDecl {
110 OfferDecl::Protocol(OfferProtocolDecl {
111 source: OfferSource::Void,
112 source_name: "fuchsia.examples.Echo".parse().unwrap(),
113 source_dictionary: Default::default(),
114 target: offer_target_static_child("echo"),
115 target_name: "fuchsia.examples.Echo".parse().unwrap(),
116 dependency_type: DependencyType::Weak,
117 availability: Availability::Optional,
118 })
119 }
120
121 #[test_case(Availability::Optional, new_offer(Availability::Optional), Ok(()))]
122 #[test_case(Availability::Optional, new_offer(Availability::Required), Ok(()))]
123 #[test_case(Availability::Optional, new_offer(Availability::SameAsTarget), Ok(()))]
124 #[test_case(
125 Availability::Optional,
126 new_offer(Availability::Transitional),
127 Err(AvailabilityRoutingError::TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
128 )]
129 #[test_case(Availability::Optional, new_void_offer(), Ok(()))]
130 #[test_case(
131 Availability::Required,
132 new_offer(Availability::Optional),
133 Err(AvailabilityRoutingError::TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
134 )]
135 #[test_case(Availability::Required, new_offer(Availability::Required), Ok(()))]
136 #[test_case(Availability::Required, new_offer(Availability::SameAsTarget), Ok(()))]
137 #[test_case(
138 Availability::Required,
139 new_offer(Availability::Transitional),
140 Err(AvailabilityRoutingError::TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
141 )]
142 #[test_case(
143 Availability::Required,
144 new_void_offer(),
145 Err(AvailabilityRoutingError::OfferFromVoidToRequiredTarget { moniker: ExtendedMoniker::ComponentManager })
146 )]
147 #[test_case(Availability::Transitional, new_offer(Availability::Optional), Ok(()))]
148 #[test_case(Availability::Transitional, new_offer(Availability::Required), Ok(()))]
149 #[test_case(Availability::Transitional, new_offer(Availability::SameAsTarget), Ok(()))]
150 #[test_case(Availability::Transitional, new_offer(Availability::Transitional), Ok(()))]
151 #[test_case(Availability::Transitional, new_void_offer(), Ok(()))]
152 fn offer_tests(
153 availability: Availability,
154 offer: OfferDecl,
155 expected: Result<(), AvailabilityRoutingError>,
156 ) {
157 let actual = advance_with_offer(&ExtendedMoniker::ComponentManager, availability, &offer)
158 .map(|_| ());
159 assert_eq!(actual, expected);
160 }
161
162 fn new_expose(availability: Availability) -> ExposeDecl {
163 ExposeDecl::Protocol(ExposeProtocolDecl {
164 source: ExposeSource::Self_,
165 source_name: "fuchsia.examples.Echo".parse().unwrap(),
166 source_dictionary: Default::default(),
167 target: ExposeTarget::Parent,
168 target_name: "fuchsia.examples.Echo".parse().unwrap(),
169 availability,
170 })
171 }
172
173 fn new_void_expose() -> ExposeDecl {
174 ExposeDecl::Protocol(ExposeProtocolDecl {
175 source: ExposeSource::Void,
176 source_name: "fuchsia.examples.Echo".parse().unwrap(),
177 source_dictionary: Default::default(),
178 target: ExposeTarget::Parent,
179 target_name: "fuchsia.examples.Echo".parse().unwrap(),
180 availability: Availability::Optional,
181 })
182 }
183
184 #[test_case(Availability::Optional, new_expose(Availability::Optional), Ok(()))]
185 #[test_case(Availability::Optional, new_expose(Availability::Required), Ok(()))]
186 #[test_case(Availability::Optional, new_expose(Availability::SameAsTarget), Ok(()))]
187 #[test_case(
188 Availability::Optional,
189 new_expose(Availability::Transitional),
190 Err(AvailabilityRoutingError::TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
191 )]
192 #[test_case(
193 Availability::Optional,
194 new_void_expose(),
195 Ok(())
196 )]
197 #[test_case(
198 Availability::Required,
199 new_expose(Availability::Optional),
200 Err(AvailabilityRoutingError::TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
201 )]
202 #[test_case(Availability::Required, new_expose(Availability::Required), Ok(()))]
203 #[test_case(Availability::Required, new_expose(Availability::SameAsTarget), Ok(()))]
204 #[test_case(
205 Availability::Required,
206 new_expose(Availability::Transitional),
207 Err(AvailabilityRoutingError::TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
208 )]
209 #[test_case(
210 Availability::Required,
211 new_void_expose(),
212 Err(AvailabilityRoutingError::ExposeFromVoidToRequiredTarget { moniker: ExtendedMoniker::ComponentManager })
213 )]
214 #[test_case(Availability::Transitional, new_expose(Availability::Optional), Ok(()))]
215 #[test_case(Availability::Transitional, new_expose(Availability::Required), Ok(()))]
216 #[test_case(Availability::Transitional, new_expose(Availability::SameAsTarget), Ok(()))]
217 #[test_case(Availability::Transitional, new_expose(Availability::Transitional), Ok(()))]
218 #[test_case(
219 Availability::Transitional,
220 new_void_expose(),
221 Ok(())
222 )]
223 fn expose_tests(
224 availability: Availability,
225 expose: ExposeDecl,
226 expected: Result<(), AvailabilityRoutingError>,
227 ) {
228 let actual = advance_with_expose(&ExtendedMoniker::ComponentManager, availability, &expose)
229 .map(|_| ());
230 assert_eq!(actual, expected);
231 }
232}