Skip to content

Commit 2fdf1ab

Browse files
committed
Refactor datetime, uuid to serializers
1 parent 64310c0 commit 2fdf1ab

9 files changed

Lines changed: 255 additions & 243 deletions

File tree

src/datetime.rs

Lines changed: 195 additions & 182 deletions
Large diffs are not rendered by default.

src/encode.rs

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::typeref::*;
77
use crate::unicode::*;
88
use crate::uuid::*;
99
use pyo3::prelude::*;
10-
use serde::ser::{self, Serialize, SerializeMap, SerializeSeq, Serializer};
10+
use serde::ser::{Error, Serialize, SerializeMap, SerializeSeq, Serializer};
1111
use std::ffi::CStr;
1212
use std::os::raw::c_char;
1313
use std::ptr::NonNull;
@@ -19,9 +19,9 @@ const STRICT_INT_MAX: i64 = 9007199254740991;
1919

2020
const RECURSION_LIMIT: u8 = 255;
2121

22-
pub const STRICT_INTEGER: u8 = 1;
2322
pub const SERIALIZE_DATACLASS: u8 = 1 << 4;
2423
pub const SERIALIZE_UUID: u8 = 1 << 5;
24+
pub const STRICT_INTEGER: u8 = 1;
2525

2626
macro_rules! obj_name {
2727
($obj:ident) => {
@@ -31,7 +31,7 @@ macro_rules! obj_name {
3131

3232
macro_rules! err {
3333
($msg:expr) => {
34-
return Err(ser::Error::custom($msg));
34+
return Err(Error::custom($msg));
3535
};
3636
}
3737

@@ -160,27 +160,10 @@ impl<'p> Serialize for SerializePyObject {
160160
ObType::NONE => serializer.serialize_unit(),
161161
ObType::FLOAT => serializer.serialize_f64(ffi!(PyFloat_AS_DOUBLE(self.ptr))),
162162
ObType::BOOL => serializer.serialize_bool(unsafe { self.ptr == TRUE }),
163-
ObType::DATETIME => {
164-
let mut buf: DateTimeBuffer = heapless::Vec::new();
165-
match write_datetime(self.ptr, self.opts, &mut buf) {
166-
Ok(_) => serializer.serialize_str(str_from_slice!(buf.as_ptr(), buf.len())),
167-
Err(DatetimeError::Library) => {
168-
err!("datetime's timezone library is not supported: use datetime.timezone.utc, pendulum, pytz, or dateutil")
169-
}
170-
}
171-
}
163+
ObType::DATETIME => DateTime::new(self.ptr, self.opts).serialize(serializer),
172164
ObType::DATE => Date::new(self.ptr).serialize(serializer),
173-
ObType::TIME => {
174-
if unsafe { (*(self.ptr as *mut pyo3::ffi::PyDateTime_Time)).hastzinfo == 1 } {
175-
err!("datetime.time must not have tzinfo set")
176-
}
177-
Time::new(self.ptr, self.opts).serialize(serializer)
178-
}
179-
ObType::UUID => {
180-
let mut buf: UUIDBuffer = heapless::Vec::new();
181-
write_uuid(self.ptr, &mut buf);
182-
serializer.serialize_str(str_from_slice!(buf.as_ptr(), buf.len()))
183-
}
165+
ObType::TIME => Time::new(self.ptr, self.opts).serialize(serializer),
166+
ObType::UUID => UUID::new(self.ptr).serialize(serializer),
184167
ObType::DICT => {
185168
if unlikely!(self.recursion == RECURSION_LIMIT) {
186169
err!(RECURSION_LIMIT_REACHED)
@@ -203,6 +186,7 @@ impl<'p> Serialize for SerializePyObject {
203186
}
204187
map.serialize_key(str_from_slice!(data, str_size)).unwrap();
205188
}
189+
206190
map.serialize_value(&SerializePyObject {
207191
ptr: value,
208192
obtype: None,

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,10 @@ fn orjson(py: Python, m: &PyModule) -> PyResult<()> {
6060
m.add("JSONEncodeError", py.get_type::<exc::JSONEncodeError>())?;
6161
m.add("OPT_NAIVE_UTC", datetime::NAIVE_UTC)?;
6262
m.add("OPT_OMIT_MICROSECONDS", datetime::OMIT_MICROSECONDS)?;
63-
m.add("OPT_STRICT_INTEGER", encode::STRICT_INTEGER)?;
64-
m.add("OPT_UTC_Z", datetime::UTC_Z)?;
6563
m.add("OPT_SERIALIZE_DATACLASS", encode::SERIALIZE_DATACLASS)?;
6664
m.add("OPT_SERIALIZE_UUID", encode::SERIALIZE_UUID)?;
65+
m.add("OPT_STRICT_INTEGER", encode::STRICT_INTEGER)?;
66+
m.add("OPT_UTC_Z", datetime::UTC_Z)?;
6767

6868
Ok(())
6969
}

src/uuid.rs

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,59 @@
22

33
use crate::datetime::HYPHEN;
44
use crate::typeref::*;
5+
use serde::ser::{Serialize, Serializer};
56
use smallvec::SmallVec;
67
use std::io::Write;
78
use std::os::raw::c_uchar;
89

9-
pub type UUIDBuffer = heapless::Vec<u8, heapless::consts::U64>;
10+
type UUIDBuffer = heapless::Vec<u8, heapless::consts::U64>;
1011

11-
#[inline(never)]
12-
pub fn write_uuid(ptr: *mut pyo3::ffi::PyObject, buf: &mut UUIDBuffer) {
13-
let value: u128;
14-
{
15-
// test_uuid_immutable, test_uuid_int
16-
let py_int = ffi!(PyObject_GetAttr(ptr, INT_ATTR_STR));
17-
ffi!(Py_DECREF(py_int));
18-
let buffer: [c_uchar; 16] = [0; 16];
19-
unsafe {
20-
// test_uuid_overflow
21-
pyo3::ffi::_PyLong_AsByteArray(
22-
py_int as *mut pyo3::ffi::PyLongObject,
23-
buffer.as_ptr() as *const c_uchar,
24-
16,
25-
1, // little_endian
26-
0, // is_signed
27-
)
28-
};
29-
value = u128::from_le_bytes(buffer);
12+
pub struct UUID {
13+
ptr: *mut pyo3::ffi::PyObject,
14+
}
15+
16+
impl UUID {
17+
pub fn new(ptr: *mut pyo3::ffi::PyObject) -> Self {
18+
UUID { ptr: ptr }
3019
}
20+
}
21+
impl<'p> Serialize for UUID {
22+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
23+
where
24+
S: Serializer,
25+
{
26+
let value: u128;
27+
{
28+
// test_uuid_immutable, test_uuid_int
29+
let py_int = ffi!(PyObject_GetAttr(self.ptr, INT_ATTR_STR));
30+
ffi!(Py_DECREF(py_int));
31+
let buffer: [c_uchar; 16] = [0; 16];
32+
unsafe {
33+
// test_uuid_overflow
34+
pyo3::ffi::_PyLong_AsByteArray(
35+
py_int as *mut pyo3::ffi::PyLongObject,
36+
buffer.as_ptr() as *const c_uchar,
37+
16,
38+
1, // little_endian
39+
0, // is_signed
40+
)
41+
};
42+
value = u128::from_le_bytes(buffer);
43+
}
3144

32-
let mut hexadecimal: SmallVec<[u8; 32]> = SmallVec::with_capacity(32);
33-
write!(hexadecimal, "{:032x}", value).unwrap();
45+
let mut hexadecimal: SmallVec<[u8; 32]> = SmallVec::with_capacity(32);
46+
write!(hexadecimal, "{:032x}", value).unwrap();
3447

35-
buf.extend_from_slice(&hexadecimal[..8]).unwrap();
36-
buf.push(HYPHEN).unwrap();
37-
buf.extend_from_slice(&hexadecimal[8..12]).unwrap();
38-
buf.push(HYPHEN).unwrap();
39-
buf.extend_from_slice(&hexadecimal[12..16]).unwrap();
40-
buf.push(HYPHEN).unwrap();
41-
buf.extend_from_slice(&hexadecimal[16..20]).unwrap();
42-
buf.push(HYPHEN).unwrap();
43-
buf.extend_from_slice(&hexadecimal[20..]).unwrap();
48+
let mut buf: UUIDBuffer = heapless::Vec::new();
49+
buf.extend_from_slice(&hexadecimal[..8]).unwrap();
50+
buf.push(HYPHEN).unwrap();
51+
buf.extend_from_slice(&hexadecimal[8..12]).unwrap();
52+
buf.push(HYPHEN).unwrap();
53+
buf.extend_from_slice(&hexadecimal[12..16]).unwrap();
54+
buf.push(HYPHEN).unwrap();
55+
buf.extend_from_slice(&hexadecimal[16..20]).unwrap();
56+
buf.push(HYPHEN).unwrap();
57+
buf.extend_from_slice(&hexadecimal[20..]).unwrap();
58+
serializer.serialize_str(str_from_slice!(buf.as_ptr(), buf.len()))
59+
}
4460
}

test/test_dataclass.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import unittest
44
import uuid
5-
65
from dataclasses import dataclass, field
76
from enum import Enum
87
from typing import Optional

test/test_parsing.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import unittest
44

55
import orjson
6-
import pytest
76

87
from .util import read_fixture_bytes
98

test/test_type.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
2-
# coding=UTF-8
32

43
import unittest
54

@@ -286,6 +285,9 @@ def test_dict(self):
286285
self.assertEqual(orjson.dumps(obj), ref.encode("utf-8"))
287286
self.assertEqual(orjson.loads(ref), obj)
288287

288+
def test_dict_duplicate_loads(self):
289+
self.assertEqual(orjson.loads(b'{"1":true,"1":false}'), {"1": False})
290+
289291
def test_dict_large(self):
290292
"""
291293
dict with >512 keys

test/test_ujson.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
2-
# coding=UTF-8
32

43
from __future__ import division, print_function, unicode_literals
54

test/test_uuid.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
22

3-
import uuid
43
import unittest
4+
import uuid
55

66
import orjson
77

0 commit comments

Comments
 (0)