use crate::error::PayloadError;
use crate::identifier::TaskId;
use crate::project::error::{ProjectError, ProjectResult};
use crate::project::finder::{ProjectFinder, ProjectPathBuf, TaskFinder, TaskPath, TaskPathBuf};
use crate::project::shared::SharedProject;
use crate::task::flags::{OptionsSlurper, WeakOptionsDecoder};
use std::collections::{HashMap, VecDeque};
#[derive(Debug)]
pub struct TaskRequests {
task_to_weak_decoder: HashMap<TaskId, usize>,
weak_decoders: Vec<WeakOptionsDecoder>,
tasks: Vec<TaskId>,
}
impl TaskRequests {
pub fn build<I: IntoIterator<Item = S>, S: AsRef<TaskPath>>(
project: &SharedProject,
args: I,
) -> ProjectResult<Self> {
let mut builder = TaskRequestsBuilder::new();
let mut reqs: VecDeque<TaskPathBuf> =
VecDeque::from_iter(args.into_iter().map(|s| s.as_ref().to_owned()));
if reqs.is_empty() {
project.with(|p| {
reqs.extend(p.default_tasks().iter().map(|s| s.clone().into()));
})
}
if reqs.is_empty() {
return Ok(builder.finish());
}
let task_finder = TaskFinder::new(project);
let proj_finder = ProjectFinder::new(project);
while let Some(task) = reqs.pop_front() {
let task_req: &TaskPath = task.as_ref();
debug!("attempting to find tasks for task path {:?}", task_req);
let ids: Option<Vec<TaskId>> = task_finder.find(task_req)?;
if let Some(ids) = ids {
let first = ids.first().unwrap();
let project = proj_finder
.find(ProjectPathBuf::from(first.project_id().unwrap()))
.unwrap();
let mut any_handle = project.get_task(first)?;
let resolved = any_handle.resolve_shared(&project)?;
if let Some(ops) = resolved.options_declarations() {
let slurper = OptionsSlurper::new(&ops);
let slice = reqs.make_contiguous();
let (weak, count) = slurper.slurp(slice).map_err(PayloadError::new)?;
builder.add_configured_tasks(ids, weak);
reqs.drain(..count);
} else {
builder.add_tasks(ids);
}
} else {
return Err(ProjectError::NoIdentifiersFound(task_req.to_string()).into());
}
}
Ok(builder.finish())
}
pub fn decoder(&self, id: &TaskId) -> Option<WeakOptionsDecoder> {
let index = self.task_to_weak_decoder.get(id)?;
Some(self.weak_decoders[*index].clone())
}
pub fn requested_tasks(&self) -> &[TaskId] {
&self.tasks[..]
}
}
struct TaskRequestsBuilder {
in_progress: TaskRequests,
}
impl TaskRequestsBuilder {
fn new() -> Self {
Self {
in_progress: TaskRequests {
task_to_weak_decoder: Default::default(),
weak_decoders: vec![],
tasks: vec![],
},
}
}
fn finish(self) -> TaskRequests {
self.in_progress
}
fn add_tasks<I>(&mut self, tasks: I)
where
I: IntoIterator<Item = TaskId>,
{
self.in_progress.tasks.extend(tasks)
}
fn add_configured_tasks<I>(&mut self, tasks: I, decoder: WeakOptionsDecoder)
where
I: IntoIterator<Item = TaskId>,
{
let index = self.in_progress.weak_decoders.len();
self.in_progress.weak_decoders.push(decoder);
for task in tasks {
self.in_progress.tasks.push(task.clone());
self.in_progress.task_to_weak_decoder.insert(task, index);
}
}
}