use std::ops;
use table::{value, Item, Table};
use value::{InlineTable, Value};
use formatted::to_table_key_value;
use document::Document;
mod private {
pub trait Sealed {}
impl Sealed for usize {}
impl Sealed for str {}
impl Sealed for String {}
impl<'a, T: ?Sized> Sealed for &'a T
where
T: Sealed,
{
}
}
pub trait Index: private::Sealed {
#[doc(hidden)]
fn index<'v>(&self, v: &'v Item) -> Option<&'v Item>;
#[doc(hidden)]
fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item;
}
impl Index for usize {
fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
match *v {
Item::ArrayOfTables(ref aot) => aot.values.get(*self),
Item::Value(ref a) if a.is_array() => a.as_array().unwrap().values.get(*self),
_ => None,
}
}
fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
match *v {
Item::ArrayOfTables(ref mut vec) => {
vec.values.get_mut(*self).expect("index out of bounds")
}
Item::Value(ref mut a) if a.is_array() => a.as_array_mut()
.unwrap()
.values
.get_mut(*self)
.expect("index out of bounds"),
_ => panic!("cannot access index {} in {:?}", self, v),
}
}
}
impl Index for str {
fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
match *v {
Item::Table(ref t) => t.get(self),
Item::Value(ref v) if v.is_inline_table() => v.as_inline_table()
.and_then(|t| t.items.get(self).map(|kv| &kv.value)),
_ => None,
}
}
fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
if let Item::None = *v {
let mut t = InlineTable::default();
t.items
.insert(self.to_owned(), to_table_key_value(self, Item::None));
*v = value(Value::InlineTable(t));
}
match *v {
Item::Table(ref mut t) => t.entry(self).or_insert(Item::None),
Item::Value(ref mut v) if v.is_inline_table() => {
&mut v.as_inline_table_mut()
.unwrap()
.items
.entry(self.to_owned())
.or_insert(to_table_key_value(self, Item::None))
.value
}
_ => panic!("cannot access key {} in {:?}", self, v),
}
}
}
impl Index for String {
fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
self[..].index(v)
}
fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
self[..].index_or_insert(v)
}
}
impl<'a, T: ?Sized> Index for &'a T
where
T: Index,
{
fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
(**self).index(v)
}
fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
(**self).index_or_insert(v)
}
}
impl<I> ops::Index<I> for Item
where
I: Index,
{
type Output = Item;
fn index(&self, index: I) -> &Item {
static NONE: Item = Item::None;
index.index(self).unwrap_or(&NONE)
}
}
impl<I> ops::IndexMut<I> for Item
where
I: Index,
{
fn index_mut(&mut self, index: I) -> &mut Item {
index.index_or_insert(self)
}
}
impl<'s> ops::Index<&'s str> for Table {
type Output = Item;
fn index(&self, key: &'s str) -> &Item {
static NONE: Item = Item::None;
self.get(key).unwrap_or(&NONE)
}
}
impl<'s> ops::IndexMut<&'s str> for Table {
fn index_mut(&mut self, key: &'s str) -> &mut Item {
self.entry(key).or_insert(Item::None)
}
}
impl<'s> ops::Index<&'s str> for Document {
type Output = Item;
fn index(&self, key: &'s str) -> &Item {
self.root.index(key)
}
}
impl<'s> ops::IndexMut<&'s str> for Document {
fn index_mut(&mut self, key: &'s str) -> &mut Item {
self.root.index_mut(key)
}
}