Skip to main content

runtimo_core/
schema.rs

1//! JSON Schema validation for capability arguments.
2//!
3//! Provides basic type-checking validation against a JSON Schema object.
4//! Currently supports simple `"type"` field matching. For full JSON Schema
5//! validation, integrate the `jsonschema` crate.
6//!
7//! # Example
8//!
9//! ```rust
10//! use runtimo_core::SchemaValidator;
11//! use serde_json::json;
12//!
13//! let validator = SchemaValidator::new();
14//! let schema = json!({"type": "object"});
15//! let args = json!({"path": "/tmp/test.txt"});
16//!
17//! assert!(validator.validate(&args, &schema).is_ok());
18//! ```
19
20use crate::Result;
21use serde_json::Value;
22
23/// Validates JSON values against a simplified JSON Schema.
24///
25/// Currently performs basic type checking. Future versions may use the
26/// `jsonschema` crate for full draft-07 validation.
27pub struct SchemaValidator {
28    // Could use jsonschema crate for full JSON Schema validation
29}
30
31impl SchemaValidator {
32    /// Creates a new (stateless) schema validator.
33    pub fn new() -> Self {
34        Self {}
35    }
36
37    /// Validates arguments against a JSON Schema.
38    ///
39    /// # Arguments
40    ///
41    /// * `args` — The JSON value to validate
42    /// * `schema` — A JSON Schema object (currently only `"type"` is checked)
43    ///
44    /// # Returns
45    ///
46    /// `Ok(())` if the value matches the schema.
47    ///
48    /// # Errors
49    ///
50    /// Returns [`Error::SchemaValidationFailed`](crate::Error::SchemaValidationFailed)
51    /// if the value's type does not match the schema's `"type"` field.
52    pub fn validate(&self, args: &Value, schema: &Value) -> Result<()> {
53        if let Some(expected_type) = schema.get("type").and_then(|t| t.as_str()) {
54            let actual_type = if args.is_string() {
55                "string"
56            } else if args.is_number() {
57                "number"
58            } else if args.is_boolean() {
59                "boolean"
60            } else if args.is_array() {
61                "array"
62            } else if args.is_object() {
63                "object"
64            } else {
65                "null"
66            };
67
68            if expected_type != actual_type {
69                return Err(crate::Error::SchemaValidationFailed(format!(
70                    "Expected type '{}', got '{}'",
71                    expected_type, actual_type
72                )));
73            }
74        }
75
76        if let Some(required) = schema.get("required").and_then(|r| r.as_array()) {
77            if let Some(obj) = args.as_object() {
78                for key in required {
79                    if let Some(key_str) = key.as_str() {
80                        if !obj.contains_key(key_str) {
81                            return Err(crate::Error::SchemaValidationFailed(format!(
82                                "Missing required field: '{}'",
83                                key_str
84                            )));
85                        }
86                    }
87                }
88            }
89        }
90
91        Ok(())
92    }
93}
94
95impl Default for SchemaValidator {
96    fn default() -> Self {
97        Self::new()
98    }
99}