From 938b3ff7787a3e99bc41cac9add5ff25835eee22 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Thu, 17 Jan 2019 15:52:45 +0100 Subject: Refactored the arg iterators to new be static interface implementations * This makes arg iterators easier to understand and implement * It should also be faster than using the fieldToParent builtin --- src/args.zig | 46 +++++++++++++++++----------------------------- src/comptime.zig | 8 ++++---- src/streaming.zig | 10 +++++----- 3 files changed, 26 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/args.zig b/src/args.zig index 304596c..8706ebc 100644 --- a/src/args.zig +++ b/src/args.zig @@ -6,51 +6,42 @@ const heap = std.heap; const mem = std.mem; const os = std.os; -/// A interface for iterating over command line arguments -pub fn Iterator(comptime E: type) type { - return struct { - const Self = @This(); - const Error = E; - - nextFn: fn (iter: *Self) Error!?[]const u8, +/// An example of what methods should be implemented on an arg iterator. +pub const ExampleArgIterator = struct { + const Error = error{}; - pub fn next(iter: *Self) Error!?[]const u8 { - return iter.nextFn(iter); - } - }; -} + pub fn next(iter: *ExampleArgIterator) Error!?[]const u8 { + return "2"; + } +}; -/// An ::ArgIterator, which iterates over a slice of arguments. +/// An argument iterator which iterates over a slice of arguments. /// This implementation does not allocate. pub const SliceIterator = struct { const Error = error{}; args: []const []const u8, index: usize, - iter: Iterator(Error), pub fn init(args: []const []const u8) SliceIterator { return SliceIterator{ .args = args, .index = 0, - .iter = Iterator(Error){ .nextFn = nextFn }, }; } - fn nextFn(iter: *Iterator(Error)) Error!?[]const u8 { - const self = @fieldParentPtr(SliceIterator, "iter", iter); - if (self.args.len <= self.index) + pub fn next(iter: *SliceIterator) Error!?[]const u8 { + if (iter.args.len <= iter.index) return null; - defer self.index += 1; - return self.args[self.index]; + defer iter.index += 1; + return iter.args[iter.index]; } }; test "clap.args.SliceIterator" { const args = [][]const u8{ "A", "BB", "CCC" }; - var slice_iter = SliceIterator.init(args); - const iter = &slice_iter.iter; + var iter = SliceIterator.init(args); for (args) |a| { const b = try iter.next(); @@ -58,20 +49,18 @@ test "clap.args.SliceIterator" { } } -/// An ::ArgIterator, which wraps the ArgIterator in ::std. +/// An argument iterator which wraps the ArgIterator in ::std. /// On windows, this iterator allocates. pub const OsIterator = struct { const Error = os.ArgIterator.NextError; arena: heap.ArenaAllocator, args: os.ArgIterator, - iter: Iterator(Error), pub fn init(allocator: *mem.Allocator) OsIterator { return OsIterator{ .arena = heap.ArenaAllocator.init(allocator), .args = os.args(), - .iter = Iterator(Error){ .nextFn = nextFn }, }; } @@ -79,12 +68,11 @@ pub const OsIterator = struct { iter.arena.deinit(); } - fn nextFn(iter: *Iterator(Error)) Error!?[]const u8 { - const self = @fieldParentPtr(OsIterator, "iter", iter); + pub fn next(iter: *OsIterator) Error!?[]const u8 { if (builtin.os == builtin.Os.windows) { - return try self.args.next(&self.arena.allocator) orelse return null; + return try iter.args.next(&iter.arena.allocator) orelse return null; } else { - return self.args.nextPosix(); + return iter.args.nextPosix(); } } }; diff --git a/src/comptime.zig b/src/comptime.zig index 808915d..0a4257e 100644 --- a/src/comptime.zig +++ b/src/comptime.zig @@ -34,7 +34,7 @@ pub fn ComptimeClap(comptime Id: type, comptime params: []const clap.Param(Id)) pos: []const []const u8, allocator: *mem.Allocator, - pub fn parse(allocator: *mem.Allocator, comptime ArgError: type, iter: *clap.args.Iterator(ArgError)) !@This() { + pub fn parse(allocator: *mem.Allocator, comptime ArgIter: type, iter: *ArgIter) !@This() { var pos = std.ArrayList([]const u8).init(allocator); var res = @This(){ .options = []?[]const u8{null} ** options, @@ -43,7 +43,7 @@ pub fn ComptimeClap(comptime Id: type, comptime params: []const clap.Param(Id)) .allocator = allocator, }; - var stream = clap.StreamingClap(usize, ArgError).init(converted_params, iter); + var stream = clap.StreamingClap(usize, ArgIter).init(converted_params, iter); while (try stream.next()) |arg| { const param = arg.param; if (param.names.long == null and param.names.short == null) { @@ -124,10 +124,10 @@ test "clap.comptime.ComptimeClap" { var buf: [1024]u8 = undefined; var fb_allocator = heap.FixedBufferAllocator.init(buf[0..]); - var arg_iter = clap.args.SliceIterator.init([][]const u8{ + var iter = clap.args.SliceIterator.init([][]const u8{ "-a", "-c", "0", "something", }); - var args = try Clap.parse(&fb_allocator.allocator, clap.args.SliceIterator.Error, &arg_iter.iter); + var args = try Clap.parse(&fb_allocator.allocator, clap.args.SliceIterator, &iter); defer args.deinit(); debug.assert(args.flag("-a")); diff --git a/src/streaming.zig b/src/streaming.zig index f33fd96..babc573 100644 --- a/src/streaming.zig +++ b/src/streaming.zig @@ -28,7 +28,7 @@ pub fn Arg(comptime Id: type) type { /// A command line argument parser which, given an ::ArgIterator, will parse arguments according /// to the ::params. ::StreamingClap parses in an iterating manner, so you have to use a loop together with /// ::StreamingClap.next to parse all the arguments of your program. -pub fn StreamingClap(comptime Id: type, comptime ArgError: type) type { +pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { return struct { const State = union(enum) { Normal, @@ -41,10 +41,10 @@ pub fn StreamingClap(comptime Id: type, comptime ArgError: type) type { }; params: []const clap.Param(Id), - iter: *args.Iterator(ArgError), + iter: *ArgIterator, state: State, - pub fn init(params: []const clap.Param(Id), iter: *args.Iterator(ArgError)) @This() { + pub fn init(params: []const clap.Param(Id), iter: *ArgIterator) @This() { var res = @This(){ .params = params, .iter = iter, @@ -189,8 +189,8 @@ pub fn StreamingClap(comptime Id: type, comptime ArgError: type) type { } fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, results: []const Arg(u8)) void { - var arg_iter = args.SliceIterator.init(args_strings); - var c = StreamingClap(u8, args.SliceIterator.Error).init(params, &arg_iter.iter); + var iter = args.SliceIterator.init(args_strings); + var c = StreamingClap(u8, args.SliceIterator).init(params, &iter); for (results) |res| { const arg = (c.next() catch unreachable) orelse unreachable; -- cgit v1.2.3