use crate::error::{ExecutorResult, RwLockExt};
use std::sync::RwLock;
use zisk_common::{InstanceType, Plan};
use zisk_pil::{ROM_AIR_IDS, ZISK_AIRGROUP_ID};
use crate::ports::{GlobalId, InstanceInfo, ProofRegistry};
use crate::AirClassifier;
pub struct InstanceAssigner;
impl InstanceAssigner {
pub fn assign_rom_instance(registry: &dyn ProofRegistry) -> ExecutorResult<GlobalId> {
registry.add_instance_assign(InstanceInfo::new(ZISK_AIRGROUP_ID, ROM_AIR_IDS[0]))
}
pub fn assign_main_instances(
registry: &dyn ProofRegistry,
global_ids: &RwLock<Vec<usize>>,
plans: Vec<Plan>,
) -> ExecutorResult<Vec<(usize, Plan)>> {
let mut assignments = Vec::with_capacity(plans.len());
for mut plan in plans {
let gid =
registry.add_instance_assign(InstanceInfo::new(plan.airgroup_id, plan.air_id))?;
plan.set_global_id(gid.0);
global_ids.write_or_poison("global_ids")?.push(gid.0);
assignments.push((gid.0, plan));
}
Ok(assignments)
}
pub fn assign_secn_instances(
registry: &dyn ProofRegistry,
global_ids: &RwLock<Vec<usize>>,
plans: &mut [Plan],
) -> ExecutorResult<()> {
for plan in plans.iter_mut() {
let info = InstanceInfo::new(plan.airgroup_id, plan.air_id);
let gid = if AirClassifier::is_rom(plan.airgroup_id, plan.air_id) {
registry.find_instance_id(InstanceInfo::new(ZISK_AIRGROUP_ID, ROM_AIR_IDS[0]))?
} else if AirClassifier::is_rank_assigned_precompile(plan.airgroup_id, plan.air_id) {
registry.add_instance_assign(info)?
} else {
match plan.instance_type {
InstanceType::Instance => registry.add_instance(info)?,
InstanceType::Table => registry.add_table(info)?,
}
};
global_ids.write_or_poison("global_ids")?.push(gid.0);
plan.set_global_id(gid.0);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ports::fakes::{AddKind, FakeProofRegistry};
#[test]
fn assign_rom_instance_uses_add_instance_assign_with_rom_air_id() {
let registry = FakeProofRegistry::new();
let gid = InstanceAssigner::assign_rom_instance(®istry).expect("ok");
let calls = registry.additions.borrow();
assert_eq!(calls.len(), 1);
assert_eq!(calls[0].kind, AddKind::InstanceAssign);
assert_eq!(calls[0].info, InstanceInfo::new(ZISK_AIRGROUP_ID, ROM_AIR_IDS[0]));
assert_eq!(calls[0].gid, gid);
}
#[test]
fn assign_main_instances_records_one_add_instance_assign_per_plan() {
let registry = FakeProofRegistry::new();
let global_ids = RwLock::new(Vec::<usize>::new());
let plans = vec![
Plan::new(7, 100, None, InstanceType::Instance, zisk_common::CheckPoint::None, None),
Plan::new(7, 101, None, InstanceType::Instance, zisk_common::CheckPoint::None, None),
];
let assignments =
InstanceAssigner::assign_main_instances(®istry, &global_ids, plans).expect("ok");
assert_eq!(assignments.len(), 2);
let calls = registry.additions.borrow();
assert_eq!(calls.len(), 2);
assert!(calls.iter().all(|c| c.kind == AddKind::InstanceAssign));
assert_eq!(calls[0].info, InstanceInfo::new(7, 100));
assert_eq!(calls[1].info, InstanceInfo::new(7, 101));
let gids = global_ids.read().unwrap();
assert_eq!(gids.len(), 2);
assert_eq!(gids[0], calls[0].gid.0);
assert_eq!(gids[1], calls[1].gid.0);
assert_eq!(assignments[0].1.global_id, Some(calls[0].gid.0));
assert_eq!(assignments[1].1.global_id, Some(calls[1].gid.0));
}
#[test]
fn assign_secn_instances_routes_by_instance_type() {
let registry = FakeProofRegistry::new();
let global_ids = RwLock::new(Vec::<usize>::new());
let mut plans = vec![
Plan::new(7, 200, None, InstanceType::Instance, zisk_common::CheckPoint::None, None),
Plan::new(7, 201, None, InstanceType::Table, zisk_common::CheckPoint::None, None),
];
InstanceAssigner::assign_secn_instances(®istry, &global_ids, &mut plans).expect("ok");
let calls = registry.additions.borrow();
assert_eq!(calls.len(), 2);
assert_eq!(calls[0].kind, AddKind::Instance);
assert_eq!(calls[1].kind, AddKind::Table);
}
}