package utils import ( "slices" "sync" ) // SequenceNumberGenerator can be used to generate increasing numbers. type SequenceNumberGenerator interface { // Next returns the next number Next() uint64 // Revert can be used to revert a specific number (e.g. in case of an error) Revert(uint64) } // DefaultSequenceNumberGenerator is a mutex protected implementation of SequenceNumberGenerator type DefaultSequenceNumberGenerator struct { backlog []uint64 sequenceNumber uint64 sequenceNumberLock sync.Mutex } // NewDefaultSequenceNumberGenerator returns an instance of DefaultSequenceNumberGenerator as pointer // of SequenceNumberGenerator. func NewDefaultSequenceNumberGenerator() SequenceNumberGenerator { var generator SequenceNumberGenerator = &DefaultSequenceNumberGenerator{ backlog: make([]uint64, 0), sequenceNumber: 0, sequenceNumberLock: sync.Mutex{}, } return generator } // Next implements SequenceNumberGenerator.Next func (g *DefaultSequenceNumberGenerator) Next() uint64 { g.sequenceNumberLock.Lock() defer g.sequenceNumberLock.Unlock() var next uint64 if len(g.backlog) == 0 { next = g.sequenceNumber g.sequenceNumber += 1 } else { next = g.backlog[0] g.backlog = g.backlog[1:] } return next } // Revert implements SequenceNumberGenerator.Revert func (g *DefaultSequenceNumberGenerator) Revert(value uint64) { g.sequenceNumberLock.Lock() defer g.sequenceNumberLock.Unlock() if value == g.sequenceNumber-1 { g.sequenceNumber -= 1 } else if !slices.Contains(g.backlog, value) { g.backlog = append(g.backlog, value) } }