1use cm_types::Availability;
6use moniker::ExtendedMoniker;
7use router_error::Explain;
8use thiserror::Error;
9use zx_status as zx;
10
11pub fn advance(
13 moniker: &ExtendedMoniker,
14 current: Availability,
15 next: Availability,
16) -> Result<Availability, TargetHasStrongerAvailability> {
17 match (current, next) {
18 (Availability::SameAsTarget, _) => Ok(next),
25
26 (Availability::Required, Availability::Required)
28 | (Availability::Optional, Availability::Optional)
29 | (Availability::Transitional, Availability::Transitional)
30
31 | (Availability::Required, Availability::SameAsTarget)
33 | (Availability::Optional, Availability::SameAsTarget)
34 | (Availability::Transitional, Availability::SameAsTarget) => Ok(current),
35
36 (Availability::Optional, Availability::Required)
38 | (Availability::Transitional, Availability::Required)
39 | (Availability::Transitional, Availability::Optional) =>
40 Ok(next),
41
42 (Availability::Optional, Availability::Transitional)
45 | (Availability::Required, Availability::Transitional)
46 | (Availability::Required, Availability::Optional) =>
47 Err(TargetHasStrongerAvailability { moniker: moniker.clone() }),
48 }
49}
50
51#[derive(Debug, Error, Clone, PartialEq)]
54#[error(
55 "Availability requested by the target has stronger guarantees than what \
56 is being provided at the source."
57)]
58pub struct TargetHasStrongerAvailability {
59 pub moniker: ExtendedMoniker,
60}
61
62impl Explain for TargetHasStrongerAvailability {
63 fn as_zx_status(&self) -> zx::Status {
64 zx::Status::NOT_FOUND
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use test_case::test_case;
72
73 #[test_case(Availability::Optional, Availability::Optional, Ok(Availability::Optional))]
74 #[test_case(Availability::Optional, Availability::Required, Ok(Availability::Required))]
75 #[test_case(Availability::Optional, Availability::SameAsTarget, Ok(Availability::Optional))]
76 #[test_case(
77 Availability::Optional,
78 Availability::Transitional,
79 Err(TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
80 )]
81 #[test_case(Availability::Required, Availability::Optional, Err(TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager }))]
82 #[test_case(Availability::Required, Availability::Required, Ok(Availability::Required))]
83 #[test_case(Availability::Required, Availability::SameAsTarget, Ok(Availability::Required))]
84 #[test_case(
85 Availability::Required,
86 Availability::Transitional,
87 Err(TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
88 )]
89 #[test_case(Availability::Transitional, Availability::Optional, Ok(Availability::Optional))]
90 #[test_case(Availability::Transitional, Availability::Required, Ok(Availability::Required))]
91 #[test_case(
92 Availability::Transitional,
93 Availability::SameAsTarget,
94 Ok(Availability::Transitional)
95 )]
96 #[test_case(
97 Availability::Transitional,
98 Availability::Transitional,
99 Ok(Availability::Transitional)
100 )]
101 fn advance_tests(
102 current: Availability,
103 next: Availability,
104 expected: Result<Availability, TargetHasStrongerAvailability>,
105 ) {
106 let actual = advance(&ExtendedMoniker::ComponentManager, current, next);
107 assert_eq!(actual, expected);
108 }
109}