1package csync
  2
  3import (
  4	"iter"
  5	"slices"
  6	"sync"
  7)
  8
  9// LazySlice is a thread-safe lazy-loaded slice.
 10type LazySlice[K any] struct {
 11	inner []K
 12	wg    sync.WaitGroup
 13}
 14
 15// NewLazySlice creates a new slice and runs the [load] function in a goroutine
 16// to populate it.
 17func NewLazySlice[K any](load func() []K) *LazySlice[K] {
 18	s := &LazySlice[K]{}
 19	s.wg.Go(func() {
 20		s.inner = load()
 21	})
 22	return s
 23}
 24
 25// Seq returns an iterator that yields elements from the slice.
 26func (s *LazySlice[K]) Seq() iter.Seq[K] {
 27	s.wg.Wait()
 28	return func(yield func(K) bool) {
 29		for _, v := range s.inner {
 30			if !yield(v) {
 31				return
 32			}
 33		}
 34	}
 35}
 36
 37// Slice is a thread-safe slice implementation that provides concurrent access.
 38type Slice[T any] struct {
 39	inner []T
 40	mu    sync.RWMutex
 41}
 42
 43// NewSlice creates a new thread-safe slice.
 44func NewSlice[T any]() *Slice[T] {
 45	return &Slice[T]{
 46		inner: make([]T, 0),
 47	}
 48}
 49
 50// NewSliceFrom creates a new thread-safe slice from an existing slice.
 51func NewSliceFrom[T any](s []T) *Slice[T] {
 52	inner := make([]T, len(s))
 53	copy(inner, s)
 54	return &Slice[T]{
 55		inner: inner,
 56	}
 57}
 58
 59// Append adds an element to the end of the slice.
 60func (s *Slice[T]) Append(items ...T) {
 61	s.mu.Lock()
 62	defer s.mu.Unlock()
 63	s.inner = append(s.inner, items...)
 64}
 65
 66// Prepend adds an element to the beginning of the slice.
 67func (s *Slice[T]) Prepend(item T) {
 68	s.mu.Lock()
 69	defer s.mu.Unlock()
 70	s.inner = append([]T{item}, s.inner...)
 71}
 72
 73// Delete removes the element at the specified index.
 74func (s *Slice[T]) Delete(index int) bool {
 75	s.mu.Lock()
 76	defer s.mu.Unlock()
 77	if index < 0 || index >= len(s.inner) {
 78		return false
 79	}
 80	s.inner = slices.Delete(s.inner, index, index+1)
 81	return true
 82}
 83
 84// Get returns the element at the specified index.
 85func (s *Slice[T]) Get(index int) (T, bool) {
 86	s.mu.RLock()
 87	defer s.mu.RUnlock()
 88	var zero T
 89	if index < 0 || index >= len(s.inner) {
 90		return zero, false
 91	}
 92	return s.inner[index], true
 93}
 94
 95// Set updates the element at the specified index.
 96func (s *Slice[T]) Set(index int, item T) bool {
 97	s.mu.Lock()
 98	defer s.mu.Unlock()
 99	if index < 0 || index >= len(s.inner) {
100		return false
101	}
102	s.inner[index] = item
103	return true
104}
105
106// Len returns the number of elements in the slice.
107func (s *Slice[T]) Len() int {
108	s.mu.RLock()
109	defer s.mu.RUnlock()
110	return len(s.inner)
111}
112
113// SetSlice replaces the entire slice with a new one.
114func (s *Slice[T]) SetSlice(items []T) {
115	s.mu.Lock()
116	defer s.mu.Unlock()
117	s.inner = make([]T, len(items))
118	copy(s.inner, items)
119}
120
121// Seq returns an iterator that yields elements from the slice.
122func (s *Slice[T]) Seq() iter.Seq[T] {
123	return func(yield func(T) bool) {
124		for _, v := range s.Seq2() {
125			if !yield(v) {
126				return
127			}
128		}
129	}
130}
131
132// Seq2 returns an iterator that yields index-value pairs from the slice.
133func (s *Slice[T]) Seq2() iter.Seq2[int, T] {
134	s.mu.RLock()
135	items := make([]T, len(s.inner))
136	copy(items, s.inner)
137	s.mu.RUnlock()
138	return func(yield func(int, T) bool) {
139		for i, v := range items {
140			if !yield(i, v) {
141				return
142			}
143		}
144	}
145}