Skip to content

Conversation

sunshowers
Copy link
Collaborator

@sunshowers sunshowers commented Jun 10, 2025

This PR adds a new function-style proc macro called impl_typed_uuid_kinds, with support for automatic replacement of UUID kinds in typify (and therefore progenitor).

A typical invocation is:

impl_typed_uuid_kinds! {
    settings = {
        schemars08 = {
            attrs = [#[cfg(feature = "schemars")]],
            rust_type = {
                crate = "my-crate",
                version = "*",
                path = "my_crate::types",
            },
        },
    },
    kinds = {
        User = {},
        Organization = {},
        Project = {},
    },
}

TODO:

(Updates to Progenitor are not necessary since the fixes are all in typify.)

Created using spr 1.3.6-beta.1
@sunshowers sunshowers marked this pull request as draft June 10, 2025 23:29
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
@sunshowers sunshowers marked this pull request as ready for review August 14, 2025 20:03
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
@sunshowers sunshowers changed the title [wip] add an impl_typed_uuid_kinds macro with x-rust-type support add an impl_typed_uuid_kinds macro with x-rust-type support Aug 14, 2025
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
@sunshowers
Copy link
Collaborator Author

Got this working end to end in Omicron with this patch: https://gist.github.com/sunshowers/1484f8cfa249c44c1426728194a258b6

Created using spr 1.3.6-beta.1
@sunshowers sunshowers requested a review from ahl August 16, 2025 00:12
Copy link

@ahl ahl left a comment

Choose a reason for hiding this comment

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

This is really beautiful.

///
/// By default, for a kind `Foo`, this macro generates:
///
/// * A `FooKind` type that implements `TypedUuidKind`: `pub type FooKind {}`.
Copy link

Choose a reason for hiding this comment

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

Suggested change
/// * A `FooKind` type that implements `TypedUuidKind`: `pub type FooKind {}`.
/// * A `FooKind` type that implements `TypedUuidKind`: `pub enum FooKind {}`.

?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks, fixed.

///
/// // This generates empty UserKind and OrganizationKind enums implementing
/// // TypedUuidKind, with the tags "user" and "organization" respectively.
/// // Tags are snake_case versions of type names.
Copy link

Choose a reason for hiding this comment

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

You might consider an example that demonstrates the snakiness of the casing e.g. BusinessUnit rather than Organization ("business_unit")

Is that PascalCasiness a constraint on the inputs or only a suggestion?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good idea re demonstrating snakiness -- thanks.

It's not a hard constraint but Rust would warn you about non-idiomatic type definitions:

image

Comment on lines 88 to 90
/// * The `Kind` types are all empty (uninhabited) enums, which means that
/// values for these types cannot be created. (Using empty enums is the
/// recommended approach for `newtype-uuid`).
Copy link

Choose a reason for hiding this comment

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

I haven't heard "uninhabited", but I have used "marker" I think in case that's a useful shibboleth?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

"Uninhabited" is a pretty Haskell-like term I guess. I'll change this to "also known as marker or uninhabited enums".

/// attrs = [#[cfg(feature = "schemars")]],
/// rust_type = {
/// crate = "my-crate",
/// version = "*",
Copy link

Choose a reason for hiding this comment

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

may I request that you use an explicit version here? I worry about copy-pasta proliferation that "works" but might be the wrong thing.

Suggested change
/// version = "*",
/// version = "0.1.0",

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Reasonable, though I'm wondering if we should document something like "if your list of kinds is append-only, consider using "*"". Probably too much detail for this documentation, though.

use ::#newtype_uuid_crate::macro_support::schemars08::schema::*;

let mut schema = SchemaObject {
instance_type: ::std::option::Option::None,
Copy link

Choose a reason for hiding this comment

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

do you need this? or just here to be explicit?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah yeah I don't think this is necessary, removed.

#[cfg(feature = "alloc")]
extern crate alloc;

/// Macro support for [`newtype-uuid-macros`].
Copy link

Choose a reason for hiding this comment

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

do you want to make it clear that this is unstable? I might have considered making it doc = hidden

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah definitely should be hidden in docs.

Comment on lines 707 to 710
/// Returns an alias for `TypedUuid<Self>`, if one is defined.
///
/// The alias must be defined in the same module as `Self`. This alias is
/// used by schemars integration to refer to `TypedUuid<Self>` if available.
Copy link

Choose a reason for hiding this comment

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

I needed to reread this a couple of times to understand it. In particular this means a type alias e.g. pub type = TypedUuid; perhaps this would have been clearer to me:

Suggested change
/// Returns an alias for `TypedUuid<Self>`, if one is defined.
///
/// The alias must be defined in the same module as `Self`. This alias is
/// used by schemars integration to refer to `TypedUuid<Self>` if available.
/// Returns a string that corresponds to a type alias for `TypedUuid<Self>`, if one is defined.
///
/// The type alias must be defined in the same module as `Self`. This function is
/// used by the schemars integration to embed a reference to that alias in the schema.

Might it make sense to mention the macro here as well? While folks can certainly use this independent of the macro, it might be worth guiding them toward the easy / intended path.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, makes sense.

Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
@sunshowers sunshowers merged commit f1bd448 into main Aug 19, 2025
5 checks passed
@sunshowers sunshowers deleted the sunshowers/spr/wip-add-an-impl_typed_uuid_kinds-macro-with-x-rust-type-support branch August 19, 2025 20:03
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.

2 participants