Skip to main content
Verticopolis engineGitHub

verticopolis_engine/
identity.rs

1//! The engine's identity record: which engine this is and which contracts
2//! it speaks (crate version, save version, frame, view and catalog layout
3//! versions, and the conformance lock's digest), so a frontend, a bug report
4//! and a benchmark all name the same engine.
5//!
6//! The record holds only what the engine knows about itself. Which build of
7//! the sources a binary came from is the packaging's fact; the crate's
8//! README describes the build metadata a host supplies for it.
9//!
10//! ```
11//! let id = verticopolis_engine::identity::identity();
12//! assert_eq!(id["crate"]["name"], "verticopolis-engine");
13//! println!("{}", verticopolis_engine::identity::identity_json());
14//! ```
15
16use serde_json::{json, Value};
17
18use crate::canonical::canonical_json;
19use crate::catalog::{catalog_digest, CATALOG_VERSION};
20use crate::clock::GameMode;
21use crate::frame::FRAME_LAYOUT_VERSION;
22use crate::load::OLDEST_SAVE_VERSION;
23use crate::sim::SAVE_VERSION;
24
25/// The record's own shape. It moves when a field is added, renamed or removed.
26pub const IDENTITY_SCHEMA: u32 = 1;
27
28/// The crate's name, as `Cargo.toml` spells it.
29pub const CRATE_NAME: &str = "verticopolis-engine";
30
31/// What `lockDigest` and `crate.version` read when the record is unreadable.
32/// A test keeps the compiled-in record readable, so a host sees this only if
33/// that test was skipped.
34const UNREADABLE: &str = "unreadable";
35
36const COMPAT_RECORD: &str = include_str!("compat-record.json");
37
38fn compat_field(name: &str) -> String {
39    serde_json::from_str::<Value>(COMPAT_RECORD)
40        .ok()
41        .and_then(|v| v.get(name).and_then(Value::as_str).map(str::to_owned))
42        .unwrap_or_else(|| UNREADABLE.to_owned())
43}
44
45/// The crate version, from `compat-record.json`.
46pub fn crate_version() -> String {
47    compat_field("crateVersion")
48}
49
50/// The identity record as a value.
51pub fn identity() -> Value {
52    json!({
53        "schema": IDENTITY_SCHEMA,
54        "crate": { "name": CRATE_NAME, "version": crate_version() },
55        "saveVersion": SAVE_VERSION,
56        "oldestSaveVersion": OLDEST_SAVE_VERSION,
57        "frameLayoutVersion": FRAME_LAYOUT_VERSION,
58        "catalogVersion": CATALOG_VERSION,
59        "catalogDigests": {
60            "classic": catalog_digest(GameMode::Classic),
61            "modern": catalog_digest(GameMode::Modern),
62        },
63        "lockDigest": compat_field("lockDigest"),
64    })
65}
66
67/// The record as canonical JSON, the text the JavaScript package returns.
68pub fn identity_json() -> String {
69    canonical_json(&identity())
70}
71
72#[cfg(test)]
73#[path = "identity_tests.rs"]
74mod tests;