Skip to content

lima1909/ztep

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

57 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ztep

Build Status License Stars

Ztep is an Iterator library written in ⚡ZIG ⚡.

It is heavily inspired by the iterators in the Rust standard library std::iter::Iterator. This also includes optimizations for special iterators, such as for arrays, where it is easy to jump to a specific item (position).

Supported zig-versions:

  • 0.14.1
  • 0.15.1

Examples

Extend a zig-std-iterator: std.mem.TokenIterator

const std = @import("std");
const iter = @import("ztep");

fn firstChar(in: []const u8) u8 {
    return in[0];
}

test "extend" {
    var it = iter.extend(std.mem.tokenizeScalar(u8, "x BB ccc", ' '))
        .map(u8, firstChar)
        .filter(std.ascii.isLower)
        .enumerate();

    try std.testing.expectEqualDeep(.{ 0, 'x' }, it.next().?);
    try std.testing.expectEqualDeep(.{ 1, 'c' }, it.next().?);
    try std.testing.expectEqual(null, it.next());
}

Create an Iterator for a given Slice

const std = @import("std");
const iter = @import("ztep");

fn firstChar(in: []const u8) u8 {
    return in[0];
}

test "from slice" {
    var it = iter.fromSlice(&[_][]const u8{ "x", "BB", "ccc" })
        .map(u8, firstChar)
        .filter(std.ascii.isLower)
        .enumerate();

    try std.testing.expectEqualDeep(.{ 0, 'x' }, it.next().?);
    try std.testing.expectEqualDeep(.{ 1, 'c' }, it.next().?);
    try std.testing.expectEqual(null, it.next());
}

Extend a zig-std-iterator: std.fs.Dir.Walker, which next-method returns an error_union

const std = @import("std");
const iter = @import("ztep");

test "iterator with error" {
    const dir = try std.fs.cwd().openDir(".", .{ .iterate = true });
    var walker = try dir.walk(std.testing.allocator);
    defer walker.deinit();

    // errors are ignored and the next Item is yield
    const build = iter.extendWithError(&walker, null).find(struct {
        fn find(entry: std.fs.Dir.Walker.Entry) bool {
            if (std.mem.eql(u8, "build.zig", entry.basename)) return true else return false;
        }
    }.find);

    try std.testing.expectEqualStrings("build.zig", build.?.basename);
}

Iterators

Create or extend a Iterator

Function Description
empty Creates an iterator that yields nothing.
extend Extend a given Iterator with the additional methods.
extendWithError Extend an Iterator which has a next-method, which returns an error_union (next() anyerror!Item).
fromFn Creates an custom iterator with the initialized (start) value and the provided (next) function.
fromSlice Create an Iterator from a given slice.
once Creates an iterator that yields an element exactly once.
range Create an Iterator from a given start and end value (end is excluded).
rangeIncl Create an Iterator from a given start and end value (end is inclusive).
repeatN Creates a new iterator that N times repeats a given value.
reverse Reverses an iterator’s direction.
toIterator Creates a Wrapper for a given Iterator, where the next-method has a different name.

The following iterators are available:

Iterators Description
arrayChunks Create iterator, which iterate over an chunk of items.
chain Takes two iterators and creates a new iterator over both in sequence.
count Consumes the iterator, counting the number of iterations and returning it.
enumerate Creates an iterator which gives the current iteration count as well as the next value.
filter Creates an iterator which uses a function to determine if an element should be yielded.
filterMap Creates an iterator that both filters and maps in one call.
find Searches for an element of an iterator that satisfies a predicate.
fold Folds every element into an accumulator by applying an operation, returning the final result.
forEach Calls a function fn(Item) on each element of an iterator.
fuse Creates an iterator which ends after the first null.
inspect This iterator do nothing, the purpose is for debugging.
last Calls a function fn(Item) on each element of an iterator.
map Transforms one iterator into another by a given mapping function.
nth Consumes the iterator, returning the nth element.
peekable Creates an iterator which can use the peek methods to look at the next element without consuming it.
reduce Reduces the elements to a single one, by repeatedly applying a reducing function.
reset Reset the Base-Iterator, if the Iterator supports it.
skip Creates an iterator that skips the first n elements.
stepBy Creates an iterator starting at the same point, but stepping by the given amount at each iteration.
take Creates an iterator that yields the first n elements, or fewer if the underlying iterator ends sooner.
takeWHile Creates an iterator which calls the predicate on each element, and yield elements while it returns true.
tryCollect Collects all the items from an iterator into a given buffer.
tryCollectInto Collects all the items from an iterator into a given collection.
tryForEach An iterator method that applies a fallible function to each item and stopping at the first error.
zip Zips up’ two iterators into a single iterator of pairs.

More examples

Try to rename all files from a given list, with tryForEach.

fn rename(fileName: []const u8) !void {
   const newFileName = try std.mem.concat(std.testing.allocator,u8,&[_][]const u8{fileName,".old"});
   defer std.testing.allocator.free(newFileName);

    try std.fs.cwd().rename(fileName, newFileName);
}

test "tryForEach with error" {
    var it = fromSlice(&[_][]const u8{ "a.txt", "not_found", "b.txt" }).tryForEach(rename);

    try std.testing.expect(it.hasError());
    try std.testing.expectEqual(error.FileNotFound, it.err.?);
    try std.testing.expectEqual("not_found", it.err_item.?);

    try std.testing.expectEqual("b.txt", it.next().?);
    try std.testing.expectEqual(null, it.next());
}

You can stop the iterations, with takeWhile and the given predicate.

test "takeWhile" {
   // stop the iteration, if the letter is upper case
   var it = fromSlice(&[_][]const u8{ "x", "BB", "ccc" })
        .map(u8, firstChar)
        .takeWhile(std.ascii.isLower); 

   try std.testing.expectEqual('x', it.next().?);
   try std.testing.expectEqual(null, it.next());
}

You can iterate not only in one step, but also in chunks: arrayChunks.

test "arrayChunks with filter and map" {
    var it = fromSlice(&[_][]const u8{ "x", "BB", "ccc", "d" })
        .map(u8, firstChar)
        .filter(std.ascii.isLower)
        .arrayChunks(2);

    try std.testing.expectEqualDeep([_]u8{ 'x', 'c' }, it.next().?);
    try std.testing.expectEqual(null, it.next());
    // the remainder is 'd'
    try std.testing.expectEqual([_]?u8{ 'd', null }, it.iter.remainder);

    it.reset();
    try std.testing.expectEqual(1, it.count());
}

About

Iterators and extensions for Iterators in Zig.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages