Created
December 3, 2020 20:57
-
-
Save marler8997/e61ec001df07b2bb38db44ffe91cecc2 to your computer and use it in GitHub Desktop.
interface.zig
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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