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