Skip to content

Commit

Permalink
Simplify, refactor misc
Browse files Browse the repository at this point in the history
  • Loading branch information
ijl committed May 11, 2019
1 parent 73a6b64 commit 036ae84
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 54 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ itoa = { version = "0.4", default_features = false }
pyo3 = { git = "https://github.com/PyO3/pyo3.git", rev = "77f0974dafb8819b95437e74da581d7d9c41a1ad", features = ["extension-module"]}
serde = { version = "1", default_features = false }
serde_json = { git = "https://github.com/ijl/json.git", rev = "2c0c55b628c9177543283a1535549e1dcb6a870a", default_features = false, features = ["num_lexical"] }
smallvec = { version = "0.6", default_features = false, features = ["union"] }
smallvec = { version = "0.6", default_features = false, features = ["union", "std", "specialization"] }

[profile.release]
codegen-units = 1
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,9 @@ can be configured to raise a `JSONEncodeError` on values exceeding the
>>> orjson.dumps(9007199254740992)
b'9007199254740992'
>>> orjson.dumps(9007199254740992, option=orjson.OPT_STRICT_INTEGER)
JSONEncodeError: Integer exceeds 53-bit max
JSONEncodeError: Integer exceeds 53-bit range
>>> orjson.dumps(-9007199254740992, option=orjson.OPT_STRICT_INTEGER)
JSONEncodeError: Integer exceeds 53-bit max
JSONEncodeError: Integer exceeds 53-bit range
```

### float
Expand Down
23 changes: 10 additions & 13 deletions src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ use std::borrow::Cow;
use std::fmt;
use std::marker::PhantomData;
use std::os::raw::c_char;
use std::ptr::NonNull;

pub fn deserialize(py: Python, ptr: *mut pyo3::ffi::PyObject) -> PyResult<PyObject> {
pub fn deserialize(ptr: *mut pyo3::ffi::PyObject) -> PyResult<NonNull<pyo3::ffi::PyObject>> {
let obj_type_ptr = unsafe { (*ptr).ob_type };
let data: Cow<str>;
if unsafe { obj_type_ptr == typeref::STR_PTR } {
Expand All @@ -19,21 +20,17 @@ pub fn deserialize(py: Python, ptr: *mut pyo3::ffi::PyObject) -> PyResult<PyObje
if unsafe { std::intrinsics::unlikely(uni.is_null()) } {
return Err(JSONDecodeError::py_err((INVALID_STR, "", 0)));
}
data = unsafe {
Cow::Borrowed(std::str::from_utf8_unchecked(std::slice::from_raw_parts(
uni,
str_size as usize,
)))
};
data = Cow::Borrowed(unsafe {
std::str::from_utf8_unchecked(std::slice::from_raw_parts(uni, str_size as usize))
});
} else if unsafe { obj_type_ptr == typeref::BYTES_PTR } {
let buffer = unsafe { pyo3::ffi::PyBytes_AsString(ptr) as *const u8 };
let length = unsafe { pyo3::ffi::PyBytes_Size(ptr) as usize };
let slice = unsafe { std::slice::from_raw_parts(buffer, length) };
if encoding_rs::Encoding::utf8_valid_up_to(slice) == length {
data = Cow::Borrowed(unsafe { std::str::from_utf8_unchecked(slice) });
} else {
if encoding_rs::Encoding::utf8_valid_up_to(slice) != length {
return Err(JSONDecodeError::py_err((INVALID_STR, "", 0)));
}
data = Cow::Borrowed(unsafe { std::str::from_utf8_unchecked(slice) });
} else {
return Err(JSONDecodeError::py_err((
"Input must be str or bytes",
Expand All @@ -45,11 +42,11 @@ pub fn deserialize(py: Python, ptr: *mut pyo3::ffi::PyObject) -> PyResult<PyObje
let seed = JsonValue {};
let mut deserializer = serde_json::Deserializer::from_str(&data);
match seed.deserialize(&mut deserializer) {
Ok(py_ptr) => {
Ok(obj) => {
deserializer
.end()
.map_err(|e| JSONDecodeError::py_err((e.to_string(), "", 0)))?;
Ok(unsafe { PyObject::from_owned_ptr(py, py_ptr) })
Ok(unsafe { NonNull::new_unchecked(obj) })
}
Err(e) => Err(JSONDecodeError::py_err((e.to_string(), "", 0))),
}
Expand Down Expand Up @@ -161,7 +158,7 @@ impl<'de, 'a> Visitor<'de> for JsonValue {
where
A: SeqAccess<'de>,
{
let mut elements: SmallVec<[*mut pyo3::ffi::PyObject; 6]> = SmallVec::new();
let mut elements: SmallVec<[*mut pyo3::ffi::PyObject; 8]> = SmallVec::new();
while let Some(elem) = seq.next_element_seed(self)? {
elements.push(elem);
}
Expand Down
58 changes: 27 additions & 31 deletions src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::ptr::NonNull;
const STRICT_INT_MIN: i64 = -9007199254740991;
const STRICT_INT_MAX: i64 = 9007199254740991;

pub const STRICT_INTEGER: u8 = 1 << 0;
pub const STRICT_INTEGER: u8 = 1;
pub const NAIVE_UTC: u8 = 1 << 1;

pub const MAX_OPT: i8 = STRICT_INTEGER as i8 | NAIVE_UTC as i8;
Expand All @@ -27,33 +27,29 @@ const COLON: u8 = 58; // ":"
const PERIOD: u8 = 46; // ":"

pub fn serialize(
py: Python,
ptr: *mut pyo3::ffi::PyObject,
default: Option<NonNull<pyo3::ffi::PyObject>>,
opts: u8,
) -> PyResult<PyObject> {
let mut buf: Vec<u8> = Vec::with_capacity(1008);
{
serde_json::to_writer(
&mut buf,
&SerializePyObject {
ptr: ptr,
default: default,
opts: opts,
recursion: 0,
},
)
}
.map_err(|error| JSONEncodeError::py_err(error.to_string()))?;
Ok(unsafe {
PyObject::from_owned_ptr(
py,
pyo3::ffi::PyBytes_FromStringAndSize(
) -> PyResult<NonNull<pyo3::ffi::PyObject>> {
let mut buf: Vec<u8> = Vec::with_capacity(1024);
match serde_json::to_writer(
&mut buf,
&SerializePyObject {
ptr,
default,
opts,
recursion: 0,
},
) {
Ok(_) => Ok(unsafe {
NonNull::new_unchecked(pyo3::ffi::PyBytes_FromStringAndSize(
buf.as_ptr() as *const c_char,
buf.len() as pyo3::ffi::Py_ssize_t,
),
)
})
))
}),

Err(err) => Err(JSONEncodeError::py_err(err.to_string())),
}
}
struct SerializePyObject {
ptr: *mut pyo3::ffi::PyObject,
Expand Down Expand Up @@ -85,11 +81,11 @@ impl<'p> Serialize for SerializePyObject {
if unsafe {
std::intrinsics::unlikely(val == -1 && !pyo3::ffi::PyErr_Occurred().is_null())
} {
return Err(ser::Error::custom("Integer exceeds 64-bit max"));
return Err(ser::Error::custom("Integer exceeds 64-bit range"));
} else if self.opts & STRICT_INTEGER == STRICT_INTEGER
&& (val > STRICT_INT_MAX || val < STRICT_INT_MIN)
{
return Err(ser::Error::custom("Integer exceeds 53-bit max"));
return Err(ser::Error::custom("Integer exceeds 53-bit range"));
}
serializer.serialize_i64(val)
} else if unsafe { obj_ptr == BOOL_PTR } {
Expand Down Expand Up @@ -355,7 +351,7 @@ impl<'p> Serialize for SerializePyObject {
std::str::from_utf8_unchecked(std::slice::from_raw_parts(dt.as_ptr(), dt.len()))
})
} else if unsafe { obj_ptr == DATE_PTR } {
let mut dt: SmallVec<[u8; 10]> = SmallVec::with_capacity(10);
let mut dt: SmallVec<[u8; 32]> = SmallVec::with_capacity(32);
{
let year = unsafe { pyo3::ffi::PyDateTime_GET_YEAR(self.ptr) as i32 };
dt.extend(itoa::Buffer::new().format(year).bytes());
Expand Down Expand Up @@ -424,9 +420,9 @@ impl<'p> Serialize for SerializePyObject {
})
} else if self.default.is_some() {
if self.recursion > 5 {
return Err(ser::Error::custom(
Err(ser::Error::custom(
"default serializer exceeds recursion limit",
));
))
} else {
let default_obj = unsafe {
pyo3::ffi::PyObject_CallFunctionObjArgs(
Expand All @@ -444,12 +440,12 @@ impl<'p> Serialize for SerializePyObject {
}
.serialize(serializer);
unsafe { pyo3::ffi::Py_DECREF(default_obj) };
return res;
res
} else if unsafe { !pyo3::ffi::PyErr_Occurred().is_null() } {
return Err(ser::Error::custom(format_args!(
Err(ser::Error::custom(format_args!(
"Type raised exception in default function: {}",
unsafe { CStr::from_ptr((*obj_ptr).tp_name).to_string_lossy() }
)));
)))
} else {
Err(ser::Error::custom(format_args!(
"Type is not JSON serializable: {}",
Expand Down
14 changes: 7 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: (Apache-2.0 OR MIT)

#![feature(custom_attribute)]
#![feature(core_intrinsics)]

#[macro_use]
Expand All @@ -14,7 +13,6 @@ extern crate smallvec;

use pyo3::prelude::*;
use pyo3::AsPyPointer;
use pyo3::IntoPyPointer;
use std::os::raw::c_char;
use std::ptr::NonNull;

Expand Down Expand Up @@ -64,11 +62,10 @@ pub unsafe extern "C" fn loads(
_self: *mut pyo3::ffi::PyObject,
obj: *mut pyo3::ffi::PyObject,
) -> *mut pyo3::ffi::PyObject {
let py = pyo3::Python::assume_gil_acquired();
match decode::deserialize(py, obj) {
Ok(val) => val.into_ptr(),
match decode::deserialize(obj) {
Ok(val) => val.as_ptr(),
Err(err) => {
err.restore(py);
err.restore(pyo3::Python::assume_gil_acquired());
std::ptr::null_mut()
}
}
Expand Down Expand Up @@ -106,5 +103,8 @@ pub fn dumps(
} else {
optsbits = 0
};
encode::serialize(py, obj.as_ptr(), pydef, optsbits as u8)
match encode::serialize(obj.as_ptr(), pydef, optsbits as u8) {
Ok(val) => unsafe { Ok(PyObject::from_owned_ptr(py, val.as_ptr())) },
Err(err) => Err(err),
}
}

0 comments on commit 036ae84

Please sign in to comment.