Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions lib/uuid.ex
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ defmodule Uniq.UUID do
# Parse version
defp parse_raw(<<_::48, version::uint(4), _::bitstring>> = bin, acc) do
case version do
v when v in [1, 3, 4, 5, 6, 7] ->
v when v in [1, 3, 4, 5, 6, 7, 8] ->
with {:ok, uuid} <- parse_raw(version, bin, acc) do
{:ok, %__MODULE__{uuid | bytes: bin}}
end
Expand Down Expand Up @@ -564,6 +564,23 @@ defmodule Uniq.UUID do
end
end

# Generic parse proposed version 8 uuids.
# We can't validate the meaningful part of a uuid itself, but we can extract version and check variant
defp parse_raw(8, <<1::1, 0::1>> = variant, pre_variant, post_variant, acc) do
with <<_custom_a::biguint(48), _version::4, _custom_b::12>> <- <<pre_variant::64>>,
<<_custom_c::62>> <- post_variant do
{:ok,
%__MODULE__{
acc
| version: 8,
variant: variant
}}
else
_ ->
{:error, {:invalid_format, :v8}}
end
end

# Parses proposed version 7 uuids
defp parse_raw(7, <<1::1, 0::1>> = variant, time, rest, acc) do
with <<time::biguint(48), _version::4, _rand_a::12>> <- <<time::64>>,
Expand Down Expand Up @@ -604,7 +621,7 @@ defmodule Uniq.UUID do

defp parse_raw(6, variant, _time, _rest, _acc), do: {:error, {:invalid_variant, variant}}

# Handles proposed version 7 and 8 uuids
# Handles other version uuids
defp parse_raw(version, _variant, _time, _rest, _acc),
do: {:error, {:unsupported_version, version}}

Expand Down
6 changes: 3 additions & 3 deletions test/support/generators.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ defmodule Uniq.Test.Generators do
@reserved_ms <<6::3>>
@reserved_future <<7::3>>
@rfc_versions [1, 3, 4, 5]
@versions [1, 3, 4, 5, 6, 7]
@versions [1, 3, 4, 5, 6, 7, 8]
@variants [@reserved_ncs, @rfc_variant, @reserved_ms, @reserved_future]
@reserved_variants [@reserved_ncs, @reserved_ms, @reserved_future]
@reserved_variants_uniform [<<0::3>>, <<6::3>>, <<7::3>>]
Expand Down Expand Up @@ -48,7 +48,7 @@ defmodule Uniq.Test.Generators do
bind(bitstring(length: 128), fn <<start::48, v::4, mid::12, var::bitstring-size(3),
rest::61>> = bits ->
case v do
v when v in [6, 7] ->
v when v in [6, 7, 8] ->
# Version 6 specifically only allows a single variant to be considered valid
case var do
<<@rfc_variant, _::1>> ->
Expand All @@ -65,7 +65,7 @@ defmodule Uniq.Test.Generators do
v when v in @rfc_versions ->
# Any 3-bit pattern is technically valid as a variant in a UUID per the RFC, so we instead generate
# a known-invalid version.
bind(integer(8..15), fn version ->
bind(integer(9..15), fn version ->
constant(<<start::48, version::4, mid::12, var::bitstring-size(3), rest::61>>)
end)

Expand Down
11 changes: 10 additions & 1 deletion test/uniq_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ defmodule Uniq.Test do
# generated in the :dns namespace, name "test"
5 => "4be0643f-1d98-573b-97cd-ca98a65347dd",
6 => "1e7126af-f130-6780-adb4-8bbe7368fc2f",
7 => "0182b66c-29e7-7ae8-b60e-4b669fe07c77"
7 => "0182b66c-29e7-7ae8-b60e-4b669fe07c77",
8 => "34e3992d-8a73-83de-9486-0f622063b665"
}

hex =
Expand Down Expand Up @@ -68,6 +69,10 @@ defmodule Uniq.Test do
assert parse(7, uuids)
end

test "can parse version 8", %{uuids: uuids} do
assert parse(8, uuids)
end

property "can parse any 128-bit binary with valid version/variant values" do
check all({version, variant, uuid} <- valid_uuid()) do
assert {:ok, %UUID{version: ^version, variant: ^variant}} = UUID.parse(uuid)
Expand Down Expand Up @@ -133,6 +138,10 @@ defmodule Uniq.Test do
test "can format version 7", %{uuids: uuids} do
assert format(7, uuids)
end

test "can format version 8", %{uuids: uuids} do
assert format(8, uuids)
end
end

describe "generating" do
Expand Down