# 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):**
```rust,ignore
// 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:**
```rust,ignore
// 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`:
```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`):
```rust,ignore
#![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](https://github.com/rhetro/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**
```rust,ignore
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.
```rust
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.
| **`?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](https://github.com/rhetro/opejson)** to perform the surgery.
Xopsy finds the context.
**[Opejson](https://crates.io/crates/opejson)** shapes the structure.
```rust,ignore
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
* 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.