What exactly did you try and what errors did you get?
I first tried a simplified sample iterator along with your helper method:
/// An iterator that vends the transformation of every 10 elements.
struct Map10ElementsIterator<Base: IteratorProtocol, Element>: IteratorProtocol {
/// The wrapped iterator
var base: Base
/// The closure to map each subsequence to an output element
let transform: (AnySequence<Base.Element>) -> Element
mutating func next() -> Element? {
func helper(_ body: () -> Base.Element?) -> Element {
return withoutActuallyEscaping(body) {
transform(AnySequence(AnyIterator($0)))
}
}
guard let first = base.next() else { return nil }
var remaining = 10
return helper {
guard remaining > 0 else { return nil }
defer { remaining -= 1 }
guard remaining < 10 else { return first }
return self.base.next()
}
}
}
let hundred = Array(0..<100)
var iterator100 = Map10ElementsIterator(base: hundred.makeIterator(), transform: { Array($0) })
iterator100.base.next() // 0
iterator100.next() // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
iterator100.base.next() // 11
iterator100.next() // [12, 13, 14, 15, 16, 17, 18, 19. 20. 21]
iterator100.base.next() // 22
let five = Array(0..<5)
var iterator5 = Map10ElementsIterator(base: five.makeIterator(), transform: Array.init)
iterator5.base.next() // 0
iterator5.next() // [1, 2, 3, 4]
iterator5.base.next() // nil
iterator5.next() // nil
I'm on Xcode 10.1 with its default Swift.
Then I tried without a helper function:
mutating func next() -> Element? {
guard let first = base.next() else { return nil }
var remaining = 10
return withoutActuallyEscaping({
guard remaining > 0 else { return nil }
defer { remaining -= 1 }
guard remaining < 10 else { return first }
return self.base.next() // Error here
}) { transform(AnySequence(AnyIterator($0))) }
}
And got an error underlined on the "s" in "self". The error was:
Closure cannot implicitly capture a mutating self parameter
The examples for withoutActuallyEscaping(_: do:)
in its documentation used a passed-in closure for the non-escaping parameter. So I rearranged the code so the increment is in a distinct function:
mutating func next() -> Element? {
guard let first = base.next() else { return nil }
var remaining = 10
func generate() -> Base.Element? {
guard remaining > 0 else { return nil }
defer { remaining -= 1 }
guard remaining < 10 else { return first }
return base.next()
}
return withoutActuallyEscaping(generate, do: { transform(AnySequence(AnyIterator($0))) })
}
And this passed. I was about to report on needing a named separately-defined argument for the first parameter of withoutActuallyEscaping(_: do:)
, but I tried out something on my actual iterator:
extension LazySplitIterator: IteratorProtocol {
public mutating func next() -> Element? {
switch remainingSplits {
case .some(0):
// Dump the remaining elements into the mapping function, whether they are separators or not.
guard let first = base.next() else { return nil }
let firstCollection = CollectionOfOne(first)
var firstIterator = firstCollection.makeIterator()
return withoutActuallyEscaping({ firstIterator.next() ?? self.base.next() }, do: { transform(AnySequence(AnyIterator($0))) })
case .some(let limit):
remainingSplits = .some(limit - 1)
fallthrough
case .none:
// Read until the next separator, possibly skipping initial separators.
return nil
}
}
}
The compiler accepted the call at the end of the .some(0)
case. Is it the length of a defined-inline closure that caused the problem, not the fact the closure is defined inline at all?