use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PerceptionTier {
Local,
Offload,
Hybrid,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TierInputs {
pub has_accelerator: bool,
pub local_inference_capable: bool,
pub models_fit_locally: bool,
pub compute_node_paired: bool,
pub bearer_acceptable: bool,
pub can_run_light_local: bool,
}
impl TierInputs {
pub fn for_drone(
has_accelerator: bool,
local_inference_capable: bool,
compute_node_paired: bool,
bearer_acceptable: bool,
) -> Self {
TierInputs {
has_accelerator,
local_inference_capable,
models_fit_locally: true,
compute_node_paired,
bearer_acceptable,
can_run_light_local: false,
}
}
}
pub fn pick_tier(inputs: &TierInputs) -> Option<PerceptionTier> {
if (inputs.has_accelerator && inputs.models_fit_locally) || inputs.local_inference_capable {
return Some(PerceptionTier::Local);
}
if inputs.compute_node_paired && inputs.bearer_acceptable {
return Some(if inputs.can_run_light_local {
PerceptionTier::Hybrid
} else {
PerceptionTier::Offload
});
}
if inputs.can_run_light_local {
return Some(PerceptionTier::Local);
}
None
}
#[cfg(test)]
mod tests {
use super::*;
fn inputs() -> TierInputs {
TierInputs {
has_accelerator: false,
local_inference_capable: false,
models_fit_locally: false,
compute_node_paired: false,
bearer_acceptable: false,
can_run_light_local: false,
}
}
#[test]
fn an_accelerator_that_fits_the_models_is_local() {
let mut i = inputs();
i.has_accelerator = true;
i.models_fit_locally = true;
i.compute_node_paired = true;
i.bearer_acceptable = true;
assert_eq!(pick_tier(&i), Some(PerceptionTier::Local));
}
#[test]
fn an_accelerator_whose_models_do_not_fit_offloads_when_a_node_is_paired() {
let mut i = inputs();
i.has_accelerator = true;
i.models_fit_locally = false; i.compute_node_paired = true;
i.bearer_acceptable = true;
assert_eq!(pick_tier(&i), Some(PerceptionTier::Offload));
}
#[test]
fn a_cpu_onnx_capable_board_runs_local_without_an_accelerator() {
let mut i = inputs();
i.has_accelerator = false;
i.local_inference_capable = true;
assert_eq!(pick_tier(&i), Some(PerceptionTier::Local));
i.compute_node_paired = true;
i.bearer_acceptable = true;
assert_eq!(pick_tier(&i), Some(PerceptionTier::Local));
}
#[test]
fn an_npu_less_board_with_a_paired_node_offloads() {
let mut i = inputs();
i.compute_node_paired = true;
i.bearer_acceptable = true;
assert_eq!(pick_tier(&i), Some(PerceptionTier::Offload));
}
#[test]
fn a_board_that_can_carry_the_light_path_is_hybrid() {
let mut i = inputs();
i.compute_node_paired = true;
i.bearer_acceptable = true;
i.can_run_light_local = true;
assert_eq!(pick_tier(&i), Some(PerceptionTier::Hybrid));
}
#[test]
fn an_unacceptable_bearer_is_not_an_offload_path() {
let mut i = inputs();
i.compute_node_paired = true;
i.bearer_acceptable = false; assert_eq!(pick_tier(&i), None);
}
#[test]
fn a_light_local_board_with_no_node_runs_local_not_none() {
let mut i = inputs();
i.can_run_light_local = true; assert_eq!(pick_tier(&i), Some(PerceptionTier::Local));
}
#[test]
fn no_accelerator_no_node_no_light_local_is_none() {
assert_eq!(pick_tier(&inputs()), None);
}
#[test]
fn for_drone_maps_the_offload_link_to_the_expected_tier() {
assert_eq!(
pick_tier(&TierInputs::for_drone(false, false, true, true)),
Some(PerceptionTier::Offload)
);
assert_eq!(
pick_tier(&TierInputs::for_drone(false, false, false, false)),
None
);
assert_eq!(
pick_tier(&TierInputs::for_drone(true, false, true, true)),
Some(PerceptionTier::Local)
);
assert_eq!(
pick_tier(&TierInputs::for_drone(false, true, true, true)),
Some(PerceptionTier::Local)
);
assert_eq!(
pick_tier(&TierInputs::for_drone(false, true, false, false)),
Some(PerceptionTier::Local)
);
assert_eq!(
pick_tier(&TierInputs::for_drone(false, false, true, false)),
None
);
}
}