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() this.valid = true } 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 }