use crate::error::{JsonTy, ResolveError};
use core::cmp::Ordering;
use serde_json::Value;
use std::ops::{Deref, Index, IndexMut};
#[derive(Clone, Debug, PartialEq)]
pub enum Idx {
Array(usize),
Object(String),
}
impl Idx {
#[must_use]
pub fn is_array(&self) -> bool {
matches!(self, Idx::Array(_))
}
#[must_use]
pub fn is_object(&self) -> bool {
matches!(self, Idx::Object(_))
}
#[must_use]
pub fn as_array(&self) -> Option<usize> {
match self {
Idx::Array(u) => Some(*u),
_ => None,
}
}
#[must_use]
pub fn as_object(&self) -> Option<&str> {
match self {
Idx::Object(s) => Some(s),
_ => None,
}
}
}
impl From<Idx> for Value {
fn from(idx: Idx) -> Self {
match idx {
Idx::Array(i) => Value::from(i),
Idx::Object(str) => Value::from(str),
}
}
}
impl Index<&Idx> for Value {
type Output = Value;
fn index(&self, index: &Idx) -> &Self::Output {
match (self, index) {
(Value::Array(a), Idx::Array(idx)) => &a[*idx],
(Value::Object(o), Idx::Object(idx)) => &o[idx],
(val, idx) => panic!("Invalid index {:?} for value {:?}", val, idx),
}
}
}
impl IndexMut<&Idx> for Value {
fn index_mut(&mut self, index: &Idx) -> &mut Self::Output {
match (self, index) {
(Value::Array(a), Idx::Array(idx)) => &mut a[*idx],
(Value::Object(o), Idx::Object(idx)) => &mut o[idx],
(val, idx) => panic!("Invalid index {:?} for value {:?}", val, idx),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct IdxPath(Vec<Idx>);
impl IdxPath {
pub(crate) const fn new(indices: Vec<Idx>) -> IdxPath {
IdxPath(indices)
}
#[must_use]
pub fn raw_path(&self) -> &[Idx] {
&self.0
}
#[must_use]
pub fn remove(&self, n: usize) -> IdxPath {
assert!(
n <= self.len(),
"Cannot remove {} items from path, path is only {} items long",
n,
self.len()
);
IdxPath(self.0[..self.len() - n].to_owned())
}
pub fn resolve_on<'a>(&self, value: &'a Value) -> Result<&'a Value, ResolveError> {
let mut cur = value;
for idx in &self.0 {
match idx {
Idx::Array(i) => {
cur = cur
.as_array()
.ok_or_else(|| ResolveError::mismatched(JsonTy::Array, cur))?
.get(*i)
.ok_or_else(|| ResolveError::MissingIdx(idx.clone()))?;
}
Idx::Object(i) => {
cur = cur
.as_object()
.ok_or_else(|| ResolveError::mismatched(JsonTy::Object, cur))?
.get(i)
.ok_or_else(|| ResolveError::MissingIdx(idx.clone()))?;
}
}
}
Ok(cur)
}
pub fn resolve_on_mut<'a>(&self, value: &'a mut Value) -> Result<&'a mut Value, ResolveError> {
let mut cur = value;
for idx in &self.0 {
match idx {
Idx::Array(i) => {
let json_ty = JsonTy::from(&*cur);
cur = cur
.as_array_mut()
.ok_or(ResolveError::MismatchedTy {
expected: JsonTy::Array,
actual: json_ty,
})?
.get_mut(*i)
.ok_or_else(|| ResolveError::MissingIdx(idx.clone()))?;
}
Idx::Object(i) => {
let json_ty = JsonTy::from(&*cur);
cur = cur
.as_object_mut()
.ok_or(ResolveError::MismatchedTy {
expected: JsonTy::Array,
actual: json_ty,
})?
.get_mut(i)
.ok_or_else(|| ResolveError::MissingIdx(idx.clone()))?;
}
}
}
Ok(cur)
}
pub(crate) fn sort_specific_last(left: &IdxPath, right: &IdxPath) -> Ordering {
if left.is_empty() && right.is_empty() {
return Ordering::Equal;
}
match right.len().cmp(&left.len()) {
Ordering::Equal => {
let left = &left.0[left.len() - 1];
let right = &right.0[right.len() - 1];
left.as_array()
.and_then(|l| right.as_array().map(|r| (l, r)))
.map_or(Ordering::Equal, |(l, r)| r.cmp(&l))
}
other => other,
}
}
}
impl Deref for IdxPath {
type Target = [Idx];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<Vec<Idx>> for IdxPath {
fn from(path: Vec<Idx>) -> Self {
IdxPath(path)
}
}