#serde-json #pattern-matching #dsl #macro #json

xopsy

Structural pattern matching DSL for JSON. Perform declarative diagnostics and surgical in-place updates on dynamic data.

3 releases

new 0.1.2 Feb 25, 2026
0.1.1 Feb 23, 2026
0.1.0 Feb 12, 2026

#583 in Rust patterns

MIT/Apache

28KB
290 lines

Xopsy πŸ©ΊπŸ“„

The Diagnostic Prism for JSON in Rust.

Forged as a byproduct of the Cognitive OS architecture.

xopsy is a structural pattern matching DSL designed to perform instant diagnostics on serde_json::Value.

Standard Rust pattern matching struggles with the dynamic, nested nature of JSON. xopsy solves this by allowing you to describe the shape you expect and extract data in a single, declarative breath.

"Don't parse. Recognize."

⚑ Signal vs. Noise

Before Xopsy (Standard Serde Pain):

// The "Option Hell" - Buried in noise
if let Some(obj) = data.as_object() {
    if let Some(users) = obj.get("users") {
        if let Some(user_arr) = users.as_array() {
            for user in user_arr {
                if user.get("active") == Some(&json!(true)) {
                    // Even extracting a string is painful...
                    if let Some(name) = user.get("name").and_then(|v| v.as_str()) {
                         println!("Found active user: {}", name);
                    }
                }
            }
        }
    }
}

After Xopsy:

// The Clear Vision
use xopsy::scope;

scope!(data, {
    "users": [
        { "active": true, "name": ?name }, // Check & Capture
        ..
    ]
} => println!("Found active user: {}", name));

πŸ“¦ Installation

Add this to your Cargo.toml:

[dependencies]
xopsy = "0.1.2"
## License

This project is licensed under either of

* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0))
* MIT license ([LICENSE-MIT](LICENSE-MIT) or [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT))

at your option.
serde_json = "1.0"

⚠️ Note on Recursion Limit

xopsy relies on recursive macro expansion. For extremely deep JSON structures or very long arrays (e.g., hundreds of elements), you might hit the compiler's default recursion limit.

If you encounter a recursion limit reached error, simply add this attribute to your crate root (main.rs or lib.rs):

#![recursion_limit = "256"] // Increase as needed

πŸš€ Core Features

xopsy provides two powerful macros:

  1. scope!: Immutable Read. Safely extracts values from complex structures using tuple-binding.
  2. focus!: Mutable Injection. Drills into the JSON and injects code for modification (Best used with Opejson).

1. The Diagnostics: scope!

Use this when you want to read data without modifying it. It returns the result of the block.

Feature: Drill Syntax & Recursive Capture

use xopsy::scope;
use serde_json::json;

fn main() {
    let data = json!({
        "network": {
            "ipv4": "192.168.1.1",
            "config": {
                "retry": 3,
                "mode": "auto"
            }
        }
    });

    let (ip, retries) = scope!(data, {
        // 1. Drill Syntax: Skip nesting with dot notation ("a"."b")
        "network"."ipv4": ?addr,
        
        // 2. Recursive Capture: Capture the object AND drill inside it
        "network"."config": ?{
            "retry": ?r,
            "mode": "auto" // Validation
        }
    } => {
        (addr.as_str().unwrap(), r.as_i64().unwrap())
    },
    // Fallback pattern
    _ => panic!("Structure mismatch"));

    assert_eq!(ip, "192.168.1.1");
    assert_eq!(retries, 3);
}

2. The Surgery: focus!

Use this when you want to modify deep structures. focus! uses a CPS (Continuation-Passing Style) architecture to safely pass a &mut Value into your code block, bypassing Rust's strict borrowing rules.

use xopsy::focus;
use serde_json::json;

fn main() {
    let mut data = json!({
        "users": [
            { "id": 101, "config": {} },
            { "id": 102, "config": {} }
        ]
    });

    // GOAL: Find user 101 and mutate its config in place.

    focus!(data, {
        "users": [
            { "id": 101, "config": ?conf },
            ..
        ]
    } => {
        // 'conf' is a &mut Value pointing directly to the config object.
        // You can mutate it freely here.
        conf["enabled"] = json!(true);
    });
}

Pro Tip: If you need to nest focus! calls, remember to dereference the variable (e.g., focus!(*parent_ref, ...)).


πŸ“– Syntax Guide

The Xopsy DSL is designed to be intuitive and minimal.

Syntax Description Example
?var Capture. Binds the value to the variable var. "id": ?my_id
?{ ... } Recursive Capture. Validates structure AND captures inner fields. "user": ?{ "name": ?n }
"key": val Check. Validates that the key exists and equals val. "status": 200
"a"."b" Drill. Syntactic sugar for nested objects. "system"."cpu": ?usage
[p1, p2] Exact Array. Matches an array of exactly 2 elements. [10, 20]
[p1, ..] Head Match. Matches start, ignores the rest. ["header", ..]
_ Wildcard. Matches anything (existence check). "meta": _
null Null Check. Explicitly matches JSON null. "error": null

🧠 Design Philosophy

1. Abstraction Without Runtime Weight

Xopsy expands into raw reference checks. Nothing runs at runtime except what you would have written yourself.

2. The "Inversion" Architecture

To handle Rust's strict borrowing rules (especially &mut), focus! does not "return" values. Instead, it injects your code into the borrow scope (CPS). This guarantees that the mutable references are valid, distinct, and safe to use, solving the common "fighting the borrow checker" problem when mutating JSON.


🀝 Relationship with Opejson

The Ultimate Combo: Use Xopsy to find the context, and Opejson to perform the surgery.

Xopsy finds the context.
Opejson shapes the structure.

use xopsy::focus;
use opejson::genesis::suture;
use serde_json::json;

// Before
let mut data = json!({
    "system": {
        "services": {
            "auth": {
                "config": {}
            }
        }
    }
});

// 1. Locate (Xopsy)
focus!(data, {
    "system"."services"."auth"."config": ?conf
} => {
    // 2. Operate (Opejson - Genesis Mode)
    // Grow a deeply nested feature flag
    suture!(conf,
        . "features" . "beta" . "v2" . "enabled" = true
    );
});

// After
assert_eq!(data, json!({
    "system": {
        "services": {
            "auth": {
                "config": {
                    "features": {
                        "beta": {
                            "v2": {
                                "enabled": true
                            }
                        }
                    }
                }
            }
        }
    }
}));

License

This project is licensed under either of

at your option.

Dependencies

~300–800KB
~16K SLoC