Stub out account creation

This commit is contained in:
jaina heartles 2022-05-15 14:21:34 -07:00
parent cf8871bbcd
commit 2a6154b5ec
1 changed files with 105 additions and 44 deletions

View File

@ -1,59 +1,120 @@
const std = @import("std");
const root = @import("root");
const Uuid = root.util.Uuid;
const util = @import("./util.zig");
const Uuid = util.Uuid;
const ciutf8 = util.ciutf8;
const assert = std.debug.assert;
pub const Actor = struct {
pub const Account = struct {
id: Uuid,
display_name: ?[]const u8 = null,
handle: []const u8,
host: []const u8,
bio: ?[]const u8 = null,
};
pub const Note = struct {
id: Uuid,
author: Uuid,
content: []const u8 = "",
};
const IdSource = struct {
data: *anyopaque,
nextFn: fn (*anyopaque) Uuid,
pub fn CreateInfo(comptime T: type) type {
if (@typeInfo(T) != .Struct) @compileError("type is not struct");
if (!std.meta.trait.hasField("id")(T)) @compileError("type does not have id field");
if (@typeInfo(T).Struct.is_tuple) @compileError("type cannot be tuple");
pub fn init(pointer: anytype, comptime nextFn: fn (ptr: @TypeOf(pointer)) Uuid) IdSource {
const Ptr = @TypeOf(pointer);
assert(@typeInfo(Ptr) == .Pointer); // Must be a pointer
assert(@typeInfo(Ptr).Pointer.size == .One); // Must be a single-item pointer
assert(@typeInfo(@typeInfo(Ptr).Pointer.child) == .Struct); // Must point to a struct
const gen = struct {
fn next(ptr: *anyopaque) Uuid {
const alignment = @typeInfo(Ptr).Pointer.alignment;
const self = @ptrCast(Ptr, @alignCast(alignment, ptr));
return nextFn(self);
}
};
var fields: [std.meta.fields(T).len - 1]std.builtin.TypeInfo.StructField = undefined;
var i = 0;
for (std.meta.fields(T)) |field| {
if (std.mem.eql(u8, field.name, "id")) continue;
fields[i] = field;
i += 1;
return .{
.data = pointer,
.nextFn = gen.next,
};
}
return @Type(.{
.Struct = .{
.layout = @typeInfo(T).Struct.layout,
.fields = &fields,
.is_tuple = false,
.decls = &[_]std.builtin.TypeInfo.Declaration{},
},
});
}
const this_host = "localhost:8080";
const actor = Actor{
.id = Uuid.parse("f75f5160-12d3-42c2-a81d-ad2245b7a74b") catch unreachable,
.handle = "testacct",
.host = this_host,
fn next(self: *IdSource) Uuid {
return self.nextFn(self.data);
}
};
pub fn getActorById(id: Uuid) !?Actor {
if (Uuid.eql(id, actor.id)) return actor;
const ConstId = struct {
val: Uuid = Uuid.Nil,
fn next(self: *ConstId) Uuid {
return self.val;
}
return null;
}
fn source(self: *ConstId) IdSource {
return IdSource.init(self, next);
}
};
pub fn createNote(_: CreateInfo(Note)) !Uuid {
return Uuid.randV4(root.util.getRandom());
pub const MemoryDb = struct {
const Self = @This();
const Table = std.ArrayListUnmanaged;
allocator: std.mem.Allocator,
id_source: IdSource,
accounts: Table(Account),
pub fn init(allocator: std.mem.Allocator, id_source: IdSource) Self {
return .{
.allocator = allocator,
.id_source = id_source,
.accounts = Table(Account){},
};
}
pub fn deinit(self: *Self) void {
self.accounts.deinit(self.allocator);
}
pub fn createAccount(self: *Self, handle: []const u8) !Account {
const id = self.id_source.next();
for (self.accounts.items) |a| {
if (ciutf8.eql(handle, a.handle)) {
return error.DuplicateHandle;
}
if (Uuid.eql(id, a.id)) {
return error.DuplicateId;
}
}
const acc = .{
.id = id,
.handle = handle,
};
try self.accounts.append(self.allocator, acc);
return acc;
}
};
test "createAccount" {
var next_id = ConstId{};
var db = MemoryDb.init(std.testing.allocator, next_id.source());
defer db.deinit();
const admin_id = try Uuid.parse("00000000-ffff-0000-0000-000000000000");
const sally_id = try Uuid.parse("00000000-eeee-0000-0000-000000000000");
const other_id = try Uuid.parse("00000000-dddd-0000-0000-000000000000");
next_id.val = admin_id;
const admin = try db.createAccount("admin");
try std.testing.expectEqual(admin_id, admin.id);
try std.testing.expectEqualStrings("admin", admin.handle);
next_id.val = other_id;
try std.testing.expectError(error.DuplicateHandle, db.createAccount("admin"));
next_id.val = sally_id;
const sally = try db.createAccount("sally");
try std.testing.expectEqual(sally_id, sally.id);
try std.testing.expectEqualStrings("sally", sally.handle);
next_id.val = admin_id;
try std.testing.expectError(error.DuplicateId, db.createAccount("jaina"));
}