allora_runtime/spec/
version.rs

1//! Shared YAML spec version validation helper.
2//! Ensures presence of integer `version` field and equality to expected version.
3//! Centralizes error message strings to keep parser modules consistent.
4//!
5//! # Purpose
6//! Single source of truth for spec version checks so all parsers emit identical
7//! error messages and evolve coherently when new versions are introduced.
8//!
9//! # Usage
10//! ```rust,ignore
11//! use serde_yaml::Value;
12//! // Inside crate: use spec::version::validate_version
13//! let v: Value = serde_yaml::from_str("version: 1").unwrap();
14//! let ver = allora::spec::version::validate_version(&v).unwrap();
15//! assert_eq!(ver, 1);
16//! ```
17//!
18//! # Error Semantics
19//! * Missing field -> `missing 'version'`
20//! * Non-integer type -> `'version' must be integer`
21//! * Unsupported value -> `unsupported version (expected 1)`
22//!
23//! # Extension Strategy
24//! For a future v2 schema, prefer adding `validate_version_v2` or making this
25//! function accept an `expected: u32` parameter. Keep old helper available to
26//! avoid breaking existing parsers. Example:
27//! ```ignore
28//! pub(crate) fn validate_version_expected(yaml: &Value, expected: u32) -> Result<u32> { /* ... */ }
29//! ```
30//!
31//! # Design Notes
32//! * Returns `u32` (small range, explicit cast from i64): avoids accidental
33//!   negative values after validation.
34//! * Does not attempt coercion (e.g. strings); strict typing keeps configs clean.
35//! * Performs only version validation; structural validation remains in each
36//!   parser to keep responsibilities localized.
37use crate::error::{Error, Result};
38use serde_yaml::Value as YamlValue;
39
40/// Validate that `yaml` contains an integer `version` equal to 1.
41///
42/// # Errors
43/// * Missing field -> `"missing 'version'"`
44/// * Non-integer -> `"'version' must be integer"`
45/// * Unsupported value -> `"unsupported version (expected 1)"`
46pub(crate) fn validate_version(yaml: &YamlValue) -> Result<u32> {
47    let version_val = yaml
48        .get("version")
49        .ok_or_else(|| Error::serialization("missing 'version'"))?;
50    if !version_val.is_i64() && !version_val.is_u64() {
51        return Err(Error::serialization("'version' must be integer"));
52    }
53    let v = version_val
54        .as_i64()
55        .unwrap_or(version_val.as_u64().unwrap_or(0) as i64);
56    if v != 1 {
57        return Err(Error::serialization("unsupported version (expected 1)"));
58    }
59    Ok(v as u32)
60}