89 lines
2.9 KiB
Zig
89 lines
2.9 KiB
Zig
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 };
|
|
}
|