forked from ijl/orjson
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathencode.rs
More file actions
132 lines (126 loc) · 5.07 KB
/
Copy pathencode.rs
File metadata and controls
132 lines (126 loc) · 5.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
use crate::typeref::*;
use pyo3::prelude::*;
use pyo3::types::*;
use pyo3::ToPyPointer;
use serde::ser::{self, Serialize, SerializeMap, SerializeSeq, Serializer};
pub fn serialize(py: Python, obj: PyObject) -> PyResult<PyObject> {
let s: Result<Vec<u8>, JsonError> = serde_json::to_vec(&SerializePyObject {
py: py,
obj: obj.as_ref(py),
})
.map_err(|error| JsonError::InvalidConversion { error });
Ok(PyBytes::new(py, (s?).as_slice()).into())
}
pub enum JsonError {
InvalidConversion { error: serde_json::Error },
}
impl From<JsonError> for PyErr {
fn from(h: JsonError) -> PyErr {
match h {
JsonError::InvalidConversion { error } => {
PyErr::new::<pyo3::exceptions::TypeError, _>(error.to_string())
}
}
}
}
#[repr(transparent)]
pub struct SerializePyObject<'p, 'a> {
pub py: Python<'p>,
pub obj: &'a PyObjectRef,
}
impl<'p, 'a> Serialize for SerializePyObject<'p, 'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let obj_ptr = self.obj.get_type_ptr();
if unsafe { obj_ptr == STR_PTR } {
let val = unsafe { <PyUnicode as PyTryFrom>::try_from_unchecked(self.obj) };
serializer.serialize_str(unsafe { std::str::from_utf8_unchecked(val.as_bytes()) })
} else if unsafe { obj_ptr == FLOAT_PTR } {
let val = unsafe { <PyFloat as PyTryFrom>::try_from_unchecked(self.obj) };
serializer.serialize_f64(val.value())
} else if unsafe { obj_ptr == INT_PTR } {
let val = unsafe { pyo3::ffi::PyLong_AsLong(self.obj.as_ptr()) };
if unsafe { std::intrinsics::unlikely(val == -1 && PyErr::occurred(self.py)) } {
return Err(ser::Error::custom(format_args!(
"Integer exceeds 64-bit max: {:?}",
self.obj
)))
}
serializer.serialize_i64(val)
} else if unsafe { obj_ptr == BOOL_PTR } {
let val = unsafe { <PyBool as PyTryFrom>::try_from_unchecked(self.obj) };
serializer.serialize_bool(val.is_true())
} else if unsafe { obj_ptr == NONE_PTR } {
serializer.serialize_unit()
} else if unsafe { obj_ptr == DICT_PTR } {
let val = unsafe { <PyDict as PyTryFrom>::try_from_unchecked(self.obj) };
let len = val.len();
if len != 0 {
let mut map = serializer.serialize_map(Some(len))?;
for (key, value) in val.iter() {
if unsafe { std::intrinsics::unlikely(key.get_type_ptr() != STR_PTR) } {
return Err(ser::Error::custom(format_args!(
"Dict key must be str, not: {:?}",
key
)));
}
map.serialize_entry(
unsafe {
std::str::from_utf8_unchecked(
<PyUnicode as PyTryFrom>::try_from_unchecked(key).as_bytes(),
)
},
&SerializePyObject {
py: self.py,
obj: value,
},
)?;
}
map.end()
} else {
serializer.serialize_map(None).unwrap().end()
}
} else if unsafe { obj_ptr == LIST_PTR } {
let val = unsafe { <PyList as PyTryFrom>::try_from_unchecked(self.obj) };
let len = val.len();
if len != 0 {
let mut seq = serializer.serialize_seq(Some(len))?;
for element in val {
seq.serialize_element(&SerializePyObject {
py: self.py,
obj: element,
})?
}
seq.end()
} else {
serializer.serialize_seq(None).unwrap().end()
}
} else if unsafe { obj_ptr == TUPLE_PTR } {
let val = unsafe { <PyTuple as PyTryFrom>::try_from_unchecked(self.obj) };
let len = val.len();
if len != 0 {
let mut seq = serializer.serialize_seq(Some(len))?;
for element in val {
seq.serialize_element(&SerializePyObject {
py: self.py,
obj: element,
})?
}
seq.end()
} else {
serializer.serialize_seq(None).unwrap().end()
}
} else if unsafe { obj_ptr == BYTES_PTR } {
let val = unsafe { <PyBytes as PyTryFrom>::try_from_unchecked(self.obj) };
serializer.serialize_str(unsafe { std::str::from_utf8_unchecked(val.as_bytes()) })
} else {
Err(ser::Error::custom(format_args!(
"Type is not JSON serializable: {}",
self.obj.get_type().name(),
)))
}
}
}