use facet_reflect::Peek;
use crate::Diff;
pub struct Interspersed<A, B> {
pub first: Option<A>,
pub values: Vec<(B, A)>,
pub last: Option<B>,
}
impl<A, B> Interspersed<A, B> {
pub fn front_a(&mut self) -> &mut A
where
A: Default,
{
self.first.get_or_insert_default()
}
pub fn front_b(&mut self) -> &mut B
where
B: Default,
{
if let Some(a) = self.first.take() {
self.values.insert(0, (B::default(), a));
}
if let Some((b, _)) = self.values.first_mut() {
b
} else {
self.last.get_or_insert_default()
}
}
}
impl<A, B> Default for Interspersed<A, B> {
fn default() -> Self {
Self {
first: Default::default(),
values: Default::default(),
last: Default::default(),
}
}
}
#[derive(Default)]
pub struct ReplaceGroup<'mem, 'facet> {
pub removals: Vec<Peek<'mem, 'facet>>,
pub additions: Vec<Peek<'mem, 'facet>>,
}
impl<'mem, 'facet> ReplaceGroup<'mem, 'facet> {
pub fn push_add(&mut self, addition: Peek<'mem, 'facet>) {
self.additions.insert(0, addition);
}
pub fn push_remove(&mut self, removal: Peek<'mem, 'facet>) {
self.removals.insert(0, removal);
}
}
#[derive(Default)]
pub struct UpdatesGroup<'mem, 'facet>(
pub Interspersed<ReplaceGroup<'mem, 'facet>, Vec<Diff<'mem, 'facet>>>,
);
impl<'mem, 'facet> UpdatesGroup<'mem, 'facet> {
pub fn push_add(&mut self, addition: Peek<'mem, 'facet>) {
self.0.front_a().push_add(addition);
}
pub fn push_remove(&mut self, removal: Peek<'mem, 'facet>) {
self.0.front_a().push_remove(removal);
}
pub fn flatten_with<C, D>(&mut self, closeness_fn: C, diff_fn: D)
where
C: Fn(Peek<'mem, 'facet>, Peek<'mem, 'facet>) -> usize,
D: Fn(Peek<'mem, 'facet>, Peek<'mem, 'facet>) -> Diff<'mem, 'facet>,
{
let Some(updates) = self.0.first.take() else {
return;
};
let mut mem = vec![vec![0; updates.additions.len() + 1]];
for x in 0..updates.removals.len() {
let mut row = vec![0];
for (y, addition) in updates.additions.iter().enumerate() {
row.push(
row.last()
.copied()
.unwrap()
.max(mem[x][y] + closeness_fn(updates.removals[x], *addition)),
);
}
mem.push(row);
}
let mut x = updates.removals.len();
let mut y = updates.additions.len();
while x > 0 || y > 0 {
if x == 0 {
self.push_add(updates.additions[y - 1]);
y -= 1;
} else if y == 0 {
self.push_remove(updates.removals[x - 1]);
x -= 1;
} else if mem[x][y - 1] == mem[x][y] {
self.push_add(updates.additions[y - 1]);
y -= 1;
} else {
let diff = diff_fn(updates.removals[x - 1], updates.additions[y - 1]);
self.0.front_b().insert(0, diff);
x -= 1;
y -= 1;
}
}
}
}
#[derive(Default)]
pub struct Updates<'mem, 'facet>(
pub Interspersed<UpdatesGroup<'mem, 'facet>, Vec<Peek<'mem, 'facet>>>,
);
impl<'mem, 'facet> Updates<'mem, 'facet> {
pub fn push_add(&mut self, addition: Peek<'mem, 'facet>) {
self.0.front_a().push_add(addition);
}
pub fn push_remove(&mut self, removal: Peek<'mem, 'facet>) {
self.0.front_a().push_remove(removal);
}
pub fn closeness(&self) -> usize {
self.0.values.iter().map(|(x, _)| x.len()).sum::<usize>()
+ self.0.last.as_ref().map(|x| x.len()).unwrap_or_default()
}
pub fn push_keep(&mut self, value: Peek<'mem, 'facet>) {
self.0.front_b().insert(0, value);
}
pub fn flatten_with<C, D>(&mut self, closeness_fn: C, diff_fn: D)
where
C: Fn(Peek<'mem, 'facet>, Peek<'mem, 'facet>) -> usize + Copy,
D: Fn(Peek<'mem, 'facet>, Peek<'mem, 'facet>) -> Diff<'mem, 'facet> + Copy,
{
if let Some(update) = &mut self.0.first {
update.flatten_with(closeness_fn, diff_fn);
}
for (_, update) in &mut self.0.values {
update.flatten_with(closeness_fn, diff_fn);
}
}
}