Skip to content

Commit

Permalink
simplify python_parse
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelcolvin committed Sep 20, 2023
1 parent 835f33f commit 78ea49a
Showing 1 changed file with 75 additions and 64 deletions.
139 changes: 75 additions & 64 deletions src/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,82 +6,93 @@ use crate::string_decoder::Tape;
use crate::{FilePosition, JsonError, NumberAny, NumberDecoder, NumberInt, Parser, Peak, StringDecoder};

pub fn python_parse(py: Python, data: &[u8]) -> PyResult<PyObject> {
let mut parser = Parser::new(data);
let mut python_parser = PythonParser {
parser: Parser::new(data),
tape: Tape::default(),
data,
};

let mje = |e: JsonError| map_json_error(data, e);

let mut tape = Tape::default();
let peak = parser.peak().map_err(mje)?;
let v = py_take_value(py, peak, &mut parser, &mut tape, data)?;
parser.finish().map_err(mje)?;
let peak = python_parser.parser.peak().map_err(mje)?;
let v = python_parser.py_take_value(py, peak)?;
python_parser.parser.finish().map_err(mje)?;
Ok(v)
}

pub(crate) fn py_take_value(
py: Python,
peak: Peak,
parser: &mut Parser,
tape: &mut Tape,
data: &[u8],
) -> PyResult<PyObject> {
let mje = |e: JsonError| map_json_error(data, e);
match peak {
Peak::True => {
parser.consume_true().map_err(mje)?;
Ok(true.to_object(py))
}
Peak::False => {
parser.consume_false().map_err(mje)?;
Ok(false.to_object(py))
}
Peak::Null => {
parser.consume_null().map_err(mje)?;
Ok(py.None())
}
Peak::String => {
let s = parser.consume_string::<StringDecoder>(tape).map_err(mje)?;
Ok(PyString::new(py, s).to_object(py))
}
Peak::Num(first) => {
let n = parser.consume_number::<NumberDecoder<NumberAny>>(first).map_err(mje)?;
match n {
NumberAny::Int(NumberInt::Int(int)) => Ok(int.to_object(py)),
NumberAny::Int(NumberInt::BigInt(big_int)) => Ok(big_int.to_object(py)),
NumberAny::Int(NumberInt::Zero) => Ok(0.to_object(py)),
NumberAny::Float(float) => Ok(float.to_object(py)),
struct PythonParser<'j> {
parser: Parser<'j>,
tape: Tape,
data: &'j [u8],
}

impl<'j> PythonParser<'j> {
fn py_take_value(&mut self, py: Python, peak: Peak) -> PyResult<PyObject> {
let mje = |e: JsonError| map_json_error(self.data, e);
match peak {
Peak::True => {
self.parser.consume_true().map_err(mje)?;
Ok(true.to_object(py))
}
}
Peak::Array => {
// TODO we should create the list with the correct size and insert directly into it
let mut vec = Vec::new();
if let Some(peak_first) = parser.array_first().map_err(mje)? {
let v = py_take_value(py, peak_first, parser, tape, data)?;
vec.push(v);
while parser.array_step().map_err(mje)? {
let peak = parser.peak().map_err(mje)?;
let v = py_take_value(py, peak, parser, tape, data)?;
vec.push(v);
Peak::False => {
self.parser.consume_false().map_err(mje)?;
Ok(false.to_object(py))
}
Peak::Null => {
self.parser.consume_null().map_err(mje)?;
Ok(py.None())
}
Peak::String => {
let s = self
.parser
.consume_string::<StringDecoder>(&mut self.tape)
.map_err(mje)?;
Ok(PyString::new(py, s).to_object(py))
}
Peak::Num(first) => {
let n = self
.parser
.consume_number::<NumberDecoder<NumberAny>>(first)
.map_err(mje)?;
match n {
NumberAny::Int(NumberInt::Int(int)) => Ok(int.to_object(py)),
NumberAny::Int(NumberInt::BigInt(big_int)) => Ok(big_int.to_object(py)),
NumberAny::Int(NumberInt::Zero) => Ok(0.to_object(py)),

Check warning on line 60 in src/python.rs

View check run for this annotation

Codecov / codecov/patch

src/python.rs#L60

Added line #L60 was not covered by tests
NumberAny::Float(float) => Ok(float.to_object(py)),
}
}
let list = PyList::new(py, vec);
Ok(list.to_object(py))
}
Peak::Object => {
let dict = PyDict::new(py);
if let Some(first_key) = parser.object_first::<StringDecoder>(tape).map_err(mje)? {
let first_key = PyString::new(py, first_key);
let peak = parser.peak().map_err(mje)?;
let first_value = py_take_value(py, peak, parser, tape, data)?;
dict.set_item(first_key, first_value)?;
while let Some(key) = parser.object_step::<StringDecoder>(tape).map_err(mje)? {
let key = PyString::new(py, key);
let peak = parser.peak().map_err(mje)?;
let value = py_take_value(py, peak, parser, tape, data)?;
dict.set_item(key, value)?;
Peak::Array => {
// TODO we should create the list with the correct size and insert directly into it
let mut vec = Vec::new();
if let Some(peak_first) = self.parser.array_first().map_err(mje)? {
let v = self.py_take_value(py, peak_first)?;
vec.push(v);
while self.parser.array_step().map_err(mje)? {
let peak = self.parser.peak().map_err(mje)?;
let v = self.py_take_value(py, peak)?;
vec.push(v);
}
}

Check warning on line 75 in src/python.rs

View check run for this annotation

Codecov / codecov/patch

src/python.rs#L75

Added line #L75 was not covered by tests
let list = PyList::new(py, vec);
Ok(list.to_object(py))
}
Peak::Object => {
let dict = PyDict::new(py);
if let Some(first_key) = self.parser.object_first::<StringDecoder>(&mut self.tape).map_err(mje)? {
let first_key = PyString::new(py, first_key);
let peak = self.parser.peak().map_err(mje)?;
let first_value = self.py_take_value(py, peak)?;
dict.set_item(first_key, first_value)?;
while let Some(key) = self.parser.object_step::<StringDecoder>(&mut self.tape).map_err(mje)? {
let key = PyString::new(py, key);
let peak = self.parser.peak().map_err(mje)?;
let value = self.py_take_value(py, peak)?;
dict.set_item(key, value)?;
}
}

Check warning on line 92 in src/python.rs

View check run for this annotation

Codecov / codecov/patch

src/python.rs#L92

Added line #L92 was not covered by tests

Ok(dict.to_object(py))
Ok(dict.to_object(py))
}
}
}
}
Expand Down

0 comments on commit 78ea49a

Please sign in to comment.