use crate::{Mapping, Value};
use std::fmt;
use std::ops;
pub trait Index: private::Sealed {
#[doc(hidden)]
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>;
#[doc(hidden)]
fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>;
#[doc(hidden)]
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value;
}
impl Index for usize {
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
match v {
Value::Sequence(vec) => vec.get(*self),
Value::Mapping(vec) => vec.get(&Value::Number((*self).into())),
_ => None,
}
}
fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
match v {
Value::Sequence(vec) => vec.get_mut(*self),
Value::Mapping(vec) => vec.get_mut(&Value::Number((*self).into())),
_ => None,
}
}
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
match v {
Value::Sequence(vec) => {
let len = vec.len();
vec.get_mut(*self).unwrap_or_else(|| {
panic!(
"cannot access index {} of YAML sequence of length {}",
self, len
)
})
}
Value::Mapping(map) => {
let n = Value::Number((*self).into());
if !map.contains_key(&n) {
map.insert(n.clone(), Value::Null);
}
map.get_mut(&n).unwrap()
}
_ => panic!("cannot access index {} of YAML {}", self, Type(v)),
}
}
}
impl Index for Value {
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
match v {
Value::Mapping(map) => map.get(self),
_ => None,
}
}
fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
match v {
Value::Mapping(map) => map.get_mut(self),
_ => None,
}
}
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
if let Value::Null = *v {
let mut map = Mapping::new();
map.insert(self.clone(), Value::Null);
*v = Value::Mapping(map);
}
match v {
Value::Mapping(map) => {
if !map.contains_key(self) {
map.insert(self.clone(), Value::Null);
}
map.get_mut(self).unwrap()
}
_ => panic!("cannot access key {:?} in YAML {}", self, Type(v)),
}
}
}
impl Index for str {
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
Value::String(self.into()).index_into(v)
}
fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
Value::String(self.into()).index_into_mut(v)
}
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
Value::String(self.into()).index_or_insert(v)
}
}
impl Index for String {
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
Value::String(self.clone()).index_into(v)
}
fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
Value::String(self.clone()).index_into_mut(v)
}
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
Value::String(self.clone()).index_or_insert(v)
}
}
impl<'a, T: ?Sized> Index for &'a T
where
T: Index,
{
fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
(**self).index_into(v)
}
fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
(**self).index_into_mut(v)
}
fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
(**self).index_or_insert(v)
}
}
mod private {
pub trait Sealed {}
impl Sealed for usize {}
impl Sealed for str {}
impl Sealed for String {}
impl Sealed for super::Value {}
impl<'a, T: ?Sized> Sealed for &'a T where T: Sealed {}
}
struct Type<'a>(&'a Value);
impl<'a> fmt::Display for Type<'a> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
Value::Null => formatter.write_str("null"),
Value::Bool(_) => formatter.write_str("boolean"),
Value::Number(_) => formatter.write_str("number"),
Value::String(_) => formatter.write_str("string"),
Value::Sequence(_) => formatter.write_str("sequence"),
Value::Mapping(_) => formatter.write_str("mapping"),
}
}
}
impl<I> ops::Index<I> for Value
where
I: Index,
{
type Output = Value;
fn index(&self, index: I) -> &Value {
static NULL: Value = Value::Null;
index.index_into(self).unwrap_or(&NULL)
}
}
impl<I> ops::IndexMut<I> for Value
where
I: Index,
{
fn index_mut(&mut self, index: I) -> &mut Value {
index.index_or_insert(self)
}
}