use std::collections::{BTreeMap, VecDeque};
use std::thread;
use anyhow::{Result, bail};
use super::{Ended, Handle, Kind, POLL};
use crate::base_fix::BaseFixAsk;
use crate::harness::Choice;
use crate::issue::IssueUrl;
use crate::security::Options;
#[derive(Default)]
pub struct Runs {
running: BTreeMap<u64, Handle>,
endings: VecDeque<(u64, Result<Ended>)>,
}
impl Runs {
pub fn start(
&mut self,
issue: &IssueUrl,
kind: Kind,
base_fix: BaseFixAsk,
security: Options,
harness: &Choice,
) -> Result<()> {
self.start_using(issue.number, || {
super::start(issue, kind, base_fix, security, harness)
})
}
pub(super) fn start_using(
&mut self,
number: u64,
launch: impl FnOnce() -> Result<Handle>,
) -> Result<()> {
if self.running.contains_key(&number)
|| self.endings.iter().any(|(queued, _)| *queued == number)
{
bail!("the Run for #{number} is already outstanding");
}
let child = launch()?;
self.running.insert(number, child);
Ok(())
}
pub fn next_ending(&mut self) -> Option<(u64, Result<Ended>)> {
loop {
self.running.retain(|&number, child| {
if let Some(ending) = child.try_wait() {
self.endings.push_back((number, ending));
false
} else {
true
}
});
if let Some(ending) = self.endings.pop_front() {
return Some(ending);
}
if self.running.is_empty() {
return None;
}
thread::sleep(POLL);
}
}
}
impl Drop for Runs {
fn drop(&mut self) {
for child in self.running.values_mut() {
child.stop();
}
while self.next_ending().is_some() {}
}
}