use std::fmt;
use num_traits::ToPrimitive;
use crate::spec::function::FunctionRegistry;
use crate::spec::query::Queryable;
use crate::ConcreteVariantArray;
use crate::LocatedNode;
use crate::NormalizedPath;
use crate::VariantValue;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Index {
index: i64,
}
impl Index {
pub fn new(index: i64) -> Self {
Self { index }
}
pub fn index(&self) -> i64 {
self.index
}
}
impl fmt::Display for Index {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.index)
}
}
fn resolve_index(index: i64, len: usize) -> Option<usize> {
let index = if index >= 0 {
index.to_usize()?
} else {
let index = len.to_i64().unwrap_or(i64::MAX) + index;
index.to_usize()?
};
if index < len {
Some(index)
} else {
None
}
}
impl Queryable for Index {
fn query<'b, T: VariantValue, Registry: FunctionRegistry<Value = T>>(
&self,
current: &'b T,
_root: &'b T,
_registry: &Registry,
) -> Vec<&'b T> {
current
.as_array()
.and_then(|list| {
let index = resolve_index(self.index, list.len())?;
list.get(index)
})
.map(|node| vec![node])
.unwrap_or_default()
}
fn query_located<'b, T: VariantValue, Registry: FunctionRegistry<Value = T>>(
&self,
current: &'b T,
_root: &'b T,
_registry: &Registry,
mut parent: NormalizedPath<'b>,
) -> Vec<LocatedNode<'b, T>> {
current
.as_array()
.and_then(|list| {
let index = resolve_index(self.index, list.len())?;
list.get(index).map(|node| (index, node))
})
.map(|(i, node)| {
parent.push(i);
vec![LocatedNode::new(parent, node)]
})
.unwrap_or_default()
}
}