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_include_subforms: bool,
31 pub last_result: Option<ValidationResult>,
33 pub field_cache: IndexMap<String, CachedFieldValidation>,
35}
36
37impl ValidationCache {
38 pub fn new() -> Self {
39 Self::default()
40 }
41
42 #[inline]
44 pub fn get_cached_full_result(
45 &self,
46 data: &str,
47 context: Option<&str>,
48 validate_readonly: bool,
49 include_subforms: bool,
50 ) -> Option<ValidationResult> {
51 if self.last_validate_readonly != validate_readonly
52 || self.last_include_subforms != include_subforms
53 {
54 return None;
55 }
56
57 let last_data = self.last_data_str.as_deref()?;
58 if last_data != data {
59 return None;
60 }
61
62 let ctx_matches = match (self.last_context_str.as_deref(), context) {
63 (None, None) => true,
64 (Some(""), None) | (None, Some("")) => true,
65 (Some("{}"), None) | (None, Some("{}")) => true,
66 (Some(a), Some(b)) => a == b,
67 _ => false,
68 };
69
70 if ctx_matches {
71 self.last_result.clone()
72 } else {
73 None
74 }
75 }
76
77 #[inline]
79 pub fn check_field_cache(
80 &self,
81 field_path: &str,
82 field_data: &Value,
83 is_hidden: bool,
84 validate_readonly: bool,
85 rules: &Value,
86 ) -> Option<Option<ValidationError>> {
87 let cached = self.field_cache.get(field_path)?;
88 if cached.is_hidden == is_hidden
89 && cached.validate_readonly == validate_readonly
90 && &cached.field_data == field_data
91 && &cached.rules_snapshot == rules
92 {
93 Some(cached.error.clone())
94 } else {
95 None
96 }
97 }
98
99 #[inline]
101 pub fn update_field(
102 &mut self,
103 field_path: String,
104 field_data: Value,
105 is_hidden: bool,
106 validate_readonly: bool,
107 rules_snapshot: Value,
108 error: Option<ValidationError>,
109 ) {
110 self.field_cache.insert(
111 field_path,
112 CachedFieldValidation {
113 field_data,
114 is_hidden,
115 validate_readonly,
116 rules_snapshot,
117 error,
118 },
119 );
120 }
121
122 #[inline]
124 pub fn save_full_result(
125 &mut self,
126 data_str: String,
127 context_str: Option<String>,
128 validate_readonly: bool,
129 include_subforms: bool,
130 result: ValidationResult,
131 ) {
132 self.last_data_str = Some(data_str);
133 self.last_context_str = context_str;
134 self.last_validate_readonly = validate_readonly;
135 self.last_include_subforms = include_subforms;
136 self.last_result = Some(result);
137 }
138
139 #[inline]
141 pub fn invalidate_full_result(&mut self) {
142 self.last_data_str = None;
143 self.last_context_str = None;
144 self.last_validate_readonly = false;
145 self.last_include_subforms = false;
146 self.last_result = None;
147 }
148
149 #[inline]
151 pub fn clear(&mut self) {
152 self.last_data_str = None;
153 self.last_context_str = None;
154 self.last_validate_readonly = false;
155 self.last_include_subforms = false;
156 self.last_result = None;
157 self.field_cache.clear();
158 }
159}