Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions commons/TupleOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import scala.compiletime.ops.int.S
import scala.reflect.ClassTag

extension (tup: Tuple)
inline def foreach(f: [t] => t => Unit): Unit = tup.map[[X] =>> Unit](f)
def foreach(f: [t] => t => Unit): Unit = tup.map[[X] =>> Unit](f)

inline def indices: Indices[tup.type] = Tuple.fromArray(Array.range(0, tup.size)).asInstanceOf[Indices[tup.type]]
def indices: Indices[tup.type] = Tuple.fromArray(Array.range(0, tup.size)).asInstanceOf[Indices[tup.type]]

inline def hasDuplicates: HasDuplicates[tup.type] = compiletime.constValue[HasDuplicates[tup.type]]

inline def mapAs[T](using inline ev: tup.type containsOnly T)[F[_ <: T]](inline f: [t <: T] => t => F[t])
def mapAs[T](using tup.type containsOnly T)[F[_ <: T]](f: [t <: T] => t => F[t])
: Tuple.Map[tup.type, [X] =>> F[X & T]] =
tup.map[[X] =>> F[X & T]]([t] => (t: t) => f(t.asInstanceOf[t & T]))

inline def toArrayOf[T](using inline ev: tup.type containsOnly T)(using ClassTag[T]): Array[T] = tup match
def toArrayOf[T](using tup.type containsOnly T)(using ClassTag[T]): Array[T] = tup match
case EmptyTuple => Array.empty[T]
case self: Product =>
val arr = new Array[T](self.productArity)
Expand All @@ -25,8 +25,7 @@ extension (tup: Tuple)
arr(i) = self.productElement(i).asInstanceOf[T]
i += 1
arr

inline def to[T](using inline ev: tup.type containsOnly T)[C](factory: Factory[T, C]): C =
def to[T](using tup.type containsOnly T)[C](factory: Factory[T, C]): C =
factory.fromSpecific(tup.productIterator.asInstanceOf[Iterator[T]])

type Indices[Tup <: Tuple] <: Tuple = Tup match
Expand All @@ -41,5 +40,5 @@ type HasDuplicates[Tup <: Tuple] <: Boolean = Tup match
case EmptyTuple => false
case h *: t => Tuple.Contains[t, h] || HasDuplicates[t]

inline def realCons(x: Any, tup: Tuple): x.type *: tup.type =
def realCons(x: Any, tup: Tuple): x.type *: tup.type =
runtime.Tuples.cons(x, tup).asInstanceOf[x.type *: tup.type]
31 changes: 14 additions & 17 deletions commons/containsOnly.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,27 @@ object containsOnly extends containsOnlyLowPriority:

def refl[Tup <: Tuple, T]: Tup containsOnly T = reusable

inline given [Tup <: Tuple, T] => (Loop[Tup, T] =:= true) => containsOnly[Tup, T] = refl
given [Tup <: Tuple, T] => (Loop[Tup, T] =:= true) => (Tup containsOnly T) = refl

/** A constant map `[_] =>> C` makes every element `C`. Unifies even for abstract `Es`. */
inline given [Es <: Tuple, C] => (Tuple.Map[Es, [_] =>> C] containsOnly C) = refl
given [Es <: Tuple, C] => (Tuple.Map[Es, [_] =>> C] containsOnly C) = refl

/** A covariant `F` gives `F[e] <: F[Any]` for every element (invariant `F` still needs `refl`). */
inline given [Es <: Tuple, F[+_]] => (Tuple.Map[Es, F] containsOnly F[Any]) = refl
given [Es <: Tuple, F[+_]] => (Tuple.Map[Es, F] containsOnly F[Any]) = refl

inline given [Tup <: Tuple, T](using inline ev: Tup containsOnly T): (Tuple.Tail[Tup] containsOnly T) = refl
inline given [Tup <: Tuple, T](using inline ev: Tup containsOnly T): (Tuple.Reverse[Tup] containsOnly T) = refl
inline given [Tup1 <: Tuple, Tup2 <: Tuple, T](
using inline ev1: Tup1 containsOnly T,
ev2: Tup2 containsOnly T,
): (Tuple.Concat[Tup1, Tup2] containsOnly T) = refl
inline given [Tup1 <: Tuple, Tup2 <: Tuple, T1, T2](
using inline ev1: Tup1 containsOnly T1,
ev2: Tup2 containsOnly T2,
): (Tuple.Zip[Tup1, Tup2] containsOnly (T1, T2)) = refl
given [Tup <: Tuple: Of[T], T] => (Tuple.Tail[Tup] containsOnly T) = refl

import scala.language.implicitConversions
given [Tup <: Tuple: Of[T], T] => (Tuple.Reverse[Tup] containsOnly T) = refl

given [Tup <: Tuple: Of[T], T] => Conversion[Tuple.Head[Tup], T] = _.asInstanceOf[T]
given [Tup1 <: Tuple: Of[T], Tup2 <: Tuple: Of[T], T] => (Tuple.Concat[Tup1, Tup2] containsOnly T) = refl

given [Tup <: Tuple: Of[T], T] => Conversion[Tuple.Last[Tup], T] = _.asInstanceOf[T]
given [Tup1 <: Tuple: Of[T1], Tup2 <: Tuple: Of[T2], T1, T2] => (Tuple.Zip[Tup1, Tup2] containsOnly (T1, T2)) = refl

given [Tup <: Tuple: Of[T], This >: Tup <: Tuple, T] => (Tuple.Head[This] <:< T) =
<:<.refl.asInstanceOf[(Tuple.Head[This] <:< T)]

given [Tup <: Tuple: Of[T], This >: Tup <: Tuple, T] => (Tuple.Last[This] <:< T) =
<:<.refl.asInstanceOf[(Tuple.Last[This] <:< T)]

sealed trait containsOnlyLowPriority:
inline given Tuple containsOnly Any = containsOnly.refl
given Tuple containsOnly Any = containsOnly.refl
2 changes: 0 additions & 2 deletions test/ContainsOnlyTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package halotukozak.commons

import halotukozak.commons.containsOnly.given

import scala.language.implicitConversions

class ContainsOnlyTest extends munit.FunSuite:

// --- Loop type-level: positive cases ---
Expand Down
Loading