rs2_stream/
schema_validation.rs

1//! Schema validation system for RS2 streams
2
3use async_trait::async_trait;
4use serde_json::Value;
5use jsonschema::{validator_for, Draft, Validator};
6use std::sync::Arc;
7
8#[derive(Debug, thiserror::Error)]
9pub enum SchemaError {
10    #[error("Validation failed: {0}")]
11    ValidationFailed(String),
12    #[error("Missing schema: {0}")]
13    MissingSchema(String),
14    #[error("Parse error: {0}")]
15    ParseError(String),
16}
17
18#[async_trait]
19pub trait SchemaValidator: Send + Sync {
20    async fn validate(&self, data: &[u8]) -> Result<(), SchemaError>;
21    fn get_schema_id(&self) -> String;
22}
23
24/// Production-ready JSON Schema validator for RS2 streams.
25pub struct JsonSchemaValidator {
26    schema_id: String,
27    schema: Value,
28    compiled: Arc<Validator>,
29}
30
31impl JsonSchemaValidator {
32    /// Create a new validator from a JSON schema value.
33    pub fn new(schema_id: &str, schema: Value) -> Self {
34        let compiled = validator_for(&schema)
35            .expect("Invalid JSON schema");
36        Self {
37            schema_id: schema_id.to_string(),
38            schema,
39            compiled: Arc::new(compiled),
40        }
41    }
42}
43
44#[async_trait]
45impl SchemaValidator for JsonSchemaValidator {
46    async fn validate(&self, data: &[u8]) -> Result<(), SchemaError> {
47        let value: Value = serde_json::from_slice(data)
48            .map_err(|e| SchemaError::ParseError(e.to_string()))?;
49        if let Err(error) = self.compiled.validate(&value) {
50            return Err(SchemaError::ValidationFailed(error.to_string()));
51        }
52        Ok(())
53    }
54    fn get_schema_id(&self) -> String {
55        self.schema_id.clone()
56    }
57}