Created
May 9, 2025 02:46
-
-
Save EtaCassiopeia/283f1a283349958beb8882603ef876ca to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.annotation.implicitNotFound | |
import scala.language.{dynamics, implicitConversions} | |
object HMap: | |
opaque type M[T <: Tuple] = Map[Any, Any] | |
extension [T <: Tuple](m: M[T]) | |
def add[K <: Singleton, V](k: K, v: V)(using | |
NoMatch[T, K] =:= true | |
): M[(K, V) *: T] = m + (k -> v) | |
def get[K <: Singleton](k: K)(using | |
NoMatch[T, K] =:= false | |
): GetMatch[T, K] = | |
m(k).asInstanceOf[GetMatch[T, K]] | |
def delete[K <: Singleton](k: K)(using | |
NoMatch[T, K] =:= false | |
): M[DropMatch[T, K]] = m - k | |
trait UpdateHandler[T <: Tuple, K <: Singleton, V] { | |
type Out <: Tuple | |
def apply(m: M[T], k: K, v: V): M[Out] | |
} | |
implicit def updateExisting[T <: Tuple, K <: Singleton, V](using | |
ev1: HMap.NoMatch[T, K] =:= false, | |
ev2: HMap.GetMatch[T, K] =:= V | |
): UpdateHandler[T, K, V] { type Out = T } = new UpdateHandler[T, K, V] { | |
type Out = T | |
def apply(m: M[T], k: K, v: V): M[T] = m + (k -> v) | |
} | |
implicit def addNew[T <: Tuple, K <: Singleton, V](using | |
ev: HMap.NoMatch[T, K] =:= true | |
): UpdateHandler[T, K, V] { type Out = (K, V) *: T } = new UpdateHandler[T, K, V] { | |
type Out = (K, V) *: T | |
def apply(m: M[T], k: K, v: V): M[(K, V) *: T] = m.add(k, v) | |
} | |
val empty: M[EmptyTuple] = Map.empty | |
type NoMatch[Tup <: Tuple, K] = Tup match | |
case (K *: ? *: EmptyTuple) *: ? => false | |
case (? *: ? *: EmptyTuple) *: rest => NoMatch[rest, K] | |
case EmptyTuple => true | |
type GetMatch[Tup <: Tuple, K] = Tup match | |
case EmptyTuple => Nothing | |
case (K *: t *: EmptyTuple) *: ? => t | |
case (? *: ? *: EmptyTuple) *: rest => GetMatch[rest, K] | |
type DropMatch[Tup, K] <: Tuple = Tup match | |
case EmptyTuple => EmptyTuple | |
case (K *: ? *: EmptyTuple) *: rest => rest | |
case (k *: t *: EmptyTuple) *: rest => | |
(k *: t *: EmptyTuple) *: DropMatch[rest, K] | |
class PseudoCaseClass[T <: Tuple](hmap: HMap.M[T]) extends Dynamic { | |
def selectDynamic[K <: Singleton](k: K)(using | |
@implicitNotFound("Could not prove that Singleton Type ${K} exists within HMap ${T}") | |
ev: HMap.NoMatch[T, K] =:= false | |
): HMap.GetMatch[T, K] = hmap.get(k)(using ev) | |
def updateDynamic[K <: Singleton, V](k: K)(v: V)(using | |
handler: HMap.UpdateHandler[T, K, V] | |
): PseudoCaseClass[handler.Out] = new PseudoCaseClass(handler(hmap, k, v)) | |
} | |
object ContextTest extends App { | |
import HMap.* | |
val hmap = HMap.empty | |
.add("name", "John") | |
.add("age", 30) | |
.add("isStudent", false) | |
val pseudoCaseClass = new PseudoCaseClass(hmap) | |
println(pseudoCaseClass.name) // John | |
println(pseudoCaseClass.age) // 30 | |
println(pseudoCaseClass.isStudent) // false | |
val updated = pseudoCaseClass.age = 31 | |
println(updated.age) // 31 | |
val updated2 = pseudoCaseClass.lastname = "Smith" | |
println(updated2.lastname) // Smith | |
val l: Any = updated2.lastname | |
case class AClass(value: String) | |
val updated3 = pseudoCaseClass.aClass = AClass(value = "123") | |
println(updated3.aClass) | |
val a: AClass = updated3.aClass | |
print(a.value) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment