Solution (source code)

= Solution

Cache only a requested current element. Merely constructing the <cursor>, or asking whether it is nonempty, must not fetch a value from the <iterator>:

``
def asCursor[T](it: Iter[T]): Cursor[T] = new Cursor[T] {
  private var cached: Option[T] = None

  def hasCurrent: Boolean = cached.nonEmpty || it.hasNext

  def current: T = {
    if (cached.isEmpty) {
      require(it.hasNext, "empty cursor")
      cached = Some(it.next())
    }
    cached.get
  }

  def next(): Unit = {
    if (cached.nonEmpty) cached = None
    else {
      require(it.hasNext, "empty cursor")
      it.next()
      ()
    }
  }
}
``

The <abstraction function> for the adapter is `it.seq` when no value is cached and `[cachedValue] ++ it.seq` otherwise. Fetching `current` removes one underlying <iterator> value but saves it, so the <cursor>'s abstract <sequence> is unchanged; repeated reads return the same value. Advancing either discards that cache or consumes one uncached <iterator> value. No following element is prefetched.

A too-eager implementation could call `it.next()` at construction, or fetch a new element immediately after every advance, even when the client never requests it. That can trigger unnecessary work or nontermination on a difficult stream. This <lazy iterator-to-cursor adapter> avoids both behaviors and checks the underlying access <preconditions> itself. The wrapped <iterator> is assumed to be used exclusively through the adapter; independent external consumption would invalidate the shared-state abstraction.