1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::collections::HashSet;
4use std::rc::Rc;
5
6use crate::RootSchema;
7use crate::YamlSchema;
8use crate::validation::ArrayUnevaluatedAnnotations;
9use crate::validation::ObjectEvaluatedNames;
10use crate::validation::ValidationError;
11
12#[derive(Debug)]
14pub struct Context<'r> {
15 pub root_schema: Option<&'r RootSchema>,
17 pub current_schema: Option<&'r YamlSchema>,
18 pub current_path: Vec<String>,
19 pub stream_started: bool,
20 pub stream_ended: bool,
21 pub errors: Rc<RefCell<Vec<ValidationError>>>,
22 pub fail_fast: bool,
23 pub resolving_refs: Rc<RefCell<HashSet<(String, usize)>>>,
28 pub schemas: Rc<RefCell<HashMap<String, Rc<RootSchema>>>>,
30 pub object_evaluated: Option<ObjectEvaluatedNames>,
32 pub array_unevaluated: Option<Rc<RefCell<ArrayUnevaluatedAnnotations>>>,
34}
35
36impl Default for Context<'_> {
37 fn default() -> Self {
38 Self {
39 root_schema: None,
40 current_schema: None,
41 current_path: Vec::new(),
42 stream_started: false,
43 stream_ended: false,
44 errors: Rc::new(RefCell::new(Vec::new())),
45 fail_fast: false,
46 resolving_refs: Rc::new(RefCell::new(HashSet::new())),
47 schemas: Rc::new(RefCell::new(HashMap::new())),
48 object_evaluated: None,
49 array_unevaluated: None,
50 }
51 }
52}
53
54impl<'r> Context<'r> {
55 pub fn has_errors(&self) -> bool {
57 !self.errors.borrow().is_empty()
58 }
59
60 pub fn path(&self) -> String {
62 self.current_path.join(".")
63 }
64
65 pub fn new(fail_fast: bool) -> Context<'r> {
66 Context {
67 fail_fast,
68 ..Default::default()
69 }
70 }
71
72 pub fn get_sub_context(&self) -> Context<'r> {
73 Context {
74 root_schema: self.root_schema,
75 current_schema: self.current_schema,
76 current_path: self.current_path.clone(),
77 stream_started: self.stream_started,
78 stream_ended: self.stream_ended,
79 errors: Rc::new(RefCell::new(Vec::new())),
80 fail_fast: self.fail_fast,
81 resolving_refs: self.resolving_refs.clone(),
82 schemas: self.schemas.clone(),
83 object_evaluated: self.object_evaluated.clone(),
84 array_unevaluated: self.array_unevaluated.clone(),
85 }
86 }
87
88 pub fn get_sub_context_fresh_eval(&self) -> Context<'r> {
90 Context {
91 root_schema: self.root_schema,
92 current_schema: self.current_schema,
93 current_path: self.current_path.clone(),
94 stream_started: self.stream_started,
95 stream_ended: self.stream_ended,
96 errors: Rc::new(RefCell::new(Vec::new())),
97 fail_fast: self.fail_fast,
98 resolving_refs: self.resolving_refs.clone(),
99 schemas: self.schemas.clone(),
100 object_evaluated: Some(ObjectEvaluatedNames::new()),
101 array_unevaluated: Some(ArrayUnevaluatedAnnotations::new_shared()),
102 }
103 }
104
105 pub fn with_root_schema(root_schema: &'r RootSchema, fail_fast: bool) -> Context<'r> {
106 Context {
107 root_schema: Some(root_schema),
108 fail_fast,
109 ..Default::default()
110 }
111 }
112
113 pub fn with_root_schema_and_schemas(
115 root_schema: &'r RootSchema,
116 fail_fast: bool,
117 schemas: HashMap<String, Rc<RootSchema>>,
118 ) -> Context<'r> {
119 Context {
120 root_schema: Some(root_schema),
121 fail_fast,
122 schemas: Rc::new(RefCell::new(schemas)),
123 ..Default::default()
124 }
125 }
126
127 fn push_error(&self, error: ValidationError) {
128 self.errors.borrow_mut().push(error);
129 }
130
131 pub fn add_doc_error<V: Into<String>>(&self, error: V) {
132 let path = self.path();
133 self.push_error(ValidationError {
134 path,
135 marker: None,
136 error: error.into(),
137 });
138 }
139
140 pub fn add_error<V: Into<String>>(&self, marked_yaml: &saphyr::MarkedYaml, error: V) {
142 let path = self.path();
143 self.push_error(ValidationError {
144 path,
145 marker: Some(marked_yaml.span.start),
146 error: error.into(),
147 });
148 }
149
150 pub fn extend_errors(&self, errors: Vec<ValidationError>) {
152 self.errors.borrow_mut().extend(errors);
153 }
154
155 pub fn append_path<V: Into<String>>(&self, path: V) -> Context<'r> {
157 let mut new_path = self.current_path.clone();
158 new_path.push(path.into());
159 Context {
160 root_schema: self.root_schema,
161 current_schema: self.current_schema,
162 current_path: new_path,
163 errors: self.errors.clone(),
164 fail_fast: self.fail_fast,
165 stream_ended: self.stream_ended,
166 stream_started: self.stream_started,
167 resolving_refs: self.resolving_refs.clone(),
168 schemas: self.schemas.clone(),
169 object_evaluated: None,
170 array_unevaluated: None,
171 }
172 }
173
174 pub fn record_evaluated_property(&self, name: &str) {
176 if let Some(oe) = &self.object_evaluated {
177 oe.insert(name.to_string());
178 }
179 }
180
181 pub fn with_object_evaluated(
182 &self,
183 object_evaluated: Option<ObjectEvaluatedNames>,
184 ) -> Context<'r> {
185 Context {
186 root_schema: self.root_schema,
187 current_schema: self.current_schema,
188 current_path: self.current_path.clone(),
189 stream_started: self.stream_started,
190 stream_ended: self.stream_ended,
191 errors: self.errors.clone(),
192 fail_fast: self.fail_fast,
193 resolving_refs: self.resolving_refs.clone(),
194 schemas: self.schemas.clone(),
195 object_evaluated,
196 array_unevaluated: self.array_unevaluated.clone(),
197 }
198 }
199
200 pub fn with_array_unevaluated(
201 &self,
202 array_unevaluated: Option<Rc<RefCell<ArrayUnevaluatedAnnotations>>>,
203 ) -> Context<'r> {
204 Context {
205 root_schema: self.root_schema,
206 current_schema: self.current_schema,
207 current_path: self.current_path.clone(),
208 stream_started: self.stream_started,
209 stream_ended: self.stream_ended,
210 errors: self.errors.clone(),
211 fail_fast: self.fail_fast,
212 resolving_refs: self.resolving_refs.clone(),
213 schemas: self.schemas.clone(),
214 object_evaluated: self.object_evaluated.clone(),
215 array_unevaluated,
216 }
217 }
218
219 pub fn is_resolving_ref(&self, ref_name: &str, value: &saphyr::MarkedYaml) -> bool {
222 let key = (ref_name.to_string(), value.span.start.index());
223 self.resolving_refs.borrow().contains(&key)
224 }
225
226 pub fn begin_resolving_ref(&self, ref_name: &str, value: &saphyr::MarkedYaml) {
228 let key = (ref_name.to_string(), value.span.start.index());
229 self.resolving_refs.borrow_mut().insert(key);
230 }
231
232 pub fn end_resolving_ref(&self, ref_name: &str, value: &saphyr::MarkedYaml) {
234 let key = (ref_name.to_string(), value.span.start.index());
235 self.resolving_refs.borrow_mut().remove(&key);
236 }
237}