func NewFifoBlockingLimiterWithDefaults(
	delegate core.Limiter,
) *FifoBlockingLimiter {
	return NewFifoBlockingLimiter(delegate, 100, time.Millisecond*1000)
}
NewFifoBlockingLimiterWithDefaults will create a new FifoBlockingLimiter with default values.
package limiter
import (
	"container/list"
	"context"
	"fmt"
	"sync"
	"time"
	"github.com/platinummonkey/go-concurrency-limits/core"
)
type fifoElement struct {
	ctx         context.Context
	releaseChan chan core.Listener
}
func (e *fifoElement) setListener(listener core.Listener) {
	select {
	case e.releaseChan <- listener:
	default:
	}
}
type fifoQueue struct {
	q  *list.List
	mu sync.RWMutex
}
func (q *fifoQueue) len() int {
	q.mu.RLock()
	defer q.mu.RUnlock()
	return q.q.Len()
}
func (q *fifoQueue) push(ctx context.Context) (*list.Element, chan core.Listener) {
	q.mu.Lock()
	defer q.mu.Unlock()
	releaseChan := make(chan core.Listener, 1)
	fe := fifoElement{
		ctx:         ctx,
		releaseChan: releaseChan,
	}
	e := q.q.PushBack(fe)
	return e, releaseChan
}
func (q *fifoQueue) pop() *fifoElement {
	q.mu.Lock()
	defer q.mu.Unlock()
	e := q.q.Front()
	if e != nil {
		fe := e.Value.(fifoElement)
		q.q.Remove(e)
		return &fe
	}
	return nil
}
func (q *fifoQueue) peek() *fifoElement {
	q.mu.RLock()
	defer q.mu.RUnlock()
	e := q.q.Front()
	if e != nil {
		fe := q.q.Front().Value.(fifoElement)
		return &fe
	}
	return nil
}
func (q *fifoQueue) remove(event *list.Element) {
	if event == nil {
		return
	}
	q.mu.Lock()
	defer q.mu.Unlock()
	q.q.Remove(event)
}
type FifoBlockingListener struct {
	delegateListener core.Listener
	limiter          *FifoBlockingLimiter
}
func (l *FifoBlockingListener) unblock() {
	l.limiter.mu.Lock()
	defer l.limiter.mu.Unlock()
	if l.limiter.backlog.len() > 0 {
		event := l.limiter.backlog.peek()
		if event != nil {
			listener, ok := l.limiter.delegate.Acquire(event.ctx)
			if ok && listener != nil {
				nextEvent := l.limiter.backlog.pop()
				nextEvent.setListener(listener)
			}
		}
	}
}
func (l *FifoBlockingListener) OnDropped() {
	l.delegateListener.OnDropped()
	l.unblock()
}
func (l *FifoBlockingListener) OnIgnore() {
	l.delegateListener.OnIgnore()
	l.unblock()
}
func (l *FifoBlockingListener) OnSuccess() {
	l.delegateListener.OnSuccess()
	l.unblock()
}
type FifoBlockingLimiter struct {
	delegate          core.Limiter
	maxBacklogSize    int
	maxBacklogTimeout time.Duration
	backlog fifoQueue
	c       *sync.Cond
	mu      sync.RWMutex
}
func NewFifoBlockingLimiter(
	delegate core.Limiter,
	maxBacklogSize int,
	maxBacklogTimeout time.Duration,
) *FifoBlockingLimiter {
	if maxBacklogSize <= 0 {
		maxBacklogSize = 100
	}
	if maxBacklogTimeout == 0 {
		maxBacklogTimeout = time.Millisecond * 1000
	}
	mu := sync.Mutex{}
	return &FifoBlockingLimiter{
		delegate:          delegate,
		maxBacklogSize:    maxBacklogSize,
		maxBacklogTimeout: maxBacklogTimeout,
		backlog: fifoQueue{
			q: list.New(),
		},
		c: sync.NewCond(&mu),
	}
}