jmbl 0.6.0

A high performance CRDT
Documentation
use jmbl::{ops::OpWithTarget, Input, ReadableJMBL, OpOutput, JMBL};
use litl::Val;
use pretty_assertions::assert_eq;
use proptest::prelude::*;

fn arb_input() -> impl Strategy<Value = Input> {
    let leaf = prop_oneof![
        Just(Input::Plain(Val::null())),
        any::<bool>().prop_map(|bool| Input::Plain(Val::bool(bool))),
        (-100.0f64..100.0).prop_map(|num| Input::Plain(Val::number(num))),
        "[a-zA-Z0-9]{0,20}".prop_map(|string| Input::Plain(Val::str(&string))),
        "[a-zA-Z0-9]{0,20}".prop_map(Input::CollabText),
    ];
    leaf.prop_recursive(
        8,  // 8 levels deep
        10, // Shoot for maximum size of 256 nodes
        5,  // We put up to 5 items per collection
        |inner| {
            prop_oneof![
                // Take the inner strategy and make the two recursive cases.
                prop::collection::vec(inner.clone(), 0..5).prop_map(Input::CollabList),
                prop::collection::hash_map("[a-zA-Z0-9]{0,20}", inner, 0..5)
                    .prop_map(|map| { Input::collab_map(map) }),
            ]
        },
    )
}

fn arb_map_or_list() -> impl Strategy<Value = Input> {
    prop_oneof![
        prop::collection::vec(arb_input(), 0..5).prop_map(Input::CollabList),
        prop::collection::hash_map("[a-zA-Z0-9]{0,20}", arb_input(), 0..5)
            .prop_map(|map| { Input::collab_map(map) }),
    ]
}

fn jmbl_and_its_suffled_ops() -> impl Strategy<Value = (ReadableJMBL, Vec<OpWithTarget>)> {
    arb_map_or_list().prop_flat_map(|input| {
        let mut jmbl = JMBL::new_from_root(|view| view.create_input_recursively(input), OpOutput::new_dummy());

        let ops = jmbl.test_get_past_sent_ops().unwrap();

        (Just(jmbl.readable), Just(ops).prop_shuffle())
    })
}

proptest! {
    #[test]
    fn jmbls_created_from_input_equal_input(input in arb_map_or_list()) {
        let jmbl = JMBL::new_from_root(|view| view.create_input_recursively(input.clone()), OpOutput::new_dummy());
        assert_eq!(jmbl.get_root().val_to_litl(), input.val_to_litl());
    }

    #[test]
    fn can_reshuffle_ops_and_get_same_arbitrary_jmbl((jmbl1, ops) in jmbl_and_its_suffled_ops()) {
        let jmbl2 = ReadableJMBL::new().with_ops_applied(&ops);
        assert_eq!(jmbl2.get_root().val_to_litl(), jmbl1.get_root().val_to_litl());
    }
}