Skip to main content

ass_editor/utils/validator/
api.rs

1//! Public validation API and cache management for `LazyValidator`.
2//!
3//! Implements the on-demand validation entry points along with cache lookup,
4//! invalidation, and content hashing used to avoid redundant work.
5
6use super::{LazyValidator, ValidationResult};
7use crate::core::{errors::EditorError, EditorDocument, Result};
8
9#[cfg(feature = "std")]
10use std::time::Instant;
11
12impl LazyValidator {
13    /// Validate document using ass-core's ScriptAnalysis
14    pub fn validate(&mut self, document: &EditorDocument) -> Result<&ValidationResult> {
15        let content = document.text();
16        let content_hash = self.calculate_hash(&content);
17
18        // Check if we can use cached result
19        if self.should_use_cache(content_hash) {
20            return self.cached_result.as_ref().ok_or_else(|| {
21                EditorError::command_failed(
22                    "Cache validation inconsistency: cached result expected but not found",
23                )
24            });
25        }
26
27        #[cfg(feature = "std")]
28        let start_time = Instant::now();
29
30        // Perform validation using ass-core
31        let issues = self.validate_with_core(&content, document)?;
32
33        // Update cache
34        #[cfg(feature = "std")]
35        let mut result = ValidationResult::new(issues);
36        #[cfg(not(feature = "std"))]
37        let result = ValidationResult::new(issues);
38
39        #[cfg(feature = "std")]
40        {
41            result.validation_time_us = start_time.elapsed().as_micros() as u64;
42        }
43
44        self.cached_result = Some(result);
45        self.content_hash = content_hash;
46
47        #[cfg(feature = "std")]
48        {
49            self.last_validation = Some(Instant::now());
50        }
51
52        self.cached_result.as_ref().ok_or_else(|| {
53            EditorError::command_failed("Validation completed but cached result is missing")
54        })
55    }
56
57    /// Force validation even if cached result exists
58    pub fn force_validate(&mut self, document: &EditorDocument) -> Result<&ValidationResult> {
59        self.cached_result = None; // Clear cache
60        self.validate(document)
61    }
62
63    /// Check if document is valid (quick check using cache if available)
64    pub fn is_valid(&mut self, document: &EditorDocument) -> Result<bool> {
65        Ok(self.validate(document)?.is_valid)
66    }
67
68    /// Get cached validation result without revalidating
69    pub fn cached_result(&self) -> Option<&ValidationResult> {
70        self.cached_result.as_ref()
71    }
72
73    /// Clear validation cache
74    pub fn clear_cache(&mut self) {
75        self.cached_result = None;
76        self.content_hash = 0;
77        #[cfg(feature = "std")]
78        {
79            self.last_validation = None;
80        }
81    }
82
83    /// Check if cached result can be used
84    fn should_use_cache(&self, content_hash: u64) -> bool {
85        if self.cached_result.is_none() || self.content_hash != content_hash {
86            return false;
87        }
88
89        #[cfg(feature = "std")]
90        {
91            if let Some(last_validation) = self.last_validation {
92                return last_validation.elapsed() < self.config.min_validation_interval;
93            }
94        }
95
96        true
97    }
98
99    /// Calculate hash of content for cache invalidation
100    fn calculate_hash(&self, content: &str) -> u64 {
101        // Simple FNV hash
102        let mut hash = 0xcbf29ce484222325u64;
103        for byte in content.bytes() {
104            hash ^= byte as u64;
105            hash = hash.wrapping_mul(0x100000001b3);
106        }
107        hash
108    }
109}