use std::collections::HashMap;
use super::patch::patch_node;
use super::mount::mount_to_dom;
use super::VNode;
pub fn patch_children(
old_children: &[VNode],
new_children: &[VNode],
parent: &web_sys::Node,
) {
let old_has_keys = old_children.iter().any(|c| c.key().is_some());
let new_has_keys = new_children.iter().any(|c| c.key().is_some());
if old_has_keys && new_has_keys {
patch_keyed_children(old_children, new_children, parent);
} else {
patch_unkeyed_children(old_children, new_children, parent);
}
}
fn patch_unkeyed_children(
old_children: &[VNode],
new_children: &[VNode],
parent: &web_sys::Node,
) {
let old_len = old_children.len();
let new_len = new_children.len();
let common_len = old_len.min(new_len);
for i in 0..common_len {
patch_node(&old_children[i], &new_children[i], parent, None);
}
if new_len > old_len {
for i in old_len..new_len {
mount_to_dom(&new_children[i], parent, None);
}
} else if old_len > new_len {
for i in new_len..old_len {
if let Some(node) = old_children[i].dom_node() {
let _ = parent.remove_child(&node);
}
}
}
}
fn patch_keyed_children(
old_children: &[VNode],
new_children: &[VNode],
parent: &web_sys::Node,
) {
let old_key_to_idx: HashMap<&str, usize> = old_children
.iter()
.enumerate()
.filter_map(|(i, c)| c.key().map(|k| (k, i)))
.collect();
let new_key_to_idx: HashMap<&str, usize> = new_children
.iter()
.enumerate()
.filter_map(|(i, c)| c.key().map(|k| (k, i)))
.collect();
let mut new_idx_for_old: Vec<Option<usize>> = vec![None; old_children.len()];
let mut old_to_new_key: Vec<Option<&str>> = vec![None; old_children.len()];
for (old_idx, old_child) in old_children.iter().enumerate() {
if let Some(key) = old_child.key() {
if let Some(&new_idx) = new_key_to_idx.get(key) {
new_idx_for_old[old_idx] = Some(new_idx);
old_to_new_key[old_idx] = Some(key);
}
}
}
let lis_indices = longest_increasing_subsequence_filtered(&new_idx_for_old);
for (old_idx, old_child) in old_children.iter().enumerate() {
if new_idx_for_old[old_idx].is_none() {
if let Some(node) = old_child.dom_node() {
let _ = parent.remove_child(&node);
}
}
}
let mut lis_set: Vec<bool> = vec![false; old_children.len()];
for &idx in &lis_indices {
lis_set[idx] = true;
}
for (new_idx, new_child) in new_children.iter().enumerate() {
if let Some(key) = new_child.key() {
if let Some(&old_idx) = old_key_to_idx.get(key) {
let old_child = &old_children[old_idx];
let is_stable = lis_set[old_idx];
if is_stable {
patch_node(old_child, new_child, parent, None);
} else {
let ref_node = find_reference_node(new_children, new_idx, parent);
patch_node(old_child, new_child, parent, ref_node.as_ref());
}
} else {
let ref_node = find_reference_node(new_children, new_idx, parent);
mount_to_dom(new_child, parent, ref_node.as_ref());
}
} else {
let ref_node = find_reference_node(new_children, new_idx, parent);
mount_to_dom(new_child, parent, ref_node.as_ref());
}
}
}
fn find_reference_node(
new_children: &[VNode],
new_idx: usize,
_parent: &web_sys::Node,
) -> Option<web_sys::Node> {
for next in (new_idx + 1)..new_children.len() {
if let Some(node) = new_children[next].dom_node() {
return Some(node);
}
}
None
}
pub fn longest_increasing_subsequence(arr: &[usize]) -> Vec<usize> {
if arr.is_empty() {
return vec![];
}
let mut tails: Vec<usize> = vec![];
let mut prev: Vec<isize> = vec![-1; arr.len()];
for (i, &val) in arr.iter().enumerate() {
let pos = match tails.binary_search_by(|&tail_idx| arr[tail_idx].cmp(&val)) {
Ok(p) => p, Err(p) => p, };
if pos == tails.len() {
tails.push(i);
} else {
tails[pos] = i;
}
if pos > 0 {
prev[i] = tails[pos - 1] as isize;
}
}
let mut result: Vec<usize> = vec![];
if let Some(&last) = tails.last() {
let mut idx = last;
loop {
result.push(idx);
if prev[idx] == -1 {
break;
}
idx = prev[idx] as usize;
}
result.reverse();
}
result
}
fn longest_increasing_subsequence_filtered(arr: &[Option<usize>]) -> Vec<usize> {
let filtered: Vec<(usize, usize)> = arr
.iter()
.enumerate()
.filter_map(|(i, &opt)| opt.map(|v| (i, v)))
.collect();
if filtered.is_empty() {
return vec![];
}
let values: Vec<usize> = filtered.iter().map(|(_, v)| *v).collect();
let lis = longest_increasing_subsequence(&values);
lis.iter().map(|&idx| filtered[idx].0).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lis_empty() {
assert_eq!(longest_increasing_subsequence(&[]), Vec::<usize>::new());
}
#[test]
fn test_lis_single() {
assert_eq!(longest_increasing_subsequence(&[5]), vec![0]);
}
#[test]
fn test_lis_increasing() {
assert_eq!(longest_increasing_subsequence(&[1, 2, 3, 4]), vec![0, 1, 2, 3]);
}
#[test]
fn test_lis_decreasing() {
let result = longest_increasing_subsequence(&[4, 3, 2, 1]);
assert_eq!(result.len(), 1);
}
#[test]
fn test_lis_mixed() {
let arr = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15];
let result = longest_increasing_subsequence(&arr);
for w in result.windows(2) {
assert!(arr[w[0]] < arr[w[1]], "LIS should be increasing");
}
assert_eq!(result.len(), 6);
}
#[test]
fn test_lis_filtered() {
let arr = vec![Some(0), None, Some(1), None, Some(2)];
let result = longest_increasing_subsequence_filtered(&arr);
assert_eq!(result, vec![0, 2, 4]);
}
#[test]
fn test_lis_filtered_out_of_order() {
let arr = vec![Some(2), None, Some(0), Some(1)];
let result = longest_increasing_subsequence_filtered(&arr);
assert_eq!(result.len(), 2);
assert!(result.contains(&2));
assert!(result.contains(&3));
}
}