cranpose-core 0.9.11

Composition runtime and reactive state for Cranpose
Documentation
use std::panic::{AssertUnwindSafe, catch_unwind};

use cranpose_core::{
    Composition, MemoryApplier,
    composer_context::{current_composer, with_composer},
    location_key, mutableStateOf, run_in_mutable_snapshot,
    snapshot_v2::take_mutable_snapshot,
};

#[test]
fn nested_compositions_restore_the_outer_composer_after_return_and_unwind() {
    for panic_in_inner in [false, true] {
        let mut outer = Composition::new(MemoryApplier::new());
        let outer_runtime = outer.runtime_handle().id();
        outer
            .render(location_key(file!(), line!(), column!()), || {
                with_composer(|composer| {
                    assert_eq!(composer.runtime_handle().id(), outer_runtime);
                    let mut inner = Composition::new(MemoryApplier::new());
                    let inner_runtime = inner.runtime_handle().id();
                    assert_ne!(outer_runtime, inner_runtime);
                    let result = catch_unwind(AssertUnwindSafe(|| {
                        inner
                            .render(location_key(file!(), line!(), column!()), || {
                                with_composer(|composer| {
                                    assert_eq!(composer.runtime_handle().id(), inner_runtime);
                                });
                                assert!(!panic_in_inner, "unwind the nested composition");
                            })
                            .expect("nested render succeeds");
                    }));
                    assert_eq!(result.is_err(), panic_in_inner);
                    with_composer(|composer| {
                        assert_eq!(composer.runtime_handle().id(), outer_runtime);
                    });
                });
            })
            .expect("outer render succeeds");
        assert!(current_composer().is_none());
    }
}

#[test]
fn unwinding_a_snapshot_restores_the_surrounding_transaction() {
    let _composition = Composition::new(MemoryApplier::new());
    let state = mutableStateOf(1);
    run_in_mutable_snapshot(|| {
        state.set(2);
        let child = take_mutable_snapshot(None, None);
        let result = catch_unwind(AssertUnwindSafe(|| {
            child.enter(|| {
                state.set(3);
                assert_eq!(state.get(), 3);
                panic!("discard the nested transaction");
            });
        }));
        assert!(result.is_err());
        assert_eq!(state.get(), 2);
        child.dispose();
        state.set(4);
    })
    .expect("outer transaction applies");
    assert_eq!(state.get(), 4);
}