package onering

import (
	"runtime"
	"sync/atomic"
	"unsafe"
)

type SPMC struct {
	multi
}

func (r *SPMC) Get(i interface{}) bool {
	var (
		rp        = r.next(&r.rp)
		data, seq = r.frame(rp)
	)

	for pread := -rp; atomic.LoadInt64(seq) != pread; runtime.Gosched() {
		if atomic.LoadInt32(&r.done) > 0 && atomic.LoadInt64(&r.wp) <= rp {
			return false
		}
	}
	inject(i, *data)
	atomic.StoreInt64(seq, rp+r.size)
	return true
}

func (r *SPMC) Consume(i interface{}) {
	var (
		fn  = extractfn(i)
		it  iter
		ptr unsafe.Pointer
	)
	for !it.stop && r.Get(&ptr) {
		fn(&it, ptr)
	}
}

func (r *SPMC) Put(i interface{}) {
	var (
		wp        = r.wp
		data, seq = r.frame(wp)
	)
	for atomic.LoadInt64(seq) < 0 {
		runtime.Gosched()
	}
	*data = extractptr(i)
	r.wp++
	atomic.StoreInt64(seq, -wp)
}