Skip to content

Instantly share code, notes, and snippets.

@marler8997
Created December 3, 2020 20:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marler8997/e61ec001df07b2bb38db44ffe91cecc2 to your computer and use it in GitHub Desktop.
Save marler8997/e61ec001df07b2bb38db44ffe91cecc2 to your computer and use it in GitHub Desktop.
interface.zig
const std = @import("std");
const Allocator = struct {
pub const Error = error{OutOfMemory};
allocFn: fn (self: *Allocator, len: usize) Error![]u8,
freeFn: fn(self: *Allocator, ptr: []u8) void,
// DOWNSIDE: we have to generate these that handle passing the self ptr
// by hand for every interface
pub fn alloc(self: *Allocator, len: usize) Error![]u8 {
return self.allocFn(self, len);
}
pub fn free(self: *Allocator, ptr: []u8) void {
return self.freeFn(self, ptr);
}
};
// DOWNSIDE: this wrapper that handles fieldParentPtr is generated by hand for every interface
fn AllocatorWrapper(comptime T: type) type { return struct {
allocator: Allocator,
t: T,
pub fn init(t: T) @This() {
return .{
.allocator = .{
.allocFn = alloc,
.freeFn = free,
},
.t = t,
};
}
// DOWNSIDE: we have to generate these functions by hand on every interface
pub fn alloc(a: *Allocator, len: usize) Allocator.Error![]u8 {
const self = @fieldParentPtr(@This(), "allocator", a);
return self.t.alloc(len);
}
pub fn free(a: *Allocator, ptr: []u8) void {
const self = @fieldParentPtr(@This(), "allocator", a);
return self.t.free(ptr);
}
};}
fn getAllocator(a: anytype) AllocatorWrapper(@TypeOf(a)) {
return AllocatorWrapper(@TypeOf(a)).init(a);
}
fn process(allocator: *Allocator, items: []const u8) !void {
// Just call functions on the interface like on normal objects.
// this is provided via created functions from .decls
const buf = try allocator.alloc(items.len);
defer allocator.free(buf);
std.debug.warn("allocated {}\n", .{items.len});
}
const FixedBufferAllocator = struct {
const Self = @This();
buffer: []u8,
allocated: bool = false,
pub fn init(buf: []u8) Self {
return Self { .buffer = buf };
}
// access public symbols of the struct we pass to std.meta.Interface
// as we can usingnamespace them
pub fn alloc(self: *Self, size: usize) Allocator.Error![]u8 {
if(self.allocated)
return error.OutOfMemory;
if(size > self.buffer.len)
return error.OutOfMemory;
self.allocated = true;
return self.buffer[0..size];
}
pub fn free(self: *Self, ptr: []u8) void {
std.debug.assert(ptr.ptr == self.buffer.ptr);
self.allocated = false;
}
};
pub fn main() !void {
var buffer : [1000]u8 = undefined;
var fba = getAllocator(FixedBufferAllocator.init(&buffer));
const allocator = &fba.allocator;
try process(allocator, "Hello, Zig");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment