use std::ops;
use crate::{VARS, VarUpdateId, VarValue};
#[derive(Debug, Clone, PartialEq)]
pub struct ObservableVec<T: VarValue> {
list: Vec<T>,
changes: VecChanges,
}
impl<T: VarValue> Default for ObservableVec<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: VarValue> ops::Deref for ObservableVec<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.list.deref()
}
}
impl<T: VarValue> ObservableVec<T> {
pub const fn new() -> Self {
Self {
list: vec![],
changes: VecChanges::new(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
list: Vec::with_capacity(capacity),
changes: VecChanges::new(),
}
}
pub fn reserve(&mut self, additional: usize) {
self.list.reserve(additional);
}
pub fn insert(&mut self, index: usize, element: T) {
self.list.insert(index, element);
self.changes.inserted(index, 1);
}
pub fn push(&mut self, element: T) {
self.insert(self.len(), element);
}
pub fn append(&mut self, other: &mut Vec<T>) {
self.changes.inserted(self.list.len(), other.len());
self.list.append(other);
}
pub fn remove(&mut self, index: usize) -> T {
let r = self.list.remove(index);
self.changes.removed(index, 1);
r
}
pub fn pop(&mut self) -> Option<T> {
if self.is_empty() { None } else { Some(self.remove(self.len() - 1)) }
}
pub fn truncate(&mut self, len: usize) {
if len < self.len() {
let count = self.len() - len;
self.changes.removed(len, count);
}
self.list.truncate(len);
}
pub fn swap_remove(&mut self, index: usize) -> T {
let r = self.list.swap_remove(index);
self.changes.removed(index, 1);
self.changes.moved(self.list.len() - 1, index);
r
}
pub fn clear(&mut self) {
if !self.is_empty() {
self.clear();
self.changes.cleared();
}
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&mut T) -> bool,
{
let mut i = 0;
self.list.retain_mut(|it| {
let retain = f(it);
if retain {
i += 1;
} else {
self.changes.removed(i, 1);
}
retain
})
}
pub fn drain<R>(&mut self, range: R) -> std::vec::Drain<'_, T>
where
R: ops::RangeBounds<usize>,
{
let range = std_slice_range(range, ..self.len());
let r = self.list.drain(range.clone());
if !range.is_empty() {
self.changes.removed(range.start, range.len());
}
r
}
pub fn resize(&mut self, new_len: usize, value: T) {
if new_len <= self.len() {
self.truncate(new_len);
} else {
let count = new_len - self.len();
self.changes.inserted(self.len(), count);
self.list.resize(new_len, value);
}
}
pub fn extend_from_slice(&mut self, other: &[T]) {
if !other.is_empty() {
self.changes.inserted(self.len(), other.len());
}
self.list.extend_from_slice(other);
}
pub fn extend_from_within<R>(&mut self, src: R)
where
R: ops::RangeBounds<usize>,
{
let src = std_slice_range(src, ..self.len());
let index = self.len();
self.list.extend_from_within(src.clone());
if !src.is_empty() {
self.changes.inserted(index, src.len());
}
}
pub fn reinsert(&mut self, from: usize, mut to: usize) {
if from != to {
if from < to {
to -= 1;
}
let el = self.list.remove(from);
self.list.insert(to, el);
self.changes.moved(from, to);
} else {
let _ = &self.list[to];
}
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
let r = self.list.get_mut(index);
if r.is_some() {
self.changes.removed(index, 1);
self.changes.inserted(index, 1);
}
r
}
pub fn slice_mut<R>(&mut self, range: R) -> &mut [T]
where
R: ops::RangeBounds<usize>,
{
let range = std_slice_range(range, ..self.len());
let r = &mut self.list[range.clone()];
let count = range.len();
if count > 0 {
self.changes.removed(range.start, count);
self.changes.inserted(range.start, count);
}
r
}
pub fn changes(&self) -> &[VecChange] {
if self.changes.update_id == VARS.update_id() {
&self.changes.changes
} else {
&[]
}
}
}
impl<T: VarValue> Extend<T> for ObservableVec<T> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
let index = self.len();
self.list.extend(iter);
let count = self.len() - index;
if count > 0 {
self.changes.inserted(index, count);
}
}
}
impl<T: VarValue> From<Vec<T>> for ObservableVec<T> {
fn from(value: Vec<T>) -> Self {
Self {
list: value,
changes: VecChanges::new(),
}
}
}
impl<T: VarValue> From<ObservableVec<T>> for Vec<T> {
fn from(value: ObservableVec<T>) -> Self {
value.list
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum VecChange {
Remove {
index: usize,
count: usize,
},
Insert {
index: usize,
count: usize,
},
Move {
from_index: usize,
to_index: usize,
},
Clear,
}
#[derive(Debug, PartialEq)]
struct VecChanges {
changes: Vec<VecChange>,
update_id: VarUpdateId,
}
impl Clone for VecChanges {
fn clone(&self) -> Self {
let update_id = VARS.update_id();
if self.update_id == update_id {
Self {
changes: self.changes.clone(),
update_id,
}
} else {
Self {
changes: vec![],
update_id,
}
}
}
}
impl VecChanges {
const fn new() -> Self {
Self {
changes: vec![],
update_id: VarUpdateId::never(),
}
}
pub fn inserted(&mut self, i: usize, n: usize) {
let update_id = VARS.update_id();
if self.update_id != update_id {
self.changes.clear();
self.changes.push(VecChange::Insert { index: i, count: n });
self.update_id = update_id;
} else if self.changes != [VecChange::Clear] {
if let Some(VecChange::Insert { index, count }) = self.changes.last_mut() {
if i >= *index && i <= *index + *count {
*count += n;
return;
} else {
self.changes.clear();
self.changes.push(VecChange::Clear);
return;
}
}
self.changes.push(VecChange::Insert { index: i, count: n });
}
}
pub fn moved(&mut self, f: usize, t: usize) {
let update_id = VARS.update_id();
if self.update_id != update_id {
self.changes.clear();
self.changes.push(VecChange::Move {
from_index: f,
to_index: t,
});
self.update_id = update_id;
} else if self.changes != [VecChange::Clear] {
self.changes.push(VecChange::Move {
from_index: f,
to_index: t,
});
}
}
pub fn removed(&mut self, i: usize, n: usize) {
let update_id = VARS.update_id();
if self.update_id != update_id {
self.changes.clear();
self.changes.push(VecChange::Remove { index: i, count: n });
self.update_id = update_id;
} else if self.changes != [VecChange::Clear] {
if let Some(last) = self.changes.last_mut() {
match last {
VecChange::Remove { index, count } => {
let s = i;
let e = i + n;
if s <= *index && e > *index {
*index = s;
*count += n;
return;
}
}
VecChange::Insert { .. } => {
self.changes.clear();
self.changes.push(VecChange::Clear);
return;
}
_ => {}
}
}
self.changes.push(VecChange::Remove { index: i, count: n });
}
}
pub fn cleared(&mut self) {
self.changes.clear();
self.changes.push(VecChange::Clear);
self.update_id = VARS.update_id();
}
}
#[track_caller]
#[must_use]
fn std_slice_range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize>
where
R: ops::RangeBounds<usize>,
{
let len = bounds.end;
let start: ops::Bound<&usize> = range.start_bound();
let start = match start {
ops::Bound::Included(&start) => start,
ops::Bound::Excluded(start) => start.checked_add(1).unwrap(),
ops::Bound::Unbounded => 0,
};
let end: ops::Bound<&usize> = range.end_bound();
let end = match end {
ops::Bound::Included(end) => end.checked_add(1).unwrap(),
ops::Bound::Excluded(&end) => end,
ops::Bound::Unbounded => len,
};
if start > end {
panic!("invalid range {start}..{end}");
}
if end > len {
panic!("invalid range {start}..{end}");
}
ops::Range { start, end }
}