use crate::eval::index::Index;
#[derive(Debug)]
pub struct Stack {
requests: Vec<Request>,
}
impl Stack {
pub fn new(target: Index) -> Self {
Self {
requests: vec![Request::new(vec![target])],
}
}
pub fn request(&mut self, targets: impl IntoIterator<Item = Index>) {
self.requests
.push(Request::new(targets.into_iter().collect()));
}
pub fn try_skip_current(&mut self) -> bool {
let Some(request) = self.requests.last_mut() else {
return false;
};
if request.skip() {
return true;
}
self.requests.pop();
self.try_skip_current()
}
pub fn remove(&mut self, index: Index) {
self.requests.retain_mut(|req| {
req.complete(index);
req.current().is_some()
});
}
pub fn stack(&self) -> Vec<Index> {
self.requests.iter().map(|r| r.current().unwrap()).collect()
}
pub fn get_current(&self) -> Option<Index> {
self.requests.last().and_then(|r| r.current())
}
pub fn len(&self) -> usize {
self.requests.len()
}
}
#[derive(Debug, Clone)]
struct Request {
pending: Vec<Index>,
failed: Vec<Index>,
}
impl Request {
pub fn new(targets: Vec<Index>) -> Self {
Self {
pending: targets,
failed: vec![],
}
}
pub fn current(&self) -> Option<Index> {
self.pending.last().copied()
}
pub fn skip(&mut self) -> bool {
let Some(failed) = self.pending.pop() else {
return false;
};
self.failed.push(failed);
!self.pending.is_empty()
}
pub fn complete(&mut self, target: Index) {
self.pending.append(&mut self.failed);
self.pending.retain(|t| *t != target);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn request_new_empty() {
let empty_request = Request::new(vec![]);
assert_eq!(empty_request.current(), None);
}
#[test]
fn request_new() {
let empty_request = Request::new(vec![Index::new(1)]);
assert_eq!(empty_request.current(), Some(Index::new(1)));
}
#[test]
fn request_skip() {
{
let mut request = Request::new(vec![]);
assert!(!request.skip(), "can not skip empty requests");
}
{
let mut request = Request::new(vec![Index::new(1)]);
assert!(!request.skip(), "can not skip when only one pending");
}
{
let mut request = Request::new(vec![Index::new(1), Index::new(2)]);
let skipped = request.current().unwrap();
assert!(request.skip(), "can skip when 2 or more pending");
let current = request.current().unwrap();
assert_ne!(skipped, current, "skip skips current item");
{
let mut request_complete_current = request.clone();
request_complete_current.complete(current);
assert_eq!(
request_complete_current.current(),
Some(skipped),
"current completed, skipped is pending"
);
}
{
let mut request_complete_skipped = request.clone();
request_complete_skipped.complete(skipped);
assert_eq!(
request_complete_skipped.current(),
Some(current),
"skipped completed, current is pending"
);
}
}
}
}