simple-update-in 0.2.0

Immutable nested update with structural sharing
Documentation
//! Shared builders for the test suite.
//!
//! These mirror the literal inputs the conformance cases use. They keep the
//! per-test code close to the source data.

#![allow(dead_code)]

use simple_update_in::{Accessor, Map, Value};

/// A number value.
pub fn n(x: f64) -> Value {
    Value::Number(x)
}

/// A string value.
pub fn s(x: &str) -> Value {
    Value::String(x.to_string())
}

/// An array value.
pub fn arr(items: Vec<Value>) -> Value {
    Value::array(items)
}

/// A map value from pairs, in order.
pub fn obj(pairs: Vec<(&str, Value)>) -> Value {
    let mut map = Map::new();
    for (k, v) in pairs {
        map.insert(k.to_string(), v);
    }
    Value::object(map)
}

/// A sparse-array hole, read back as missing.
pub fn hole() -> Value {
    Value::Undefined
}

/// A key accessor.
pub fn key(k: &str) -> Accessor {
    Accessor::key(k)
}

/// An index accessor.
pub fn idx(i: usize) -> Accessor {
    Accessor::index(i)
}

/// An updater that returns a constant value, like `() => x`.
pub fn constant(value: Value) -> impl Fn(Value) -> Value {
    move |_| value.clone()
}

/// An updater that multiplies a number by `factor`, like `v => v * factor`.
pub fn multiply(factor: f64) -> impl Fn(Value) -> Value {
    move |v| match v {
        Value::Number(x) => Value::Number(x * factor),
        other => other,
    }
}

/// The identity updater, `v => v`.
pub fn identity(v: Value) -> Value {
    v
}

/// An updater that multiplies only when the input is truthy, like
/// `v => v && v * factor`. A falsy input returns `Undefined`, the removal
/// sentinel.
pub fn guarded_multiply(factor: f64) -> impl Fn(Value) -> Value {
    move |v| match v {
        Value::Number(x) if x != 0.0 && !x.is_nan() => Value::Number(x * factor),
        Value::Bool(true) => Value::Bool(true),
        Value::String(ref st) if !st.is_empty() => v,
        Value::Array(_) | Value::Object(_) => v,
        _ => Value::Undefined,
    }
}

/// Run `update_in` with no updater, which removes the addressed leaf.
pub fn remove(obj: Value, path: &[Accessor]) -> Value {
    simple_update_in::update_in(obj, path, None)
}

/// Run `update_in` with an updater.
pub fn run(obj: Value, path: &[Accessor], updater: impl Fn(Value) -> Value) -> Value {
    simple_update_in::update_in(obj, path, Some(&updater))
}