summaryrefslogtreecommitdiffstats
path: root/src/path
diff options
context:
space:
mode:
authorRyan Leckey <ryan@launchbadge.com>2017-06-03 01:21:10 -0700
committerRyan Leckey <ryan@launchbadge.com>2017-06-03 01:21:10 -0700
commitc26907b3ecf2b139fe61bf1403c952b85285ae02 (patch)
tree1cb1f275e9942c08c3d6f085de63bba43c652130 /src/path
parent028aaf5247dd3cd184b250afdba235d683525f97 (diff)
Add set and set_default (and deep merging)
Diffstat (limited to 'src/path')
-rw-r--r--src/path/mod.rs120
1 files changed, 120 insertions, 0 deletions
diff --git a/src/path/mod.rs b/src/path/mod.rs
index f889283..d2df442 100644
--- a/src/path/mod.rs
+++ b/src/path/mod.rs
@@ -1,4 +1,5 @@
use std::str::FromStr;
+use std::collections::HashMap;
use nom::ErrorKind;
use error::*;
use value::{Value, ValueKind};
@@ -33,6 +34,125 @@ impl Expression {
}
}
+ Expression::Child(expr, key) => {
+ match expr.get(root) {
+ Some(value) => {
+ match value.kind {
+ // Access on a table is identical to Identifier, it just forwards
+ ValueKind::Table(ref map) => map.get(&key),
+
+ // all other variants return None
+ _ => None,
+ }
+ }
+
+ _ => None,
+ }
+ }
+
+ _ => {
+ unimplemented!();
+ }
+ }
+ }
+
+ pub fn get_mut<'a>(&self, root: &'a mut Value) -> Option<&'a mut Value> {
+ match *self {
+ Expression::Identifier(ref id) => {
+ match root.kind {
+ ValueKind::Table(ref mut map) => {
+ Some(map.entry(id.clone()).or_insert(Value::new(None, ValueKind::Nil)))
+ }
+
+ _ => None,
+ }
+ }
+
+ Expression::Child(ref expr, ref key) => {
+ match expr.get_mut(root) {
+ Some(value) => {
+ match value.kind {
+ ValueKind::Table(ref mut map) => {
+ Some(map.entry(key.clone()).or_insert(Value::new(None, ValueKind::Nil)))
+ }
+
+ _ => {
+ *value = HashMap::<String, Value>::new().into();
+
+ if let ValueKind::Table(ref mut map) = value.kind {
+ Some(map.entry(key.clone()).or_insert(Value::new(None, ValueKind::Nil)))
+ } else {
+ println!("WHAT THE FUCK?");
+
+ unreachable!();
+ }
+ }
+ }
+ }
+
+ _ => None,
+ }
+ }
+
+ _ => {
+ unimplemented!();
+ }
+ }
+ }
+
+ pub fn set<'a>(&self, root: &'a mut Value, value: Value) {
+ match *self {
+ Expression::Identifier(ref id) => {
+ // Ensure that root is a table
+ match root.kind {
+ ValueKind::Table(_) => { }
+
+ _ => {
+ *root = HashMap::<String, Value>::new().into();
+ }
+ }
+
+ match value.kind {
+ ValueKind::Table(ref incoming_map) => {
+ // Pull out another table
+ let mut target = if let ValueKind::Table(ref mut map) = root.kind {
+ map.entry(id.clone()).or_insert(HashMap::<String, Value>::new().into())
+ } else {
+ unreachable!();
+ };
+
+ // Continue the deep merge
+ for (key, val) in incoming_map {
+ Expression::Identifier(key.clone()).set(&mut target, val.clone());
+ }
+ }
+
+ _ => {
+ if let ValueKind::Table(ref mut map) = root.kind {
+ // Just do a simple set
+ map.insert(id.clone(), value);
+ }
+ }
+ }
+ }
+
+ Expression::Child(ref expr, ref key) => {
+ if let Some(parent) = expr.get_mut(root) {
+ match parent.kind {
+ ValueKind::Table(_) => {
+ Expression::Identifier(key.clone()).set(parent, value);
+ }
+
+ _ => {
+ // Didn't find a table. Oh well. Make a table and do this anyway
+ *parent = HashMap::<String, Value>::new().into();
+
+ Expression::Identifier(key.clone()).set(parent, value);
+ }
+ }
+ }
+ }
+
_ => {
unimplemented!();
}