From 13cb4951940e677dae5c012b333a73cd0a2931f8 Mon Sep 17 00:00:00 2001 From: Meghan Denny Date: Thu, 7 Oct 2021 19:34:22 -0700 Subject: [PATCH] add code initial imlplementation --- base32.zig | 37 ++++++++++++++++++++++++++++++++ build.zig | 23 ++++++++++++++++++++ main.zig | 32 +++++++++++++++++++++++++++ ulid.zig | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++ zig.mod | 8 +++++++ zigmod.lock | 3 +++ 6 files changed, 165 insertions(+) create mode 100644 base32.zig create mode 100644 build.zig create mode 100644 main.zig create mode 100644 ulid.zig create mode 100644 zig.mod create mode 100644 zigmod.lock diff --git a/base32.zig b/base32.zig new file mode 100644 index 0000000000000000000000000000000000000000..16080c6aed19450b2ffde09f023f51aff445c423 --- /dev/null +++ b/base32.zig @@ -0,0 +1,37 @@ +//! https://www.crockford.com/base32.html + +const std = @import("std"); +const string = []const u8; +const range = @import("range").range; + +const alphabet = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"; + +pub fn decode(alloc: *std.mem.Allocator, input: string) ![]const u5 { + const list = &std.ArrayList(u5).init(alloc); + defer list.deinit(); + + for (input) |c| { + for (alphabet) |d, i| { + if (c == d) { + try list.append(@intCast(u5, i)); + } + } + } + return list.toOwnedSlice(); +} + +pub fn formatInt(comptime T: type, n: T, buf: []u8) void { + const l = @intCast(T, alphabet.len); + var x = n; + var i = buf.len; + for (range(i)) |_, j| { + buf[j] = alphabet[0]; + } + while (true) { + const a = @intCast(usize, x % l); + x = x / l; + buf[i - 1] = alphabet[a]; + i -= 1; + if (x == 0) break; + } +} diff --git a/build.zig b/build.zig new file mode 100644 index 0000000000000000000000000000000000000000..7818a0d022613b2a483f21139f145cacadc864ad --- /dev/null +++ b/build.zig @@ -0,0 +1,23 @@ +const std = @import("std"); +const deps = @import("./deps.zig"); + +pub fn build(b: *std.build.Builder) void { + const target = b.standardTargetOptions(.{}); + + const mode = b.standardReleaseOptions(); + + const exe = b.addExecutable("zig-ulid", "main.zig"); + exe.setTarget(target); + exe.setBuildMode(mode); + deps.addAllTo(exe); + exe.install(); + + const run_cmd = exe.run(); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| { + run_cmd.addArgs(args); + } + + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); +} diff --git a/main.zig b/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..743e646323889efd61c4c64ee92bd7317f403620 --- /dev/null +++ b/main.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const string = []const u8; +const ulid = @import("ulid"); + +pub fn main() anyerror!void { + std.log.info("All your codebase are belong to us.", .{}); + + try ensureFromTo("001HX7QW7K2PP61CS28B4YF00X"); + try ensureFromTo("0015KMZ1NDDFP4WRWSVA31N0CD"); + try ensureFromTo("0015MFYM13K180VCNCACTFRJAB"); + try ensureFromTo("0015RMHR0WVSCBE4CJWKPCC4GJ"); + try ensureFromTo("0017NSY29QD0YYPB0H0W5GQJQX"); + try ensureFromTo("0017TZRGVZYHK9C26FK5AP3HTG"); + try ensureFromTo("0017Y302CVXHJABSPHNNEBE0R7"); + try ensureFromTo("00183KTME6PJZ773Q9A1BWFJ3X"); + try ensureFromTo("0018ZPQ92P0NDDKNVB3PBW7D18"); + try ensureFromTo("00193A6YMTQR01XTY757XRRJKE"); + try ensureFromTo("0019ABB5M0YK71B4ATA90A8F81"); + try ensureFromTo("0019GFR7YK5HNTFPS2BAQNG0PX"); + try ensureFromTo("001A2YPKW942R97BXRAJG2BD7S"); + try ensureFromTo("001C38D808VW1EG3JS6XJHT4EQ"); + try ensureFromTo("001C9DSQ8SC6SVEVHFK09XBFTC"); + try ensureFromTo("001DEJXKVPDV7BZT1Q80ZEN2PF"); + try ensureFromTo("001F1Z79BCKADWYPDCMZ8B8G0G"); +} + +fn ensureFromTo(before: string) !void { + const alloc = std.heap.page_allocator; + const ul = try ulid.ULID.fromString(alloc, before); + const after = try ul.toString(alloc); + try std.testing.expectEqualStrings(before, after); +} diff --git a/ulid.zig b/ulid.zig new file mode 100644 index 0000000000000000000000000000000000000000..c8c10e60c0f5412cda33f5bdc1a689f98bc73896 --- /dev/null +++ b/ulid.zig @@ -0,0 +1,62 @@ +//! https://github.com/ulid/spec + +const std = @import("std"); +const string = []const u8; +const base32 = @import("./base32.zig"); +const extras = @import("extras"); + +pub const Factory = struct { + epoch: i64, + rand: *std.rand.Random, + + pub fn init(epoch: i64, rand: *std.rand.Random) Factory { + return Factory{ + .epoch = epoch, + .rand = rand, + }; + } + + pub fn newULID(self: Factory) ULID { + const now = std.time.milliTimestamp(); + return ULID{ + .timestamp = std.math.cast(u48, now - self.epoch) catch @panic("time.milliTimestamp() is higher than 281474976710655"), + .randomnes = self.rand.int(u80), + }; + } +}; + +/// 01AN4Z07BY 79KA1307SR9X4MV3 +/// +/// |----------| |----------------| +/// Timestamp Randomness +/// 48bits 80bits +pub const ULID = struct { + timestamp: u48, + randomnes: u80, + + pub const BaseType = string; + + pub fn readField(alloc: *std.mem.Allocator, value: BaseType) !ULID { + if (value.len != 26) return error.Ulid; + return ULID{ + .timestamp = try std.math.cast(u48, try extras.sliceToInt(u50, u5, try base32.decode(alloc, value[0..10]))), + .randomnes = try extras.sliceToInt(u80, u5, try base32.decode(alloc, value[10..26])), + }; + } + + pub fn bindField(self: ULID, alloc: *std.mem.Allocator) !BaseType { + var res = try alloc.alloc(u8, 26); + base32.formatInt(u48, self.timestamp, res[0..10]); + base32.formatInt(u80, self.randomnes, res[10..26]); + return res; + } + + pub const fromString = readField; + pub const toString = bindField; + + pub fn format(self: ULID, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) @TypeOf(writer).Error!void { + _ = fmt; + _ = options; + try writer.writeAll(self.toString()); + } +}; diff --git a/zig.mod b/zig.mod new file mode 100644 index 0000000000000000000000000000000000000000..8cd22300725e6d974aaea838b1b1903801e4db31 --- /dev/null +++ b/zig.mod @@ -0,0 +1,8 @@ +id: 1vu3948bgf52ytvq9u4skpj8es5hd30s0tfx2f15hjaa4tnl +name: ulid +main: ulid.zig +license: MIT +description: ULID implementation for Zig +dependencies: + - src: git https://github.com/nektro/zig-range + - src: git https://github.com/nektro/zig-extras diff --git a/zigmod.lock b/zigmod.lock new file mode 100644 index 0000000000000000000000000000000000000000..6052dc6974ba3663ac5310df85f403c59445caea --- /dev/null +++ b/zigmod.lock @@ -0,0 +1,3 @@ +2 +git https://github.com/nektro/zig-range commit-890ca308fe09b3d5c866d5cfb3b3d7a95dbf939f +git https://github.com/nektro/zig-extras commit-86e312abea8012e39f868f1f2fbc72d6e28a466b -- 2.54.0