--- /dev/null
+package core.iter
+
+use package core.intrinsics.onyx { __zero_value }
+
+filter :: (it: Iterator($T), predicate: (T) -> bool) -> Iterator(T) {
+ FoldIterator :: struct (T: type_expr) {
+ iterator: Iterator(T);
+ predicate: (T) -> bool;
+ }
+
+ fold_iterator := new(#type FoldIterator(T));
+ fold_iterator.iterator = it;
+ fold_iterator.predicate = predicate;
+
+ next :: ($T: type_expr, data: rawptr) -> (T, bool) {
+ fi := cast(^FoldIterator(T)) data;
+
+ value, cont := fi.iterator.next(fi.iterator.data);
+ if cont {
+ while !fi.predicate(value) {
+ value, cont = fi.iterator.next(fi.iterator.data);
+ if !cont do return value, false;
+ }
+
+ return value, true;
+ } else {
+ return value, false;
+ }
+ }
+
+ close :: ($T: type_expr, data: rawptr) {
+ fi := cast(^FoldIterator(T)) data;
+ fi.iterator.close(fi.iterator.data);
+ cfree(data);
+ }
+
+ return .{
+ data = fold_iterator,
+ next = #solidify next { T=T },
+ close = #solidify close { T=T },
+ };
+}
+
+map :: (it: Iterator($T), transform: (T) -> $R) -> Iterator(R) {
+ MapIterator :: struct (T: type_expr, R: type_expr) {
+ iterator: Iterator(T);
+ transform: (T) -> R;
+ }
+
+ map_iterator := new(#type MapIterator(T, R));
+ map_iterator.iterator = it;
+ map_iterator.transform = transform;
+
+ next :: ($T: type_expr, $R: type_expr, data: rawptr) -> (R, bool) {
+ mi := cast(^MapIterator(T, R)) data;
+
+ value, cont := mi.iterator.next(mi.iterator.data);
+ if !cont do return value, false;
+
+ return mi.transform(value), true;
+ }
+
+ close :: ($T: type_expr, $R: type_expr, data: rawptr) {
+ mi := cast(^MapIterator(T, R)) data;
+ mi.iterator.close(mi.iterator.data);
+ cfree(data);
+ }
+
+ return .{
+ data = map_iterator,
+ next = #solidify next { T=T, R=R },
+ close = #solidify close { T=T, R=R },
+ };
+}
+
+fold :: (it: Iterator($T), initial_value: R = __zero_value(R), combine: (T, $R) -> R) -> R {
+ assert(false, "Not implemented yet");
+ return initial_value;
+}
+
+to_array :: (it: Iterator($T), allocator := context.allocator) -> [..] T {
+ array :: package core.array
+
+ arr := array.make(T, allocator=allocator);
+ for v: it do array.push(^arr, v);
+
+ return arr;
+}
--- /dev/null
+#load "core/std"
+
+use package core
+
+count_iterator :: (lo: i32, hi: i32, step := 1) -> Iterator(i32) {
+ next :: (data: rawptr) -> (i32, bool) {
+ ci := cast(^CountIterator) data;
+ if ci.current > ci.high do return 0, false;
+
+ defer ci.current += ci.step;
+ return ci.current, true;
+ }
+
+ close :: (data: rawptr) {
+ println("Closing the count iterator...");
+ cfree(data);
+ }
+
+ CountIterator :: struct {
+ low, high, step: i32;
+ current: i32;
+ }
+
+ count_iterator := new(CountIterator);
+ count_iterator.low = lo;
+ count_iterator.high = hi;
+ count_iterator.step = step;
+ count_iterator.current = lo;
+
+ return .{
+ data = count_iterator,
+ next = next,
+ close = close,
+ };
+}
+
+main :: (args: [] cstr) {
+
+ iterator := count_iterator(1, 10)
+ |> iter.map((x: i32) -> i32 do return x * 2;)
+ |> iter.filter((x: i32) -> bool do return x > 10;)
+ |> iter.map((x: i32) -> i32 do return x + 42;);
+
+ println("Starting the iteration...");
+ for i: iterator {
+ println(i);
+ }
+
+ arr := count_iterator(1, 10)
+ |> iter.map((x: i32) -> i32 do return x * 2;)
+ |> iter.filter((x: i32) -> bool do return x > 10;)
+ |> iter.map((x: i32) -> i32 do return x + 42;)
+ |> iter.to_array();
+
+ println(arr[2]);
+}