func (st *FIFO) GetLen() int {
	st.rwmutex.RLock()
	defer st.rwmutex.RUnlock()
	return len(st.slice)
}
GetLen returns the number of enqueued elements
package goconcurrentqueue
import (
	"context"
	"fmt"
	"sync"
	"time"
)
const (
	WaitForNextElementChanCapacity           = 1000
	dequeueOrWaitForNextElementInvokeGapTime = 10
)
type FIFO struct {
	slice       []interface{}
	rwmutex     sync.RWMutex
	lockRWmutex sync.RWMutex
	isLocked    bool
	waitForNextElementChan chan chan interface{}
}
func NewFIFO() *FIFO {
	ret := &FIFO{}
	ret.initialize()
	return ret
}
func (st *FIFO) initialize() {
	st.slice = make([]interface{}, 0)
	st.waitForNextElementChan = make(chan chan interface{}, WaitForNextElementChanCapacity)
}
func (st *FIFO) Enqueue(value interface{}) error {
	if st.isLocked {
		return NewQueueError(QueueErrorCodeLockedQueue, "The queue is locked")
	}
	select {
	case listener := <-st.waitForNextElementChan:
		select {
		case listener <- value:
		default:
			st.rwmutex.Lock()
			st.slice = append(st.slice, value)
			defer st.rwmutex.Unlock()
		}
	default:
		st.rwmutex.Lock()
		st.slice = append(st.slice, value)
		defer st.rwmutex.Unlock()
	}
	return nil
}
func (st *FIFO) Dequeue() (interface{}, error) {
	if st.isLocked {
		return nil, NewQueueError(QueueErrorCodeLockedQueue, "The queue is locked")
	}
	st.rwmutex.Lock()
	defer st.rwmutex.Unlock()
	len := len(st.slice)
	if len == 0 {
		return nil, NewQueueError(QueueErrorCodeEmptyQueue, "empty queue")
	}
	elementToReturn := st.slice[0]
	st.slice = st.slice[1:]
	return elementToReturn, nil
}
func (st *FIFO) DequeueOrWaitForNextElement() (interface{}, error) {
	return st.DequeueOrWaitForNextElementContext(context.Background())
}
func (st *FIFO) DequeueOrWaitForNextElementContext(ctx context.Context) (interface{}, error) {
	for {
		if st.isLocked {
			return nil, NewQueueError(QueueErrorCodeLockedQueue, "The queue is locked")
		}
		st.rwmutex.Lock()
		length := len(st.slice)
		st.rwmutex.Unlock()
		if length == 0 {
			waitChan := make(chan interface{})
			select {
			case st.waitForNextElementChan <- waitChan:
				for i := 0; i < dequeueOrWaitForNextElementInvokeGapTime; i++ {
					select {
					case <-ctx.Done():
						return nil, ctx.Err()
					case dequeuedItem := <-waitChan:
						return dequeuedItem, nil
					case <-time.After(time.Millisecond * time.Duration(i)):
						if dequeuedItem, err := st.Dequeue(); err == nil {
							return dequeuedItem, nil
						}
					}
				}
				select {
					case item := <-waitChan:
						return item, nil
					case <-ctx.Done():
						return nil, ctx.Err()
				}
			default:
				return nil, NewQueueError(QueueErrorCodeEmptyQueue, "empty queue and can't wait for next element because there are too many DequeueOrWaitForNextElement() waiting")
			}
		}
		st.rwmutex.Lock()
		if len(st.slice) == 0 {
			st.rwmutex.Unlock()
			continue
		}
		elementToReturn := st.slice[0]
		st.slice = st.slice[1:]
		st.rwmutex.Unlock()
		return elementToReturn, nil
	}
}
func (st *FIFO) Get(index int) (interface{}, error) {
	if st.isLocked {
		return nil, NewQueueError(QueueErrorCodeLockedQueue, "The queue is locked")
	}
	st.rwmutex.RLock()
	defer st.rwmutex.RUnlock()
	if len(st.slice) <= index {
		return nil, NewQueueError(QueueErrorCodeIndexOutOfBounds, fmt.Sprintf("index out of bounds: %v", index))
	}
	return st.slice[index], nil
}
func (st *FIFO) Remove(index int) error {
	if st.isLocked {
		return NewQueueError(QueueErrorCodeLockedQueue, "The queue is locked")
	}
	st.rwmutex.Lock()
	defer st.rwmutex.Unlock()
	if len(st.slice) <= index {
		return NewQueueError(QueueErrorCodeIndexOutOfBounds, fmt.Sprintf("index out of bounds: %v", index))
	}
	st.slice = append(st.slice[:index], st.slice[index+1:]...)
	return nil
}