pipecircuit 0.0.23

Correct. Robust. Fast. Portable. Pick four.
Documentation
use core::borrow::Borrow;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(super) enum ProjectionChange<Value> {
    Unchanged,
    Upsert { incarnation: u64, value: Value },
    Remove { incarnation: u64 },
}

pub(super) fn projection_change<Value: Eq, Current: Borrow<Value>>(
    before: Option<(u64, &Value)>,
    after: Option<(u64, Current)>,
) -> ProjectionChange<Current> {
    match (before, after) {
        (None, None) => ProjectionChange::Unchanged,
        (Some((old_incarnation, old)), Some((incarnation, value)))
            if old_incarnation == incarnation && old == value.borrow() =>
        {
            ProjectionChange::Unchanged
        }
        (Some((..)) | None, Some((incarnation, value))) => {
            ProjectionChange::Upsert { incarnation, value }
        }
        (Some((incarnation, _)), None) => ProjectionChange::Remove { incarnation },
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn every_small_change_reconstructs_the_exact_target_state() {
        let states = [None, Some((1, 2_u8)), Some((1, 3)), Some((2, 2))];
        for before in states {
            for after in states {
                let change = projection_change(
                    before
                        .as_ref()
                        .map(|(incarnation, value)| (*incarnation, value)),
                    after,
                );
                let reconstructed = match change {
                    ProjectionChange::Unchanged => {
                        assert_eq!(before, after);
                        before
                    }
                    ProjectionChange::Upsert { incarnation, value } => {
                        assert_ne!(before, after);
                        Some((incarnation, value))
                    }
                    ProjectionChange::Remove { incarnation } => {
                        assert_eq!(
                            before.map(|(incarnation, _)| incarnation),
                            Some(incarnation)
                        );
                        None
                    }
                };
                assert_eq!(reconstructed, after);
            }
        }
    }

    #[test]
    fn upsert_preserves_owned_payloads_and_borrowed_identity() -> Result<(), &'static str> {
        #[derive(Debug, Eq, PartialEq)]
        struct Payload(u8);
        let before = Payload(7);
        let after = Payload(11);
        let ProjectionChange::Upsert { incarnation, value } =
            projection_change(Some((13, &before)), Some((17, &after)))
        else {
            return Err("changed borrowed payload was not carried");
        };
        assert_eq!(incarnation, 17);
        assert!(core::ptr::eq(value, &after));
        assert_eq!(
            projection_change(Some((13, &before)), Some((17, after))),
            ProjectionChange::Upsert {
                incarnation: 17,
                value: Payload(11)
            }
        );
        Ok(())
    }
}