Skip to content

Commit d00641b

Browse files
committed
writer::uuid
1 parent c84d9b4 commit d00641b

10 files changed

Lines changed: 72 additions & 52 deletions

File tree

Cargo.lock

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

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ serde = { version = "1", default-features = false }
5656
serde_json = { version = "1", default-features = false, features = ["std"] }
5757
simdutf8 = { version = "0.1", default-features = false, features = ["std", "public_imp", "aarch64_neon"] }
5858
unwinding = { version = "=0.2.8", default-features = false, features = ["unwinder"], optional = true }
59-
uuid = { version = "1", default-features = false }
6059
xxhash-rust = { version = "^0.8", default-features = false, features = ["xxh3"] }
6160
zmij = { version = "1", default-features = false }
6261

script/blame-to-header

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ TO_EXCLUDE = {
3838
"script/pybench",
3939
"script/pytest",
4040
"script/valgrind",
41+
"src/serialize/writer/uuid.rs",
4142
}
4243

4344

src/ffi/pyuuidref.rs

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
// SPDX-License-Identifier: MPL-2.0
22
// Copyright ijl (2026)
33

4-
use core::ffi::c_uchar;
4+
use super::{Py_DECREF, PyLong_AsByteArray, PyLongObject, PyObject, PyObject_GetAttr};
5+
use crate::typeref::INT_ATTR_STR;
56

67
#[derive(Clone)]
78
#[repr(transparent)]
89
pub(crate) struct PyUuidRef {
9-
ptr: core::ptr::NonNull<pyo3_ffi::PyObject>,
10+
ptr: core::ptr::NonNull<PyObject>,
1011
}
1112

