--[[ 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 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