json_eval_rs/jsoneval/
validation_cache.rs1use crate::jsoneval::types::{ValidationError, ValidationResult};
2use indexmap::IndexMap;
3use serde_json::Value;
4
5#[derive(Clone, Debug)]
7pub struct CachedFieldValidation {
8 pub field_data: Value,
10 pub is_hidden: bool,
12 pub validate_readonly: bool,
14 pub rules_snapshot: Value,
16 pub error: Option<ValidationError>,
18}
19
20#[derive(Clone, Default, Debug)]
22pub struct ValidationCache {
23 pub last_data_str: Option<String>,
25 pub last_context_str: Option<String>,
27 pub last_validate_readonly: bool,
29 pub last_result: Option<ValidationResult>,
31 pub field_cache: IndexMap<String, CachedFieldValidation>,
33}
34
35impl ValidationCache {
36 pub fn new() -> Self {
37 Self::default()
38 }
39
40 #[inline]
42 pub fn get_cached_full_result(
43 &self,
44 data: &str,
45 context: Option<&str>,
46 validate_readonly: bool,
47 ) -> Option<ValidationResult> {
48 if self.last_validate_readonly != validate_readonly {
49 return None;
50 }
51
52 let last_data = self.last_data_str.as_deref()?;
53 if last_data != data {
54 return None;
55 }
56
57 let ctx_matches = match (self.last_context_str.as_deref(), context) {
58 (None, None) => true,
59 (Some(""), None) | (None, Some("")) => true,
60 (Some("{}"), None) | (None, Some("{}")) => true,
61 (Some(a), Some(b)) => a == b,
62 _ => false,
63 };
64
65 if ctx_matches {
66 self.last_result.clone()
67 } else {
68 None
69 }
70 }
71
72 #[inline]
74 pub fn check_field_cache(
75 &self,
76 field_path: &str,
77 field_data: &Value,
78 is_hidden: bool,
79 validate_readonly: bool,
80 rules: &Value,
81 ) -> Option<Option<ValidationError>> {
82 let cached = self.field_cache.get(field_path)?;
83 if cached.is_hidden == is_hidden
84 && cached.validate_readonly == validate_readonly
85 && &cached.field_data == field_data
86 && &cached.rules_snapshot == rules
87 {
88 Some(cached.error.clone())
89 } else {
90 None
91 }
92 }
93
94 #[inline]
96 pub fn update_field(
97 &mut self,
98 field_path: String,
99 field_data: Value,
100 is_hidden: bool,
101 validate_readonly: bool,
102 rules_snapshot: Value,
103 error: Option<ValidationError>,
104 ) {
105 self.field_cache.insert(
106 field_path,
107 CachedFieldValidation {
108 field_data,
109 is_hidden,
110 validate_readonly,
111 rules_snapshot,
112 error,
113 },
114 );
115 }
116
117 #[inline]
119 pub fn save_full_result(
120 &mut self,
121 data_str: String,
122 context_str: Option<String>,
123 validate_readonly: bool,
124 result: ValidationResult,
125 ) {
126 self.last_data_str = Some(data_str);
127 self.last_context_str = context_str;
128 self.last_validate_readonly = validate_readonly;
129 self.last_result = Some(result);
130 }
131
132 #[inline]
134 pub fn invalidate_full_result(&mut self) {
135 self.last_data_str = None;
136 self.last_context_str = None;
137 self.last_validate_readonly = false;
138 self.last_result = None;
139 }
140
141 #[inline]
143 pub fn clear(&mut self) {
144 self.last_data_str = None;
145 self.last_context_str = None;
146 self.last_validate_readonly = false;
147 self.last_result = None;
148 self.field_cache.clear();
149 }
150}