use crate::{Dir, Nextable};
#[derive(Debug)]
pub(super) enum Strategy {
First(First),
Last(Last),
Previous(Previous),
Next(Next),
Random(Random),
Keep(Keep),
}
pub(super) trait Nexter {
fn next_with<'a>(&self, dirs: &'a impl Nextable, step: i32) -> Option<Dir<'a>>;
}
#[derive(Debug)]
pub(super) struct First {}
#[derive(Debug)]
pub(super) struct Last {}
#[derive(Debug)]
pub(super) struct Previous {}
#[derive(Debug)]
pub(super) struct Next {}
#[derive(Debug)]
pub(super) struct Random {}
#[derive(Debug)]
pub(super) struct Keep {}
impl Nexter for First {
fn next_with<'a>(&self, dirs: &'a impl Nextable, _step: i32) -> Option<Dir<'a>> {
if dirs.dirs().is_empty() {
None
} else {
Some(Dir::new(dirs.dirs(), 0))
}
}
}
impl Nexter for Last {
fn next_with<'a>(&self, dirs: &'a impl Nextable, _step: i32) -> Option<Dir<'a>> {
if dirs.dirs().is_empty() {
None
} else {
let next = dirs.dirs().len() - 1;
Some(Dir::new(dirs.dirs(), next))
}
}
}
impl Nexter for Previous {
fn next_with<'a>(&self, dirs: &'a impl Nextable, step: i32) -> Option<Dir<'a>> {
next_impl(dirs, -step)
}
}
impl Nexter for Next {
fn next_with<'a>(&self, dirs: &'a impl Nextable, step: i32) -> Option<Dir<'a>> {
next_impl(dirs, step)
}
}
impl Nexter for Random {
fn next_with<'a>(&self, dirs: &'a impl Nextable, _step: i32) -> Option<Dir<'a>> {
if dirs.dirs().is_empty() {
log::warn!("Random::next_with: no directory to choose");
return None;
}
let next = rand::random_range(0..dirs.dirs().len());
log::trace!("Random::next_with -> index {next}");
Some(Dir::new(dirs.dirs(), next))
}
}
impl Nexter for Keep {
fn next_with<'a>(&self, dirs: &'a impl Nextable, _step: i32) -> Option<Dir<'a>> {
match dirs.current_index() {
Some(index) => Some(Dir::new(dirs.dirs(), index)),
None => {
log::warn!("Keep::next_with: no current directory to keep");
None
}
}
}
}
fn next_impl<'a>(dirs: &'a impl Nextable, step: i32) -> Option<Dir<'a>> {
let current = dirs
.current_index()
.map_or(-1, |index| i32::try_from(index).unwrap());
let next = current + step;
let length = i32::try_from(dirs.dirs().len()).unwrap();
log::trace!("next_impl(step={step}, current={current}, next={next})");
if next < 0 || next >= length {
log::warn!("next_impl: out of range (next={next}, len={length})",);
None
} else if next == 0 {
Some(Dir::new(dirs.dirs(), 0))
} else if next == length - 1 {
Some(Dir::new(dirs.dirs(), usize::try_from(length - 1).unwrap()))
} else {
Some(Dir::new(dirs.dirs(), usize::try_from(next).unwrap()))
}
}