routing/
availability.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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}