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,ignore
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.
27#[allow(clippy::exhaustive_structs)]
28pub struct SchemaValidator {
29 // Could use jsonschema crate for full JSON Schema validation
30}
31
32impl SchemaValidator {
33 /// Creates a new (stateless) schema validator.
34 #[must_use]
35 pub fn new() -> Self {
36 Self {}
37 }
38
39 /// Validates arguments against a JSON Schema.
40 ///
41 /// # Arguments
42 ///
43 /// * `args` — The JSON value to validate
44 /// * `schema` — A JSON Schema object (currently only `"type"` is checked)
45 ///
46 /// # Returns
47 ///
48 /// `Ok(())` if the value matches the schema.
49 ///
50 /// # Errors
51 ///
52 /// Returns [`Error::SchemaValidationFailed`](crate::Error::SchemaValidationFailed)
53 /// if the value's type does not match the schema's `"type"` field.
54 pub fn validate(&self, args: &Value, schema: &Value) -> Result<()> {
55 if let Some(expected_type) = schema.get("type").and_then(|t| t.as_str()) {
56 let actual_type = if args.is_string() {
57 "string"
58 } else if args.is_number() {
59 "number"
60 } else if args.is_boolean() {
61 "boolean"
62 } else if args.is_array() {
63 "array"
64 } else if args.is_object() {
65 "object"
66 } else {
67 "null"
68 };
69
70 if expected_type != actual_type {
71 return Err(crate::Error::SchemaValidationFailed(format!(
72 "Expected type '{}', got '{}'",
73 expected_type, actual_type
74 )));
75 }
76 }
77
78 if let Some(required) = schema.get("required").and_then(|r| r.as_array()) {
79 if let Some(obj) = args.as_object() {
80 for key in required {
81 if let Some(key_str) = key.as_str() {
82 if !obj.contains_key(key_str) {
83 return Err(crate::Error::SchemaValidationFailed(format!(
84 "Missing required field: '{}'",
85 key_str
86 )));
87 }
88 }
89 }
90 }
91 }
92
93 Ok(())
94 }
95}
96
97impl Default for SchemaValidator {
98 fn default() -> Self {
99 Self::new()
100 }
101}