leftwm_core/utils/
helpers.rsuse std::cmp::Ordering;
pub fn intersect<T>(v1: &[T], v2: &[T]) -> bool
where
T: PartialEq,
{
for a in v1 {
for b in v2 {
if a == b {
return true;
}
}
}
false
}
pub fn vec_extract<T, F>(list: &mut Vec<T>, test: F) -> Vec<T>
where
F: Fn(&T) -> bool,
T: Clone,
{
let len = list.len();
let mut removed = vec![];
let mut del = 0;
{
let v = &mut **list;
for i in 0..len {
if test(&v[i]) {
removed.push(v[i].clone());
del += 1;
} else if del > 0 {
v.swap(i - del, i);
}
}
}
list.truncate(len - del);
removed
}
pub fn cycle_vec<T>(list: &mut Vec<T>, shift: i32) -> Option<()>
where
T: Clone,
{
let v = &mut **list;
let change = shift.unsigned_abs() as usize;
if v.len() < change {
return None;
}
match shift.cmp(&0) {
Ordering::Less => v.rotate_left(change),
Ordering::Greater => v.rotate_right(change),
Ordering::Equal => {}
}
Some(())
}
pub fn reorder_vec<T, F>(list: &mut Vec<T>, test: F, shift: i32) -> Option<()>
where
F: Fn(&T) -> bool,
T: Clone,
{
let len = list.len() as i32;
if len < 2 {
return None;
}
let index = list.iter().position(test)?;
let item = list.get(index)?.clone();
let mut new_index = index as i32 + shift;
list.remove(index);
let v = &mut **list;
if new_index < 0 {
new_index += len;
v.rotate_right(1);
} else if new_index >= len {
new_index -= len;
v.rotate_left(1);
}
list.insert(new_index as usize, item);
Some(())
}
pub fn relative_find<T, F>(
list: &[T],
reference_finder: F,
shift: i32,
should_loop: bool,
) -> Option<&T>
where
F: Fn(&T) -> bool,
{
let len = list.len() as i32;
let reference_index = list.iter().position(reference_finder)?;
let loops = if shift.is_negative() {
shift.unsigned_abs() as usize > reference_index
} else {
shift as usize > len as usize - (reference_index + 1)
};
let relative_index = if loops && !should_loop {
None
} else {
let shift = shift % len;
let shifted_index = reference_index as i32 + shift;
let max_index = len - 1;
if shifted_index < 0 {
Some((len + shifted_index) as usize)
} else if shifted_index > max_index {
Some((shifted_index - len) as usize)
} else {
Some(shifted_index as usize)
}
}?;
list.get(relative_index)
}
#[cfg(test)]
pub(crate) mod test {
use crate::utils::helpers::relative_find;
pub async fn temp_path() -> std::io::Result<std::path::PathBuf> {
tokio::task::spawn_blocking(|| tempfile::Builder::new().tempfile_in("../target"))
.await
.expect("Blocking task joined")?
.into_temp_path()
.keep()
.map_err(Into::into)
}
#[test]
fn relative_find_should_work_both_ways() {
let list = vec!["hello", "world", "foo", "bar"];
let result = relative_find(&list, |&e| e == "hello", 2, false);
assert_eq!(result, Some(&"foo"));
let result = relative_find(&list, |&e| e == "bar", -2, false);
assert_eq!(result, Some(&"world"));
}
#[test]
fn relative_find_with_inexistent_reference_must_return_none() {
let list = vec!["hello", "world", "foo", "bar"];
let result = relative_find(&list, |&e| e == "inexistent", 2, false);
assert_eq!(result, None);
}
#[test]
fn relative_find_should_be_able_to_loop() {
let list = vec!["hello", "world", "foo", "bar"];
let result = relative_find(&list, |&e| e == "hello", 4, true);
assert_eq!(result, Some(&"hello"));
let result = relative_find(&list, |&e| e == "hello", 9, true);
assert_eq!(result, Some(&"world"));
let result = relative_find(&list, |&e| e == "hello", -9, true);
assert_eq!(result, Some(&"bar"));
}
#[test]
fn relative_find_loop_can_be_disabled() {
let list = vec!["hello", "world", "foo", "bar"];
let result = relative_find(&list, |&e| e == "hello", 9, false);
assert_eq!(result, None);
}
}