Skip to content

Commit 37cff16

Browse files
committed
REF: convert var to lazy op; update formatting
1 parent 26f4564 commit 37cff16

File tree

11 files changed

+351
-311
lines changed

11 files changed

+351
-311
lines changed

.rustfmt.toml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
max_width = 88

src/data.rs

+32-153
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
// as operators. They were originally done as parsers because there wasn't
55
// yet a LazyOperator concept.
66

7-
use crate::error::Error;
8-
use crate::value::Evaluated;
9-
use crate::{Parser, NULL};
107
use serde_json::{Map, Number, Value};
118
use std::convert::{From, TryFrom};
129

10+
use crate::error::Error;
11+
use crate::value::Evaluated;
12+
use crate::Parser;
13+
1314
#[derive(Debug)]
1415
pub enum KeyType<'a> {
1516
String(&'a String),
@@ -159,163 +160,39 @@ impl<'a> From<MissingSome<'a>> for Value {
159160
}
160161
}
161162

162-
#[derive(Debug)]
163-
pub struct Variable<'a> {
164-
value: &'a Value,
165-
}
166-
impl<'a> Parser<'a> for Variable<'a> {
167-
fn from_value(value: &'a Value) -> Result<Option<Self>, Error> {
168-
match value {
169-
Value::Object(map) => {
170-
if map.len() != 1 {
171-
return Ok(None);
172-
};
173-
match map.get("var") {
174-
Some(var) => match var {
175-
Value::String(_) => Ok(Some(Variable { value: var })),
176-
Value::Number(_) => Ok(Some(Variable { value: var })),
177-
Value::Array(arr) => match arr.len() {
178-
0..=2 => Ok(Some(Variable { value: var })),
179-
_ => Err(Error::InvalidVariable {
180-
value: value.clone(),
181-
reason: "Array variables must be of len 0..2 inclusive".into(),
182-
}),
183-
},
184-
_ => Err(Error::InvalidVariable {
185-
value: value.clone(),
186-
reason: "Variables must be strings, integers, or arrays".into(),
187-
}),
188-
},
189-
None => Ok(None),
190-
}
191-
}
192-
_ => Ok(None),
193-
}
194-
}
195-
196-
fn evaluate(&self, data: &'a Value) -> Result<Evaluated, Error> {
197-
// if self.name == "" { return data };
198-
match self.value {
199-
Value::Null => Ok(Evaluated::Raw(data)),
200-
Value::String(var_name) => self.interpolate_string_var(data, var_name).map(Evaluated::Raw),
201-
Value::Number(idx) => self.interpolate_numeric_var(data, idx).map(Evaluated::Raw),
202-
Value::Array(var) => self.interpolate_array_var(data, var).map(Evaluated::Raw),
203-
_ => Err(Error::InvalidVariable{
204-
value: self.value.clone(),
205-
reason: "Unsupported variable type. Variables must be strings, integers, arrays, or null.".into()
206-
})
207-
}
208-
}
209-
}
210-
impl<'a> Variable<'a> {
211-
fn get_default(&self) -> &'a Value {
212-
match self.value {
213-
Value::Array(val) => val.get(1).unwrap_or(&NULL),
214-
_ => &NULL,
215-
}
216-
}
217-
218-
fn interpolate_array_var(
219-
&self,
220-
data: &'a Value,
221-
var: &'a Vec<Value>,
222-
) -> Result<&'a Value, Error> {
223-
let len = var.len();
224-
match len {
225-
0 => Ok(data),
226-
1 | 2 => match &var[0] {
227-
Value::String(var_name) => self.interpolate_string_var(data, &var_name),
228-
Value::Number(var_idx) => self.interpolate_numeric_var(data, &var_idx),
229-
_ => Err(Error::InvalidVariable {
230-
value: Value::Array(var.clone()),
231-
reason: "Variables must be strings or integers".into(),
232-
}),
233-
},
234-
_ => Err(Error::InvalidVariable {
235-
value: Value::Array(var.clone()),
236-
reason: format!("Array variables must be of len 1 or 2, not {}", len),
237-
}),
238-
}
239-
}
240-
241-
fn interpolate_numeric_var(
242-
&self,
243-
data: &'a Value,
244-
idx: &'a Number,
245-
) -> Result<&'a Value, Error> {
246-
let default = self.get_default();
247-
match data {
248-
Value::Array(val) => {
249-
idx
250-
// Option<u64>
251-
.as_u64()
252-
// Option<Result<usize, Error>>
253-
.map(|i| {
254-
usize::try_from(i).map_err(|e| Error::InvalidVariable {
255-
value: Value::Number(idx.clone()),
256-
reason: format!(
257-
"Could not convert value to a system-sized integer: {:?}",
258-
e
259-
),
260-
})
261-
})
262-
// Option<Result<Value, Error>>
263-
.map(|res| res.map(|i| val.get(i).unwrap_or(default)))
264-
// Result<Value, Error>
265-
.unwrap_or(Ok(default))
266-
}
267-
_ => Err(Error::InvalidVariable {
268-
value: Value::Number(idx.clone()),
269-
reason: "Cannot access non-array data with an index variable".into(),
270-
}),
271-
}
272-
}
273-
274-
fn interpolate_string_var(
275-
&self,
276-
data: &'a Value,
277-
var_name: &'a String,
278-
) -> Result<&'a Value, Error> {
279-
if var_name == "" {
280-
return Ok(data);
281-
};
282-
let key = KeyType::String(var_name);
283-
get_key(data, &key).map(|v| v.unwrap_or(self.get_default()))
284-
}
285-
}
286-
impl<'a> From<Variable<'a>> for Value {
287-
fn from(var: Variable) -> Self {
288-
let mut map = Map::with_capacity(1);
289-
map.insert("var".into(), var.value.clone());
290-
Value::Object(map)
291-
}
292-
}
293-
294163
fn get_key<'a>(data: &'a Value, key: &KeyType) -> Result<Option<&'a Value>, Error> {
164+
if let Value::Null = data {
165+
return Ok(None);
166+
};
295167
match key {
296168
KeyType::String(key) => {
297169
match data {
298-
Value::Object(_) => key.split(".").fold(Ok(Some(data)), |acc, i| match acc? {
299-
// If a previous key was not found, just send the None on through
300-
None => Ok(None),
301-
// If the current value is an object, try to get the value
302-
Some(Value::Object(map)) => Ok(map.get(i)),
303-
// If the current value is an array, we need an integer
304-
// index. If integer conversion fails, return an error.
305-
Some(Value::Array(arr)) => {
306-
i.parse::<usize>()
170+
Value::Object(_) | Value::Array(_) => {
171+
key.split(".").fold(Ok(Some(data)), |acc, i| match acc? {
172+
// If a previous key was not found, just send the None on through
173+
None => Ok(None),
174+
// If the current value is an object, try to get the value
175+
Some(Value::Object(map)) => Ok(map.get(i)),
176+
// If the current value is an array, we need an integer
177+
// index. If integer conversion fails, return an error.
178+
Some(Value::Array(arr)) => i
179+
.parse::<usize>()
307180
.map(|i| arr.get(i))
308181
.map_err(|_| Error::InvalidVariable {
309182
value: Value::String(String::from(*key)),
310-
reason: "Cannot access array data with non-integer key".into(),
311-
})
312-
}
313-
_ => Ok(None),
314-
}),
315-
// We can only get string values off of objects. Anything else is an error.
183+
reason: "Cannot access array data with non-integer key"
184+
.into(),
185+
}),
186+
_ => Ok(None),
187+
})
188+
}
189+
// We can only get string values off of objects or arrays. Anything else is an error.
316190
_ => Err(Error::InvalidData {
317191
value: data.clone(),
318-
reason: format!("Cannot get string key '{:?}' from non-object data", key),
192+
reason: format!(
193+
"Cannot get string key '{:?}' from non-object data",
194+
key
195+
),
319196
}),
320197
}
321198
}
@@ -345,7 +222,8 @@ fn get_key<'a>(data: &'a Value, key: &KeyType) -> Result<Option<&'a Value>, Erro
345222
}
346223
_ => Err(Error::InvalidVariable {
347224
value: Value::Number((*idx).clone()),
348-
reason: "Cannot access non-array data with an index variable".into(),
225+
reason: "Cannot access non-array data with an index variable"
226+
.into(),
349227
}),
350228
}
351229
}
@@ -398,7 +276,8 @@ fn keys_from_val<'a>(val: &'a Value) -> Result<Vec<KeyType<'a>>, Error> {
398276
Value::String(key) => Ok(KeyType::String(key)),
399277
Value::Number(idx) => Ok(KeyType::Number(idx)),
400278
_ => Err(Error::UnexpectedError(
401-
"Some keys were not strings or numbers even after validation".into(),
279+
"Some keys were not strings or numbers even after validation"
280+
.into(),
402281
)),
403282
})
404283
.collect()

