Skip to main content

shape_runtime/simulation/
validation.rs

1//! TypedObject Validation for High-Performance Simulation
2//!
3//! This module provides validation functions to check if a Value is suitable
4//! for TypedObject optimization, enabling high-performance simulation (>10M ticks/sec).
5
6use crate::type_schema::{SchemaId, TypeSchemaRegistry};
7use shape_ast::error::{Result, ShapeError};
8use shape_value::ValueWord;
9
10/// Checks if a Value is suitable for TypedObject optimization.
11///
12/// For high-performance simulation (>10M ticks/sec), the state must be an Object
13/// that can be converted to a TypedObject. This requires:
14/// 1. The value is a TypedObject
15/// 2. A corresponding `TypeSchema` exists (from a `type` declaration)
16///
17/// Returns `Ok(schema_id)` if the value can be optimized, `Err` otherwise.
18pub fn validate_typed_state(
19    value: &ValueWord,
20    _registry: &TypeSchemaRegistry,
21) -> Result<Option<SchemaId>> {
22    if value.as_typed_object().is_some() {
23        // TypedObject can potentially match a schema
24        // We can't know the schema just from the Value - the caller
25        // must provide the type name from the declaration context
26        Ok(None) // Schema lookup requires type name
27    } else if value.is_none() {
28        // None is acceptable as initial state (will be initialized)
29        Ok(None)
30    } else {
31        Err(ShapeError::RuntimeError {
32            message: format!(
33                "Simulation state must be an Object (from type declaration) for optimal performance. \
34                     Got: {}. Use 'type MyState {{ ... }}' to declare a typed state.",
35                value.type_name()
36            ),
37            location: None,
38        })
39    }
40}
41
42/// Validates that a Value is a typed Object with a known schema.
43///
44/// This is the strict validation used by high-performance simulation kernels.
45/// It requires the state to have a registered TypeSchema for JIT optimization.
46///
47/// # Arguments
48/// * `value` - The value to validate
49/// * `type_name` - Expected type name (from declaration)
50/// * `registry` - Type schema registry
51///
52/// # Returns
53/// * `Ok(schema_id)` - The schema ID for TypedObject allocation
54/// * `Err` - If the value cannot be optimized
55pub fn require_typed_state_with_schema(
56    value: &ValueWord,
57    type_name: &str,
58    registry: &TypeSchemaRegistry,
59) -> Result<SchemaId> {
60    // First, ensure it's a TypedObject
61    if value.as_typed_object().is_none() {
62        return Err(ShapeError::RuntimeError {
63            message: format!(
64                "Simulation state must be a '{}' object. Got: {}",
65                type_name,
66                value.type_name()
67            ),
68            location: None,
69        });
70    }
71
72    // Look up the schema
73    match registry.get(type_name) {
74        Some(schema) => Ok(schema.id),
75        None => Err(ShapeError::RuntimeError {
76            message: format!(
77                "Type '{}' not found in schema registry. \
78                 Declare it with 'type {} {{ ... }}' before using in simulation.",
79                type_name, type_name
80            ),
81            location: None,
82        }),
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    #[test]
90    fn test_validate_typed_state() {
91        let registry = TypeSchemaRegistry::new();
92
93        // TypedObject should be valid
94        let obj = crate::type_schema::typed_object_from_pairs(&[]);
95        assert!(validate_typed_state(&obj, &registry).is_ok());
96
97        // None should be valid
98        assert!(validate_typed_state(&ValueWord::none(), &registry).is_ok());
99
100        // Number should be invalid
101        let num = ValueWord::from_f64(42.0);
102        assert!(validate_typed_state(&num, &registry).is_err());
103    }
104
105    #[test]
106    fn test_require_typed_state_with_schema() {
107        use crate::type_schema::TypeSchemaBuilder;
108
109        let mut registry = TypeSchemaRegistry::new();
110
111        // Register a type
112        let schema = TypeSchemaBuilder::new("TestState")
113            .f64_field("value")
114            .build();
115        registry.register(schema);
116
117        // Valid object with registered type
118        let obj = crate::type_schema::typed_object_from_pairs(&[]);
119        assert!(require_typed_state_with_schema(&obj, "TestState", &registry).is_ok());
120
121        // Invalid: unregistered type
122        assert!(require_typed_state_with_schema(&obj, "UnknownType", &registry).is_err());
123
124        // Invalid: not an object
125        let num = ValueWord::from_f64(42.0);
126        assert!(require_typed_state_with_schema(&num, "TestState", &registry).is_err());
127    }
128}