simple-update-in 0.2.0

Immutable nested update with structural sharing
Documentation
//! Async parity. The async entry point runs the same engine and returns the
//! same results as the sync one. These mirror the Promise-based source tests.
//!
//! The async cases in the source use Promise updaters and predicates. The engine
//! does no IO, so they collapse to the sync path here. A tiny blocking executor
//! drives the future, since it never pends.

mod common;

use std::future::Future;
use std::task::{Context, Poll, Waker};

use common::*;
use simple_update_in::{update_in_async, Accessor, Value};

/// Drive a future to completion. The future never pends, so polling once is
/// enough. The no-op waker is never invoked.
fn block_on<F: Future>(fut: F) -> F::Output {
    let waker = Waker::noop();
    let mut cx = Context::from_waker(waker);
    let mut fut = Box::pin(fut);
    loop {
        if let Poll::Ready(out) = fut.as_mut().poll(&mut cx) {
            return out;
        }
    }
}

#[test]
fn async_update_map() {
    let from = obj(vec![("abc", n(123.0)), ("def", n(456.0))]);
    let actual = block_on(update_in_async(
        from.clone(),
        &[key("xyz")],
        Some(&constant(n(789.0))),
    ));
    assert!(!from.ptr_eq(&actual));
    assert_eq!(
        actual,
        obj(vec![
            ("abc", n(123.0)),
            ("def", n(456.0)),
            ("xyz", n(789.0))
        ]),
    );
}

#[test]
fn async_remove_in_map() {
    let from = obj(vec![("abc", n(123.0)), ("def", n(456.0))]);
    let actual = block_on(update_in_async(from.clone(), &[key("def")], None));
    assert!(!from.ptr_eq(&actual));
    assert_eq!(actual, obj(vec![("abc", n(123.0))]));
}

#[test]
fn async_multiple_predicates() {
    let from = obj(vec![
        ("one", arr(vec![n(1.1), n(1.2), n(1.3)])),
        ("two", arr(vec![n(2.1), n(2.2), n(2.3)])),
    ]);
    let always = Accessor::predicate(|_, _| true);
    let pick = Accessor::predicate(|v, _| match v {
        Value::Number(x) => *x == 1.2 || *x == 2.2,
        _ => false,
    });
    let actual = block_on(update_in_async(
        from,
        &[always, pick],
        Some(&multiply(10.0)),
    ));
    assert_eq!(
        actual,
        obj(vec![
            ("one", arr(vec![n(1.1), n(12.0), n(1.3)])),
            ("two", arr(vec![n(2.1), n(22.0), n(2.3)])),
        ]),
    );
}

#[test]
fn async_non_existing_key_then_predicate_is_no_op() {
    let from = obj(vec![]);
    let always = Accessor::predicate(|_, _| true);
    let actual = block_on(update_in_async(
        from.clone(),
        &[key("abc"), always],
        Some(&constant(n(1.0))),
    ));
    assert!(from.ptr_eq(&actual));
}

#[test]
fn async_reserved_key_is_no_op() {
    let from = obj(vec![]);
    let actual = block_on(update_in_async(
        from.clone(),
        &[key("__proto__")],
        Some(&constant(n(0.0))),
    ));
    assert!(from.ptr_eq(&actual));
}