Skip to content

Add UUID v4 generation to the standard library. #6618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions lib/std/Uuid.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2015-2020 Zig Contributors
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.
const std = @import("std.zig");

const Uuid = @This();
id: u128,

/// Creates a brand new UUID v4 object.
pub fn newv4() Uuid {
// This sets the 4 bits at the 48 bit to 0
const flip: u128 = 0b1111 << 48;

// We then set the 4 bits at 48 to 0x4 (0b0100)
return Uuid{ .id = (std.crypto.random.int(u128) & ~flip) | (0x4 << 48) };
}

/// Creates a string from the ID.
/// Format: xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx
pub fn format(self: Uuid, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
var buf = [_]u8{0} ** 36;

const chars = if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "x"))
// use lower-case hexadecimal digits for printing
"0123456789abcdef"
else if (comptime std.mem.eql(u8, fmt, "X"))
// use upper-case hexadecimal digits
"0123456789ABCDEF"
else
@compileError("invalid format string '" ++ fmt ++ "'");

// Pre-set known values
buf[8] = '-';
buf[13] = '-';
buf[18] = '-';
buf[23] = '-';

// Generate the string
var i: usize = 0;
var shift: u7 = 0;
while (i < 36) : (i += 1) {
// Skip pre-set values
if (i != 8 and i != 13 and i != 18 and i != 23) {
const selector = @truncate(u4, self.id >> shift);
// Wrapping addition since 4*32=128 will overflow after
// the last character
shift +%= 4;

buf[i] = chars[selector];
}
}

try writer.writeAll(&buf);
}

test "uuid format" {
var buf: [36]u8 = undefined;

var uuid = newv4();
std.testing.expect(uuid.id & (0b1111 << 48) == 0x4 << 48);

// generated using newv4()
uuid = .{ .id = 167152534942602288892154198807769749718 };
std.testing.expectEqualStrings("6d897582-18ac-496f-abf1-d95604860cd7", try std.fmt.bufPrint(&buf, "{}", .{uuid}));
std.testing.expectEqualStrings("6d897582-18ac-496f-abf1-d95604860cd7", try std.fmt.bufPrint(&buf, "{x}", .{uuid}));
std.testing.expectEqualStrings("6D897582-18AC-496F-ABF1-D95604860CD7", try std.fmt.bufPrint(&buf, "{X}", .{uuid}));
}
1 change: 1 addition & 0 deletions lib/std/std.zig
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub const StringArrayHashMapUnmanaged = array_hash_map.StringArrayHashMapUnmanag
pub const TailQueue = @import("linked_list.zig").TailQueue;
pub const Target = @import("target.zig").Target;
pub const Thread = @import("thread.zig").Thread;
pub const Uuid = @import("Uuid.zig");

pub const array_hash_map = @import("array_hash_map.zig");
pub const atomic = @import("atomic.zig");
Expand Down