1use std::collections::HashMap;
2use std::ops::Deref;
3use std::prelude::v1::Result as StdResult;
4use std::rc::Rc;
5
6use indexmap::IndexMap;
7use regex::Regex;
8use std::fmt::Error as FormatError;
9use std::io::Error as IoError;
10use thiserror::Error;
11
12use crate::json_value::JsonValue;
13use crate::reader::Location;
14use crate::regex_cache::{RegexCache, RegexCompile};
15use crate::selection::Get;
16
17use regex::Error as RegexError;
18
19#[derive(Debug, Error)]
20pub enum ProcessError {
21 #[error("{0}")]
22 Format(#[from] FormatError),
23 #[error("{0}")]
24 Io(#[from] IoError),
25 #[error("{0}")]
26 InvalidInputError(&'static str),
27}
28
29#[derive(Default)]
30pub struct Titles {
31 titles: Vec<Rc<String>>,
32}
33
34impl Titles {
35 pub fn with_title(&self, title: &Rc<String>) -> Self {
36 let mut titles = self.titles.clone();
37 titles.push(title.clone());
38 Titles { titles }
39 }
40
41 pub fn len(&self) -> usize {
42 self.titles.len()
43 }
44
45 pub fn to_list(&self) -> Vec<Option<JsonValue>> {
46 let mut lst = Vec::with_capacity(self.titles.len());
47 for str in &self.titles {
48 let value = Some(str.deref().clone().into());
49 lst.push(value);
50 }
51 lst
52 }
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, Hash)]
56pub enum ContextKey {
57 Value(JsonValue),
58 Results(Vec<Option<JsonValue>>),
59}
60
61#[derive(Clone)]
62pub struct InputContext {
63 pub start_location: Location,
64 pub end_location: Location,
65 pub file_index: u64,
66 pub index: u64,
67}
68
69pub struct Context {
70 input: Rc<JsonValue>,
71 results: Vec<(Rc<String>, Option<JsonValue>)>,
72 parent_inputs: Vec<Rc<JsonValue>>,
73 variables: Rc<HashMap<String, JsonValue>>,
74 definitions: Rc<HashMap<String, Rc<dyn Get>>>,
75 input_context: Option<Rc<InputContext>>,
76 regex_cache: RegexCache,
77}
78
79impl Context {
80 pub fn new_empty() -> Self {
81 Context {
82 input: Rc::new(JsonValue::Null),
83 results: Vec::new(),
84 parent_inputs: Vec::new(),
85 variables: Rc::new(HashMap::new()),
86 definitions: Rc::new(HashMap::new()),
87 input_context: None,
88 regex_cache: RegexCache::new(0),
89 }
90 }
91 pub fn new_with_no_context(input: JsonValue) -> Self {
92 Context {
93 input: Rc::new(input),
94 results: Vec::new(),
95 parent_inputs: Vec::new(),
96 variables: Rc::new(HashMap::new()),
97 definitions: Rc::new(HashMap::new()),
98 input_context: None,
99 regex_cache: RegexCache::new(0),
100 }
101 }
102 pub fn new_with_input(
103 input: JsonValue,
104 start_location: Location,
105 end_location: Location,
106 file_index: u64,
107 index: u64,
108 regex_cache: &RegexCache,
109 ) -> Self {
110 let input_context = InputContext {
111 start_location,
112 end_location,
113 file_index,
114 index,
115 };
116 Context {
117 input: Rc::new(input),
118 results: Vec::new(),
119 parent_inputs: Vec::new(),
120 variables: Rc::new(HashMap::new()),
121 definitions: Rc::new(HashMap::new()),
122 input_context: Some(Rc::new(input_context)),
123 regex_cache: regex_cache.clone(),
124 }
125 }
126 pub fn with_inupt(&self, value: JsonValue) -> Self {
127 let input = Rc::new(value);
128 let mut parent_inputs = Vec::with_capacity(self.parent_inputs.len() + 1);
129 parent_inputs.push(self.input.clone());
130 for i in &self.parent_inputs {
131 parent_inputs.push(i.clone());
132 }
133 Context {
134 input,
135 results: Vec::new(),
136 parent_inputs,
137 variables: self.variables.clone(),
138 definitions: self.definitions.clone(),
139 input_context: self.input_context.clone(),
140 regex_cache: self.regex_cache.clone(),
141 }
142 }
143 pub fn with_result(&self, title: &Rc<String>, result: Option<JsonValue>) -> Self {
144 let mut results = self.results.clone();
145 results.push((title.clone(), result));
146 Context {
147 input: self.input().clone(),
148 results,
149 parent_inputs: Vec::new(),
150 variables: self.variables.clone(),
151 definitions: self.definitions.clone(),
152 input_context: self.input_context.clone(),
153 regex_cache: self.regex_cache.clone(),
154 }
155 }
156 pub fn with_variable(&self, name: String, value: JsonValue) -> Self {
157 let mut variables = HashMap::with_capacity(self.variables.len() + 1);
158 for (k, v) in &*self.variables {
159 variables.insert(k.clone(), v.clone());
160 }
161 variables.insert(name, value);
162 Context {
163 input: self.input().clone(),
164 results: self.results.clone(),
165 parent_inputs: Vec::new(),
166 variables: Rc::new(variables),
167 definitions: self.definitions.clone(),
168 input_context: self.input_context.clone(),
169 regex_cache: self.regex_cache.clone(),
170 }
171 }
172 pub fn with_variables(&self, variables: &Rc<HashMap<String, JsonValue>>) -> Self {
173 Context {
174 input: self.input().clone(),
175 results: self.results.clone(),
176 parent_inputs: Vec::new(),
177 variables: variables.clone(),
178 definitions: self.definitions.clone(),
179 input_context: self.input_context.clone(),
180 regex_cache: self.regex_cache.clone(),
181 }
182 }
183 pub fn with_definition(&self, name: String, definition: &Rc<dyn Get>) -> Self {
184 let mut definitions = HashMap::with_capacity(self.definitions.len() + 1);
185 for (k, d) in &*self.definitions {
186 definitions.insert(k.clone(), d.clone());
187 }
188 definitions.insert(name, definition.clone());
189 Context {
190 input: self.input().clone(),
191 results: self.results.clone(),
192 parent_inputs: Vec::new(),
193 variables: self.variables.clone(),
194 definitions: Rc::new(definitions),
195 input_context: self.input_context.clone(),
196 regex_cache: self.regex_cache.clone(),
197 }
198 }
199 pub fn with_definitions(&self, definitions: &Rc<HashMap<String, Rc<dyn Get>>>) -> Self {
200 Context {
201 input: self.input().clone(),
202 results: self.results.clone(),
203 parent_inputs: Vec::new(),
204 variables: self.variables.clone(),
205 definitions: definitions.clone(),
206 input_context: self.input_context.clone(),
207 regex_cache: self.regex_cache.clone(),
208 }
209 }
210 pub fn build(&self) -> JsonValue {
211 if self.results.is_empty() {
212 self.input().deref().clone()
213 } else {
214 let mut mp = IndexMap::new();
215 for (title, value) in &self.results {
216 if let Some(value) = value {
217 mp.insert(title.deref().clone(), value.clone());
218 }
219 }
220 JsonValue::Object(mp)
221 }
222 }
223 pub fn to_list(&self) -> Vec<Option<JsonValue>> {
224 self.results.iter().map(|i| i.1.clone()).collect()
225 }
226
227 pub fn get_variable_value(&self, name: &String) -> Option<&JsonValue> {
228 self.variables.get(name)
229 }
230
231 pub fn get_definition(&self, name: &String) -> Option<&Rc<dyn Get>> {
232 self.definitions.get(name)
233 }
234
235 pub fn get_selected(&self, name: &String) -> Option<JsonValue> {
236 for (title, result) in &self.results {
237 if &**title == name {
238 return result.clone();
239 }
240 }
241 None
242 }
243
244 pub fn input(&self) -> &Rc<JsonValue> {
245 &self.input
246 }
247
248 pub fn parent_input(&self, count: usize) -> &JsonValue {
249 if count == 0 {
250 self.input()
251 } else {
252 self.parent_inputs
253 .get(count - 1)
254 .unwrap_or_else(|| self.input())
255 }
256 }
257
258 pub fn key(&self) -> ContextKey {
259 if self.results.is_empty() {
260 ContextKey::Value(self.input().deref().clone())
261 } else {
262 ContextKey::Results(self.to_list())
263 }
264 }
265
266 pub fn input_context(&self) -> Option<Rc<InputContext>> {
267 self.input_context.clone()
268 }
269}
270
271impl RegexCompile for Context {
272 fn compile_regex(&self, regex: &str) -> Rc<StdResult<Regex, RegexError>> {
273 self.regex_cache.compile_regex(regex)
274 }
275}
276
277#[derive(Debug, PartialEq)]
278pub enum ProcessDecision {
279 Continue,
280 Break,
281}
282
283pub type Result<T> = std::result::Result<T, ProcessError>;
284
285pub trait Process {
286 fn start(&mut self, titles_so_far: Titles) -> Result<()>;
287 fn process(&mut self, context: Context) -> Result<ProcessDecision>;
288 fn complete(&mut self) -> Result<()>;
289}