haematite-cli 0.21.1

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
use std::collections::BTreeMap;

use serde_json::Value;
use serde_json::value::RawValue;

use crate::serve::storage::Failure;

fn json_error(error: &serde_json::Error) -> Failure {
    Failure::new(
        "query_parameters_invalid",
        format!("query parameters are not JSON: {error}"),
    )
}

fn write(value: &Value, bytes: &mut Vec<u8>) -> Result<(), Failure> {
    match value {
        Value::Object(object) => {
            bytes.push(b'{');
            // Key order must be stable even when maps preserve insertion order.
            let ordered: BTreeMap<_, _> = object.iter().collect();
            for (index, (key, value)) in ordered.into_iter().enumerate() {
                if index != 0 {
                    bytes.push(b',');
                }
                serde_json::to_writer(&mut *bytes, key).map_err(|error| json_error(&error))?;
                bytes.push(b':');
                write(value, bytes)?;
            }
            bytes.push(b'}');
        }
        Value::Array(array) => {
            bytes.push(b'[');
            for (index, value) in array.iter().enumerate() {
                if index != 0 {
                    bytes.push(b',');
                }
                write(value, bytes)?;
            }
            bytes.push(b']');
        }
        scalar => serde_json::to_writer(bytes, scalar).map_err(|error| json_error(&error))?,
    }
    Ok(())
}

pub fn parameters(parameters: &BTreeMap<String, Box<RawValue>>) -> Result<Vec<u8>, Failure> {
    let mut bytes = vec![b'{'];
    for (index, (name, raw)) in parameters.iter().enumerate() {
        if index != 0 {
            bytes.push(b',');
        }
        serde_json::to_writer(&mut bytes, name).map_err(|error| json_error(&error))?;
        bytes.push(b':');
        let value: Value = serde_json::from_str(raw.get()).map_err(|error| json_error(&error))?;
        write(&value, &mut bytes)?;
    }
    bytes.push(b'}');
    Ok(bytes)
}