state-tree 4.0.0-alpha.5

Utility for keeping internal states of signal between 2 compiled source codes
Documentation
pub mod patch;
pub mod tree;
pub mod tree_diff;

use crate::patch::CopyFromPatch;
use crate::tree::{SizedType, StateTreeSkeleton};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StateStoragePatchPlan {
    pub total_size: usize,
    pub patches: Vec<CopyFromPatch>,
}

pub fn build_state_storage_patch_plan<T: SizedType + PartialEq>(
    old_state_skeleton: StateTreeSkeleton<T>,
    new_state_skeleton: StateTreeSkeleton<T>,
) -> Option<StateStoragePatchPlan> {
    if old_state_skeleton == new_state_skeleton {
        return None;
    }

    let total_size = new_state_skeleton.total_size() as usize;
    let patches = tree_diff::take_diff(&old_state_skeleton, &new_state_skeleton)
        .into_iter()
        .collect::<Vec<_>>();

    Some(StateStoragePatchPlan {
        total_size,
        patches,
    })
}

pub fn apply_state_storage_patch_plan(
    old_storage: &[u64],
    patch_plan: &StateStoragePatchPlan,
) -> Vec<u64> {
    let mut new_storage = vec![0u64; patch_plan.total_size];
    patch::apply_patches(&mut new_storage, old_storage, patch_plan.patches.as_slice());

    debug_assert_eq!(new_storage.len(), patch_plan.total_size);

    new_storage
}

pub fn update_state_storage<T: SizedType + PartialEq>(
    old: &[u64],
    old_state_skeleton: StateTreeSkeleton<T>,
    new_state_skeleton: StateTreeSkeleton<T>,
) -> Result<Option<Vec<u64>>, Box<dyn std::error::Error>> {
    let patch_plan = build_state_storage_patch_plan(old_state_skeleton, new_state_skeleton);
    if let Some(plan) = patch_plan {
        for patch in &plan.patches {
            log::debug!("Patch: {patch:?}");
        }

        Ok(Some(apply_state_storage_patch_plan(old, &plan)))
    } else {
        Ok(None)
    }
}