Skip to content

Commit 3b2db89

Browse files
authored
Merge pull request #2245 from RustPython/coolreader18/serde_json-opt
Make serde_json an optional optimization for the json module
2 parents 48bb335 + a950aa6 commit 3b2db89

6 files changed

Lines changed: 69 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/json/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@
107107
from .encoder import JSONEncoder
108108
import codecs
109109

110+
_use_serde_json = False
111+
def use_serde_json(x=True):
112+
global _use_serde_json
113+
_use_serde_json = x
114+
110115
_default_encoder = JSONEncoder(
111116
skipkeys=False,
112117
ensure_ascii=True,
@@ -354,6 +359,13 @@ def loads(s, *, cls=None, object_hook=None, parse_float=None,
354359
if (cls is None and object_hook is None and
355360
parse_int is None and parse_float is None and
356361
parse_constant is None and object_pairs_hook is None and not kw):
362+
if _use_serde_json:
363+
try:
364+
import _serde_json
365+
except ImportError:
366+
pass
367+
else:
368+
return _serde_json.decode(s)
357369
return _default_decoder.decode(s)
358370
if cls is None:
359371
cls = JSONDecoder

Lib/json/decoder.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@ class JSONDecodeError(ValueError):
2727
colno: The column corresponding to pos
2828
2929
"""
30+
# RUSTPYTHON SPECIFIC
31+
@classmethod
32+
def _from_serde(cls, msg, doc, line, col):
33+
pos = 0
34+
# 0-indexed
35+
line -= 1
36+
col -= 1
37+
while line > 0:
38+
i = doc.index('\n', pos)
39+
line -= 1
40+
pos = i
41+
pos += col
42+
return cls(msg, doc, pos)
43+
44+
3045
# Note that this exception is used from _json
3146
def __init__(self, msg, doc, pos):
3247
lineno = doc.count('\n', 0, pos) + 1

vm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ rustpython-bytecode = { path = "../bytecode", version = "0.1.2" }
4747
rustpython-jit = { path = "../jit", optional = true, version = "0.1.2" }
4848
rustpython-pylib = { path = "pylib-crate", optional = true, version = "0.1.0" }
4949
serde = { version = "1.0.66", features = ["derive"] }
50+
serde_json = "1.0"
5051
byteorder = "1.2.6"
5152
regex = "1"
5253
rustc_version_runtime = "0.1.*"

vm/src/stdlib/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ mod platform;
2626
mod pystruct;
2727
mod random;
2828
mod re;
29+
mod serde_json;
2930
#[cfg(not(target_arch = "wasm32"))]
3031
pub mod socket;
3132
mod string;
@@ -91,6 +92,7 @@ pub fn get_module_inits() -> HashMap<String, StdlibInitFunc> {
9192
"_platform".to_owned() => Box::new(platform::make_module),
9293
"regex_crate".to_owned() => Box::new(re::make_module),
9394
"_random".to_owned() => Box::new(random::make_module),
95+
"_serde_json".to_owned() => Box::new(serde_json::make_module),
9496
"_string".to_owned() => Box::new(string::make_module),
9597
"_struct".to_owned() => Box::new(pystruct::make_module),
9698
"time".to_owned() => Box::new(time_module::make_module),

vm/src/stdlib/serde_json.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
pub(crate) use _serde_json::make_module;
2+
3+
#[pymodule]
4+
mod _serde_json {
5+
use crate::common::borrow::BorrowValue;
6+
use crate::obj::objstr::PyStrRef;
7+
use crate::py_serde;
8+
use crate::pyobject::{PyResult, TryFromObject};
9+
use crate::VirtualMachine;
10+
11+
#[pyfunction]
12+
fn decode(s: PyStrRef, vm: &VirtualMachine) -> PyResult {
13+
let res = (|| -> serde_json::Result<_> {
14+
let mut de = serde_json::Deserializer::from_str(s.borrow_value());
15+
let res = py_serde::deserialize(vm, &mut de)?;
16+
de.end()?;
17+
Ok(res)
18+
})();
19+
20+
res.or_else(|err| {
21+
let decode_error = vm.try_class("json", "JSONDecodeError")?;
22+
let from_serde = vm.get_attribute(decode_error.into_object(), "_from_serde")?;
23+
let mut err_msg = err.to_string();
24+
let pos = err_msg.rfind(" at line ").unwrap();
25+
err_msg.truncate(pos);
26+
let decode_error = vm.invoke(
27+
&from_serde,
28+
vec![
29+
vm.ctx.new_str(err_msg),
30+
s.into_object(),
31+
vm.ctx.new_int(err.line()),
32+
vm.ctx.new_int(err.column()),
33+
],
34+
)?;
35+
TryFromObject::try_from_object(vm, decode_error)
36+
})
37+
}
38+
}

0 commit comments

Comments
 (0)