Commit 47bb7068 authored by Tom Almeida's avatar Tom Almeida Committed by AdminXVII
Browse files

feat: Make arrays able to nest

Prior to this commit, the following type was considered invalid:
    `[[float]]`

Of course, sometimes it is helpful to have arrays within arrays, and as
such, this patch allows for nested arrays. To do this, the array types
in `Primitive` have all been converted to a `Primitive::Array` type,
that holds a `Box<>` to another `Primitive`. There is - of course - a
slight performance penalty to be expected with moving to using another
`Box` for arrays, however after having run the benchmarks, the
difference appears to be negligible.
parent 6fc89548
......@@ -107,10 +107,7 @@ impl<'a> Action<'a> {
) -> Result<Action<'a>, AssignmentError<'a>> {
match var.kind {
Primitive::Indexed(..) | Primitive::Str => Ok(Action(var, operator, value)),
Primitive::StrArray
| Primitive::BooleanArray
| Primitive::FloatArray
| Primitive::IntegerArray
Primitive::Array(_)
| Primitive::HashMap(_)
| Primitive::BTreeMap(_) => {
if is_array {
......@@ -120,7 +117,7 @@ impl<'a> Action<'a> {
}
}
_ if !is_array => Ok(Action(var, operator, value)),
_ => Err(AssignmentError::InvalidValue(var.kind, Primitive::StrArray)),
_ => Err(AssignmentError::InvalidValue(var.kind, Primitive::Array(Box::new(Primitive::Str)))),
}
}
}
......@@ -167,7 +164,7 @@ mod tests {
assert_eq!(
actions[1],
Ok(Action(
Key { name: "b", kind: Primitive::StrArray },
Key { name: "b", kind: Primitive::Array(Box::new(Primitive::Str)) },
Operator::Equal,
"[two three]",
))
......@@ -175,7 +172,7 @@ mod tests {
assert_eq!(
actions[2],
Ok(Action(
Key { name: "c", kind: Primitive::IntegerArray },
Key { name: "c", kind: Primitive::Array(Box::new(Primitive::Integer)) },
Operator::Equal,
"[4 5 6]",
))
......@@ -186,7 +183,7 @@ mod tests {
assert_eq!(actions.len(), 3);
assert_eq!(
actions[0],
Ok(Action(Key { name: "a", kind: Primitive::StrArray }, Operator::Equal, "[one two]",))
Ok(Action(Key { name: "a", kind: Primitive::Array(Box::new(Primitive::Str)) }, Operator::Equal, "[one two]",))
);
assert_eq!(
actions[1],
......@@ -195,7 +192,7 @@ mod tests {
assert_eq!(
actions[2],
Ok(Action(
Key { name: "c", kind: Primitive::StrArray },
Key { name: "c", kind: Primitive::Array(Box::new(Primitive::Str)) },
Operator::Equal,
"[four five]",
))
......
......@@ -99,21 +99,13 @@ pub fn value_check<E: Expander>(
if is_array(value) {
let extracted = shell.get_array(value)?;
match expected {
Primitive::StrArray | Primitive::Str => extracted
Primitive::Str => extracted
.iter()
.map(|item| value_check(shell, item, &Primitive::Str))
.collect::<Result<_, _>>(),
Primitive::BooleanArray => extracted
Primitive::Array(ref inner) => extracted
.iter()
.map(|item| value_check(shell, item, &Primitive::Boolean))
.collect::<Result<_, _>>(),
Primitive::IntegerArray => extracted
.iter()
.map(|item| value_check(shell, item, &Primitive::Integer))
.collect::<Result<_, _>>(),
Primitive::FloatArray => extracted
.iter()
.map(|item| value_check(shell, item, &Primitive::Float))
.map(|item| value_check(shell, item, inner))
.collect::<Result<_, _>>(),
Primitive::HashMap(_) | Primitive::BTreeMap(_) => get_map_of(expected, shell, value),
Primitive::Indexed(_, ref kind) => value_check(shell, value, kind),
......@@ -181,13 +173,13 @@ mod test {
#[test]
fn is_integer_array_() {
assert_eq!(
value_check(&mut DummyExpander, "[1 2 3]", &Primitive::IntegerArray).unwrap(),
value_check(&mut DummyExpander, "[1 2 3]", &Primitive::Array(Box::new(Primitive::Integer))).unwrap(),
Value::Array(vec![
Value::Str("1".into()),
Value::Str("2".into()),
Value::Str("3".into())
])
);
assert!(value_check(&mut DummyExpander, "[1 2 three]", &Primitive::IntegerArray).is_err());
assert!(value_check(&mut DummyExpander, "[1 2 three]", &Primitive::Array(Box::new(Primitive::Integer))).is_err());
}
}
......@@ -63,7 +63,7 @@ impl<'a> KeyIterator<'a> {
&& (eol || self.data.as_bytes()[self.read + 1] == b' ')
{
let kind = match &self.data[index_ident_start..self.read] {
"" => Primitive::StrArray,
"" => Primitive::Array(Box::new(Primitive::Str)),
s => Primitive::Indexed(s.to_owned(), Box::new(Primitive::Str)),
};
self.read += 1;
......@@ -82,7 +82,7 @@ impl<'a> KeyIterator<'a> {
}
let kind = match &self.data[index_ident_start..index_ident_end] {
"" => Primitive::StrArray,
"" => Primitive::Array(Box::new(Primitive::Str)),
s => match Primitive::parse(&self.data[index_ident_end + 2..self.read]) {
Some(kind) => Primitive::Indexed(s.to_owned(), Box::new(kind)),
None => {
......@@ -171,10 +171,10 @@ mod tests {
p:bmap[hmap[bool]] d:a",
);
assert_eq!(parser.next().unwrap(), Ok(Key { name: "a", kind: Primitive::Integer },));
assert_eq!(parser.next().unwrap(), Ok(Key { name: "b", kind: Primitive::StrArray },));
assert_eq!(parser.next().unwrap(), Ok(Key { name: "b", kind: Primitive::Array(Box::new(Primitive::Str)) },));
assert_eq!(parser.next().unwrap(), Ok(Key { name: "c", kind: Primitive::Boolean },));
assert_eq!(parser.next().unwrap(), Ok(Key { name: "d", kind: Primitive::Str },));
assert_eq!(parser.next().unwrap(), Ok(Key { name: "e", kind: Primitive::IntegerArray },));
assert_eq!(parser.next().unwrap(), Ok(Key { name: "e", kind: Primitive::Array(Box::new(Primitive::Integer)) },));
assert_eq!(
parser.next().unwrap(),
Ok(Key { name: "f", kind: Primitive::Indexed("0".into(), Box::new(Primitive::Str)) },)
......@@ -203,14 +203,14 @@ mod tests {
);
assert_eq!(
parser.next().unwrap(),
Ok(Key { name: "k", kind: Primitive::HashMap(Box::new(Primitive::IntegerArray)) },)
Ok(Key { name: "k", kind: Primitive::HashMap(Box::new(Primitive::Array(Box::new(Primitive::Integer)))) },)
);
assert_eq!(
parser.next().unwrap(),
Ok(Key {
name: "l",
kind: Primitive::HashMap(Box::new(Primitive::HashMap(Box::new(
Primitive::BooleanArray
Primitive::Array(Box::new(Primitive::Boolean))
)))),
},)
);
......@@ -224,7 +224,7 @@ mod tests {
);
assert_eq!(
parser.next().unwrap(),
Ok(Key { name: "o", kind: Primitive::BTreeMap(Box::new(Primitive::FloatArray)) },)
Ok(Key { name: "o", kind: Primitive::BTreeMap(Box::new(Primitive::Array(Box::new(Primitive::Float)))) },)
);
assert_eq!(
parser.next().unwrap(),
......
......@@ -5,20 +5,14 @@ use std::fmt::{self, Display, Formatter};
pub enum Primitive {
/// A plain string (ex: `"a string"`)
Str,
/// An array of string (ex: `["-" b c d]`)
StrArray,
/// A true-false value
Boolean,
/// An array of booleans
BooleanArray,
/// An integer numeric type
Integer,
/// An array of integer numeric type
IntegerArray,
/// A floating-point value
Float,
/// A floating-point value array
FloatArray,
/// Arrays
Array(Box<Primitive>),
/// A hash map
HashMap(Box<Primitive>),
/// A btreemap
......@@ -31,13 +25,9 @@ impl Primitive {
pub(crate) fn parse(data: &str) -> Option<Self> {
match data {
"str" => Some(Primitive::Str),
"[str]" => Some(Primitive::StrArray),
"bool" => Some(Primitive::Boolean),
"[bool]" => Some(Primitive::BooleanArray),
"int" => Some(Primitive::Integer),
"[int]" => Some(Primitive::IntegerArray),
"float" => Some(Primitive::Float),
"[float]" => Some(Primitive::FloatArray),
_ => {
let open_bracket = data.find('[')?;
let close_bracket = data.rfind(']')?;
......@@ -49,7 +39,8 @@ impl Primitive {
} else if kind == "bmap" {
Some(Primitive::BTreeMap(Box::new(Self::parse(inner)?)))
} else {
None
// It's an array
Some(Primitive::Array(Box::new(Self::parse(inner)?)))
}
}
}
......@@ -60,13 +51,10 @@ impl Display for Primitive {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match *self {
Primitive::Str => write!(f, "str"),
Primitive::StrArray => write!(f, "[str]"),
Primitive::Boolean => write!(f, "bool"),
Primitive::BooleanArray => write!(f, "[bool]"),
Primitive::Float => write!(f, "float"),
Primitive::FloatArray => write!(f, "[float]"),
Primitive::Integer => write!(f, "int"),
Primitive::IntegerArray => write!(f, "[int]"),
Primitive::Array(ref kind) => write!(f, "[{}]", kind),
Primitive::HashMap(ref kind) => match **kind {
Primitive::Str => write!(f, "hmap[]"),
ref kind => write!(f, "hmap[{}]", kind),
......
......@@ -56,7 +56,7 @@ mod tests {
Ok(vec![
KeyBuf { name: "a".into(), kind: Primitive::Integer },
KeyBuf { name: "b".into(), kind: Primitive::Boolean },
KeyBuf { name: "c".into(), kind: Primitive::StrArray },
KeyBuf { name: "c".into(), kind: Primitive::Array(Box::new(Primitive::Str)) },
KeyBuf { name: "d".into(), kind: Primitive::Str },
])
);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment