use std::cmp::Ordering;
pub trait Sortable {
type Key: Ord + ?Sized;
fn key(&self) -> &Self::Key;
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct SortedVec<T>(Vec<T>);
impl<T: Sortable> SortedVec<T> {
pub fn new() -> Self {
Self(Vec::new())
}
pub fn from_vec(mut vec: Vec<T>) -> Self {
vec.sort_by(|a, b| a.key().cmp(b.key()));
vec.dedup_by(|a, b| a.key() == b.key());
Self(vec)
}
pub fn insert(&mut self, value: T) -> bool {
match self
.0
.binary_search_by(|candidate| candidate.key().cmp(value.key()))
{
Ok(_) => false,
Err(idx) => {
self.0.insert(idx, value);
true
}
}
}
pub fn remove(&mut self, key: &T::Key) -> bool {
match self
.0
.binary_search_by(|candidate| candidate.key().cmp(key))
{
Ok(idx) => {
self.0.remove(idx);
true
}
Err(_) => false,
}
}
pub fn remove_if<F: FnOnce(&T) -> bool>(&mut self, key: &T::Key, condition: F) -> Option<bool> {
match self
.0
.binary_search_by(|candidate| candidate.key().cmp(key))
{
Ok(idx) => {
if condition(&self.0[idx]) {
self.0.remove(idx);
Some(true)
} else {
Some(false)
}
}
Err(_) => None,
}
}
pub fn find(&self, key: &T::Key) -> Option<&T> {
match self
.0
.binary_search_by(|candidate| candidate.key().cmp(key))
{
Ok(idx) => Some(&self.0[idx]),
Err(_) => None,
}
}
pub fn find_mut(&mut self, key: &T::Key) -> Option<&mut T> {
match self
.0
.binary_search_by(|candidate| candidate.key().cmp(key))
{
Ok(idx) => Some(&mut self.0[idx]),
Err(_) => None,
}
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn iter(&self) -> std::slice::Iter<T> {
self.0.iter()
}
pub fn pop(&mut self) -> Option<T> {
self.0.pop()
}
pub fn iter_zip_map<U, FSelf, FBoth, FOther, Ret, Err>(
&self,
other: &SortedVec<U>,
mut fself: FSelf,
mut fboth: FBoth,
mut fother: FOther,
) -> Result<Vec<Ret>, Err>
where
U: Sortable<Key = T::Key>,
FSelf: FnMut(&T) -> Result<Ret, Err>,
FBoth: FnMut(&T, &U) -> Result<Ret, Err>,
FOther: FnMut(&U) -> Result<Ret, Err>,
{
let mut ret = Vec::new();
let mut self_iter = self.iter();
let mut other_iter = other.iter();
let mut self_item_opt = self_iter.next();
let mut other_item_opt = other_iter.next();
while let (Some(self_item), Some(other_item)) = (self_item_opt, other_item_opt) {
match self_item.key().cmp(other_item.key()) {
Ordering::Less => {
ret.push(fself(self_item)?);
self_item_opt = self_iter.next()
}
Ordering::Equal => {
ret.push(fboth(self_item, other_item)?);
self_item_opt = self_iter.next();
other_item_opt = other_iter.next();
}
Ordering::Greater => {
ret.push(fother(other_item)?);
other_item_opt = other_iter.next();
}
}
}
while let Some(self_item) = self_item_opt {
ret.push(fself(self_item)?);
self_item_opt = self_iter.next();
}
while let Some(other_item) = other_item_opt {
ret.push(fother(other_item)?);
other_item_opt = other_iter.next();
}
Ok(ret)
}
pub fn unchecked_from_vec(vec: Vec<T>) -> Self {
Self(vec)
}
pub fn unchecked_extend(&mut self, other: Self) {
self.0.extend(other);
}
pub fn unchecked_flatten<I: IntoIterator<Item = Self>>(iter: I) -> Self {
let flattened = iter.into_iter().flat_map(|sorted| sorted.0).collect();
Self::from_vec(flattened)
}
}
impl<T> IntoIterator for SortedVec<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<T: Sortable> From<Vec<T>> for SortedVec<T> {
fn from(value: Vec<T>) -> Self {
Self::from_vec(value)
}
}
impl<T: Sortable> From<SortedVec<T>> for Vec<T> {
fn from(value: SortedVec<T>) -> Self {
value.0
}
}
impl<T: Sortable + Clone> From<&[T]> for SortedVec<T> {
fn from(value: &[T]) -> Self {
Self::from_vec(value.to_vec())
}
}
impl<const N: usize, T: Sortable + Clone> From<[T; N]> for SortedVec<T> {
fn from(value: [T; N]) -> Self {
Self::from_vec(value.to_vec())
}
}
impl<T: Sortable> Default for SortedVec<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Clone + Sortable> SortedVec<T> {
pub fn replace(&mut self, value: T) -> Option<T> {
match self
.0
.binary_search_by(|candidate| candidate.key().cmp(value.key()))
{
Ok(idx) => {
let prev = self.0[idx].clone();
self.0[idx] = value;
Some(prev)
}
Err(idx) => {
self.0.insert(idx, value);
None
}
}
}
}
#[cfg(test)]
mod test {
use crate::{
test_utils::TestNode::{D, F},
vfs::dir_tree::NodeKind,
};
use super::SortedVec;
#[test]
fn test_ordering_creation() {
let test_nodes = vec![
F("f1"),
D("a", vec![]),
D("f1", vec![]),
F("f2"),
F("a"),
D("b", vec![]),
]
.into_iter()
.map(|val| val.into_node())
.collect();
let vec = SortedVec::from_vec(test_nodes);
let reference: Vec<_> = [D("a", vec![]), D("b", vec![]), F("f1"), F("f2")]
.into_iter()
.map(|val| val.into_node())
.collect();
assert!(
vec.0
.iter()
.zip(reference.iter())
.all(|(a, b)| a.structural_eq(b))
)
}
#[test]
fn test_insertion() {
let test_nodes = [D("a", vec![]), D("b", vec![]), F("f1"), F("f2")]
.into_iter()
.map(|val| val.into_node())
.collect();
let mut vec = SortedVec::from_vec(test_nodes);
assert!(!vec.insert(F("b").into_node()));
assert!(vec.insert(D("e", vec![]).into_node()));
assert!(!vec.insert(D("a", vec![]).into_node()));
assert!(vec.insert(F("f3").into_node()));
let reference: Vec<_> = vec![
D("a", vec![]),
D("b", vec![]),
D("e", vec![]),
F("f1"),
F("f2"),
F("f3"),
]
.into_iter()
.map(|val| val.into_node())
.collect();
assert!(
vec.0
.iter()
.zip(reference.iter())
.all(|(a, b)| a.structural_eq(b))
)
}
#[test]
fn test_replacement() {
let test_nodes = [D("a", vec![]), D("b", vec![]), F("f1"), F("f2")]
.into_iter()
.map(|val| val.into_node())
.collect();
let mut vec = SortedVec::from_vec(test_nodes);
assert!(vec.replace(F("b").into_node()).is_some());
assert!(vec.replace(D("e", vec![]).into_node()).is_none());
assert!(vec.replace(D("a", vec![]).into_node()).is_some());
assert!(vec.replace(F("f3").into_node()).is_none());
let reference: Vec<_> = vec![
D("a", vec![]),
F("b"),
D("e", vec![]),
F("f1"),
F("f2"),
F("f3"),
]
.into_iter()
.map(|val| val.into_node())
.collect();
assert!(
vec.0
.iter()
.zip(reference.iter())
.all(|(a, b)| a.structural_eq(b))
)
}
#[test]
fn test_removal() {
let test_nodes = vec![
D("a", vec![]),
D("b", vec![]),
D("e", vec![]),
F("f1"),
F("f2"),
F("f3"),
]
.into_iter()
.map(|val| val.into_node())
.collect();
let mut vec = SortedVec::from_vec(test_nodes);
assert!(vec.remove("e"));
assert!(!vec.remove("j"));
assert!(!vec.remove("e"));
assert!(
vec.remove_if("f3", |node| node.kind() == NodeKind::File)
.unwrap()
);
assert_eq!(
vec.remove_if("a", |node| node.kind() == NodeKind::File),
Some(false)
);
let reference: Vec<_> = [D("a", vec![]), D("b", vec![]), F("f1"), F("f2")]
.into_iter()
.map(|val| val.into_node())
.collect();
assert!(
vec.0
.iter()
.zip(reference.iter())
.all(|(a, b)| a.structural_eq(b))
)
}
#[test]
fn test_pop() {
let test_nodes = vec![D("a", vec![]), D("b", vec![]), D("c", vec![])]
.into_iter()
.map(|val| val.into_node())
.collect();
let mut vec = SortedVec::from_vec(test_nodes);
assert_eq!(vec.pop().unwrap().name(), "c");
assert_eq!(vec.pop().unwrap().name(), "b");
assert_eq!(vec.pop().unwrap().name(), "a");
assert!(vec.pop().is_none());
}
}