123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- package uuid
- import "base:runtime"
- import "core:time"
- /*
- 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[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[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[VARIANT_BYTE_INDEX] & 0x80 == 0:
- return .Reserved_Apollo_NCS
- case id[VARIANT_BYTE_INDEX] & 0xC0 == 0x80:
- return .RFC_4122
- case id[VARIANT_BYTE_INDEX] & 0xE0 == 0xC0:
- return .Reserved_Microsoft_COM
- case id[VARIANT_BYTE_INDEX] & 0xF0 == 0xE0:
- return .Reserved_Future
- case:
- return .Unknown
- }
- }
- /*
- Get the clock sequence of a version 1 or version 6 UUID.
- Inputs:
- - id: The identifier.
- Returns:
- - clock_seq: The 14-bit clock sequence field.
- */
- clock_seq :: proc "contextless" (id: Identifier) -> (clock_seq: u16) {
- return cast(u16)id[9] | cast(u16)id[8] & 0x3F << 8
- }
- /*
- Get the node of a version 1 or version 6 UUID.
- Inputs:
- - id: The identifier.
- Returns:
- - node: The 48-bit spatially unique identifier.
- */
- node :: proc "contextless" (id: Identifier) -> (node: [6]u8) {
- mutable_id := id
- runtime.mem_copy_non_overlapping(&node, &mutable_id[10], 6)
- return
- }
- /*
- Get the raw timestamp of a version 1 UUID.
- Inputs:
- - id: The identifier.
- Returns:
- - timestamp: The timestamp, in 100-nanosecond intervals since 1582-10-15.
- */
- raw_time_v1 :: proc "contextless" (id: Identifier) -> (timestamp: u64) {
- timestamp_octets: [8]u8
- timestamp_octets[0] = id[0]
- timestamp_octets[1] = id[1]
- timestamp_octets[2] = id[2]
- timestamp_octets[3] = id[3]
- timestamp_octets[4] = id[4]
- timestamp_octets[5] = id[5]
- timestamp_octets[6] = id[6] << 4 | id[7] >> 4
- timestamp_octets[7] = id[7] & 0xF
- return cast(u64)transmute(u64le)timestamp_octets
- }
- /*
- Get the timestamp of a version 1 UUID.
- Inputs:
- - id: The identifier.
- Returns:
- - timestamp: The timestamp of the UUID.
- */
- time_v1 :: proc "contextless" (id: Identifier) -> (timestamp: time.Time) {
- return time.from_nanoseconds(cast(i64)(raw_time_v1(id) - HNS_INTERVALS_BETWEEN_GREG_AND_UNIX) * 100)
- }
- /*
- Get the raw timestamp of a version 6 UUID.
- Inputs:
- - id: The identifier.
- Returns:
- - timestamp: The timestamp, in 100-nanosecond intervals since 1582-10-15.
- */
- raw_time_v6 :: proc "contextless" (id: Identifier) -> (timestamp: u64) {
- temporary := transmute(u128be)id
- timestamp |= cast(u64)(temporary & 0xFFFFFFFF_FFFF0000_00000000_00000000 >> 68)
- timestamp |= cast(u64)(temporary & 0x00000000_00000FFF_00000000_00000000 >> 64)
- return timestamp
- }
- /*
- Get the timestamp of a version 6 UUID.
- Inputs:
- - id: The identifier.
- Returns:
- - timestamp: The timestamp, in 100-nanosecond intervals since 1582-10-15.
- */
- time_v6 :: proc "contextless" (id: Identifier) -> (timestamp: time.Time) {
- return time.from_nanoseconds(cast(i64)(raw_time_v6(id) - HNS_INTERVALS_BETWEEN_GREG_AND_UNIX) * 100)
- }
- /*
- Get the raw timestamp of a version 7 UUID.
- Inputs:
- - id: The identifier.
- Returns:
- - timestamp: The timestamp, in milliseconds since the UNIX epoch.
- */
- raw_time_v7 :: proc "contextless" (id: Identifier) -> (timestamp: u64) {
- time_bits := transmute(u128be)id & VERSION_7_TIME_MASK
- return cast(u64)(time_bits >> VERSION_7_TIME_SHIFT)
- }
- /*
- Get the timestamp of a version 7 UUID.
- Inputs:
- - id: The identifier.
- Returns:
- - timestamp: The timestamp, in milliseconds since the UNIX epoch.
- */
- time_v7 :: proc "contextless" (id: Identifier) -> (timestamp: time.Time) {
- return time.from_nanoseconds(cast(i64)raw_time_v7(id) * 1e6)
- }
- /*
- Get the 12-bit counter value of a version 7 UUID.
- The UUID must have been generated with a counter, otherwise this procedure will
- return random bits.
- Inputs:
- - id: The identifier.
- Returns:
- - counter: The 12-bit counter value.
- */
- counter_v7 :: proc "contextless" (id: Identifier) -> (counter: u16) {
- counter_bits := transmute(u128be)id & VERSION_7_COUNTER_MASK
- return cast(u16)(counter_bits >> VERSION_7_COUNTER_SHIFT)
- }
|