|
1 | 1 | // SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
2 | 2 |
|
3 |
| -use crate::ffi::{pylong_is_unsigned, pylong_is_zero, pylong_value_signed, pylong_value_unsigned}; |
| 3 | +use crate::ffi::{pylong_fits_in_i32, pylong_get_inline_value, pylong_is_unsigned, pylong_is_zero}; |
| 4 | +use crate::opt::{Opt, STRICT_INTEGER}; |
4 | 5 | use crate::serialize::error::SerializeError;
|
5 | 6 | use serde::ser::{Serialize, Serializer};
|
6 | 7 |
|
| 8 | +use core::ffi::c_uchar; |
| 9 | +use core::mem::transmute; |
| 10 | + |
7 | 11 | // https://tools.ietf.org/html/rfc7159#section-6
|
8 | 12 | // "[-(2**53)+1, (2**53)-1]"
|
9 | 13 | const STRICT_INT_MIN: i64 = -9007199254740991;
|
10 | 14 | const STRICT_INT_MAX: i64 = 9007199254740991;
|
11 | 15 |
|
12 |
| -#[repr(transparent)] |
13 | 16 | pub struct IntSerializer {
|
14 | 17 | ptr: *mut pyo3_ffi::PyObject,
|
| 18 | + opts: Opt, |
15 | 19 | }
|
16 | 20 |
|
17 | 21 | impl IntSerializer {
|
18 |
| - pub fn new(ptr: *mut pyo3_ffi::PyObject) -> Self { |
19 |
| - IntSerializer { ptr: ptr } |
| 22 | + pub fn new(ptr: *mut pyo3_ffi::PyObject, opts: Opt) -> Self { |
| 23 | + IntSerializer { |
| 24 | + ptr: ptr, |
| 25 | + opts: opts, |
| 26 | + } |
20 | 27 | }
|
21 | 28 | }
|
22 | 29 |
|
23 | 30 | impl Serialize for IntSerializer {
|
24 |
| - #[inline(never)] |
| 31 | + #[inline(always)] |
25 | 32 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
26 | 33 | where
|
27 | 34 | S: Serializer,
|
28 | 35 | {
|
29 |
| - if pylong_is_zero(self.ptr) { |
30 |
| - serializer.serialize_u64(0) |
31 |
| - } else if pylong_is_unsigned(self.ptr) { |
32 |
| - let val = pylong_value_unsigned(self.ptr); |
33 |
| - if unlikely!(val == u64::MAX) && !ffi!(PyErr_Occurred()).is_null() { |
34 |
| - err!(SerializeError::Integer64Bits) |
35 |
| - } else { |
36 |
| - serializer.serialize_u64(val) |
| 36 | + unsafe { |
| 37 | + if pylong_is_zero(self.ptr) { |
| 38 | + return serializer.serialize_bytes(b"0"); |
37 | 39 | }
|
38 |
| - } else { |
39 |
| - let val = pylong_value_signed(self.ptr); |
40 |
| - if unlikely!(val == -1) && !ffi!(PyErr_Occurred()).is_null() { |
41 |
| - err!(SerializeError::Integer64Bits) |
42 |
| - } |
43 |
| - serializer.serialize_i64(val) |
44 |
| - } |
45 |
| - } |
46 |
| -} |
47 |
| - |
48 |
| -#[repr(transparent)] |
49 |
| -pub struct Int53Serializer { |
50 |
| - ptr: *mut pyo3_ffi::PyObject, |
51 |
| -} |
52 |
| - |
53 |
| -impl Int53Serializer { |
54 |
| - pub fn new(ptr: *mut pyo3_ffi::PyObject) -> Self { |
55 |
| - Int53Serializer { ptr: ptr } |
56 |
| - } |
57 |
| -} |
58 |
| - |
59 |
| -impl Serialize for Int53Serializer { |
60 |
| - #[cold] |
61 |
| - #[inline(never)] |
62 |
| - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
63 |
| - where |
64 |
| - S: Serializer, |
65 |
| - { |
66 |
| - let val = pylong_value_signed(self.ptr); |
67 |
| - if unlikely!(val == -1) { |
68 |
| - if ffi!(PyErr_Occurred()).is_null() { |
69 |
| - serializer.serialize_i64(val) |
| 40 | + let is_signed = !pylong_is_unsigned(self.ptr) as i32; |
| 41 | + if pylong_fits_in_i32(self.ptr) { |
| 42 | + if is_signed == 0 { |
| 43 | + serializer.serialize_u64(pylong_get_inline_value(self.ptr) as u64) |
| 44 | + } else { |
| 45 | + serializer.serialize_i64(pylong_get_inline_value(self.ptr) as i64) |
| 46 | + } |
70 | 47 | } else {
|
71 |
| - err!(SerializeError::Integer53Bits) |
| 48 | + let mut buffer: [u8; 8] = [0; 8]; |
| 49 | + let ret = pyo3_ffi::_PyLong_AsByteArray( |
| 50 | + self.ptr as *mut pyo3_ffi::PyLongObject, |
| 51 | + buffer.as_mut_ptr() as *mut c_uchar, |
| 52 | + 8, |
| 53 | + 1, |
| 54 | + is_signed, |
| 55 | + ); |
| 56 | + if unlikely!(ret == -1) { |
| 57 | + ffi!(PyErr_Clear()); |
| 58 | + err!(SerializeError::Integer64Bits) |
| 59 | + } |
| 60 | + if is_signed == 0 { |
| 61 | + let val = transmute::<[u8; 8], u64>(buffer); |
| 62 | + if unlikely!(opt_enabled!(self.opts, STRICT_INTEGER)) |
| 63 | + && val > STRICT_INT_MAX as u64 |
| 64 | + { |
| 65 | + err!(SerializeError::Integer53Bits) |
| 66 | + } |
| 67 | + serializer.serialize_u64(val) |
| 68 | + } else { |
| 69 | + let val = transmute::<[u8; 8], i64>(buffer); |
| 70 | + if unlikely!(opt_enabled!(self.opts, STRICT_INTEGER)) |
| 71 | + && !(STRICT_INT_MIN..=STRICT_INT_MAX).contains(&val) |
| 72 | + { |
| 73 | + err!(SerializeError::Integer53Bits) |
| 74 | + } |
| 75 | + serializer.serialize_i64(val) |
| 76 | + } |
72 | 77 | }
|
73 |
| - } else if !(STRICT_INT_MIN..=STRICT_INT_MAX).contains(&val) { |
74 |
| - err!(SerializeError::Integer53Bits) |
75 |
| - } else { |
76 |
| - serializer.serialize_i64(val) |
77 | 78 | }
|
78 | 79 | }
|
79 | 80 | }
|
0 commit comments