Imports System.Threading

''' <summary>
''' An object representing an iterator.
''' </summary>
''' <typeparam name="T">The type of the elements to iterate.</typeparam>
''' <typeparam name="TState">The type of the state to provide.</typeparam>
''' <remarks></remarks>
Public Class Iterator(Of T, TState)
    Implements IEnumerable(Of T)
    Implements IEnumerator(Of T)

    Public Delegate Function MoveNextFunc(ByRef nextItem As T, ByRef state As TState) As Boolean

    ''' <summary>
    ''' Initializes a new instance of the Iterator(of T) class with the specified delegate.
    ''' </summary>
    ''' <param name="func">A delegate to a function that determines 
    ''' if the iterator can move to the next item.</param>
    ''' <param name="initialState">The initial state of this enumerator.</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal func As MoveNextFunc, ByVal initialState As TState)
        Me._func = func
        Me._state = initialState
    End Sub

    Private _state As TState
    Private _current As T
    Private _func As MoveNextFunc

    ''' <summary>
    ''' Gets the element at the current position.
    ''' </summary>
    ''' <returns>The element at the current position.</returns>
    ''' <remarks></remarks>
    Public ReadOnly Property Current() As T Implements System.Collections.Generic.IEnumerator(Of T).Current
        Get
            Return Me._current
        End Get
    End Property

    Private ReadOnly Property IEnumerator_Current() As Object Implements System.Collections.IEnumerator.Current
        Get
            Return Me.Current
        End Get
    End Property

    ''' <summary>
    ''' Advances the enumerator to the next element in the collection.
    ''' </summary>
    ''' <returns>True if the iterator can advance; otherwise, false.</returns>
    ''' <remarks></remarks>
    Public Function MoveNext() As Boolean Implements System.Collections.IEnumerator.MoveNext
        Return Me._func(Me._current, Me._state)
    End Function

    ''' <summary>
    ''' Sets the enumerator to its initial position.  This is not possible with an iterator.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Reset() Implements System.Collections.IEnumerator.Reset
        Throw New NotImplementedException("An iterator cannot be reset.")
    End Sub

#Region "IDisposable"
    Private disposedValue As Boolean = False        ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: free other state (managed objects).
            End If

            ' TODO: free your own state (unmanaged objects).
            ' TODO: set large fields to null.
        End If
        Me.disposedValue = True
    End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

#Region "IEnumerable"

    ''' <summary>
    ''' Returns an enumerator that iterates through a collection.
    ''' </summary>
    ''' <returns>An enumerator that iterates through a collection.</returns>
    ''' <remarks></remarks>
    Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of T) Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator
        Static called As Integer
        If (called = 0) AndAlso Interlocked.Increment(called) = 1 Then
            Return Me
        Else
            Return New Iterator(Of T, TState)(Me._func, Me._state)
        End If
    End Function

    Private Function IEnumerator_GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
        Return Me.GetEnumerator()
    End Function

#End Region

End Class