⎇ be4de986bef3409a6d4108ccadbcf28436c862c1
crates/protocol/brahman-cards/src/entity_loader.rs
Historia
Quién tocó qué
crudo
refactor(loader): A3 — unificar loader, eliminar duplicación
1//! Loader de `EntityCard` (≡ `brahman_card::Card`) desde archivos JSON.
2//!
3//! Card-loading consolidado: antes vivía duplicado en `arje-brain/loader.rs`.
4//! La fuente de verdad del shape es Rust + serde; en disco se guarda JSON
5//! crudo. Toda card-loading del ecosistema vive ahora en `brahman-cards`.
6
7use brahman_card::Card as EntityCard;
8use std::path::Path;
9
10/// Carga una `EntityCard` desde un archivo JSON. Pasa por
11/// `EntityCard::validate()` antes de devolver — falla rápida.
12pub fn load_card_file(path: &Path) -> anyhow::Result<EntityCard> {
13 let raw = std::fs::read_to_string(path)?;
14 let card = extract_card_from_json(&raw)?;
15 card.validate()
16 .map_err(|e| anyhow::anyhow!("Card inválida ({}): {e}", path.display()))?;
17 Ok(card)
18}
19
20/// Extrae una `EntityCard` de JSON. Acepta:
21/// 1. Object directamente serializable como EntityCard.
22/// 2. Object dict con un único valor que sea EntityCard (compat con
23/// salidas de generadores que envuelven en `{"seed": {...}}`).
24pub fn extract_card_from_json(raw: &str) -> anyhow::Result<EntityCard> {
25 let v: serde_json::Value = serde_json::from_str(raw)?;
26 let direct_err = match serde_json::from_value::<EntityCard>(v.clone()) {
27 Ok(c) => return Ok(c),
28 Err(e) => e,
29 };
30 if let serde_json::Value::Object(map) = v {
31 for (_, vv) in map {
32 if let Ok(c) = serde_json::from_value::<EntityCard>(vv) {
33 return Ok(c);
34 }
35 }
36 }
37 // Propagamos el error del intento directo: es el caso típico (JSON
38 // top-level = EntityCard) y su mensaje apunta al campo que rompió.
39 anyhow::bail!("JSON no contiene una EntityCard válida: {direct_err}")
40}