liminal-rs 0.16.2

A conversation-based messaging bus built on beamr
Documentation
//! JSON with every object's keys in sorted order at every depth.
//!
//! `serde_json::Map` is a `BTreeMap` unless some crate in the build turns on
//! the `preserve_order` feature of `serde_json`, and Cargo unifies that feature across
//! every crate linked into one binary (`agent-client-protocol-schema` turns it
//! on). Canonical bytes therefore never lean on the map type: they are written
//! from a value rebuilt in key order, which both map types keep.

use serde_json::{Map, Value};

/// Rebuilds `value` with every object's members inserted in sorted key order.
#[must_use]
pub fn sorted(value: Value) -> Value {
    match value {
        Value::Object(object) => {
            let mut members: Vec<(String, Value)> = object.into_iter().collect();
            members.sort_by(|(left, _), (right, _)| left.cmp(right));
            let mut ordered = Map::with_capacity(members.len());
            for (name, member) in members {
                ordered.insert(name, sorted(member));
            }
            Value::Object(ordered)
        }
        Value::Array(items) => Value::Array(items.into_iter().map(sorted).collect()),
        scalar => scalar,
    }
}

/// The canonical bytes of `value`: sorted keys at every depth, no whitespace.
///
/// # Errors
/// Returns the `serde_json` error when the value cannot be written.
pub fn to_vec(value: Value) -> Result<Vec<u8>, serde_json::Error> {
    serde_json::to_vec(&sorted(value))
}

#[cfg(test)]
#[path = "canonical_tests.rs"]
mod tests;