use std::fmt;
use crate::spec::function::FunctionRegistry;
use crate::spec::query::Queryable;
use crate::spec::select_wildcard;
use crate::spec::selector::Selector;
use crate::ConcreteVariantArray;
use crate::ConcreteVariantObject;
use crate::LocatedNode;
use crate::NormalizedPath;
use crate::VariantValue;
#[derive(Debug, Clone)]
pub struct QuerySegment {
pub kind: QuerySegmentKind,
pub segment: Segment,
}
impl QuerySegment {
pub fn is_child(&self) -> bool {
matches!(self.kind, QuerySegmentKind::Child)
}
pub fn is_descendent(&self) -> bool {
!self.is_child()
}
}
impl fmt::Display for QuerySegment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if matches!(self.kind, QuerySegmentKind::Descendant) {
write!(f, "..")?;
}
write!(f, "{}", self.segment)
}
}
impl Queryable for QuerySegment {
fn query<'b, T: VariantValue, Registry: FunctionRegistry<Value = T>>(
&self,
current: &'b T,
root: &'b T,
registry: &Registry,
) -> Vec<&'b T> {
let mut query = self.segment.query(current, root, registry);
if matches!(self.kind, QuerySegmentKind::Descendant) {
query.append(&mut descend(self, current, root, registry));
}
query
}
fn query_located<'b, T: VariantValue, Registry: FunctionRegistry<Value = T>>(
&self,
current: &'b T,
root: &'b T,
registry: &Registry,
parent: NormalizedPath<'b>,
) -> Vec<LocatedNode<'b, T>> {
if matches!(self.kind, QuerySegmentKind::Descendant) {
let mut result = self
.segment
.query_located(current, root, registry, parent.clone());
result.append(&mut descend_paths(self, current, root, registry, parent));
result
} else {
self.segment.query_located(current, root, registry, parent)
}
}
}
fn descend<'b, T: VariantValue, Registry: FunctionRegistry<Value = T>>(
segment: &QuerySegment,
current: &'b T,
root: &'b T,
registry: &Registry,
) -> Vec<&'b T> {
let mut query = Vec::new();
if let Some(list) = current.as_array() {
for v in list.iter() {
query.append(&mut segment.query(v, root, registry));
}
} else if let Some(obj) = current.as_object() {
for v in obj.values() {
query.append(&mut segment.query(v, root, registry));
}
}
query
}
fn descend_paths<'b, T: VariantValue, Registry: FunctionRegistry<Value = T>>(
segment: &QuerySegment,
current: &'b T,
root: &'b T,
registry: &Registry,
parent: NormalizedPath<'b>,
) -> Vec<LocatedNode<'b, T>> {
let mut result = Vec::new();
if let Some(list) = current.as_array() {
for (i, v) in list.iter().enumerate() {
result.append(&mut segment.query_located(v, root, registry, parent.clone_and_push(i)));
}
} else if let Some(obj) = current.as_object() {
for (k, v) in obj.iter() {
result.append(&mut segment.query_located(v, root, registry, parent.clone_and_push(k)));
}
}
result
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum QuerySegmentKind {
Child,
Descendant,
}
#[derive(Debug, Clone)]
pub enum Segment {
LongHand(Vec<Selector>),
DotName(String),
Wildcard,
}
impl Segment {
pub fn is_singular(&self) -> bool {
match self {
Segment::LongHand(selectors) => {
if selectors.len() > 1 {
return false;
}
if let Some(s) = selectors.first() {
s.is_singular()
} else {
true
}
}
Segment::DotName(_) => true,
Segment::Wildcard => false,
}
}
pub fn as_long_hand(&self) -> Option<&[Selector]> {
match self {
Segment::LongHand(v) => Some(v.as_slice()),
_ => None,
}
}
pub fn as_dot_name(&self) -> Option<&str> {
match self {
Segment::DotName(s) => Some(s.as_str()),
_ => None,
}
}
}
impl fmt::Display for Segment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Segment::LongHand(selectors) => {
write!(f, "[")?;
for (i, s) in selectors.iter().enumerate() {
write!(
f,
"{s}{comma}",
comma = if i == selectors.len() - 1 { "" } else { "," }
)?;
}
write!(f, "]")?;
}
Segment::DotName(name) => write!(f, ".{name}")?,
Segment::Wildcard => write!(f, ".*")?,
}
Ok(())
}
}
impl Queryable for Segment {
fn query<'b, T: VariantValue, Registry: FunctionRegistry<Value = T>>(
&self,
current: &'b T,
root: &'b T,
registry: &Registry,
) -> Vec<&'b T> {
let mut result = Vec::new();
match self {
Segment::LongHand(selectors) => {
for selector in selectors {
result.append(&mut selector.query(current, root, registry));
}
}
Segment::DotName(key) => {
if let Some(obj) = current.as_object() {
if let Some(v) = obj.get(key) {
result.push(v);
}
}
}
Segment::Wildcard => select_wildcard(&mut result, current),
}
result
}
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>> {
let mut result = vec![];
match self {
Segment::LongHand(selectors) => {
for s in selectors {
result.append(&mut s.query_located(current, root, registry, parent.clone()));
}
}
Segment::DotName(name) => {
if let Some((k, v)) = current.as_object().and_then(|o| o.get_key_value(name)) {
parent.push(k);
result.push(LocatedNode::new(parent, v));
}
}
Segment::Wildcard => {
if let Some(list) = current.as_array() {
for (i, v) in list.iter().enumerate() {
result.push(LocatedNode::new(parent.clone_and_push(i), v));
}
} else if let Some(obj) = current.as_object() {
for (k, v) in obj.iter() {
result.push(LocatedNode::new(parent.clone_and_push(k), v));
}
}
}
}
result
}
}