sim-expr-tree-calc 0.1.0

Bounded incremental calculation of ordinary SIM expressions and values.
Documentation
use std::{
    fmt,
    sync::{Arc, RwLock},
};

use super::*;

pub(super) fn expr_identity(expr: &Expr) -> u64 {
    let mut identity = StableIdentity::new();
    identity.write_debug(&expr.canonical_key());
    identity.finish()
}

pub(super) fn state_identities(
    state: &Arc<RwLock<CalcState>>,
    context_factory: &Arc<ContextFactory>,
) -> Result<(u64, u64), DerivedSnapshotError> {
    let (
        cells,
        bound_names,
        bound_values,
        codec_registry_revision,
        tree_calc_policy,
        dir_calc_policies,
        cell_calc_policies,
        tree_codec_policy,
        dir_codec_policies,
        cell_codec_policies,
        authority_ceiling,
        tree_authority_policy,
        dir_authority_policies,
        cell_authority_policies,
        mounts,
    ) = {
        let state = state.read().expect("calc state poisoned");
        (
            state.cells.clone(),
            state.bound_names.clone(),
            state.bound_values.clone(),
            state.codec_registry_revision,
            state.tree_calc_policy.clone(),
            state.dir_calc_policies.clone(),
            state.cell_calc_policies.clone(),
            state.tree_codec_policy.clone(),
            state.dir_codec_policies.clone(),
            state.cell_codec_policies.clone(),
            state.authority_ceiling.clone(),
            state.tree_authority_policy.clone(),
            state.dir_authority_policies.clone(),
            state.cell_authority_policies.clone(),
            state.mounts.clone(),
        )
    };
    let mut source = StableIdentity::new();
    source.write_debug(&cells);
    source.write_debug(&bound_names);
    let mut cx = context_factory();
    for (name, value) in &bound_values {
        source.write(name.to_string().as_bytes());
        let expr = value.object().as_expr(&mut cx).map_err(backend_error)?;
        source.write_debug(&expr.canonical_key());
    }
    let mut control = StableIdentity::new();
    control.write_debug(&codec_registry_revision);
    control.write_debug(&tree_calc_policy);
    control.write_debug(&dir_calc_policies);
    control.write_debug(&cell_calc_policies);
    control.write_debug(&tree_codec_policy);
    control.write_debug(&dir_codec_policies);
    control.write_debug(&cell_codec_policies);
    control.write_debug(&authority_ceiling);
    control.write_debug(&tree_authority_policy);
    control.write_debug(&dir_authority_policies);
    control.write_debug(&cell_authority_policies);
    control.write_debug(&mounts);
    Ok((source.finish(), control.finish()))
}

pub(super) struct StableIdentity(u64);

impl StableIdentity {
    const OFFSET: u64 = 0xcbf2_9ce4_8422_2325;
    const PRIME: u64 = 0x0000_0100_0000_01b3;

    pub(super) fn new() -> Self {
        Self(Self::OFFSET)
    }

    pub(super) fn write(&mut self, bytes: &[u8]) {
        for byte in bytes {
            self.0 ^= u64::from(*byte);
            self.0 = self.0.wrapping_mul(Self::PRIME);
        }
        self.0 ^= 0xff;
        self.0 = self.0.wrapping_mul(Self::PRIME);
    }

    pub(super) fn write_debug(&mut self, value: &impl fmt::Debug) {
        self.write(format!("{value:?}").as_bytes());
    }

    pub(super) fn finish(self) -> u64 {
        self.0
    }
}