use toml::Value;
use toml::value::Index;
use std::ops::{Div, BitOr, Shl, ShlAssign, Not, Deref, DerefMut};
fn path<'tr, B>(v: Option<&'tr Value>, p: B) -> Option<&'tr Value>
where B: PathBuilder + Index + Copy
{
if v.is_none() {
return None;
}
let v = v.unwrap();
let from_index = v.get(p);
if from_index.is_some() {
return from_index;
}
let path_segment = p.build_path();
if path_segment.paths.len() > 1 {
return path_segment.apply(v);
}
return None;
}
fn path_mut<'tr, B>(v: Option<&'tr mut Value>, p: B) -> Option<&'tr mut Value>
where B: PathBuilder + Index + Copy
{
if v.is_none() {
return None;
}
let v = v.unwrap();
let target = v.get(p);
if target.is_some() {
return v.get_mut(p);
}
else {
let path_segment = p.build_path();
if path_segment.paths.len() > 1 {
return path_segment.apply_mut(v);
}
else {
return None;
}
}
}
struct PathSegment
{
paths: Vec<String>,
}
impl PathSegment
{
fn apply<'tr>(&self, v: &'tr Value) -> Option<&'tr Value> {
let mut target = Some(v);
for p in &self.paths {
if target.is_none() {
return None;
}
if p.is_empty() {
continue;
}
match target.unwrap() {
Value::Table(table) => { target = table.get(p); },
Value::Array(array) => {
if let Ok(index) = p.parse::<usize>() {
target = array.get(index);
}
},
_ => { return None; }
}
}
return target;
}
fn apply_mut<'tr>(&self, v: &'tr mut Value) -> Option<&'tr mut Value> {
let mut target = Some(v);
for p in &self.paths {
if target.is_none() {
return None;
}
if p.is_empty() {
continue;
}
match p.parse::<usize>() {
Ok(index) => { target = target.unwrap().get_mut(index); },
Err(_) => { target = target.unwrap().get_mut(p); },
}
}
return target;
}
}
trait PathBuilder {
fn build_path(&self) -> PathSegment {
PathSegment { paths: Vec::new() }
}
}
impl PathBuilder for &str {
fn build_path(&self) -> PathSegment {
let paths = self
.split(|c| c == '/' || c == '.')
.map(|s| s.to_string())
.collect();
PathSegment { paths }
}
}
impl PathBuilder for usize {}
pub trait PathOperator
{
fn path<'tr>(&'tr self) -> TomlPtr<'tr>;
fn pathto<'tr>(&'tr self, p: &str) -> TomlPtr<'tr>;
fn path_mut<'tr>(&'tr mut self) -> TomlPtrMut<'tr>;
fn pathto_mut<'tr>(&'tr mut self, p: &str) -> TomlPtrMut<'tr>;
}
impl PathOperator for Value
{
fn path<'tr>(&'tr self) -> TomlPtr<'tr> {
TomlPtr::path(self)
}
fn pathto<'tr>(&'tr self, p: &str) -> TomlPtr<'tr> {
let valop = p.build_path().apply(self);
TomlPtr { valop }
}
fn path_mut<'tr>(&'tr mut self) -> TomlPtrMut<'tr> {
TomlPtrMut::path(self)
}
fn pathto_mut<'tr>(&'tr mut self, p: &str) -> TomlPtrMut<'tr> {
let valop = p.build_path().apply_mut(self);
TomlPtrMut { valop }
}
}
#[derive(Copy, Clone)]
pub struct TomlPtr<'tr> {
valop: Option<&'tr Value>,
}
impl<'tr> TomlPtr<'tr> {
pub fn path(v: &'tr Value) -> Self {
Self { valop: Some(v) }
}
pub fn unpath(&self) -> &Option<&'tr Value> {
&self.valop
}
}
impl<'tr> Not for TomlPtr<'tr> {
type Output = bool;
fn not(self) -> Self::Output {
self.valop.is_none()
}
}
impl<'tr> Deref for TomlPtr<'tr>
{
type Target = Option<&'tr Value>;
fn deref(&self) -> &Self::Target {
self.unpath()
}
}
impl<'tr, Rhs> Div<Rhs> for TomlPtr<'tr>
where Rhs: PathBuilder + Index + Copy
{
type Output = Self;
fn div(self, rhs: Rhs) -> Self::Output {
TomlPtr { valop: path(self.valop, rhs) }
}
}
impl<'tr> BitOr<String> for TomlPtr<'tr>
{
type Output = String;
fn bitor(self, rhs: String) -> Self::Output {
if self.valop.is_none() {
return rhs;
}
match self.valop.unwrap().as_str() {
Some(s) => s.to_string(),
None => rhs
}
}
}
impl<'tr> BitOr<&'static str> for TomlPtr<'tr>
{
type Output = &'tr str;
fn bitor(self, rhs: &'static str) -> Self::Output {
match self.valop {
Some(v) => v.as_str().unwrap_or(rhs),
None => rhs,
}
}
}
impl<'tr> BitOr<i64> for TomlPtr<'tr>
{
type Output = i64;
fn bitor(self, rhs: i64) -> Self::Output {
match self.valop {
Some(v) => v.as_integer().unwrap_or(rhs),
None => rhs,
}
}
}
impl<'tr> BitOr<f64> for TomlPtr<'tr>
{
type Output = f64;
fn bitor(self, rhs: f64) -> Self::Output {
match self.valop {
Some(v) => v.as_float().unwrap_or(rhs),
None => rhs,
}
}
}
impl<'tr> BitOr<bool> for TomlPtr<'tr>
{
type Output = bool;
fn bitor(self, rhs: bool) -> Self::Output {
match self.valop {
Some(v) => v.as_bool().unwrap_or(rhs),
None => rhs,
}
}
}
pub struct TomlPtrMut<'tr> {
valop: Option<&'tr mut Value>,
}
impl<'tr> TomlPtrMut<'tr> {
pub fn path(v: &'tr mut Value) -> Self {
Self { valop: Some(v) }
}
pub fn unpath(&self) -> &Option<&'tr mut Value> {
&self.valop
}
pub fn assign<T>(&mut self, rhs: T) where Value: From<T> {
if let Some(ref mut v) = self.valop {
**v = Value::from(rhs);
}
}
fn none() -> Self {
Self { valop: None }
}
fn put_val<T>(v: &'tr mut Value, rhs: T) -> Self
where Value: From<T>
{
*v = Value::from(rhs);
Self::path(v)
}
fn put_string(&mut self, rhs: String) -> Self {
if self.valop.is_none() {
return Self::none();
}
let v = self.valop.take().unwrap();
if v.is_str() {
return Self::put_val(v, rhs);
}
return Self::none();
}
fn put_integer(&mut self, rhs: i64) -> Self {
if self.valop.is_none() {
return Self::none();
}
let v = self.valop.take().unwrap();
if v.is_integer() {
return Self::put_val(v, rhs);
}
return Self::none();
}
fn put_float(&mut self, rhs: f64) -> Self {
if self.valop.is_none() {
return Self::none();
}
let v = self.valop.take().unwrap();
if v.is_float() {
return Self::put_val(v, rhs);
}
return Self::none();
}
fn put_bool(&mut self, rhs: bool) -> Self {
if self.valop.is_none() {
return Self::none();
}
let v = self.valop.take().unwrap();
if v.is_bool() {
return Self::put_val(v, rhs);
}
return Self::none();
}
fn push_table<K: ToString, T>(&mut self, key: K, val: T) -> Self
where Value: From<T>
{
if self.valop.is_none() {
return Self::none();
}
let v = self.valop.take().unwrap();
if v.is_table() {
v.as_table_mut().unwrap().insert(key.to_string(), Value::from(val));
return Self::path(v);
}
return Self::none();
}
fn push_array<T>(&mut self, val: T) -> Self
where Value: From<T>
{
if self.valop.is_none() {
return Self::none();
}
let v = self.valop.take().unwrap();
if v.is_array() {
v.as_array_mut().unwrap().push(Value::from(val));
return Self::path(v);
}
return Self::none();
}
}
impl<'tr> Not for TomlPtrMut<'tr> {
type Output = bool;
fn not(self) -> Self::Output {
self.valop.is_none()
}
}
impl<'tr> Deref for TomlPtrMut<'tr> {
type Target = Option<&'tr mut Value>;
fn deref(&self) -> &Self::Target {
&self.valop
}
}
impl<'tr> DerefMut for TomlPtrMut<'tr> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.valop
}
}
impl<'tr, Rhs> Div<Rhs> for TomlPtrMut<'tr>
where Rhs: PathBuilder + Index + Copy
{
type Output = Self;
fn div(self, rhs: Rhs) -> Self::Output {
TomlPtrMut { valop: path_mut(self.valop, rhs) }
}
}
impl<'tr> BitOr<String> for TomlPtrMut<'tr>
{
type Output = String;
fn bitor(self, rhs: String) -> Self::Output {
if self.valop.is_none() {
return rhs;
}
match self.valop.unwrap().as_str() {
Some(s) => s.to_string(),
None => rhs
}
}
}
impl<'tr> BitOr<&'static str> for TomlPtrMut<'tr>
{
type Output = &'tr str;
fn bitor(self, rhs: &'static str) -> Self::Output {
match self.valop {
Some(v) => v.as_str().unwrap_or(rhs),
None => rhs,
}
}
}
impl<'tr> BitOr<i64> for TomlPtrMut<'tr>
{
type Output = i64;
fn bitor(self, rhs: i64) -> Self::Output {
match self.valop {
Some(v) => v.as_integer().unwrap_or(rhs),
None => rhs,
}
}
}
impl<'tr> BitOr<f64> for TomlPtrMut<'tr>
{
type Output = f64;
fn bitor(self, rhs: f64) -> Self::Output {
match self.valop {
Some(v) => v.as_float().unwrap_or(rhs),
None => rhs,
}
}
}
impl<'tr> BitOr<bool> for TomlPtrMut<'tr>
{
type Output = bool;
fn bitor(self, rhs: bool) -> Self::Output {
match self.valop {
Some(v) => v.as_bool().unwrap_or(rhs),
None => rhs,
}
}
}
impl<'tr> Shl<&str> for TomlPtrMut<'tr> {
type Output = Self;
fn shl(mut self, rhs: &str) -> Self::Output {
self.put_string(rhs.to_string())
}
}
impl<'tr> Shl<String> for TomlPtrMut<'tr> {
type Output = Self;
fn shl(mut self, rhs: String) -> Self::Output {
self.put_string(rhs)
}
}
impl<'tr> Shl<i64> for TomlPtrMut<'tr> {
type Output = Self;
fn shl(mut self, rhs: i64) -> Self::Output {
self.put_integer(rhs)
}
}
impl<'tr> Shl<f64> for TomlPtrMut<'tr> {
type Output = Self;
fn shl(mut self, rhs: f64) -> Self::Output {
self.put_float(rhs)
}
}
impl<'tr> Shl<bool> for TomlPtrMut<'tr> {
type Output = Self;
fn shl(mut self, rhs: bool) -> Self::Output {
self.put_bool(rhs)
}
}
impl<'tr, K: ToString, T> Shl<(K, T)> for TomlPtrMut<'tr> where Value: From<T>
{
type Output = Self;
fn shl(mut self, rhs: (K, T)) -> Self::Output {
self.push_table(rhs.0, rhs.1)
}
}
impl<'tr, T> Shl<(T,)> for TomlPtrMut<'tr> where Value: From<T>
{
type Output = Self;
fn shl(mut self, rhs: (T,)) -> Self::Output {
self.push_array(rhs.0)
}
}
impl<'tr, T: Copy> Shl<[T;1]> for TomlPtrMut<'tr> where Value: From<T>
{
type Output = Self;
fn shl(mut self, rhs: [T;1]) -> Self::Output {
self.push_array(rhs[0])
}
}
impl<'tr, T: Copy> Shl<&[T]> for TomlPtrMut<'tr> where Value: From<T>
{
type Output = Self;
fn shl(mut self, rhs: &[T]) -> Self::Output {
for item in rhs {
self = self.push_array(*item);
}
self
}
}
impl<'tr, T> ShlAssign<T> for TomlPtrMut<'tr> where Value: From<T>
{
fn shl_assign(&mut self, rhs: T) {
self.assign(rhs);
}
}
#[cfg(test)]
mod tests;