mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-16 16:14:06 +00:00
Add core:encoding/uuid
This commit is contained in:
28
core/encoding/uuid/LICENSE
Normal file
28
core/encoding/uuid/LICENSE
Normal file
@@ -0,0 +1,28 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2024, Feoramund
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
59
core/encoding/uuid/definitions.odin
Normal file
59
core/encoding/uuid/definitions.odin
Normal file
@@ -0,0 +1,59 @@
|
||||
package uuid
|
||||
|
||||
// A RFC 4122 Universally Unique Identifier
|
||||
Identifier :: struct #raw_union {
|
||||
integer: u128be,
|
||||
bytes: [16]u8,
|
||||
}
|
||||
|
||||
EXPECTED_LENGTH :: 8 + 4 + 4 + 4 + 12 + 4
|
||||
|
||||
VERSION_BYTE_INDEX :: 6
|
||||
VARIANT_BYTE_INDEX :: 8
|
||||
|
||||
Read_Error :: enum {
|
||||
None,
|
||||
Invalid_Length,
|
||||
Invalid_Hexadecimal,
|
||||
Invalid_Separator,
|
||||
}
|
||||
|
||||
Variant_Type :: enum {
|
||||
Unknown,
|
||||
Reserved_Apollo_NCS, // 0b0xx
|
||||
RFC_4122, // 0b10x
|
||||
Reserved_Microsoft_COM, // 0b110
|
||||
Reserved_Future, // 0b111
|
||||
}
|
||||
|
||||
// Name string is a URL.
|
||||
Namespace_DNS := Identifier {
|
||||
bytes = {
|
||||
0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
|
||||
0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
|
||||
},
|
||||
}
|
||||
|
||||
// Name string is a fully-qualified domain name.
|
||||
Namespace_URL := Identifier {
|
||||
bytes = {
|
||||
0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1,
|
||||
0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
|
||||
},
|
||||
}
|
||||
|
||||
// Name string is an ISO OID.
|
||||
Namespace_OID := Identifier {
|
||||
bytes = {
|
||||
0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1,
|
||||
0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
|
||||
},
|
||||
}
|
||||
|
||||
// Name string is an X.500 DN (in DER or a text output format).
|
||||
Namespace_X500 := Identifier {
|
||||
bytes = {
|
||||
0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1,
|
||||
0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
|
||||
},
|
||||
}
|
||||
15
core/encoding/uuid/doc.odin
Normal file
15
core/encoding/uuid/doc.odin
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
package uuid implements Universally Unique Identifiers according to the
|
||||
standard outlined in RFC 4122.
|
||||
|
||||
See here for more information: https://www.rfc-editor.org/rfc/rfc4122.html
|
||||
|
||||
Generation of versions 1 and 2 (the MAC address-based versions) are not yet
|
||||
implemented.
|
||||
|
||||
The UUIDs are textually represented and read in the following string format:
|
||||
`00000000-0000-4000-8000-000000000000`
|
||||
|
||||
Outside of string representations, they are represented in memory by a 128-bit structure.
|
||||
*/
|
||||
package uuid
|
||||
159
core/encoding/uuid/generation.odin
Normal file
159
core/encoding/uuid/generation.odin
Normal file
@@ -0,0 +1,159 @@
|
||||
package uuid
|
||||
|
||||
import "core:crypto/legacy/md5"
|
||||
import "core:crypto/legacy/sha1"
|
||||
import "core:math/rand"
|
||||
import "core:mem"
|
||||
|
||||
/*
|
||||
Generate a version 3 UUID.
|
||||
|
||||
This UUID is generated from a name within a namespace.
|
||||
MD5 is used to hash the name with the namespace to produce the UUID.
|
||||
|
||||
Inputs:
|
||||
- namespace: Another `Identifier` that is used to represent the underlying namespace.
|
||||
This can be any one of the `Namespace_*` values provided in this package.
|
||||
- name: The byte slice used to generate the name on top of the namespace.
|
||||
|
||||
Returns:
|
||||
- result: The generated UUID.
|
||||
*/
|
||||
generate_v3_bytes :: proc(
|
||||
namespace: Identifier,
|
||||
name: []byte,
|
||||
) -> (
|
||||
result: Identifier,
|
||||
) {
|
||||
namespace := namespace
|
||||
|
||||
ctx: md5.Context
|
||||
md5.init(&ctx)
|
||||
md5.update(&ctx, namespace.bytes[:])
|
||||
md5.update(&ctx, name)
|
||||
md5.final(&ctx, result.bytes[:])
|
||||
|
||||
result.bytes[VERSION_BYTE_INDEX] &= 0x0F
|
||||
result.bytes[VERSION_BYTE_INDEX] |= 0x30
|
||||
|
||||
result.bytes[VARIANT_BYTE_INDEX] &= 0x3F
|
||||
result.bytes[VARIANT_BYTE_INDEX] |= 0x80
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Generate a version 3 UUID.
|
||||
|
||||
This UUID is generated from a name within a namespace.
|
||||
MD5 is used to hash the name with the namespace to produce the UUID.
|
||||
|
||||
Inputs:
|
||||
- namespace: Another `Identifier` that is used to represent the underlying namespace.
|
||||
This can be any one of the `Namespace_*` values provided in this package.
|
||||
- name: The string used to generate the name on top of the namespace.
|
||||
|
||||
Returns:
|
||||
- result: The generated UUID.
|
||||
*/
|
||||
generate_v3_string :: proc(
|
||||
namespace: Identifier,
|
||||
name: string,
|
||||
) -> (
|
||||
result: Identifier,
|
||||
) {
|
||||
return generate_v3_bytes(namespace, transmute([]byte)name)
|
||||
}
|
||||
|
||||
generate_v3 :: proc {
|
||||
generate_v3_bytes,
|
||||
generate_v3_string,
|
||||
}
|
||||
|
||||
/*
|
||||
Generate a version 4 UUID.
|
||||
|
||||
This UUID will be pseudorandom, save for 6 pre-determined version and variant bits.
|
||||
|
||||
Returns:
|
||||
- result: The generated UUID.
|
||||
*/
|
||||
generate_v4 :: proc() -> (result: Identifier) {
|
||||
result.integer = transmute(u128be)rand.uint128()
|
||||
|
||||
result.bytes[VERSION_BYTE_INDEX] &= 0x0F
|
||||
result.bytes[VERSION_BYTE_INDEX] |= 0x40
|
||||
|
||||
result.bytes[VARIANT_BYTE_INDEX] &= 0x3F
|
||||
result.bytes[VARIANT_BYTE_INDEX] |= 0x80
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Generate a version 5 UUID.
|
||||
|
||||
This UUID is generated from a name within a namespace.
|
||||
SHA1 is used to hash the name with the namespace to produce the UUID.
|
||||
|
||||
Inputs:
|
||||
- namespace: Another `Identifier` that is used to represent the underlying namespace.
|
||||
This can be any one of the `Namespace_*` values provided in this package.
|
||||
- name: The byte slice used to generate the name on top of the namespace.
|
||||
|
||||
Returns:
|
||||
- result: The generated UUID.
|
||||
*/
|
||||
generate_v5_bytes :: proc(
|
||||
namespace: Identifier,
|
||||
name: []byte,
|
||||
) -> (
|
||||
result: Identifier,
|
||||
) {
|
||||
namespace := namespace
|
||||
digest: [sha1.DIGEST_SIZE]byte
|
||||
|
||||
ctx: sha1.Context
|
||||
sha1.init(&ctx)
|
||||
sha1.update(&ctx, namespace.bytes[:])
|
||||
sha1.update(&ctx, name)
|
||||
sha1.final(&ctx, digest[:])
|
||||
|
||||
mem.copy_non_overlapping(&result.bytes, &digest, 16)
|
||||
|
||||
result.bytes[VERSION_BYTE_INDEX] &= 0x0F
|
||||
result.bytes[VERSION_BYTE_INDEX] |= 0x50
|
||||
|
||||
result.bytes[VARIANT_BYTE_INDEX] &= 0x3F
|
||||
result.bytes[VARIANT_BYTE_INDEX] |= 0x80
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Generate a version 5 UUID.
|
||||
|
||||
This UUID is generated from a name within a namespace.
|
||||
SHA1 is used to hash the name with the namespace to produce the UUID.
|
||||
|
||||
Inputs:
|
||||
- namespace: Another `Identifier` that is used to represent the underlying namespace.
|
||||
This can be any one of the `Namespace_*` values provided in this package.
|
||||
- name: The string used to generate the name on top of the namespace.
|
||||
|
||||
Returns:
|
||||
- result: The generated UUID.
|
||||
*/
|
||||
generate_v5_string :: proc(
|
||||
namespace: Identifier,
|
||||
name: string,
|
||||
) -> (
|
||||
result: Identifier,
|
||||
) {
|
||||
return generate_v5_bytes(namespace, transmute([]byte)name)
|
||||
}
|
||||
|
||||
generate_v5 :: proc {
|
||||
generate_v5_bytes,
|
||||
generate_v5_string,
|
||||
}
|
||||
97
core/encoding/uuid/reading.odin
Normal file
97
core/encoding/uuid/reading.odin
Normal file
@@ -0,0 +1,97 @@
|
||||
package uuid
|
||||
|
||||
/*
|
||||
Convert a string to a UUID.
|
||||
|
||||
Inputs:
|
||||
- str: A string in the 8-4-4-4-12 format.
|
||||
|
||||
Returns:
|
||||
- id: The converted identifier, or `nil` if there is an error.
|
||||
- error: A description of the error, or `nil` if successful.
|
||||
*/
|
||||
read :: proc "contextless" (str: string) -> (id: Identifier, error: Read_Error) #no_bounds_check {
|
||||
// Only exact-length strings are acceptable.
|
||||
if len(str) != EXPECTED_LENGTH {
|
||||
return {}, .Invalid_Length
|
||||
}
|
||||
|
||||
// Check ahead to see if the separators are in the right places.
|
||||
if str[8] != '-' || str[13] != '-' || str[18] != '-' || str[23] != '-' {
|
||||
return {}, .Invalid_Separator
|
||||
}
|
||||
|
||||
read_nibble :: proc "contextless" (nibble: u8) -> u8 {
|
||||
switch nibble {
|
||||
case '0' ..= '9':
|
||||
return nibble - '0'
|
||||
case 'A' ..= 'F':
|
||||
return nibble - 'A' + 10
|
||||
case 'a' ..= 'f':
|
||||
return nibble - 'a' + 10
|
||||
case:
|
||||
// Return an error value.
|
||||
return 0xFF
|
||||
}
|
||||
}
|
||||
|
||||
index := 0
|
||||
octet_index := 0
|
||||
|
||||
CHUNKS :: [5]int{8, 4, 4, 4, 12}
|
||||
|
||||
for chunk in CHUNKS {
|
||||
for i := index; i < index + chunk; i += 2 {
|
||||
high := read_nibble(str[i])
|
||||
low := read_nibble(str[i + 1])
|
||||
|
||||
if high | low > 0xF {
|
||||
return {}, .Invalid_Hexadecimal
|
||||
}
|
||||
|
||||
id.bytes[octet_index] = low | high << 4
|
||||
octet_index += 1
|
||||
}
|
||||
|
||||
index += chunk + 1
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Get the version of a UUID.
|
||||
|
||||
Inputs:
|
||||
- id: The identifier.
|
||||
|
||||
Returns:
|
||||
- number: The version number.
|
||||
*/
|
||||
version :: proc "contextless" (id: Identifier) -> (number: int) #no_bounds_check {
|
||||
return cast(int)(id.bytes[VERSION_BYTE_INDEX] & 0xF0 >> 4)
|
||||
}
|
||||
|
||||
/*
|
||||
Get the variant of a UUID.
|
||||
|
||||
Inputs:
|
||||
- id: The identifier.
|
||||
|
||||
Returns:
|
||||
- variant: The variant type.
|
||||
*/
|
||||
variant :: proc "contextless" (id: Identifier) -> (variant: Variant_Type) #no_bounds_check {
|
||||
switch {
|
||||
case id.bytes[VARIANT_BYTE_INDEX] & 0x80 == 0:
|
||||
return .Reserved_Apollo_NCS
|
||||
case id.bytes[VARIANT_BYTE_INDEX] & 0xC0 == 0x80:
|
||||
return .RFC_4122
|
||||
case id.bytes[VARIANT_BYTE_INDEX] & 0xE0 == 0xC0:
|
||||
return .Reserved_Microsoft_COM
|
||||
case id.bytes[VARIANT_BYTE_INDEX] & 0xF0 == 0xE0:
|
||||
return .Reserved_Future
|
||||
case:
|
||||
return .Unknown
|
||||
}
|
||||
}
|
||||
61
core/encoding/uuid/writing.odin
Normal file
61
core/encoding/uuid/writing.odin
Normal file
@@ -0,0 +1,61 @@
|
||||
package uuid
|
||||
|
||||
import "base:runtime"
|
||||
import "core:io"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
|
||||
/*
|
||||
Write a UUID in the 8-4-4-4-12 format.
|
||||
|
||||
Inputs:
|
||||
- w: A writable stream.
|
||||
- id: The identifier to convert.
|
||||
*/
|
||||
write :: proc(w: io.Writer, id: Identifier) #no_bounds_check {
|
||||
write_octet :: proc (w: io.Writer, octet: u8) {
|
||||
high_nibble := octet >> 4
|
||||
low_nibble := octet & 0xF
|
||||
|
||||
io.write_byte(w, strconv.digits[high_nibble])
|
||||
io.write_byte(w, strconv.digits[low_nibble])
|
||||
}
|
||||
|
||||
for index in 0 ..< 4 { write_octet(w, id.bytes[index]) }
|
||||
io.write_byte(w, '-')
|
||||
for index in 4 ..< 6 { write_octet(w, id.bytes[index]) }
|
||||
io.write_byte(w, '-')
|
||||
for index in 6 ..< 8 { write_octet(w, id.bytes[index]) }
|
||||
io.write_byte(w, '-')
|
||||
for index in 8 ..< 10 { write_octet(w, id.bytes[index]) }
|
||||
io.write_byte(w, '-')
|
||||
for index in 10 ..< 16 { write_octet(w, id.bytes[index]) }
|
||||
}
|
||||
|
||||
/*
|
||||
Convert a UUID to a string in the 8-4-4-4-12 format.
|
||||
|
||||
*Allocates Using Provided Allocator*
|
||||
|
||||
Inputs:
|
||||
- id: The identifier to convert.
|
||||
- allocator: (default: context.allocator)
|
||||
- loc: The caller location for debugging purposes (default: #caller_location)
|
||||
|
||||
Returns:
|
||||
- str: The allocated and converted string.
|
||||
- error: An optional allocator error if one occured, `nil` otherwise.
|
||||
*/
|
||||
to_string :: proc(
|
||||
id: Identifier,
|
||||
allocator := context.allocator,
|
||||
loc := #caller_location,
|
||||
) -> (
|
||||
str: string,
|
||||
error: runtime.Allocator_Error,
|
||||
) #optional_allocator_error {
|
||||
buf := make([]byte, EXPECTED_LENGTH, allocator, loc) or_return
|
||||
builder := strings.builder_from_bytes(buf[:])
|
||||
write(strings.to_writer(&builder), id)
|
||||
return strings.to_string(builder), nil
|
||||
}
|
||||
@@ -62,6 +62,7 @@ import varint "core:encoding/varint"
|
||||
import xml "core:encoding/xml"
|
||||
import endian "core:encoding/endian"
|
||||
import cbor "core:encoding/cbor"
|
||||
import uuid "core:encoding/uuid"
|
||||
|
||||
import fmt "core:fmt"
|
||||
import hash "core:hash"
|
||||
@@ -237,6 +238,7 @@ _ :: datetime
|
||||
_ :: flags
|
||||
_ :: sysinfo
|
||||
_ :: unicode
|
||||
_ :: uuid
|
||||
_ :: utf8
|
||||
_ :: utf8string
|
||||
_ :: utf16
|
||||
|
||||
118
tests/core/encoding/uuid/test_core_uuid.odin
Normal file
118
tests/core/encoding/uuid/test_core_uuid.odin
Normal file
@@ -0,0 +1,118 @@
|
||||
package test_core_uuid
|
||||
|
||||
import "core:testing"
|
||||
import "core:encoding/uuid"
|
||||
|
||||
@(test)
|
||||
test_version_and_variant :: proc(t: ^testing.T) {
|
||||
v3 := uuid.generate_v3(uuid.Namespace_DNS, "")
|
||||
v4 := uuid.generate_v4()
|
||||
v5 := uuid.generate_v5(uuid.Namespace_DNS, "")
|
||||
|
||||
testing.expect_value(t, uuid.version(v3), 3)
|
||||
testing.expect_value(t, uuid.variant(v3), uuid.Variant_Type.RFC_4122)
|
||||
testing.expect_value(t, uuid.version(v4), 4)
|
||||
testing.expect_value(t, uuid.variant(v4), uuid.Variant_Type.RFC_4122)
|
||||
testing.expect_value(t, uuid.version(v5), 5)
|
||||
testing.expect_value(t, uuid.variant(v5), uuid.Variant_Type.RFC_4122)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_namespaced_uuids :: proc(t: ^testing.T) {
|
||||
TEST_NAME :: "0123456789ABCDEF0123456789ABCDEF"
|
||||
|
||||
Expected_Result :: struct {
|
||||
namespace: uuid.Identifier,
|
||||
v3, v5: string,
|
||||
}
|
||||
|
||||
Expected_Results := [?]Expected_Result {
|
||||
{ uuid.Namespace_DNS, "80147f37-36db-3b82-b78f-810c3c6504ba", "18394c41-13a2-593f-abf2-a63e163c2860" },
|
||||
{ uuid.Namespace_URL, "8136789b-8e16-3fbd-800b-1587e2f22521", "07337422-eb77-5fd3-99af-c7f59e641e13" },
|
||||
{ uuid.Namespace_OID, "adbb95bc-ea50-3226-9a75-20c34a6030f8", "24db9b0f-70b8-53c4-a301-f695ce17276d" },
|
||||
{ uuid.Namespace_X500, "a8965ad1-0e54-3d65-b933-8b7cca8e8313", "3012bf2d-fac4-5187-9825-493e6636b936" },
|
||||
}
|
||||
|
||||
for exp in Expected_Results {
|
||||
v3 := uuid.generate_v3(exp.namespace, TEST_NAME)
|
||||
v5 := uuid.generate_v5(exp.namespace, TEST_NAME)
|
||||
|
||||
v3_str := uuid.to_string(v3)
|
||||
defer delete(v3_str)
|
||||
|
||||
v5_str := uuid.to_string(v5)
|
||||
defer delete(v5_str)
|
||||
|
||||
testing.expect_value(t, v3_str, exp.v3)
|
||||
testing.expect_value(t, v5_str, exp.v5)
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_writing :: proc(t: ^testing.T) {
|
||||
id: uuid.Identifier
|
||||
|
||||
for &b, i in id.bytes {
|
||||
b = u8(i)
|
||||
}
|
||||
|
||||
s := uuid.to_string(id)
|
||||
defer delete(s)
|
||||
|
||||
testing.expect_value(t, s, "00010203-0405-0607-0809-0a0b0c0d0e0f")
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_reading :: proc(t: ^testing.T) {
|
||||
id, err := uuid.read("00010203-0405-0607-0809-0a0b0c0d0e0f")
|
||||
testing.expect_value(t, err, nil)
|
||||
|
||||
for b, i in id.bytes {
|
||||
testing.expect_value(t, b, u8(i))
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_reading_errors :: proc(t: ^testing.T) {
|
||||
{
|
||||
BAD_STRING :: "|.......@....@....@....@............"
|
||||
_, err := uuid.read(BAD_STRING)
|
||||
testing.expect_value(t, err, uuid.Read_Error.Invalid_Separator)
|
||||
}
|
||||
|
||||
{
|
||||
BAD_STRING :: "|.......-....-....-....-............"
|
||||
_, err := uuid.read(BAD_STRING)
|
||||
testing.expect_value(t, err, uuid.Read_Error.Invalid_Hexadecimal)
|
||||
}
|
||||
|
||||
{
|
||||
BAD_STRING :: ".......-....-....-....-............"
|
||||
_, err := uuid.read(BAD_STRING)
|
||||
testing.expect_value(t, err, uuid.Read_Error.Invalid_Length)
|
||||
}
|
||||
|
||||
{
|
||||
BAD_STRING :: "|.......-....-....-....-............|"
|
||||
_, err := uuid.read(BAD_STRING)
|
||||
testing.expect_value(t, err, uuid.Read_Error.Invalid_Length)
|
||||
}
|
||||
|
||||
{
|
||||
BAD_STRING :: "00000000-0000-0000-0000-0000000000001"
|
||||
_, err := uuid.read(BAD_STRING)
|
||||
testing.expect_value(t, err, uuid.Read_Error.Invalid_Length)
|
||||
}
|
||||
|
||||
{
|
||||
BAD_STRING :: "00000000000000000000000000000000"
|
||||
_, err := uuid.read(BAD_STRING)
|
||||
testing.expect_value(t, err, uuid.Read_Error.Invalid_Length)
|
||||
}
|
||||
|
||||
{
|
||||
OK_STRING :: "00000000-0000-0000-0000-000000000000"
|
||||
_, err := uuid.read(OK_STRING)
|
||||
testing.expect_value(t, err, nil)
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ download_assets :: proc() {
|
||||
@(require) import "encoding/hex"
|
||||
@(require) import "encoding/hxa"
|
||||
@(require) import "encoding/json"
|
||||
@(require) import "encoding/uuid"
|
||||
@(require) import "encoding/varint"
|
||||
@(require) import "encoding/xml"
|
||||
@(require) import "flags"
|
||||
|
||||
Reference in New Issue
Block a user