2
0
Эх сурвалжийг харах

Add API for creating custom version 8 UUIDs

Feoramund 1 жил өмнө
parent
commit
5a75cac5b9

+ 89 - 0
core/encoding/uuid/stamping.odin

@@ -0,0 +1,89 @@
+package uuid
+
+import "base:runtime"
+
+/*
+Stamp a 128-bit integer as being a valid version 8 UUID.
+
+Per the specification, all version 8 UUIDs are either for experimental or
+vendor-specific purposes. This procedure allows for converting arbitrary data
+into custom UUIDs.
+
+Inputs:
+- integer: Any integer type.
+
+Returns:
+- result: A valid version 8 UUID.
+*/
+stamp_v8_int :: proc(#any_int integer: u128) -> (result: Identifier) {
+	result = transmute(Identifier)cast(u128be)integer
+
+	result[VERSION_BYTE_INDEX] &= 0x0F
+	result[VERSION_BYTE_INDEX] |= 0x80
+
+	result[VARIANT_BYTE_INDEX] &= 0x3F
+	result[VARIANT_BYTE_INDEX] |= 0x80
+
+	return
+}
+
+/*
+Stamp an array of 16 bytes as being a valid version 8 UUID.
+
+Per the specification, all version 8 UUIDs are either for experimental or
+vendor-specific purposes. This procedure allows for converting arbitrary data
+into custom UUIDs.
+
+Inputs:
+- array: An array of 16 bytes.
+
+Returns:
+- result: A valid version 8 UUID.
+*/
+stamp_v8_array :: proc(array: [16]u8) -> (result: Identifier) {
+	result = transmute(Identifier)array
+
+	result[VERSION_BYTE_INDEX] &= 0x0F
+	result[VERSION_BYTE_INDEX] |= 0x80
+
+	result[VARIANT_BYTE_INDEX] &= 0x3F
+	result[VARIANT_BYTE_INDEX] |= 0x80
+
+	return
+}
+
+/*
+Stamp a slice of bytes as being a valid version 8 UUID.
+
+If the slice is less than 16 bytes long, the data available will be used.
+If it is longer than 16 bytes, only the first 16 will be used.
+
+This procedure does not modify the underlying slice.
+
+Per the specification, all version 8 UUIDs are either for experimental or
+vendor-specific purposes. This procedure allows for converting arbitrary data
+into custom UUIDs.
+
+Inputs:
+- slice: A slice of bytes.
+
+Returns:
+- result: A valid version 8 UUID.
+*/
+stamp_v8_slice :: proc(slice: []u8) -> (result: Identifier) {
+	runtime.mem_copy_non_overlapping(&result, &slice[0], min(16, len(slice)))
+
+	result[VERSION_BYTE_INDEX] &= 0x0F
+	result[VERSION_BYTE_INDEX] |= 0x80
+
+	result[VARIANT_BYTE_INDEX] &= 0x3F
+	result[VARIANT_BYTE_INDEX] |= 0x80
+
+	return
+}
+
+stamp_v8 :: proc {
+	stamp_v8_int,
+	stamp_v8_array,
+	stamp_v8_slice,
+}

+ 17 - 3
tests/core/encoding/uuid/test_core_uuid.odin

@@ -18,7 +18,13 @@ test_version_and_variant :: proc(t: ^testing.T) {
 	v5 := uuid_legacy.generate_v5(uuid.Namespace_DNS, "")
 	v6 := uuid.generate_v6()
 	v7 := uuid.generate_v7()
-	v8 := uuid.generate_v8_hash(uuid.Namespace_DNS, "", .SHA512)
+
+	_v8_array: [16]u8 = 0xff
+	v8_int := uuid.stamp_v8(max(u128))
+	v8_array := uuid.stamp_v8(_v8_array)
+	v8_slice := uuid.stamp_v8(_v8_array[:])
+
+	v8_hash := uuid.generate_v8_hash(uuid.Namespace_DNS, "", .SHA512)
 
 	testing.expect_value(t, uuid.version(v1), 1)
 	testing.expect_value(t, uuid.variant(v1), uuid.Variant_Type.RFC_4122)
@@ -32,8 +38,16 @@ test_version_and_variant :: proc(t: ^testing.T) {
 	testing.expect_value(t, uuid.variant(v6), uuid.Variant_Type.RFC_4122)
 	testing.expect_value(t, uuid.version(v7), 7)
 	testing.expect_value(t, uuid.variant(v7), uuid.Variant_Type.RFC_4122)
-	testing.expect_value(t, uuid.version(v8), 8)
-	testing.expect_value(t, uuid.variant(v8), uuid.Variant_Type.RFC_4122)
+
+	testing.expect_value(t, uuid.version(v8_int), 8)
+	testing.expect_value(t, uuid.variant(v8_int), uuid.Variant_Type.RFC_4122)
+	testing.expect_value(t, uuid.version(v8_array), 8)
+	testing.expect_value(t, uuid.variant(v8_array), uuid.Variant_Type.RFC_4122)
+	testing.expect_value(t, uuid.version(v8_slice), 8)
+	testing.expect_value(t, uuid.variant(v8_slice), uuid.Variant_Type.RFC_4122)
+
+	testing.expect_value(t, uuid.version(v8_hash), 8)
+	testing.expect_value(t, uuid.variant(v8_hash), uuid.Variant_Type.RFC_4122)
 }
 
 @(test)