ajson 0.3.1

JSON Parser for Rust - Get JSON values quickly
Documentation
use std::fmt;

use super::{parser, Path, DEFAULT_NONE_PATH};
#[cfg(feature = "wild")]
use crate::wild;
use crate::{element::Element, Result, Value};

pub const DEFAULT_NONE_QUERY: Query = Query {
    on:    false,
    path:  &[],
    key:   None,
    op:    None,
    value: None,
    all:   false,
};

#[derive(Debug, PartialEq)]
pub enum QueryValue<'a> {
    String(&'a [u8]),
    F64(f64),
    Boolean(bool),
    Null,
    NotExist,
}

impl<'a> QueryValue<'a> {
    pub fn exists(&self) -> bool {
        *self != QueryValue::NotExist
    }
}

pub struct Query<'a> {
    pub on:    bool,
    pub path:  &'a [u8],
    pub key:   Option<Box<Path<'a>>>,
    pub op:    Option<&'a str>,
    pub value: Option<QueryValue<'a>>,
    pub all:   bool,
}

impl<'a> fmt::Debug for Query<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Query")?;
        write!(f, " on={}", self.on)?;
        write!(f, " all={}", self.all)?;
        if !self.path.is_empty() {
            write!(f, " path=`{}`", unsafe {
                std::str::from_utf8_unchecked(self.path)
            })?;
        }
        if self.key.is_some() {
            write!(f, " key=`{:?}`", self.key.as_ref().unwrap())?;
        }
        if self.op.is_some() {
            write!(f, " op=`{}`", self.op.as_ref().unwrap())?;
        }
        if self.value.is_some() {
            write!(f, " value=`{:?}`", self.value.as_ref().unwrap())?;
        }
        write!(f, ">")
    }
}

impl<'a> Query<'a> {
    pub fn empty() -> Query<'a> {
        Query {
            on:    false,
            path:  &[],
            key:   None,
            op:    None,
            value: None,
            all:   false,
        }
    }

    pub fn has_path(&self) -> bool {
        !self.path.is_empty()
    }

    pub fn get_path(&self) -> Result<Path> {
        match self.has_path() {
            true => parser::parse(self.path),
            false => Ok(Path::default()),
        }
    }

    pub fn has_key(&self) -> bool {
        self.key.is_some()
    }

    pub fn get_key(&self) -> &Path {
        match self.key {
            Some(_) => self.key.as_ref().unwrap(),
            None => &DEFAULT_NONE_PATH,
        }
    }

    pub fn set_path(&mut self, v: &'a [u8]) {
        self.path = v;
    }

    pub fn set_op(&mut self, op: &'a str) {
        self.op = Some(op);
    }

    pub fn set_val(&mut self, val: QueryValue<'a>) {
        self.value = Some(val);
    }

    pub fn set_all(&mut self, all: bool) {
        self.all = all;
    }

    pub fn set_key(&mut self, key: Path<'a>) {
        if key.ok {
            self.key = Some(Box::new(key));
        }
    }

    pub fn set_on(&mut self, on: bool) {
        self.on = on;
    }

    pub fn match_element(&self, element: &Element) -> bool {
        if self.value.is_none() {
            return true;
        }

        let op = match &self.op {
            Some(ref s) => s,
            None => return true,
        };

        let target = self.value.as_ref().unwrap();
        let v = element.to_value();

        match *target {
            QueryValue::String(q) => match v {
                Value::String(ref s) => match *op {
                    "==" => s.as_bytes() == q,
                    "=" => s.as_bytes() == q,
                    "!=" => s.as_bytes() != q,
                    ">" => s.as_bytes() > q,
                    ">=" => s.as_bytes() >= q,
                    "<" => s.as_bytes() < q,
                    "<=" => s.as_bytes() <= q,
                    #[cfg(feature = "wild")]
                    "%" => wild::is_match_u8(s.as_bytes(), q),
                    #[cfg(feature = "wild")]
                    "!%" => !wild::is_match_u8(s.as_bytes(), q),
                    _ => false,
                },
                _ => false,
            },

            QueryValue::F64(q) => match v {
                Value::Number(n) => match *op {
                    "=" => (n.to_f64() - q).abs() < f64::EPSILON,
                    "==" => (n.to_f64() - q).abs() < f64::EPSILON,
                    "!=" => (n.to_f64() - q).abs() > f64::EPSILON,
                    "<" => n.to_f64() < q,
                    "<=" => n.to_f64() <= q,
                    ">" => n.to_f64() > q,
                    ">=" => n.to_f64() >= q,
                    _ => false,
                },
                _ => false,
            },

            QueryValue::Boolean(q) => match v {
                Value::Boolean(b) => match *op {
                    "=" => b == q,
                    "==" => b == q,
                    "!=" => b != q,
                    _ => false,
                },
                _ => false,
            },

            QueryValue::Null => match *op {
                "=" => v == Value::Null,
                "==" => v == Value::Null,
                "!=" => v != Value::Null,
                _ => false,
            },
            _ => false,
        }
    }
}