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