use std::fs;
use std::path::PathBuf;
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct BrainConfig {
#[serde(default)]
pub depart_id_v1: Option<crate::config::sys::SystemMeta>,
#[serde(default)]
pub simulation: SimulationConfigRef,
#[serde(rename = "zone", default)]
pub zones: Vec<ZoneEntry>,
#[serde(rename = "connection", default)]
pub connections: Vec<ConnectionEntry>,
}
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Default, Clone)]
pub struct SimulationConfigRef {
pub config: PathBuf,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ZoneEntry {
#[serde(default)]
pub shard_id_v1: Option<crate::config::sys::SystemMeta>,
pub name: String,
pub blueprints: PathBuf,
pub anatomy: PathBuf,
pub io: PathBuf,
pub baked_dir: PathBuf,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ConnectionEntry {
#[serde(default)]
pub conn_id_v1: Option<crate::config::sys::SystemMeta>,
pub from: String,
pub to: String,
pub output_matrix: Option<String>,
pub entry_z: Option<String>,
pub target_type: Option<String>,
pub growth_steps: Option<u32>,
#[serde(default)]
pub axon_ids: Vec<u32>,
pub width: Option<u16>,
pub height: Option<u16>,
}
pub fn parse_brain_config(path: &std::path::Path) -> Result<BrainConfig, String> {
let content = fs::read_to_string(path)
.map_err(|e| format!("Failed to read brain config file at {:?}: {}", path, e))?;
parse_brain_config_from_str(&content)
}
pub fn parse_brain_config_from_str(content: &str) -> Result<BrainConfig, String> {
let config: BrainConfig = toml::from_str(content)
.map_err(|e| format!("Failed to parse brain config from string: {}", e))?;
let mut seen = std::collections::HashSet::new();
for zone in &config.zones {
if !seen.insert(&zone.name) {
return Err(format!("CRITICAL INVARIANT BROKEN: Duplicate zone name found: '{}'", zone.name));
}
}
Ok(config)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_brain_config() {
let toml_str = r#"
[simulation]
config = "config/simulation.toml"
[[zone]]
name = "V1"
blueprints = "config/zones/V1/blueprints.toml"
anatomy = "config/zones/V1/anatomy.toml"
io = "config/zones/V1/io.toml"
baked_dir = "baked/V1/"
[[zone]]
name = "V2"
blueprints = "config/zones/V2/blueprints.toml"
anatomy = "config/zones/V2/anatomy.toml"
io = "config/zones/V2/io.toml"
baked_dir = "baked/V2/"
[[connection]]
from = "V1"
to = "V2"
axon_ids = [100, 101, 102]
"#;
let config: BrainConfig = toml::from_str(toml_str).unwrap();
assert_eq!(
config.simulation.config.to_str().unwrap(),
"config/simulation.toml"
);
assert_eq!(config.zones.len(), 2);
assert_eq!(config.zones[0].name, "V1");
assert_eq!(
config.zones[0].blueprints.to_str().unwrap(),
"config/zones/V1/blueprints.toml"
);
assert_eq!(
config.zones[0].anatomy.to_str().unwrap(),
"config/zones/V1/anatomy.toml"
);
assert_eq!(
config.zones[0].io.to_str().unwrap(),
"config/zones/V1/io.toml"
);
assert_eq!(config.zones[0].baked_dir.to_str().unwrap(), "baked/V1/");
assert_eq!(config.zones[1].name, "V2");
assert_eq!(
config.zones[1].blueprints.to_str().unwrap(),
"config/zones/V2/blueprints.toml"
);
assert_eq!(
config.zones[1].anatomy.to_str().unwrap(),
"config/zones/V2/anatomy.toml"
);
assert_eq!(
config.zones[1].io.to_str().unwrap(),
"config/zones/V2/io.toml"
);
assert_eq!(config.zones[1].baked_dir.to_str().unwrap(), "baked/V2/");
assert_eq!(config.connections.len(), 1);
assert_eq!(config.connections[0].from, "V1");
assert_eq!(config.connections[0].to, "V2");
assert_eq!(config.connections[0].axon_ids, vec![100, 101, 102]);
}
}