Accept case-insensitive urn:uuid: prefixes when parsing #912

Open
jaideeppyne wants to merge 0 commits from jaideeppyne/fix/urn-prefix-case-insensitive into main
jaideeppyne commented 2026-09-16 04:09:34 -05:00 (Migrated from github.com)

RFC 2141 and RFC 8141 treat both the urn: scheme and the NID as case-insensitive, so strings such as URN:UUID:... and Urn:Uuid:... are valid URN forms of a UUID.

Uuid::parse_str and Urn::from_str only accepted the lowercase urn:uuid: prefix. Hex digits were already case-insensitive; this extends the same treatment to the prefix.

assert!(Uuid::parse_str("URN:UUID:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
assert!(Uuid::parse_str("Urn:Uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());

Adds parser tests and a uuid!() compile-pass case.

RFC 2141 and RFC 8141 treat both the `urn:` scheme and the NID as case-insensitive, so strings such as `URN:UUID:...` and `Urn:Uuid:...` are valid URN forms of a UUID. `Uuid::parse_str` and `Urn::from_str` only accepted the lowercase `urn:uuid:` prefix. Hex digits were already case-insensitive; this extends the same treatment to the prefix. ```rust assert!(Uuid::parse_str("URN:UUID:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok()); assert!(Uuid::parse_str("Urn:Uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok()); ``` Adds parser tests and a `uuid!()` compile-pass case.
KodrAus (Migrated from github.com) reviewed 2026-09-16 15:26:35 -05:00
KodrAus (Migrated from github.com) commented 2026-09-16 15:20:23 -05:00

This could be something like bytes[..9].eq_ignore_ascii_case(b"urn:uuid:")

This could be something like `bytes[..9].eq_ignore_ascii_case(b"urn:uuid:")`
KodrAus (Migrated from github.com) commented 2026-09-16 15:20:52 -05:00

Comment addition here is not necessary

Comment addition here is not necessary
KodrAus (Migrated from github.com) commented 2026-09-16 15:21:58 -05:00

We could lift the if up into the 38 => pattern here and remove the else branch. It'll fall through to the _ case.

We could lift the `if` up into the `38 =>` pattern here and remove the `else` branch. It'll fall through to the `_` case.
KodrAus (Migrated from github.com) commented 2026-09-16 15:22:39 -05:00

This could just be &input[9..]

This could just be `&input[9..]`
KodrAus (Migrated from github.com) commented 2026-09-16 15:23:17 -05:00

As above; &input[9..]

As above; `&input[9..]`
jaideeppyne (Migrated from github.com) reviewed 2026-09-16 19:53:58 -05:00
jaideeppyne (Migrated from github.com) commented 2026-09-16 19:53:58 -05:00

Applied the prefix slice comparison in cb8b1d5. This is a const fn, so stable Rust does not allow bytes[..9]; bytes.split_at(9).0.eq_ignore_ascii_case(...) is the const-compatible equivalent.

Applied the prefix slice comparison in cb8b1d5. This is a `const fn`, so stable Rust does not allow `bytes[..9]`; `bytes.split_at(9).0.eq_ignore_ascii_case(...)` is the const-compatible equivalent.
jaideeppyne (Migrated from github.com) reviewed 2026-09-16 19:54:00 -05:00
jaideeppyne (Migrated from github.com) commented 2026-09-16 19:54:00 -05:00

Removed the redundant comment in cb8b1d5.

Removed the redundant comment in cb8b1d5.
jaideeppyne (Migrated from github.com) reviewed 2026-09-16 19:54:02 -05:00
jaideeppyne (Migrated from github.com) commented 2026-09-16 19:54:02 -05:00

Applied in cb8b1d5 by matching (38, [b'{', s @ .., b'}']) directly, so non-braced inputs fall through to the existing catch-all arm.

Applied in cb8b1d5 by matching `(38, [b'{', s @ .., b'}'])` directly, so non-braced inputs fall through to the existing catch-all arm.
jaideeppyne (Migrated from github.com) reviewed 2026-09-16 19:54:05 -05:00
jaideeppyne (Migrated from github.com) commented 2026-09-16 19:54:05 -05:00

Kept the equivalent input.split_at(9).1 in cb8b1d5 because &input[9..] is not stable in this const fn; the full all-features test suite passes.

Kept the equivalent `input.split_at(9).1` in cb8b1d5 because `&input[9..]` is not stable in this `const fn`; the full all-features test suite passes.
jaideeppyne (Migrated from github.com) reviewed 2026-09-16 19:54:07 -05:00
jaideeppyne (Migrated from github.com) commented 2026-09-16 19:54:07 -05:00

Same const constraint applies in parse_urn: &input[9..] does not compile on stable Rust in a const fn, so the existing split_at(9).1 remains.

Same const constraint applies in `parse_urn`: `&input[9..]` does not compile on stable Rust in a `const fn`, so the existing `split_at(9).1` remains.
KodrAus (Migrated from github.com) reviewed 2026-09-18 01:57:26 -05:00
KodrAus (Migrated from github.com) left a comment

Thanks @jaideeppyne! I just had a few more comments but it's getting closer now.

Thanks @jaideeppyne! I just had a few more comments but it's getting closer now.
@ -87,10 +87,11 @@ impl<'a> InvalidUuid<'a> {
return Error(ErrorKind::ParseChar { character, index });
KodrAus (Migrated from github.com) commented 2026-09-18 01:49:34 -05:00

The error module doesn't already depend on parser, it's an alternative implementation. I think we should remove is_urn_prefix altogether and inline the calls to ascii_eq_ignore_case where it's used now that it's just a single function call.

This is the only branch that needs a length check or split_at_checked, since we already check lengths in the other cases.

The `error` module doesn't already depend on `parser`, it's an alternative implementation. I think we should remove `is_urn_prefix` altogether and inline the calls to `ascii_eq_ignore_case` where it's used now that it's just a single function call. This is the only branch that needs a length check or `split_at_checked`, since we already check lengths in the other cases.
KodrAus (Migrated from github.com) commented 2026-09-18 01:56:53 -05:00

slop: Unnecessary comment update

slop: Unnecessary comment update
jaideeppyne (Migrated from github.com) reviewed 2026-09-18 20:08:15 -05:00
@ -87,10 +87,11 @@ impl<'a> InvalidUuid<'a> {
return Error(ErrorKind::ParseChar { character, index });
jaideeppyne (Migrated from github.com) commented 2026-09-18 20:08:15 -05:00

Updated in 5055fd4: removed is_urn_prefix and inlined eq_ignore_ascii_case at each parser/error call site. The error path keeps the explicit length guard; fixed-length parser branches rely on their existing length checks.

Updated in 5055fd4: removed is_urn_prefix and inlined eq_ignore_ascii_case at each parser/error call site. The error path keeps the explicit length guard; fixed-length parser branches rely on their existing length checks.
jaideeppyne (Migrated from github.com) reviewed 2026-09-18 20:08:17 -05:00
jaideeppyne (Migrated from github.com) commented 2026-09-18 20:08:17 -05:00

Restored the original concise URN comment in 5055fd4.

Restored the original concise URN comment in 5055fd4.
KodrAus (Migrated from github.com) reviewed 2026-09-19 05:00:52 -05:00
@ -87,10 +87,11 @@ impl<'a> InvalidUuid<'a> {
return Error(ErrorKind::ParseChar { character, index });
KodrAus (Migrated from github.com) commented 2026-09-19 04:58:12 -05:00

This method isn't const so we can use bytes[..9].eq_ignore_ascii_case(..)

This method isn't `const` so we can use `bytes[..9].eq_ignore_ascii_case(..)`
@ -152,10 +152,15 @@ const fn try_parse(input: &'_ [u8]) -> Result<[u8; 16], InvalidUuid<'_>> {
// - `{UUID}` for braced UUIDs
KodrAus (Migrated from github.com) commented 2026-09-19 05:00:26 -05:00

Now that we've inlined the calls, I think this would now look better closer to your original formulation:

(45, s) => {
    let (prefix, s) = s.split_at(9);

    if prefix.eq_ignore_ascii_case(..) {
        parse_hyphenated(s)
    } else {
        Err(InvalidUuid(input, RequestedUuid::Any))
    }
}
Now that we've inlined the calls, I think this would now look better closer to your original formulation: ```rust (45, s) => { let (prefix, s) = s.split_at(9); if prefix.eq_ignore_ascii_case(..) { parse_hyphenated(s) } else { Err(InvalidUuid(input, RequestedUuid::Any)) } } ```
jaideeppyne (Migrated from github.com) reviewed 2026-09-19 06:16:04 -05:00
@ -87,10 +87,11 @@ impl<'a> InvalidUuid<'a> {
return Error(ErrorKind::ParseChar { character, index });
jaideeppyne (Migrated from github.com) commented 2026-09-19 06:16:04 -05:00

Updated this to use as suggested. Formatting and the full feature-matrix tests pass.

Updated this to use as suggested. Formatting and the full feature-matrix tests pass.
jaideeppyne (Migrated from github.com) reviewed 2026-09-19 06:16:13 -05:00
@ -152,10 +152,15 @@ const fn try_parse(input: &'_ [u8]) -> Result<[u8; 16], InvalidUuid<'_>> {
// - `{UUID}` for braced UUIDs
jaideeppyne (Migrated from github.com) commented 2026-09-19 06:16:13 -05:00

Updated the 45-byte arm to split once and use the explicit if/else form from the suggestion. The no-default-features and all-features suites, UI tests, and doctests pass.

Updated the 45-byte arm to split once and use the explicit if/else form from the suggestion. The no-default-features and all-features suites, UI tests, and doctests pass.
KodrAus commented 2026-09-19 07:24:25 -05:00 (Migrated from github.com)

We can bump our MSRV to 1.89.0, it’s over 12 months old and not too far from our current one.

We can bump our MSRV to `1.89.0`, it’s over 12 months old and not too far from our current one.
KodrAus commented 2026-09-22 03:14:23 -05:00 (Migrated from github.com)

@jaideeppyne Would you like a hand bumping our MSRV? It’s maintained in our GitHub Actions workflow, and as rust-version in our Cargo.toml. We just need to update those so we can use a few more const features in this new code.

@jaideeppyne Would you like a hand bumping our MSRV? It’s maintained in our GitHub Actions workflow, and as `rust-version` in our `Cargo.toml`. We just need to update those so we can use a few more `const` features in this new code.
This pull request is broken due to missing fork information.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin 'jaideeppyne/fix/urn-prefix-case-insensitive:jaideeppyne/fix/urn-prefix-case-insensitive'
git switch 'jaideeppyne/fix/urn-prefix-case-insensitive'

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch 'main'
git merge --no-ff 'jaideeppyne/fix/urn-prefix-case-insensitive'
git switch 'jaideeppyne/fix/urn-prefix-case-insensitive'
git rebase 'main'
git switch 'main'
git merge --ff-only 'jaideeppyne/fix/urn-prefix-case-insensitive'
git switch 'jaideeppyne/fix/urn-prefix-case-insensitive'
git rebase 'main'
git switch 'main'
git merge --no-ff 'jaideeppyne/fix/urn-prefix-case-insensitive'
git switch 'main'
git merge --squash 'jaideeppyne/fix/urn-prefix-case-insensitive'
git switch 'main'
git merge --ff-only 'jaideeppyne/fix/urn-prefix-case-insensitive'
git switch 'main'
git merge 'jaideeppyne/fix/urn-prefix-case-insensitive'
git push origin 'main'
Sign in to join this conversation.
No reviewers
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-uuid-rs/uuid!912
No description provided.