import Base.iterate

const _POSSIBLE_OPERATIONS_FIELDS = fieldnames(PossibleOperations)

_POIteratorStateType =
    NamedTuple{(:result, :state), Tuple{Union{NodeFusion, NodeReduction, NodeSplit}, Tuple{Symbol, Int64}}}

@inline function iterate(possibleOperations::PossibleOperations)::Union{Nothing, _POIteratorStateType}
    for fieldname in _POSSIBLE_OPERATIONS_FIELDS
        iterator = iterate(getfield(possibleOperations, fieldname))
        if (!isnothing(iterator))
            return (result = iterator[1], state = (fieldname, iterator[2]))
        end
    end

    return nothing
end

@inline function iterate(possibleOperations::PossibleOperations, state)::Union{Nothing, _POIteratorStateType}
    newStateSym = state[1]
    newStateIt = iterate(getfield(possibleOperations, newStateSym), state[2])
    if !isnothing(newStateIt)
        return (result = newStateIt[1], state = (newStateSym, newStateIt[2]))
    end

    # cycle to next field
    index = findfirst(x -> x == newStateSym, _POSSIBLE_OPERATIONS_FIELDS) + 1

    while index <= length(_POSSIBLE_OPERATIONS_FIELDS)
        newStateSym = _POSSIBLE_OPERATIONS_FIELDS[index]
        newStateIt = iterate(getfield(possibleOperations, newStateSym))
        if !isnothing(newStateIt)
            return (result = newStateIt[1], state = (newStateSym, newStateIt[2]))
        end
        index += 1
    end

    return nothing
end
