package apple

import (
	"golang.org/x/exp/constraints"
)

// PosLoopDetector is used for detecting loops when writing decoders, and can
// short-circuit infinite recursion that can cause stack overflows.
type PosLoopDetector[T constraints.Integer] []T

// Push adds the current offset to the stack and executes the supplied
// detection function
func (pld *PosLoopDetector[T]) Push(offset T, detect func()) {
	for _, o := range *pld {
		if offset == o {
			detect()
		}
	}
	*pld = append(*pld, offset)
}

// Pop removes the most recently added offset from the stack.
func (pld *PosLoopDetector[T]) Pop() {
	*pld = (*pld)[:len(*pld)-1]
}

// PushAndPop adds the current offset to the stack, executes the supplied
// detection function, and returns the Pop method. A good usage of this is to
// pair this method call with a defer statement.
func (pld *PosLoopDetector[T]) PushAndPop(offset T, detect func()) func() {
	pld.Push(offset, detect)
	return pld.Pop
}
