Last active
April 22, 2018 12:59
-
-
Save alexnask/e299728343571f54fbffcc7f07af78b0 to your computer and use it in GitHub Desktop.
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"); | |
// standard metaprogramming library, exposes wrappers over low level @reflect/@reify stuff. | |
const meta = std.meta; | |
pub const VTableEntry = struct { | |
const Self = this; | |
name: []const u8, | |
ftype: type, | |
fn is_nullable(self: const &Self) bool { | |
return meta.is_nullable(self.ftype); | |
} | |
} | |
// This type function could be rewritten as: | |
// return vtable_gen([]VTableEntry { | |
// VTableEntry { .name = "next", .ftype = fn() ?T, }, | |
// VTableEntry { .name = "reset", .ftype = ?fn() void, }, | |
// }); | |
// With @reify (which would enable us to write vtable_gen) | |
pub fn IteratorVTable(comptime T: type) type { | |
return struct { | |
const Entries = []VTableEntry { | |
VTableEntry { .name = "next", .ftype = fn()?T, }, | |
VTableEntry { .name = "reset", .ftype = ?fn()void }, | |
}; | |
// These fields would be generated by vtable_gen | |
nextFn: fn(usize) ?T, | |
resetFn: ?fn(usize) void, | |
}; | |
} | |
fn add_usize_param(comptime FnType: type) type { | |
@compileError("Need @reflect/@reify."); | |
} | |
fn vtable_getter(comptime T: type, comptime name: []const u8, comptime FnType: type) add_usize_param(FnType) { | |
if (FnType.arg_count > 0) { | |
@compileError("vtable_getter only supports no-arg functions for now."); | |
} | |
return struct { | |
// TODO: func should have a usize argument + whatever FnType's arguments are. | |
fn func(s: usize) FnType.ReturnType { | |
var self = @intToPtr(&T, s); | |
return @inlineCall(@field(self, name)); | |
} | |
}.func; | |
} | |
fn vtable_from(comptime VTableType: type, comptime ImplType: type) VTableType { | |
// TODO: This assumes the ImplType is a &struct. | |
const Unwrapped = meta.child_type(ImplType); | |
var vtable: VTableType = undefined; | |
for(VTableType.Entries) |entry| { | |
if (entry.is_nullable()) { | |
if (meta.has_method(Unwrapped, entry.name)) { | |
@field(vtable, entry.name ++ "Fn") = vtable_getter(Unwrapped, entry.name, meta.child_type(entry.ftype)); | |
} else { | |
@field(vtable, entry.name ++ "Fn") = null; | |
} | |
} else { | |
@field(vtable, entry.name ++ "Fn") = vtable_getter(Unwrapped, entry.name, meta.child_type(entry.ftype)); | |
} | |
} | |
return vtable; | |
} | |
pub fn Iterator(comptime T: type) type { | |
return struct { | |
const Self = this; | |
self: usize, | |
vtable_ptr: &const IteratorVTable(T), | |
pub fn init(iter: var) Self { | |
return Self { | |
.self = @ptrToInt(iter), | |
.vtable_ptr = &comptime vtable_from(IteratorVTable(T), @typeOf(iter)), | |
} | |
} | |
pub fn next(self: &Self) ?T { | |
return vtable_ptr.nextFn(@ptrToInt(self)); | |
} | |
pub fn reset(self: &Self) !void { | |
if (vtable_ptr.resetFn == null) { | |
return error.NotResetable; | |
} | |
(??vtable_ptr.resetFn)(@ptrToInt(self)); | |
} | |
}; | |
} | |
// Iterator example | |
pub fn RepeatIterator(comptime val: var, comptime times: usize) type { | |
return struct { | |
const Self = this; | |
const T = @typeOf(val); | |
current: usize, | |
fn init() Self { | |
return Self { | |
.current = 0, | |
}; | |
} | |
fn next(self: &Self) ?T { | |
if (self.current < times) { | |
self.current += 1; | |
return val; | |
} | |
return null; | |
} | |
fn reset(self: &Self) void { | |
self.current = 0; | |
} | |
}; | |
} | |
fn consume_usize_iterator(iter: Iterator(usize)) void { | |
for (iter.next()) |item| { | |
std.debug.warn("{}\n", item); | |
} | |
} | |
test "Repeat iterator" { | |
var iter = RepeatIterator(usize(42), 5).init(); | |
consume_usize_iterator(Iterator(usize).from(iter)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment