From 005d8a8510f9e209e9a794bfaf45a36974ae7ef0 Mon Sep 17 00:00:00 2001 From: Heptazhou Date: Fri, 29 Mar 2024 21:14:18 +0000 Subject: [PATCH] Update --- .github/workflows/CI.yml | 8 +-- Project.toml | 6 +-- src/UUID4.jl | 109 ++++++++++++++++++--------------------- test/runtests.jl | 11 ++-- 4 files changed, 64 insertions(+), 70 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 63e14e2..43e8ecd 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -32,16 +32,18 @@ jobs: - os: macos-latest julia-version: nightly steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: persist-credentials: false - - uses: julia-actions/setup-julia@v1 + - uses: julia-actions/setup-julia@v2 with: show-versioninfo: true version: ${{ matrix.julia-version }} - uses: julia-actions/julia-buildpkg@v1 + with: + ignore-no-cache: true - uses: julia-actions/julia-runtest@v1 - uses: heptazhou/julia-codecov@v1 - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v3.1.5 with: file: lcov.info diff --git a/Project.toml b/Project.toml index 912a55f..adff298 100644 --- a/Project.toml +++ b/Project.toml @@ -1,14 +1,14 @@ name = "UUID4" uuid = "379725f3-1ad5-416d-b88a-50ced391fe04" authors = ["Heptazhou "] -version = "1.8.0" +version = "1.10.0" [deps] -OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [extras] +OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test"] +test = ["OrderedCollections", "Test"] diff --git a/src/UUID4.jl b/src/UUID4.jl index 1da92b0..283a2be 100644 --- a/src/UUID4.jl +++ b/src/UUID4.jl @@ -1,4 +1,4 @@ -# Copyright (C) 2022-2023 Heptazhou +# Copyright (C) 2022-2024 Heptazhou # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -16,29 +16,31 @@ """ UUID4 -The `UUID4` module provides universally unique identifier (UUID), version 4, +This module provides universally unique identifier (UUID) version 4, along with related functions. """ module UUID4 export uuid, uuid4 + export uuid_formats export uuid_parse export uuid_string +export uuid_tryparse export uuid_version export AbstractRNG, MersenneTwister, RandomDevice -export LittleDict, OrderedDict export UUID + +const Maybe{T} = Union{Nothing, T} const UUID = Base.UUID -using OrderedCollections: LittleDict, OrderedDict using Random: AbstractRNG, MersenneTwister, RandomDevice """ - uuid(rng::AbstractRNG = RandomDevice()) -> UUID + uuid(rng::AbstractRNG = Random.RandomDevice()) -> UUID -Generate a version 4 (random or pseudo-random) universally unique identifier -(UUID), as specified by [RFC 4122](https://www.ietf.org/rfc/rfc4122). +Generate a version 4 (random or pseudo-random) universally unique identifier (UUID), +as specified by [RFC 4122](https://tools.ietf.org/html/rfc4122). # Examples ```jldoctest @@ -76,39 +78,22 @@ function uuid_formats()::Vector{Int} end """ - uuid_parse(str::String; fmt::Int = length(str)) -> Tuple{Int, UUID} + uuid_parse(str::AbstractString; fmt::Int = length(str)) -> Tuple{Int, UUID} """ function uuid_parse end -function uuid_parse(str::UUID; fmt::Any = 0x0)::Tuple{Int, UUID} - uuid_parse(string(str); fmt = Int(fmt)) +function uuid_parse(id::UUID)::Tuple{Int, UUID} + (length("$id"), id) # (36, id) end -function uuid_parse(str::Any; fmt::Number = 0)::Tuple{Int, UUID} - uuid_parse(String(str); fmt = Int(fmt)) -end -function uuid_parse(str::String; fmt::Int = 0)::Tuple{Int, UUID} +function uuid_parse(str::AbstractString; fmt::Int = 0)::Tuple{Int, UUID} len = length(str) - ret = if 0 > fmt - argumenterror("Invalid format `$fmt` (should be positive)") - elseif len ≠ fmt > 0 - argumenterror("Invalid id `$str` with length = $len (should be $fmt)") - elseif len ≡ 24 - uuid_parse(replace((str), "-" => ""), fmt = 22)[end] - elseif len ≡ 29 - uuid_parse(replace((str), "-" => ""), fmt = 25)[end] - elseif len ≡ 39 - uuid_parse(replace((str), "-" => ""), fmt = 32)[end] - elseif len ≡ 22 - UUID(parse(UInt128, str, base = 62)) - elseif len ≡ 25 - UUID(parse(UInt128, str, base = 36)) - elseif len ≡ 32 - UUID(parse(UInt128, str, base = 16)) - elseif len ≡ 36 - UUID(str) - else + (id = uuid_tryparse(str)) |> isnothing && argumenterror("Invalid id `$str` with length = $len") + if 0 < fmt ≠ len + argumenterror("Invalid id `$str` with length = $len (should be $fmt)") + elseif fmt < 0 + argumenterror("Invalid format `$fmt` (should be positive)") end - len, ret + len, id |> UUID end """ @@ -159,33 +144,38 @@ function uuid_string(fmt::Int, id::UUID = uuid())::String uuid_string(id, fmt) end function uuid_string(id::UUID, fmt::Int)::String - if 0 ≥ fmt - argumenterror("Invalid format `$fmt` (should be positive)") - elseif fmt ≡ 36 - string(id) - elseif fmt ≡ 22 - string(id.value, base = 62, pad = fmt) - elseif fmt ≡ 25 - string(id.value, base = 36, pad = fmt) - elseif fmt ≡ 32 - string(id.value, base = 16, pad = fmt) - elseif fmt ≡ 24 - replace(uuid_string(id, 22), r"(.{7})" => s"\1-", count = fmt - 22) - elseif fmt ≡ 29 - replace(uuid_string(id, 25), r"(.{5})" => s"\1-", count = fmt - 25) - elseif fmt ≡ 39 - replace(uuid_string(id, 32), r"(.{4})" => s"\1-", count = fmt - 32) - else - argumenterror("Invalid format `$fmt` (undefined)") - end + fmt ≤ 0 ? + argumenterror("Invalid format `$fmt` (should be positive)") : + fmt ≡ 36 ? string(id) : + fmt ≡ 22 ? string(id.value, base = 62, pad = fmt) : + fmt ≡ 25 ? string(id.value, base = 36, pad = fmt) : + fmt ≡ 32 ? string(id.value, base = 16, pad = fmt) : + fmt ≡ 24 ? replace(uuid_string(id, 22), r"(.{7})" => s"\1-", count = fmt - 22) : + fmt ≡ 29 ? replace(uuid_string(id, 25), r"(.{5})" => s"\1-", count = fmt - 25) : + fmt ≡ 39 ? replace(uuid_string(id, 32), r"(.{4})" => s"\1-", count = fmt - 32) : + argumenterror("Invalid format `$fmt` (not defined)") +end + +""" + uuid_tryparse(s::AbstractString) -> Maybe{Union{AbstractString, UInt128}} +""" +function uuid_tryparse(str::AbstractString)::Maybe{Union{AbstractString, UInt128}} + len = ncodeunits(str) + len ≡ 24 ? uuid_tryparse(replace(str, "-" => "")) : + len ≡ 29 ? uuid_tryparse(replace(str, "-" => "")) : + len ≡ 39 ? uuid_tryparse(replace(str, "-" => "")) : + len ≡ 22 ? Base.tryparse(UInt128, str, base = 62) : + len ≡ 25 ? Base.tryparse(UInt128, str, base = 36) : + len ≡ 32 ? Base.tryparse(UInt128, str, base = 16) : + len ≡ 36 ? str : nothing end """ - uuid_version(id::String) -> Int - uuid_version(id::UUID) -> Int + uuid_version(id::AbstractString) -> Int + uuid_version(id::UUID) -> Int -Inspect the given UUID or UUID string and return its version (see [RFC -4122](https://www.ietf.org/rfc/rfc4122)). +Inspect the given UUID or UUID string and return its version +(see [RFC 4122](https://tools.ietf.org/html/rfc4122)). # Examples ```jldoctest @@ -194,9 +184,8 @@ julia> uuid_version(uuid()) ``` """ function uuid_version end -uuid_version(id::Any)::Int = uuid_version(String(id)) -uuid_version(id::String)::Int = uuid_version(uuid_parse(id)[end]) -uuid_version(id::UUID)::Int = Int(id.value >> 76 & 0xf) +uuid_version(id::Any)::Int = uuid_version(uuid_parse(id)[end]) +uuid_version(id::UUID)::Int = id.value >> 76 & 0xf |> Int @noinline argumenterror(msg::AbstractString) = throw(ArgumentError(msg)) diff --git a/test/runtests.jl b/test/runtests.jl index ff26c7f..c2083f6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ -# Copyright (C) 2022-2023 Heptazhou +# Copyright (C) 2022-2024 Heptazhou # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -13,6 +13,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +using OrderedCollections: LittleDict, OrderedDict using Random: Random using Test, UUID4 @@ -40,7 +41,7 @@ str = "22b4a8a1-e548-4eeb-9270-60426d66a48e" @test_throws ArgumentError UUID("22b4a8a1-e548-4eeba9270-60426d66a48e") @test_throws ArgumentError UUID("22b4a8a1-e548-4eeb-9270a60426d66a48e") @test UUID(uppercase(str)) == UUID(str) -for r in (rand(UInt128, 10^3)) +for r ∈ rand(UInt128, 10^3) @test UUID(r) == UUID(string(UUID(r))) end @@ -58,9 +59,10 @@ d_o, d_u = OrderedDict(vec), Dict(vec) u = UUID(d_u[36]) s = GenericString(string(u)) +@test uuid_tryparse("") |> isnothing @test uuid_parse(s) == uuid_parse(u) == (36, u) @test uuid_formats() == d_o.keys == fmt -for n in fmt +for n ∈ fmt @test (n, u) == uuid_parse(d_u[n]) == uuid_parse(d_u[n] |> GenericString) @test d_u[n] == uuid_string(n, u) == uuid_string(u, n |> UInt32) == d_o[n] @test d_o[n] == uuid_string(n, u |> string) == uuid_string(u |> string, n) @@ -71,9 +73,10 @@ end @test_throws ArgumentError uuid_parse(d_u[32], fmt = 42) @test_throws ArgumentError uuid_parse(d_u[32]^2) +@test uuid_string(u, LittleDict) == uuid_string(LittleDict, u) @test uuid_string(u, OrderedDict) == uuid_string(OrderedDict, u) @test uuid_string(u) == uuid_string(Dict, u) == d_u == Dict(d_o) -@test uuid_string(u) == uuid_string(Dict, s) == uuid_string(s, Dict) +@test uuid_string(u) == uuid_string(s, Dict) == uuid_string(Dict, s) @test_throws ArgumentError uuid_string(u, -1) @test_throws ArgumentError uuid_string(u, 42)