jmbl 0.6.0

A high performance CRDT
Documentation
use jmbl::{ Value, OpOutput, JMBL};
use litl::Val;

#[test]
fn create_simple_root_object() {
    let jmbl = JMBL::new_from_root(
        |view| view.create_map([
            ("a", Value::Plain(Val::number(1.0))),
            ("b", "hello".into()),
        ]),
        OpOutput::new_dummy(),
    );

    let root = jmbl.get_root();

    let map = root.if_map().unwrap();
    assert_eq!(map.get("a"), Value::plain(Val::number(1.0)));
    assert_eq!(map.get("b"), Value::plain(Val::str("hello")));
    assert_eq!(map.get("c"), Value::plain(Val::null()));
}

#[test]
fn change_root_obect() {
    let mut jmbl = JMBL::new_from_root(
        |view| view.create_map([
            ("a", Value::Plain(Val::number(1.0))),
            ("b", "hello".into()),
        ]),
        OpOutput::new_dummy(),
    );

    let jmbl1 = jmbl.readable.clone();

    jmbl.change(|root, _| root.if_map_mut().unwrap().insert("c", Value::plain(Val::bool(true))));

    let jmbl2 = jmbl.readable.clone();

    assert_eq!(
        jmbl2.get_root().if_map().unwrap().get("c"),
        Value::plain(Val::bool(true))
    );

    assert_eq!(
        jmbl1.get_root().if_map().unwrap().get("c"),
        Value::plain(Val::null())
    );
}

#[test]
fn get_and_apply_op_diffs_results_in_same_jmbl() {
    let mut jmbl = JMBL::new_from_root(
        |view| view.create_map([
            ("a", Value::Plain(Val::number(1.0))),
            ("b", "hello".into()),
        ]),
        OpOutput::new_dummy(),
    );

    let jmbl1 = jmbl.readable.clone();

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

    jmbl.change(|root, _| root.if_map_mut().unwrap().insert("c", Value::Plain(Val::bool(true))));

    let jmbl2 = jmbl.readable.clone();

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

    let op_diff_since = jmbl2.ops_since(&jmbl1).collect::<Vec<_>>();

    assert_eq!(diff_from_edit, op_diff_since);

    let jmbl2b = jmbl1.with_ops_applied(&op_diff_since);

    assert_eq!(jmbl2.get_root().val_to_litl(), jmbl2b.get_root().val_to_litl());
}

#[test]
fn create_and_modify_nested_objects() {
    let mut jmbl = JMBL::new_from_root(
        |view| view.create_map([
            ("a", Value::Plain(Val::number(1.0))),
            ("b", "hello".into()),
        ]),
        OpOutput::new_dummy(),
    );

    jmbl.change(|root, view| {
        let nested = view.create_map([("inner", Value::Plain(Val::bool(true)))]);
        root.if_map_mut().unwrap().insert(
            "nested",
            nested
        )
    });

    let jmbl2 = jmbl.readable.clone();

    assert_eq!(
        jmbl2
            .get_root()
            .if_map()
            .unwrap()
            .get("nested")
            .if_map()
            .unwrap()
            .get("inner"),
        Value::plain(Val::bool(true))
    );

    jmbl.change(|root, _| {
        root.if_map_mut()
            .unwrap()
            .get("nested")
            .if_map_mut()
            .unwrap()
            .insert("x", "y")
    });

    let jmbl3 = jmbl.readable.clone();

    assert_eq!(
        jmbl3
            .get_root()
            .if_map()
            .unwrap()
            .get("nested")
            .if_map()
            .unwrap()
            .get("x"),
        Value::plain(Val::str("y"))
    );
}