const util = @import("util.zig");
const ReprCSlice = util.ReprCSlice;
const std_mem = @import("std").mem;
pub const Alignment = enum(u8) {
a1 = 0,
a2 = 1,
a4 = 2,
a8 = 3,
a16 = 4,
a32 = 5,
a64 = 6,
_,
inline fn from_std(alignment: std_mem.Alignment) @This() {
return switch (alignment) {
.@"1" => .a1,
.@"2" => .a2,
.@"4" => .a4,
.@"8" => .a8,
.@"16" => .a16,
.@"32" => .a32,
.@"64" => .a64,
_ => unreachable
};
}
inline fn to_std(self: @This()) std_mem.Alignment {
return switch (self) {
.a1 => .@"1",
.a2 => .@"2",
.a4 => .@"4",
.a8 => .@"8",
.a16 => .@"16",
.a32 => .@"32",
.a64 => .@"64",
_ => unreachable
};
}
};
pub const Allocator = extern struct {
ptr: *anyopaque,
vtable: VTable,
inline fn from_std(allocator: std_mem.Allocator) @This() {
return .{
.ptr = allocator.ptr,
.vtable = VTable.from_std_ptr(allocator.vtable)
};
}
inline fn to_std(self: @This()) std_mem.Allocator {
return .{
.ptr = self.ptr,
.vtable = self.vtable.to_std_ptr()
};
}
};
pub const VTable = extern struct {
vtable_zig: *const anyopaque,
alloc_c: *const fn (
vtable_zig: *const anyopaque,
allocator: *anyopaque,
len: usize,
alignment: Alignment,
ret_addr: usize
) callconv(.c) ReprCSlice(u8),
resize_c: *const fn (
vtable_zig: *const anyopaque,
allocator: *anyopaque,
memory: ReprCSlice(u8),
alignment: Alignment,
new_len: usize,
ret_addr: usize
) callconv(.c) bool,
remap_c: *const fn (
vtable_zig: *const anyopaque,
allocator: *anyopaque,
memory: ReprCSlice(u8),
alignment: Alignment,
new_len: usize,
ret_addr: usize
) callconv(.c) ReprCSlice(u8),
free_c: *const fn (
vtable_zig: *const anyopaque,
allocator: *anyopaque,
memory: ReprCSlice(u8),
alignment: Alignment,
ret_addr: usize
) callconv(.c) void,
inline fn from_std_ptr(vtable: *const std_mem.Allocator.VTable) @This() {
return .{
.vtable_zig = vtable,
.alloc_c = alloc_c,
.resize_c = resize_c,
.remap_c = remap_c,
.free_c = free_c
};
}
inline fn to_std_ptr(self: @This()) *const std_mem.Allocator.VTable {
return @ptrCast(@alignCast(self.vtable_zig));
}
};
fn alloc_c(
vtable_zig: *const anyopaque,
allocator: *anyopaque,
len: usize,
alignment: Alignment,
ret_addr: usize
) callconv(.c) ReprCSlice(u8) {
const vtable: *const std_mem.Allocator.VTable = @ptrCast(@alignCast(vtable_zig));
const ptr = vtable.alloc(allocator, len, alignment.to_std(), ret_addr);
return ReprCSlice(u8).from_ptr_len(ptr, len);
}
fn resize_c(
vtable_zig: *const anyopaque,
allocator: *anyopaque,
memory: ReprCSlice(u8),
alignment: Alignment,
new_len: usize,
ret_addr: usize
) callconv(.c) bool {
const vtable: *const std_mem.Allocator.VTable = @ptrCast(@alignCast(vtable_zig));
return vtable.resize(allocator, memory.to_slice().?, alignment.to_std(), new_len, ret_addr);
}
fn remap_c(
vtable_zig: *const anyopaque,
allocator: *anyopaque,
memory: ReprCSlice(u8),
alignment: Alignment,
new_len: usize,
ret_addr: usize
) callconv(.c) ReprCSlice(u8) {
const vtable: *const std_mem.Allocator.VTable = @ptrCast(@alignCast(vtable_zig));
const slice = vtable.remap(allocator, memory.to_slice().?, alignment.to_std(), new_len, ret_addr);
return ReprCSlice(u8).from_ptr_len(slice, new_len);
}
fn free_c(
vtable_zig: *const anyopaque,
allocator: *anyopaque,
memory: ReprCSlice(u8),
alignment: Alignment,
ret_addr: usize
) callconv(.c) void {
const vtable: *const std_mem.Allocator.VTable = @ptrCast(@alignCast(vtable_zig));
vtable.free(allocator, memory.to_slice().?, alignment.to_std(), ret_addr);
}
comptime {
const assert = @import("std").debug.assert;
// smoke tests
_ = Alignment.from_std(Alignment.a8.to_std());
const allocator = @import("std").heap.page_allocator;
_ = Allocator.from_std(allocator).to_std();
_ = VTable.from_std_ptr(allocator.vtable).to_std_ptr();
// size/align assertions
assert(@sizeOf(Alignment) == 1);
assert(@alignOf(Alignment) == 1);
assert(@sizeOf(Allocator) == 6 * @sizeOf(usize));
assert(@alignOf(Allocator) == @alignOf(usize));
assert(@sizeOf(VTable) == 5 * @sizeOf(usize));
assert(@alignOf(VTable) == @alignOf(usize));
}