1213
unsafe impl Send for PyUuidRef {}
@@ -20,7 +21,7 @@ impl PartialEq for PyUuidRef {
2021

2122
impl PyUuidRef {
2223
#[inline]
23-
pub(crate) unsafe fn from_ptr_unchecked(ptr: *mut pyo3_ffi::PyObject) -> Self {
24+
pub(crate) unsafe fn from_ptr_unchecked(ptr: *mut PyObject) -> Self {
2425
unsafe {
2526
debug_assert!(!ptr.is_null());
2627
debug_assert!(crate::ffi::PyObject_Type(ptr) == crate::typeref::UUID_TYPE);
@@ -30,27 +31,12 @@ impl PyUuidRef {
3031
}
3132
}
3233

33-
#[inline(never)]
34-
pub(crate) fn value(&self) -> u128 {
34+
#[inline]
35+
pub(crate) fn value(&self, buffer: &mut [u8; 16]) {
3536
unsafe {
36-
{
37-
// test_uuid_immutable, test_uuid_int
38-
let py_int =
39-
crate::ffi::PyObject_GetAttr(self.ptr.as_ptr(), crate::typeref::INT_ATTR_STR);
40-
ffi!(Py_DECREF(py_int));
41-
let mut buffer: [c_uchar; 16] = [0; 16];
42-
unsafe {
43-
// test_uuid_overflow
44-
crate::ffi::PyLong_AsByteArray(
45-
py_int.cast::<crate::ffi::PyLongObject>(),
46-
buffer.as_mut_ptr(),
47-
16,
48-
1, // little_endian
49-
0, // is_signed
50-
);
51-
};
52-
u128::from_le_bytes(buffer)
53-
}
37+
let py_int = PyObject_GetAttr(self.ptr.as_ptr(), INT_ATTR_STR);
38+
PyLong_AsByteArray(py_int.cast::<PyLongObject>(), buffer as *mut u8, 16, 0, 0);
39+
Py_DECREF(py_int);
5440
}
5541
}
5642
}

src/serialize/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod obtype;
88
mod per_type;
99
mod serializer;
1010
mod state;
11+
mod uuid;
1112
pub(crate) mod writer;
1213

1314
pub(crate) use serializer::serialize;

src/serialize/per_type/dict.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::serialize::per_type::{
1717
};
1818
use crate::serialize::serializer::PyObjectSerializer;
1919
use crate::serialize::state::SerializerState;
20+
use crate::serialize::uuid::write_uuid;
2021
use crate::serialize::writer::{SmallFixedBuffer, write_integer_i64, write_integer_u64};
2122
use crate::typeref::{STR_TYPE, TRUE, VALUE_STR};
2223
use core::ptr::NonNull;
@@ -417,7 +418,7 @@ fn non_str_time(key: PyTimeRef, opts: crate::opt::Opt) -> Result<String, Seriali
417418
#[inline(never)]
418419
fn non_str_uuid(key: PyUuidRef) -> Result<String, SerializeError> {
419420
let mut buf = SmallFixedBuffer::new();
420-
UUID::new(key).write_buf(&mut buf);
421+
write_uuid(key, &mut buf);
421422
let key_as_str = str_from_slice!(buf.as_ptr(), buf.len());
422423
Ok(String::from(key_as_str))
423424
}

src/serialize/per_type/uuid.rs

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Copyright ijl (2018-2026)
33

44
use crate::ffi::PyUuidRef;
5+
use crate::serialize::uuid::write_uuid;
56
use crate::serialize::writer::SmallFixedBuffer;
67
use serde::ser::{Serialize, Serializer};
78

@@ -14,34 +15,16 @@ impl UUID {
1415
pub fn new(ptr: PyUuidRef) -> Self {
1516
UUID { ob: ptr }
1617
}
17-
18-
#[inline(never)]
19-
pub fn write_buf<B>(&self, buf: &mut B)
20-
where
21-
B: bytes::BufMut,
22-
{
23-
unsafe {
24-
let buffer_length: usize = 40;
25-
debug_assert!(buf.remaining_mut() >= buffer_length);
26-
let len = uuid::Uuid::from_u128(self.ob.value())
27-
.hyphenated()
28-
.encode_lower(core::slice::from_raw_parts_mut(
29-
buf.chunk_mut().as_mut_ptr(),
30-
buffer_length,
31-
))
32-
.len();
33-
buf.advance_mut(len);
34-
}
35-
}
3618
}
19+
3720
impl Serialize for UUID {
3821
#[inline(always)]
3922
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
4023
where
4124
S: Serializer,
4225
{
4326
let mut buf = SmallFixedBuffer::new();
44-
self.write_buf(&mut buf);
27+
write_uuid(self.ob.clone(), &mut buf);
4528
serializer.serialize_unit_struct(str_from_slice!(buf.as_ptr(), buf.len()))
4629
}
4730
}

src/serialize/uuid.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: MPL-2.0
2+
// Copyright ijl (2026)
3+
4+
use crate::ffi::PyUuidRef;
5+
use crate::serialize::writer::{WriteExt, format_hyphenated};
6+
7+
#[cold]
8+
#[inline(never)]
9+
pub(crate) fn write_uuid<B>(ob: PyUuidRef, buf: &mut B)
10+
where
11+
B: ?Sized + WriteExt + bytes::BufMut,
12+
{
13+
unsafe {
14+
const UUID_LENGTH: usize = 36;
15+
debug_assert!(buf.remaining_mut() >= UUID_LENGTH);
16+
let dst: &mut [u8; UUID_LENGTH] = &mut *buf.as_mut_buffer_ptr().cast::<[u8; UUID_LENGTH]>();
17+
format_hyphenated(ob, dst);
18+
buf.advance_mut(UUID_LENGTH);
19+
}
20+
}

src/serialize/writer/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod json;
88
mod num;
99
mod smallfixedbuffer;
1010
mod str;
11+
mod uuid;
1112

1213
pub(crate) use byteswriter::{BytesWriter, WriteExt};
1314
pub(crate) use format_str::set_str_formatter_fn;
@@ -17,3 +18,4 @@ pub(crate) use num::{
1718
write_integer_u64,
1819
};
1920
pub(crate) use smallfixedbuffer::SmallFixedBuffer;
21+
pub(crate) use uuid::format_hyphenated;

src/serialize/writer/uuid.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
2+
// Copyright The Rust Project Developers (2013-2014), The Uuid Project Developers (2018)
3+
4+
use crate::ffi::PyUuidRef;
5+
6+
pub(crate) fn format_hyphenated(ob: PyUuidRef, dst: &mut [u8; 36]) {
7+
const LOWER: [u8; 16] = [
8+
b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e',
9+
b'f',
10+
];
11+
const GROUPS: [(usize, usize); 5] = [(0, 8), (9, 13), (14, 18), (19, 23), (24, 36)];
12+
13+
let mut src: [u8; 16] = [0; 16];
14+
ob.value(&mut src);
15+
16+
let mut group_idx = 0;
17+
let mut i = 0;
18+
while group_idx < 5 {
19+
let (start, end) = GROUPS[group_idx];
20+
let mut j = start;
21+
while j < end {
22+
let x = src[i];
23+
i += 1;
24+
25+
dst[j] = LOWER[(x >> 4) as usize];
26+
dst[j + 1] = LOWER[(x & 0x0f) as usize];
27+
j += 2;
28+
}
29+
if group_idx < 4 {
30+
dst[end] = b'-';
31+
}
32+
group_idx += 1;
33+
}
34+
}

0 commit comments

Comments
 (0)