♻️ Integra config-rs sólo para archivos TOML
This commit is contained in:
parent
4daab33499
commit
104efd116f
10 changed files with 2185 additions and 0 deletions
254
pagetop/src/config/path.rs
Normal file
254
pagetop/src/config/path.rs
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
use crate::config::error::*;
|
||||
use crate::config::value::{Value, ValueKind};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
mod parser;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
|
||||
pub enum Expression {
|
||||
Identifier(String),
|
||||
Child(Box<Expression>, String),
|
||||
Subscript(Box<Expression>, isize),
|
||||
}
|
||||
|
||||
impl FromStr for Expression {
|
||||
type Err = ConfigError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Expression> {
|
||||
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::<String, Value>::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::<Value>::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::<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_with(|| 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_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::<String, Value>::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::<Value>::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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue