Add headless runtime tooling and Campaign.win analysis
This commit is contained in:
parent
57bf0666e0
commit
27172e3786
37 changed files with 11867 additions and 302 deletions
133
crates/rrt-runtime/src/import.rs
Normal file
133
crates/rrt-runtime/src/import.rs
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
use std::path::Path;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::RuntimeState;
|
||||
|
||||
pub const STATE_DUMP_FORMAT_VERSION: u32 = 1;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
pub struct RuntimeStateDumpSource {
|
||||
#[serde(default)]
|
||||
pub description: Option<String>,
|
||||
#[serde(default)]
|
||||
pub source_binary: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct RuntimeStateDumpDocument {
|
||||
pub format_version: u32,
|
||||
pub dump_id: String,
|
||||
#[serde(default)]
|
||||
pub source: RuntimeStateDumpSource,
|
||||
pub state: RuntimeState,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct RuntimeStateImport {
|
||||
pub import_id: String,
|
||||
pub description: Option<String>,
|
||||
pub state: RuntimeState,
|
||||
}
|
||||
|
||||
pub fn validate_runtime_state_dump_document(
|
||||
document: &RuntimeStateDumpDocument,
|
||||
) -> Result<(), String> {
|
||||
if document.format_version != STATE_DUMP_FORMAT_VERSION {
|
||||
return Err(format!(
|
||||
"unsupported state dump format_version {} (expected {})",
|
||||
document.format_version, STATE_DUMP_FORMAT_VERSION
|
||||
));
|
||||
}
|
||||
if document.dump_id.trim().is_empty() {
|
||||
return Err("dump_id must not be empty".to_string());
|
||||
}
|
||||
document.state.validate()
|
||||
}
|
||||
|
||||
pub fn load_runtime_state_import(
|
||||
path: &Path,
|
||||
) -> Result<RuntimeStateImport, Box<dyn std::error::Error>> {
|
||||
let text = std::fs::read_to_string(path)?;
|
||||
load_runtime_state_import_from_str(
|
||||
&text,
|
||||
path.file_stem()
|
||||
.and_then(|stem| stem.to_str())
|
||||
.unwrap_or("runtime-state"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn load_runtime_state_import_from_str(
|
||||
text: &str,
|
||||
fallback_id: &str,
|
||||
) -> Result<RuntimeStateImport, Box<dyn std::error::Error>> {
|
||||
if let Ok(document) = serde_json::from_str::<RuntimeStateDumpDocument>(text) {
|
||||
validate_runtime_state_dump_document(&document)
|
||||
.map_err(|err| format!("invalid runtime state dump document: {err}"))?;
|
||||
return Ok(RuntimeStateImport {
|
||||
import_id: document.dump_id,
|
||||
description: document.source.description,
|
||||
state: document.state,
|
||||
});
|
||||
}
|
||||
|
||||
let state: RuntimeState = serde_json::from_str(text)?;
|
||||
state
|
||||
.validate()
|
||||
.map_err(|err| format!("invalid runtime state: {err}"))?;
|
||||
Ok(RuntimeStateImport {
|
||||
import_id: fallback_id.to_string(),
|
||||
description: None,
|
||||
state,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{CalendarPoint, RuntimeServiceState};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
fn state() -> RuntimeState {
|
||||
RuntimeState {
|
||||
calendar: CalendarPoint {
|
||||
year: 1830,
|
||||
month_slot: 0,
|
||||
phase_slot: 0,
|
||||
tick_slot: 0,
|
||||
},
|
||||
world_flags: BTreeMap::new(),
|
||||
companies: Vec::new(),
|
||||
event_runtime_records: Vec::new(),
|
||||
service_state: RuntimeServiceState::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn loads_dump_document() {
|
||||
let text = serde_json::to_string(&RuntimeStateDumpDocument {
|
||||
format_version: STATE_DUMP_FORMAT_VERSION,
|
||||
dump_id: "dump-smoke".to_string(),
|
||||
source: RuntimeStateDumpSource {
|
||||
description: Some("test dump".to_string()),
|
||||
source_binary: None,
|
||||
},
|
||||
state: state(),
|
||||
})
|
||||
.expect("dump should serialize");
|
||||
|
||||
let import =
|
||||
load_runtime_state_import_from_str(&text, "fallback").expect("dump should load");
|
||||
assert_eq!(import.import_id, "dump-smoke");
|
||||
assert_eq!(import.description.as_deref(), Some("test dump"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn loads_bare_runtime_state() {
|
||||
let text = serde_json::to_string(&state()).expect("state should serialize");
|
||||
let import =
|
||||
load_runtime_state_import_from_str(&text, "fallback").expect("state should load");
|
||||
assert_eq!(import.import_id, "fallback");
|
||||
assert!(import.description.is_none());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue