diff --git a/lib/iter.luau b/lib/iter.luau new file mode 100644 index 0000000..4884942 --- /dev/null +++ b/lib/iter.luau @@ -0,0 +1,216 @@ +--[[ + Reference: https://doc.rust-lang.org/std/slice/struct.Iter.html +]] + +local option = require("option") +type Option = option.Option +local Some = option.Some +local None = option.None + +local result = require("result") +type Result = result.Result +local Ok = result.Ok +local Err = result.Err + +local Iter = {} +type Iter = typeof(Iter) & { + _inner: { T }, + _rev: { T }?, + _currentPos: number, + _length: number, +} + +local function revTable(tab: {}) + local tbl = tab + + for i = 1, #tbl // 2, 1 do + tbl[i], tbl[#tbl - i + 1] = tbl[#tbl - i + 1], tbl[i] + end + + return tbl +end + +function Iter.new(iterable: { T }) + return setmetatable( + { + _inner = iterable, + _currentPos = 0, + _len = #iterable, + } :: Iter, + { + __index = Iter, + } + ) +end + +function Iter.nextBack(self: Iter): Option + local elem = table.remove(self._inner, #self._inner) + + if elem == nil then + return None() + end + + return Some(elem) +end + +function Iter.nthBack(self: Iter, n: number): Option + local rev = self._rev or revTable(self._inner) + local elem: T? = rev[n] + + if elem ~= nil then + return Some(elem) + end + + return None() +end + +-- function Iter.advanceBackBy(self: Iter, n: number): Result<(), number> end + +--@canError +function Iter.tryRfold(self: Iter, init: B, f: (B, T) -> Result): R + local accum = init + + local next: Option = self:nextBack() + while next:isSome() do + accum = f(accum :: B, next:getInner() :: T):unwrap() + next = self:nextBack() + end + + return accum +end + +function Iter.rfold(self: Iter, init: B, f: (B, T) -> R): B + local accum: B | R = init + + local next: Option = self:nextBack() + while next:isSome() do + accum = f(accum :: B, next:getInner() :: T) + next = self:nextBack() + end + + return accum :: B +end + +function Iter.rfind(self: Iter, predicate: (T) -> boolean): Option + local rev = self._rev or revTable(self._inner) + + for _, val in rev do + if predicate(val) == true then + return Some(val) + end + end + + return None() +end + +function Iter.len(self: Iter): number + return #self._inner +end + +function Iter.next(self: Iter): Option + local nextIdx = self._currentPos + 1 + + if nextIdx > self._length then + return None() + end + + self._currentPos = nextIdx + return Some(self._inner[nextIdx]) +end + +function Iter.count(self: Iter): number + local count = self._currentPos + + -- "Consume" self + self = self.new({}) + + return count +end + +function Iter.nth(self: Iter, n: number): Option + local elem: T? = self._inner[n] + + if elem ~= nil then + return Some(elem) + end + + return None() +end + +function Iter.last(self: Iter): Option + local val = self._inner[self._length] + + -- "Consume" self + self = self.new({}) + + if val == nil then + -- Should only occur when iterator is empty + return None() + end + + return Some(val) +end + +function Iter.fold(self: Iter, init: B, f: (B, T) -> B) + local accum = init + + local next: Option = self:nextBack() + while next:isSome() do + accum = f(accum, next:getInner() :: T) + next = self:nextBack() + end + + return accum +end + +function Iter.forEach(self: Iter, f: (T) -> nil): () + for _, v in self._inner do + f(v) + end +end + +function Iter.all(self: Iter, f: (T) -> boolean): boolean + for _, v in self._inner do + local predicate = f + + if predicate(v) == false then + return false + end + end + + return true +end + +function Iter.any(self: Iter, f: (T) -> boolean): boolean + for _, v in self._inner do + local predicate = f + + if predicate(v) == true then + return true + end + end + + return false +end + +function Iter.find(self: Iter, predicate: (T) -> boolean): Option + local next = self:next() + + while next:isSome() do + local inner: T = next:getInner() + if predicate(inner) == true then + return Some(inner) + end + + next = self:next() + end + + return None() +end + +-- TODO: findMap after filterMap +function Iter.findMap(self: Iter, f: (T) -> Option): Option + return nil :: any +end + +return Iter