McpScope

class McpScope<T>(val sink: Capture) : Iterator<T> , Continuation<Unit>

Receiver of a cross-tick iterator { ... } snippet — scope and iterator in one object, as the stdlib's SequenceBuilderIterator is. Replaces the stdlib builder for two reasons:

  • yield renders what it is handed. The lane drives the iterator to exhaustion and discards every element, so under the stdlib builder iterator { ...; yield(answer) } reported "(no output)" — the one snippet shape that could not answer, silently. Rendering must happen at the yield, not at the driver: by then the value is a bare Object, and a runtime type is no substitute (listOf(1, 2) reads as java.util.Arrays$ArrayList). Only a reified parameter, resolved per call site, keeps kotlin.collections.List<kotlin.Int> — and a reified yield must be inline, which rules out overriding the stdlib's abstract one.

  • RestrictsSuspension carries its weight. It is what makes yield the only suspension point in the body, so a step always resumes on the thread that called hasNext. Without it a snippet can kotlinx.coroutines.delay(..) — on the game loader here — and wake on a foreign thread while the lane still believes it owns the tick. The annotation is public, so we keep that guard without extending SequenceScope.

No yieldAll: its only remaining meaning would be "yield in bulk, silently", which is the opposite of the point. for (v in xs) yield(v) is one line and reports each element.

Constructors

Link copied to clipboard
internal constructor(sink: Capture)

Types

Link copied to clipboard
private enum Step : Enum<McpScope.Step>

Five states: the stdlib's six, less the two that go with yieldAll's delegate-pull, plus the split of its single Failed — see Resuming.

Properties

Link copied to clipboard
private var cont: Continuation<Unit>?
Link copied to clipboard
open override val context: CoroutineContext
Link copied to clipboard
private var pending: T?
Link copied to clipboard
private val sink: Capture

Never exposed, not even as @PublishedApi: handing a snippet the Capture hands it take(), which seals the sink and drops the rest of the eval's output. emitValue is the write-only door yield needs.

Link copied to clipboard
private var step: McpScope.Step

Functions

Link copied to clipboard
internal fun begin(block: suspend McpScope<T>.() -> Unit)

Split from the constructor because createCoroutineUnintercepted needs the receiver instance — the same two-step the stdlib builder does.

Link copied to clipboard
internal fun emitValue(type: String, value: Any?)

The same ValueRender.line a single-tick result goes through, so the two cannot report differently.

Link copied to clipboard
open operator override fun hasNext(): Boolean
Link copied to clipboard
open operator override fun next(): T

One precondition, not the stdlib's next()nextNotReady() recursion: hasNext already answers every state, so asking it IS "is there a value".

Link copied to clipboard
open override fun resumeWith(result: Result<Unit>)

Rethrow so a throw surfaces out of the hasNext that resumed it — the lane's guard turns it into partial output plus a stack. State FIRST: getOrThrow does not return on a failure, so setting it after would strand Step.Resuming and misreport the next entry as a suspension that never happened.

Link copied to clipboard
inline suspend fun <V : T> yield(value: V, typeName: String = typeOf<V>().toString())

Suspend until the next tick, reporting value as this step's result.

Link copied to clipboard
internal suspend fun yieldRaw(value: T)

The suspension itself — everything yield does apart from rendering. @PublishedApi for the inline call.