132 lines
3.0 KiB
Go
132 lines
3.0 KiB
Go
package util
|
|
|
|
import "io"
|
|
import "image/color"
|
|
|
|
// IndexOf returns the index of needle within haystack. If needle does not exist
|
|
// within haystack, it returns -1.
|
|
func IndexOf[T comparable] (haystack []T, needle T) int {
|
|
for index, test := range haystack {
|
|
if test == needle {
|
|
return index
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// Remove removes an element from slice at index.
|
|
func Remove[T any] (slice []T, index int) []T {
|
|
return append(slice[:index], slice[index + 1:]...)
|
|
}
|
|
|
|
// Insert inserts an element into slice at index.
|
|
func Insert[T any] (slice []T, index int, element T) []T {
|
|
slice = append(slice[:index + 1], slice[index:]...)
|
|
slice[index] = element
|
|
return slice
|
|
}
|
|
|
|
// Transparent returns whether or not a color has transparency.
|
|
func Transparent (c color.Color) bool {
|
|
_, _, _, a := c.RGBA()
|
|
return a != 0xFFFF
|
|
}
|
|
|
|
// Set is a set of unique items, built on top of map.
|
|
type Set[T comparable] map[T] struct { }
|
|
|
|
// Empty returns true if there are no items in the set.
|
|
func (set Set[T]) Empty () bool {
|
|
return set == nil || len(set) == 0
|
|
}
|
|
|
|
// Has returns true if the set contains item.
|
|
func (set Set[T]) Has (item T) bool {
|
|
if set == nil {
|
|
return false
|
|
}
|
|
_, ok := set[item]
|
|
return ok
|
|
}
|
|
|
|
// Add adds an item to the set.
|
|
func (set Set[T]) Add (item T) {
|
|
set[item] = struct { } { }
|
|
}
|
|
|
|
// Pop removes the first accessible item from the set and returns it.
|
|
func (set Set[T]) Pop () (item T) {
|
|
for item := range set {
|
|
delete(set, item)
|
|
return item
|
|
}
|
|
return
|
|
}
|
|
|
|
// Memo holds a cached value.
|
|
type Memo[T any] struct {
|
|
cache T
|
|
valid bool
|
|
update func () T
|
|
}
|
|
|
|
// NewMemo creates a new Memo which will take its value from the specified
|
|
// update callback.
|
|
func NewMemo[T any] (update func () T) Memo[T] {
|
|
return Memo[T] {
|
|
update: update,
|
|
}
|
|
}
|
|
|
|
// Value returns the Memo's value, updating it if the current cached value is
|
|
// invalid.
|
|
func (this *Memo[T]) Value () T {
|
|
if !this.valid {
|
|
this.cache = this.update()
|
|
}
|
|
return this.cache
|
|
}
|
|
|
|
// Invalidate marks the Memo's value as invalid, which will cause it to be
|
|
// updated the next time Value is called.
|
|
func (this *Memo[T]) Invalidate () {
|
|
this.valid = false
|
|
}
|
|
|
|
// InvalidateTo invalidates the Memo and sets its value. The new value will be
|
|
// entirely inaccessible. This is only intended to be used for setting a
|
|
// reference to nil
|
|
func (this *Memo[T]) InvalidateTo (value T) {
|
|
this.Invalidate()
|
|
this.cache = value
|
|
}
|
|
|
|
// Cycler stores a value and an accompanying io.Closer. When the value is set,
|
|
// the closer associated with the previous value is closed.
|
|
type Cycler[T any] struct {
|
|
value T
|
|
closer io.Closer
|
|
}
|
|
|
|
// Value returns the cycler's value.
|
|
func (this *Cycler[T]) Value () T {
|
|
return this.value
|
|
}
|
|
|
|
// Set sets the value and associated closer, closing the previous one.
|
|
func (this *Cycler[T]) Set (value T, closer io.Closer) (err error) {
|
|
if this.closer != nil {
|
|
err = this.closer.Close()
|
|
}
|
|
this.value = value
|
|
this.closer = closer
|
|
return err
|
|
}
|
|
|
|
// Close closes the associated closer early.
|
|
func (this *Cycler[T]) Close () error {
|
|
err := this.closer.Close()
|
|
this.closer = nil
|
|
return err
|
|
}
|