use cm_types::Availability;
use moniker::ExtendedMoniker;
use router_error::Explain;
use thiserror::Error;
use zx_status as zx;
pub fn advance(
moniker: &ExtendedMoniker,
current: Availability,
next: Availability,
) -> Result<Availability, TargetHasStrongerAvailability> {
match (current, next) {
(Availability::SameAsTarget, _) => Ok(next),
(Availability::Required, Availability::Required)
| (Availability::Optional, Availability::Optional)
| (Availability::Transitional, Availability::Transitional)
| (Availability::Required, Availability::SameAsTarget)
| (Availability::Optional, Availability::SameAsTarget)
| (Availability::Transitional, Availability::SameAsTarget) => Ok(current),
(Availability::Optional, Availability::Required)
| (Availability::Transitional, Availability::Required)
| (Availability::Transitional, Availability::Optional) =>
Ok(next),
(Availability::Optional, Availability::Transitional)
| (Availability::Required, Availability::Transitional)
| (Availability::Required, Availability::Optional) =>
Err(TargetHasStrongerAvailability { moniker: moniker.clone() }),
}
}
#[derive(Debug, Error, Clone, PartialEq)]
#[error(
"Availability requested by the target has stronger guarantees than what \
is being provided at the source."
)]
pub struct TargetHasStrongerAvailability {
pub moniker: ExtendedMoniker,
}
impl Explain for TargetHasStrongerAvailability {
fn as_zx_status(&self) -> zx::Status {
zx::Status::NOT_FOUND
}
}
#[cfg(test)]
mod tests {
use super::*;
use test_case::test_case;
#[test_case(Availability::Optional, Availability::Optional, Ok(Availability::Optional))]
#[test_case(Availability::Optional, Availability::Required, Ok(Availability::Required))]
#[test_case(Availability::Optional, Availability::SameAsTarget, Ok(Availability::Optional))]
#[test_case(
Availability::Optional,
Availability::Transitional,
Err(TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
)]
#[test_case(Availability::Required, Availability::Optional, Err(TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager }))]
#[test_case(Availability::Required, Availability::Required, Ok(Availability::Required))]
#[test_case(Availability::Required, Availability::SameAsTarget, Ok(Availability::Required))]
#[test_case(
Availability::Required,
Availability::Transitional,
Err(TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
)]
#[test_case(Availability::Transitional, Availability::Optional, Ok(Availability::Optional))]
#[test_case(Availability::Transitional, Availability::Required, Ok(Availability::Required))]
#[test_case(
Availability::Transitional,
Availability::SameAsTarget,
Ok(Availability::Transitional)
)]
#[test_case(
Availability::Transitional,
Availability::Transitional,
Ok(Availability::Transitional)
)]
fn advance_tests(
current: Availability,
next: Availability,
expected: Result<Availability, TargetHasStrongerAvailability>,
) {
let actual = advance(&ExtendedMoniker::ComponentManager, current, next);
assert_eq!(actual, expected);
}
}