src/error.rs

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ pub enum Error {
1717
#[error("Invalid variable - '{value:?}', reason: {reason:?}")]
1818
InvalidVariable { value: Value, reason: String },
1919

20+
#[error("Invalid variable key - '{value:?}', reason: {reason:?}")]
21+
InvalidVariableKey { value: Value, reason: String },
22+
2023
#[error("Invalid argument for '{operation}' - '{value:?}', reason: {reason}")]
2124
InvalidArgument {
2225
value: Value,

src/js_op.rs

+3-10
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const NUMERICS: &'static [char] = &[
1515
// - there are too many tests in docstrings
1616
// - the docstrings are too sarcastic about JS equality
1717

18-
fn to_string(value: &Value) -> String {
18+
pub fn to_string(value: &Value) -> String {
1919
match value {
2020
Value::Object(_) => String::from("[object Object]"),
2121
Value::Bool(val) => val.to_string(),
@@ -56,7 +56,7 @@ fn to_primitive_number(value: &Value) -> Option<f64> {
5656
}
5757
}
5858

59-
fn str_to_number<S: AsRef<str>>(string: S) -> Option<f64> {
59+
pub fn str_to_number<S: AsRef<str>>(string: S) -> Option<f64> {
6060
let s = string.as_ref();
6161
if s == "" {
6262
Some(0.0)
@@ -90,7 +90,7 @@ fn to_primitive(value: &Value, hint: PrimitiveHint) -> Primitive {
9090
///
9191
/// Should be pretty much equivalent to calling Number(value) in JS,
9292
/// returning None where that would return NaN.
93-
fn to_number(value: &Value) -> Option<f64> {
93+
pub fn to_number(value: &Value) -> Option<f64> {
9494
match to_primitive(value, PrimitiveHint::Number) {
9595
Primitive::Number(num) => Some(num),
9696
Primitive::String(string) => str_to_number(string),
@@ -556,7 +556,6 @@ pub fn parse_float_mul(vals: &Vec<&Value>) -> Result<f64, Error> {
556556
})
557557
}
558558

559-
560559
/// Do minus
561560
pub fn abstract_minus(first: &Value, second: &Value) -> Result<f64, Error> {
562561
let first_num = to_number(first);
@@ -580,7 +579,6 @@ pub fn abstract_minus(first: &Value, second: &Value) -> Result<f64, Error> {
580579
Ok(first_num.unwrap() - second_num.unwrap())
581580
}
582581

583-
584582
/// Do division
585583
pub fn abstract_div(first: &Value, second: &Value) -> Result<f64, Error> {
586584
let first_num = to_number(first);
@@ -604,7 +602,6 @@ pub fn abstract_div(first: &Value, second: &Value) -> Result<f64, Error> {
604602
Ok(first_num.unwrap() / second_num.unwrap())
605603
}
606604

607-
608605
/// Do modulo
609606
pub fn abstract_mod(first: &Value, second: &Value) -> Result<f64, Error> {
610607
let first_num = to_number(first);
@@ -628,7 +625,6 @@ pub fn abstract_mod(first: &Value, second: &Value) -> Result<f64, Error> {
628625
Ok(first_num.unwrap() % second_num.unwrap())
629626
}
630627

631-
632628
/// Attempt to convert a value to a negative number
633629
pub fn to_negative(val: &Value) -> Result<f64, Error> {
634630
to_number(val)
@@ -1128,7 +1124,6 @@ mod test_abstract_max {
11281124
}
11291125
}
11301126

1131-
11321127
#[cfg(test)]
11331128
mod test_abstract_min {
11341129
use super::*;
@@ -1163,7 +1158,6 @@ mod test_abstract_min {
11631158
}
11641159
}
11651160

1166-
11671161
#[cfg(test)]
11681162
mod test_abstract_minus {
11691163
use super::*;
@@ -1311,4 +1305,3 @@ mod test_parse_float {
13111305
.for_each(|(input, exp)| assert_eq!(parse_float(&input), exp));
13121306
}
13131307
}
1314-

0 commit comments

Comments
 (0)