use error::*; use nom::error::ErrorKind; use std::collections::HashMap; use std::str::FromStr; use value::{Value, ValueKind}; mod parser; #[derive(Debug, Eq, PartialEq, Clone, Hash)] pub enum Expression { Identifier(String), Child(Box, String), Subscript(Box, isize), } impl FromStr for Expression { type Err = ConfigError; fn from_str(s: &str) -> Result { parser::from_str(s).map_err(ConfigError::PathParse) } } fn sindex_to_uindex(index: isize, len: usize) -> usize { if index >= 0 { index as usize } else { len - (index.abs() as usize) } } impl Expression { pub fn get(self, root: &Value) -> Option<&Value> { match self { Expression::Identifier(id) => { match root.kind { // `x` access on a table is equivalent to: map[x] ValueKind::Table(ref map) => map.get(&id), // all other variants return None _ => None, } } 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, } } Expression::Subscript(expr, index) => match expr.get(root) { Some(value) => match value.kind { ValueKind::Array(ref array) => { let index = sindex_to_uindex(index, array.len()); if index >= array.len() { None } else { Some(&array[index]) } } _ => None, }, _ => None, }, } } 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) => map.get_mut(id), _ => None, }, Expression::Child(ref expr, ref key) => match expr.get_mut(root) { Some(value) => match value.kind { ValueKind::Table(ref mut map) => map.get_mut(key), _ => None, }, _ => None, }, Expression::Subscript(ref expr, index) => match expr.get_mut(root) { Some(value) => match value.kind { ValueKind::Array(ref mut array) => { let index = sindex_to_uindex(index, array.len()); if index >= array.len() { None } else { Some(&mut array[index]) } } _ => None, }, _ => None, }, } } pub fn get_mut_forcibly<'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_with(|| Value::new(None, ValueKind::Nil)), ), _ => None, }, Expression::Child(ref expr, ref key) => match expr.get_mut_forcibly(root) { Some(value) => match value.kind { ValueKind::Table(ref mut map) => Some( map.entry(key.clone()) .or_insert_with(|| Value::new(None, ValueKind::Nil)), ), _ => { *value = HashMap::::new().into(); if let ValueKind::Table(ref mut map) = value.kind { Some( map.entry(key.clone()) .or_insert_with(|| Value::new(None, ValueKind::Nil)), ) } else { unreachable!(); } } }, _ => None, }, Expression::Subscript(ref expr, index) => match expr.get_mut_forcibly(root) { Some(value) => { match value.kind { ValueKind::Array(_) => (), _ => *value = Vec::::new().into(), } match value.kind { ValueKind::Array(ref mut array) => { let index = sindex_to_uindex(index, array.len()); if index >= array.len() { array .resize((index + 1) as usize, Value::new(None, ValueKind::Nil)); } Some(&mut array[index]) } _ => None, } } _ => None, }, } } pub fn set(&self, root: &mut Value, value: Value) { match *self { Expression::Identifier(ref id) => { // Ensure that root is a table match root.kind { ValueKind::Table(_) => {} _ => { *root = HashMap::::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_with(|| HashMap::::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_forcibly(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::::new().into(); Expression::Identifier(key.clone()).set(parent, value); } } } } Expression::Subscript(ref expr, index) => { if let Some(parent) = expr.get_mut_forcibly(root) { match parent.kind { ValueKind::Array(_) => (), _ => *parent = Vec::::new().into(), } if let ValueKind::Array(ref mut array) = parent.kind { let uindex = sindex_to_uindex(index, array.len()); if uindex >= array.len() { array.resize((uindex + 1) as usize, Value::new(None, ValueKind::Nil)); } array[uindex] = value; } } } } } }