use std::{io::Read, rc::Rc};
use crate::{
json_value::JsonValue,
processor::Context,
reader::Reader,
selection::{Get, Result, SelectionParseError},
};
enum SingleExtract {
ByKey(String),
ByIndex(usize),
}
enum ExtractFromInput {
Root,
Element(Vec<SingleExtract>),
}
struct Extract {
number_of_parents: usize,
extract_from_input: ExtractFromInput,
}
impl ExtractFromInput {
fn extract(&self, input: &JsonValue) -> Option<JsonValue> {
match self {
ExtractFromInput::Root => Some(input.clone()),
ExtractFromInput::Element(es) => {
let mut val = Some(input.clone());
for e in es {
match val {
None => {
break;
}
Some(value) => {
val = e.extract(&value);
}
}
}
val
}
}
}
}
impl Get for Extract {
fn get(&self, value: &Context) -> Option<JsonValue> {
let input = value.parent_input(self.number_of_parents);
self.extract_from_input.extract(input)
}
}
pub fn parse_extractor<R: Read>(reader: &mut Reader<R>) -> Result<Rc<dyn Get>> {
let number_of_parents = read_number_of_parents(reader)?;
let extract_from_input = ExtractFromInput::parse(reader)?;
Ok(Rc::new(Extract {
number_of_parents,
extract_from_input,
}))
}
fn read_number_of_parents<R: Read>(reader: &mut Reader<R>) -> Result<usize> {
let mut size = 0;
loop {
match reader.peek()? {
Some(b'^') => {
size += 1;
reader.next()?;
}
_ => {
return Ok(size);
}
}
}
}
pub fn root() -> Rc<dyn Get> {
Rc::new(Extract {
extract_from_input: ExtractFromInput::Root,
number_of_parents: 0,
})
}
impl ExtractFromInput {
fn parse<R: Read>(reader: &mut Reader<R>) -> Result<Self> {
let mut ext = vec![];
loop {
match reader.peek()? {
Some(b'.') => {
let key = Self::read_extract_key(reader)?;
if key.is_empty() {
return if ext.is_empty() {
Ok(ExtractFromInput::Root)
} else {
Err(SelectionParseError::MissingKey(reader.where_am_i()))
};
}
let es = SingleExtract::ByKey(key);
ext.push(es);
}
Some(b'#') => match Self::read_extract_index(reader)? {
None => {
return if ext.is_empty() {
Ok(ExtractFromInput::Root)
} else {
Err(SelectionParseError::MissingKey(reader.where_am_i()))
};
}
Some(index) => {
let es = SingleExtract::ByIndex(index);
ext.push(es);
}
},
_ => {
return Ok(ExtractFromInput::Element(ext));
}
}
}
}
fn read_extract_key<R: Read>(reader: &mut Reader<R>) -> Result<String> {
let mut buf = Vec::new();
loop {
match reader.next()? {
None => {
break;
}
Some(ch) => {
if ch.is_ascii_whitespace()
|| ch == b'.'
|| ch == b','
|| ch == b'='
|| ch == b'('
|| ch == b')'
|| ch.is_ascii_control()
|| ch == b'\"'
|| ch == b']'
|| ch == b'['
|| ch == b'{'
|| ch == b'}'
|| ch == b'#'
{
break;
}
buf.push(ch);
}
}
}
let str = String::from_utf8(buf)?;
Ok(str)
}
fn read_extract_index<R: Read>(reader: &mut Reader<R>) -> Result<Option<usize>> {
reader.next()?;
let mut digits = Vec::new();
reader.read_digits(&mut digits)?;
let str = String::from_utf8(digits)?;
if str.is_empty() {
return Ok(None);
}
let number = str.parse::<usize>()?;
Ok(Some(number))
}
}
impl SingleExtract {
fn extract(&self, value: &JsonValue) -> Option<JsonValue> {
match value {
JsonValue::Array(list) => match self {
SingleExtract::ByIndex(index) => list.get(*index).cloned(),
_ => None,
},
JsonValue::Object(map) => match self {
SingleExtract::ByKey(key) => map.get(key).cloned(),
_ => None,
},
_ => None,
}
}
}