package extypes import ( "encoding/json" "fmt" "reflect" "strings" ) // Tuple is a read-oriented wrapper around Slice. // // It exposes indexed access and conversion helpers and is useful when an API // should return an ordered collection without slice-specific mutation helpers. type Tuple[T any] struct { s Slice[T] } // NewTupleFrom wraps src as a Tuple without copying it. func NewTupleFrom[T any](src []T) Tuple[T] { return Tuple[T]{src} } // NewTuple returns an empty Tuple. func NewTuple[T any]() Tuple[T] { return Tuple[T]{make(Slice[T], 0)} } // Len returns the number of elements in the tuple. func (t Tuple[T]) Len() int { return t.s.Len() } // Cap returns the capacity of the underlying slice. func (t Tuple[T]) Cap() int { return t.s.Cap() } // Get returns the element at index. func (t Tuple[T]) Get(index int) T { return t.s.Get(index) } // Equal reports whether both tuples have the same length and pairwise equal // elements according to reflect.DeepEqual. func (t Tuple[T]) Equal(t2 Tuple[T]) bool { if t.Len() != t2.Len() { return false } for i := range t.s { if !reflect.DeepEqual(t.s[i], t2.s[i]) { return false } } return true } // ToArray returns a copy of the tuple as a built-in slice. func (t Tuple[T]) ToArray() []T { out := make([]T, t.Len()) copy(out, t.s) return out } // ToAnyArray returns a copy of the tuple converted to []any. func (t Tuple[T]) ToAnyArray() []any { out := make([]any, t.Len()) for i, v := range t.s { out[i] = v } return out } // ToSet returns a Set built from the tuple values. func (t Tuple[T]) ToSet() Set[T] { return NewSetFrom(t.s) } // ToSlice returns a copy of the tuple as a Slice. func (t Tuple[T]) ToSlice() Slice[T] { return NewSliceFrom(t.s) } // Filter returns a new tuple containing only elements accepted by f. func (t Tuple[T]) Filter(f func(e T) bool) Tuple[T] { out := make(Slice[T], 0) for _, v := range t.s { if f(v) { out = append(out, v) } } t.s = out return t } // ForEach calls f for every element and returns the original tuple. func (t Tuple[T]) ForEach(f func(int, T)) Tuple[T] { for i, v := range t.s { f(i, v) } return t } // Join formats every element with fmt.Sprintf("%v", value) and joins them // using sep. func (t Tuple[T]) Join(sep string) string { st := make([]string, len(t.s)) for i, v := range t.s { st[i] = fmt.Sprintf("%v", v) } return strings.Join(st, sep) } // String returns the tuple formatted like its underlying slice. func (t Tuple[T]) String() string { return fmt.Sprint(t.s) } // UnmarshalJSON decodes the tuple from a JSON array. func (t *Tuple[T]) UnmarshalJSON(data []byte) error { return json.Unmarshal(data, &t.s) } // MarshalJSON encodes the tuple as a JSON array. func (t Tuple[T]) MarshalJSON() ([]byte, error) { return json.Marshal(t.s) }