diff options
| author | 2019-01-17 15:52:45 +0100 | |
|---|---|---|
| committer | 2019-01-17 15:52:45 +0100 | |
| commit | 938b3ff7787a3e99bc41cac9add5ff25835eee22 (patch) | |
| tree | efefe7cd2d0cbaebdb664de37848a5ad01a87fef | |
| parent | Renamed helpEx to helpFull and added a new helpEx that wraps helpFull (diff) | |
| download | zig-clap-938b3ff7787a3e99bc41cac9add5ff25835eee22.tar.gz zig-clap-938b3ff7787a3e99bc41cac9add5ff25835eee22.tar.xz zig-clap-938b3ff7787a3e99bc41cac9add5ff25835eee22.zip | |
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
Diffstat (limited to '')
| -rw-r--r-- | example/comptime-clap.zig | 7 | ||||
| -rw-r--r-- | example/streaming-clap.zig | 7 | ||||
| -rw-r--r-- | src/args.zig | 46 | ||||
| -rw-r--r-- | src/comptime.zig | 8 | ||||
| -rw-r--r-- | src/streaming.zig | 10 |
5 files changed, 32 insertions, 46 deletions
diff --git a/example/comptime-clap.zig b/example/comptime-clap.zig index b275dc7..8517db8 100644 --- a/example/comptime-clap.zig +++ b/example/comptime-clap.zig | |||
| @@ -27,15 +27,14 @@ pub fn main() !void { | |||
| 27 | 27 | ||
| 28 | // We then initialize an argument iterator. We will use the OsIterator as it nicely | 28 | // We then initialize an argument iterator. We will use the OsIterator as it nicely |
| 29 | // wraps iterating over arguments the most efficient way on each os. | 29 | // wraps iterating over arguments the most efficient way on each os. |
| 30 | var os_iter = clap.args.OsIterator.init(allocator); | 30 | var iter = clap.args.OsIterator.init(allocator); |
| 31 | const iter = &os_iter.iter; | 31 | defer iter.deinit(); |
| 32 | defer os_iter.deinit(); | ||
| 33 | 32 | ||
| 34 | // Consume the exe arg. | 33 | // Consume the exe arg. |
| 35 | const exe = try iter.next(); | 34 | const exe = try iter.next(); |
| 36 | 35 | ||
| 37 | // Finally we can parse the arguments | 36 | // Finally we can parse the arguments |
| 38 | var args = try clap.ComptimeClap([]const u8, params).parse(allocator, clap.args.OsIterator.Error, iter); | 37 | var args = try clap.ComptimeClap([]const u8, params).parse(allocator, clap.args.OsIterator, &iter); |
| 39 | defer args.deinit(); | 38 | defer args.deinit(); |
| 40 | 39 | ||
| 41 | // clap.help is a function that can print a simple help message, given a | 40 | // clap.help is a function that can print a simple help message, given a |
diff --git a/example/streaming-clap.zig b/example/streaming-clap.zig index 57ebe71..a52a222 100644 --- a/example/streaming-clap.zig +++ b/example/streaming-clap.zig | |||
| @@ -17,15 +17,14 @@ pub fn main() !void { | |||
| 17 | 17 | ||
| 18 | // We then initialize an argument iterator. We will use the OsIterator as it nicely | 18 | // We then initialize an argument iterator. We will use the OsIterator as it nicely |
| 19 | // wraps iterating over arguments the most efficient way on each os. | 19 | // wraps iterating over arguments the most efficient way on each os. |
| 20 | var os_iter = clap.args.OsIterator.init(allocator); | 20 | var iter = clap.args.OsIterator.init(allocator); |
| 21 | const iter = &os_iter.iter; | 21 | defer iter.deinit(); |
| 22 | defer os_iter.deinit(); | ||
| 23 | 22 | ||
| 24 | // Consume the exe arg. | 23 | // Consume the exe arg. |
| 25 | const exe = try iter.next(); | 24 | const exe = try iter.next(); |
| 26 | 25 | ||
| 27 | // Finally we initialize our streaming parser. | 26 | // Finally we initialize our streaming parser. |
| 28 | var parser = clap.StreamingClap(u8, clap.args.OsIterator.Error).init(params, iter); | 27 | var parser = clap.StreamingClap(u8, clap.args.OsIterator).init(params, &iter); |
| 29 | 28 | ||
| 30 | // Because we use a streaming parser, we have to consume each argument parsed individually. | 29 | // Because we use a streaming parser, we have to consume each argument parsed individually. |
| 31 | while (try parser.next()) |arg| { | 30 | while (try parser.next()) |arg| { |
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; | |||
| 6 | const mem = std.mem; | 6 | const mem = std.mem; |
| 7 | const os = std.os; | 7 | const os = std.os; |
| 8 | 8 | ||
| 9 | /// A interface for iterating over command line arguments | 9 | /// An example of what methods should be implemented on an arg iterator. |
| 10 | pub fn Iterator(comptime E: type) type { | 10 | pub const ExampleArgIterator = struct { |
| 11 | return struct { | 11 | const Error = error{}; |
| 12 | const Self = @This(); | ||
| 13 | const Error = E; | ||
| 14 | |||
| 15 | nextFn: fn (iter: *Self) Error!?[]const u8, | ||
| 16 | 12 | ||
| 17 | pub fn next(iter: *Self) Error!?[]const u8 { | 13 | pub fn next(iter: *ExampleArgIterator) Error!?[]const u8 { |
| 18 | return iter.nextFn(iter); | 14 | return "2"; |
| 19 | } | 15 | } |
| 20 | }; | 16 | }; |
| 21 | } | ||
| 22 | 17 | ||
| 23 | /// An ::ArgIterator, which iterates over a slice of arguments. | 18 | /// An argument iterator which iterates over a slice of arguments. |
| 24 | /// This implementation does not allocate. | 19 | /// This implementation does not allocate. |
| 25 | pub const SliceIterator = struct { | 20 | pub const SliceIterator = struct { |
| 26 | const Error = error{}; | 21 | const Error = error{}; |
| 27 | 22 | ||
| 28 | args: []const []const u8, | 23 | args: []const []const u8, |
| 29 | index: usize, | 24 | index: usize, |
| 30 | iter: Iterator(Error), | ||
| 31 | 25 | ||
| 32 | pub fn init(args: []const []const u8) SliceIterator { | 26 | pub fn init(args: []const []const u8) SliceIterator { |
| 33 | return SliceIterator{ | 27 | return SliceIterator{ |
| 34 | .args = args, | 28 | .args = args, |
| 35 | .index = 0, | 29 | .index = 0, |
| 36 | .iter = Iterator(Error){ .nextFn = nextFn }, | ||
| 37 | }; | 30 | }; |
| 38 | } | 31 | } |
| 39 | 32 | ||
| 40 | fn nextFn(iter: *Iterator(Error)) Error!?[]const u8 { | 33 | pub fn next(iter: *SliceIterator) Error!?[]const u8 { |
| 41 | const self = @fieldParentPtr(SliceIterator, "iter", iter); | 34 | if (iter.args.len <= iter.index) |
| 42 | if (self.args.len <= self.index) | ||
| 43 | return null; | 35 | return null; |
| 44 | 36 | ||
| 45 | defer self.index += 1; | 37 | defer iter.index += 1; |
| 46 | return self.args[self.index]; | 38 | return iter.args[iter.index]; |
| 47 | } | 39 | } |
| 48 | }; | 40 | }; |
| 49 | 41 | ||
| 50 | test "clap.args.SliceIterator" { | 42 | test "clap.args.SliceIterator" { |
| 51 | const args = [][]const u8{ "A", "BB", "CCC" }; | 43 | const args = [][]const u8{ "A", "BB", "CCC" }; |
| 52 | var slice_iter = SliceIterator.init(args); | 44 | var iter = SliceIterator.init(args); |
| 53 | const iter = &slice_iter.iter; | ||
| 54 | 45 | ||
| 55 | for (args) |a| { | 46 | for (args) |a| { |
| 56 | const b = try iter.next(); | 47 | const b = try iter.next(); |
| @@ -58,20 +49,18 @@ test "clap.args.SliceIterator" { | |||
| 58 | } | 49 | } |
| 59 | } | 50 | } |
| 60 | 51 | ||
| 61 | /// An ::ArgIterator, which wraps the ArgIterator in ::std. | 52 | /// An argument iterator which wraps the ArgIterator in ::std. |
| 62 | /// On windows, this iterator allocates. | 53 | /// On windows, this iterator allocates. |
| 63 | pub const OsIterator = struct { | 54 | pub const OsIterator = struct { |
| 64 | const Error = os.ArgIterator.NextError; | 55 | const Error = os.ArgIterator.NextError; |
| 65 | 56 | ||
| 66 | arena: heap.ArenaAllocator, | 57 | arena: heap.ArenaAllocator, |
| 67 | args: os.ArgIterator, | 58 | args: os.ArgIterator, |
| 68 | iter: Iterator(Error), | ||
| 69 | 59 | ||
| 70 | pub fn init(allocator: *mem.Allocator) OsIterator { | 60 | pub fn init(allocator: *mem.Allocator) OsIterator { |
| 71 | return OsIterator{ | 61 | return OsIterator{ |
| 72 | .arena = heap.ArenaAllocator.init(allocator), | 62 | .arena = heap.ArenaAllocator.init(allocator), |
| 73 | .args = os.args(), | 63 | .args = os.args(), |
| 74 | .iter = Iterator(Error){ .nextFn = nextFn }, | ||
| 75 | }; | 64 | }; |
| 76 | } | 65 | } |
| 77 | 66 | ||
| @@ -79,12 +68,11 @@ pub const OsIterator = struct { | |||
| 79 | iter.arena.deinit(); | 68 | iter.arena.deinit(); |
| 80 | } | 69 | } |
| 81 | 70 | ||
| 82 | fn nextFn(iter: *Iterator(Error)) Error!?[]const u8 { | 71 | pub fn next(iter: *OsIterator) Error!?[]const u8 { |
| 83 | const self = @fieldParentPtr(OsIterator, "iter", iter); | ||
| 84 | if (builtin.os == builtin.Os.windows) { | 72 | if (builtin.os == builtin.Os.windows) { |
| 85 | return try self.args.next(&self.arena.allocator) orelse return null; | 73 | return try iter.args.next(&iter.arena.allocator) orelse return null; |
| 86 | } else { | 74 | } else { |
| 87 | return self.args.nextPosix(); | 75 | return iter.args.nextPosix(); |
| 88 | } | 76 | } |
| 89 | } | 77 | } |
| 90 | }; | 78 | }; |
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)) | |||
| 34 | pos: []const []const u8, | 34 | pos: []const []const u8, |
| 35 | allocator: *mem.Allocator, | 35 | allocator: *mem.Allocator, |
| 36 | 36 | ||
| 37 | pub fn parse(allocator: *mem.Allocator, comptime ArgError: type, iter: *clap.args.Iterator(ArgError)) !@This() { | 37 | pub fn parse(allocator: *mem.Allocator, comptime ArgIter: type, iter: *ArgIter) !@This() { |
| 38 | var pos = std.ArrayList([]const u8).init(allocator); | 38 | var pos = std.ArrayList([]const u8).init(allocator); |
| 39 | var res = @This(){ | 39 | var res = @This(){ |
| 40 | .options = []?[]const u8{null} ** options, | 40 | .options = []?[]const u8{null} ** options, |
| @@ -43,7 +43,7 @@ pub fn ComptimeClap(comptime Id: type, comptime params: []const clap.Param(Id)) | |||
| 43 | .allocator = allocator, | 43 | .allocator = allocator, |
| 44 | }; | 44 | }; |
| 45 | 45 | ||
| 46 | var stream = clap.StreamingClap(usize, ArgError).init(converted_params, iter); | 46 | var stream = clap.StreamingClap(usize, ArgIter).init(converted_params, iter); |
| 47 | while (try stream.next()) |arg| { | 47 | while (try stream.next()) |arg| { |
| 48 | const param = arg.param; | 48 | const param = arg.param; |
| 49 | if (param.names.long == null and param.names.short == null) { | 49 | if (param.names.long == null and param.names.short == null) { |
| @@ -124,10 +124,10 @@ test "clap.comptime.ComptimeClap" { | |||
| 124 | 124 | ||
| 125 | var buf: [1024]u8 = undefined; | 125 | var buf: [1024]u8 = undefined; |
| 126 | var fb_allocator = heap.FixedBufferAllocator.init(buf[0..]); | 126 | var fb_allocator = heap.FixedBufferAllocator.init(buf[0..]); |
| 127 | var arg_iter = clap.args.SliceIterator.init([][]const u8{ | 127 | var iter = clap.args.SliceIterator.init([][]const u8{ |
| 128 | "-a", "-c", "0", "something", | 128 | "-a", "-c", "0", "something", |
| 129 | }); | 129 | }); |
| 130 | var args = try Clap.parse(&fb_allocator.allocator, clap.args.SliceIterator.Error, &arg_iter.iter); | 130 | var args = try Clap.parse(&fb_allocator.allocator, clap.args.SliceIterator, &iter); |
| 131 | defer args.deinit(); | 131 | defer args.deinit(); |
| 132 | 132 | ||
| 133 | debug.assert(args.flag("-a")); | 133 | 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 { | |||
| 28 | /// A command line argument parser which, given an ::ArgIterator, will parse arguments according | 28 | /// A command line argument parser which, given an ::ArgIterator, will parse arguments according |
| 29 | /// to the ::params. ::StreamingClap parses in an iterating manner, so you have to use a loop together with | 29 | /// to the ::params. ::StreamingClap parses in an iterating manner, so you have to use a loop together with |
| 30 | /// ::StreamingClap.next to parse all the arguments of your program. | 30 | /// ::StreamingClap.next to parse all the arguments of your program. |
| 31 | pub fn StreamingClap(comptime Id: type, comptime ArgError: type) type { | 31 | pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { |
| 32 | return struct { | 32 | return struct { |
| 33 | const State = union(enum) { | 33 | const State = union(enum) { |
| 34 | Normal, | 34 | Normal, |
| @@ -41,10 +41,10 @@ pub fn StreamingClap(comptime Id: type, comptime ArgError: type) type { | |||
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | params: []const clap.Param(Id), | 43 | params: []const clap.Param(Id), |
| 44 | iter: *args.Iterator(ArgError), | 44 | iter: *ArgIterator, |
| 45 | state: State, | 45 | state: State, |
| 46 | 46 | ||
| 47 | pub fn init(params: []const clap.Param(Id), iter: *args.Iterator(ArgError)) @This() { | 47 | pub fn init(params: []const clap.Param(Id), iter: *ArgIterator) @This() { |
| 48 | var res = @This(){ | 48 | var res = @This(){ |
| 49 | .params = params, | 49 | .params = params, |
| 50 | .iter = iter, | 50 | .iter = iter, |
| @@ -189,8 +189,8 @@ pub fn StreamingClap(comptime Id: type, comptime ArgError: type) type { | |||
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, results: []const Arg(u8)) void { | 191 | fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, results: []const Arg(u8)) void { |
| 192 | var arg_iter = args.SliceIterator.init(args_strings); | 192 | var iter = args.SliceIterator.init(args_strings); |
| 193 | var c = StreamingClap(u8, args.SliceIterator.Error).init(params, &arg_iter.iter); | 193 | var c = StreamingClap(u8, args.SliceIterator).init(params, &iter); |
| 194 | 194 | ||
| 195 | for (results) |res| { | 195 | for (results) |res| { |
| 196 | const arg = (c.next() catch unreachable) orelse unreachable; | 196 | const arg = (c.next() catch unreachable) orelse unreachable; |