// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information

package sync2

import (
	"context"

	"golang.org/x/sync/semaphore"
)

// Semaphore implements a closable semaphore.
type Semaphore struct {
	noCopy noCopy //nolint:structcheck

	ctx   context.Context
	close func()
	sema  *semaphore.Weighted
}

// NewSemaphore creates a semaphore with the specified size.
func NewSemaphore(size int) *Semaphore {
	sema := &Semaphore{}
	sema.Init(size)
	return sema
}

// Init initializes semaphore to the specified size.
func (sema *Semaphore) Init(size int) {
	sema.ctx, sema.close = context.WithCancel(context.Background())
	sema.sema = semaphore.NewWeighted(int64(size))
}

// Close closes the semaphore from further use.
func (sema *Semaphore) Close() {
	sema.close()
}

// Lock locks the semaphore.
func (sema *Semaphore) Lock() bool {
	return sema.sema.Acquire(sema.ctx, 1) == nil
}

// Unlock unlocks the semaphore.
func (sema *Semaphore) Unlock() {
	sema.sema.Release(1)
}
