Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional conversions to/from UUID. #4371

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Hooksie
Copy link
Contributor

@Hooksie Hooksie commented Jul 22, 2024

This is a first pass for #4365. It is based mainly off the current rust_decimal.

There is an open question here about what is the most appropriate set of types to allow automatic conversion from. Currently, I have:

  • bytes that are accepted by Uuid::try_parse_ascii
  • otherwise, anything with a str that will be accepted by Uuid::try_parse

This does feel a bit too permissive -- but IMO this is more of a maintenance/API question than anything, so @davidhewitt your thoughts would be appreciated here.

Will follow up with the docs if the structure here seems reasonable, and a few more tests.

@Hooksie
Copy link
Contributor Author

Hooksie commented Jul 22, 2024

This does feel a bit too permissive

Taking some liberties here in the meantime and scoping this down. I've limited it now to converting from types that are already Python UUID instances or types that can be extracted to bytes. (With additional validation after). This feels a lot more predictable, IMO

Adjusted IntoPy as well to consume the Uuid. I've had to use some unsafe here, and I would appreciate some sanity checking on that in particular. That said, I'm noticing the Uuid doesnt seem to be getting consumed, despite using what I understand are both a consuming self reference and into_bytes. My amateur Rust knowledge is probably showing here, or maybe I've just configured rust-analyzer incorrectly.

More tests still pending

@birkenfeld
Copy link
Member

As for the "getting consumed" part, that is expected, Uuid is Copy so it will never be moved anywhere.

@Hooksie
Copy link
Contributor Author

Hooksie commented Jul 23, 2024

Uuid is Copy

🤦 that makes sense

fn into_py(self, py: Python<'_>) -> PyObject {
let rs_bytes = self.into_bytes();
let py_bytes =
unsafe { PyBytes::bound_from_ptr(py, &rs_bytes as *const u8, rs_bytes.len()) };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need for unsafe here, you can just forward to the ToPyObject implementation

// Not propagating Err up here because the UUID class should be an invariant.
let uuid_cls = get_uuid_cls(ob.py()).expect("failed to load uuid.UUID");
let py_bytes: Bound<'_, PyBytes> = if ob.is_exact_instance(&uuid_cls) {
ob.getattr(intern!(ob.py(), "bytes"))?.downcast_into()?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pydantic uses the int value to convert to the rust uuid. So dump question: Which one will be faster, int, bytes or does it not matter.

ref pydantic/pydantic-core#1362

Copy link
Contributor Author

@Hooksie Hooksie Jul 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh, that's a good point. I had assumed the bytes argument had the lowest overhead, but looking into the UUID class the bytes argument is just a proxy to passing an integer anyways:

if bytes is not None:
    if len(bytes) != 16:
        raise ValueError('bytes is not a 16-char string')
    assert isinstance(bytes, bytes_), repr(bytes)
    int = int_.from_bytes(bytes)  # big endian

https://github.com/python/cpython/blob/main/Lib/uuid.py#L192

I'll go ahead and switch to that 👍

@Hooksie
Copy link
Contributor Author

Hooksie commented Jul 31, 2024

A little pressed for time last week, but I'll be following up on this shortly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants