const std = @import("std"); const UUID = @This(); bytes: [16]u8, pub const zero: UUID = .{ .bytes = @splat(0) }; pub fn v4(io: std.Io) UUID { var bytes: [16]u8 = undefined; io.random(&bytes); bytes[6] = (bytes[6] & 0x0F) | 0x40; bytes[8] = (bytes[8] & 0x3F) | 0x80; return .{ .bytes = bytes }; } pub const namespaces = struct { /// Name string is a fully-qualified domain name /// /// `6ba7b810-9dad-11d1-80b4-00c04fd430c8` pub const dns: UUID = .{ .bytes = .{ 0x6B, 0xA7, 0xB8, 0x10, 0x9D, 0xAD, 0x11, 0xD1, 0x80, 0xB4, 0x00, 0xC0, 0x4F, 0xD4, 0x30, 0xC8 } }; /// Name string is a URL /// /// `6ba7b811-9dad-11d1-80b4-00c04fd430c8` pub const url: UUID = .{ .bytes = .{ 0x6B, 0xA7, 0xB8, 0x11, 0x9D, 0xAD, 0x11, 0xD1, 0x80, 0xB4, 0x00, 0xC0, 0x4F, 0xD4, 0x30, 0xC8 } }; /// Name string is an ISO OID /// /// `6ba7b812-9dad-11d1-80b4-00c04fd430c8` pub const oid: UUID = .{ .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) /// /// `6ba7b814-9dad-11d1-80b4-00c04fd430c8` pub const x500: UUID = .{ .bytes = .{ 0x6B, 0xA7, 0xB8, 0x14, 0x9D, 0xAD, 0x11, 0xD1, 0x80, 0xB4, 0x00, 0xC0, 0x4F, 0xD4, 0x30, 0xC8 } }; }; pub fn v5(namespace: UUID, name: []const u8) UUID { const hash = blk: { var hasher = std.crypto.hash.Sha1.init(.{}); hasher.update(namespace.bytes); hasher.update(name); break :blk hasher.finalResult(); }; var bytes: [16]u8 = hash[0..16].*; bytes[6] = (bytes[6] & 0x0F) | 0x50; bytes[8] = (bytes[8] & 0x3F) | 0x80; return .{ .bytes = bytes }; } var v7_lock: std.Io.Mutex = .init; var v7_last_timestamp: std.atomic.Value(u64) = .init(0); var v7_counter: std.atomic.Value(u32) = .init(0); fn getCount(io: std.Io, timestamp: u64) u32 { v7_lock.lockUncancelable(io); defer v7_lock.unlock(io); if (v7_last_timestamp.swap(timestamp, .monotonic) != timestamp) { v7_counter.store(0, .monotonic); } return v7_counter.fetchAdd(1, .monotonic) % 4096; } pub fn v7(io: std.Io) UUID { const timestamp: u64 = @intCast(@max(0, std.time.milliTimestamp())); const count = getCount(timestamp); const random = blk: { var bytes: [8]u8 = undefined; io.random(&bytes); break :blk bytes; }; var bytes: [16]u8 = undefined; bytes[0] = @truncate(timestamp >> 40); bytes[1] = @truncate(timestamp >> 32); bytes[2] = @truncate(timestamp >> 24); bytes[3] = @truncate(timestamp >> 16); bytes[4] = @truncate(timestamp >> 8); bytes[5] = @truncate(timestamp); bytes[6] = (@as(u8, 7) << 4) | @as(u8, @truncate((count >> 8) & 0x0F)); bytes[7] = @truncate(count); bytes[8] = (random[0] & 0x3F) | 0x80; @memcpy(bytes[9..16], random[1..8]); return .{ .bytes = bytes }; }