Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

replacing codec macros with inlines #160

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
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
88 changes: 12 additions & 76 deletions core/src/main/scala/besom/internal/CodecMacros.scala
Original file line number Diff line number Diff line change
@@ -1,79 +1,15 @@
package besom.internal

import scala.quoted.*

import scala.compiletime.*
object CodecMacros:
inline def summonLabels[A] = ${ summonLabelsImpl[A] }

private def summonLabelsImpl[A: Type](using Quotes): Expr[List[String]] =
import quotes.reflect.*
Expr(recSummonLabelsImpl(Type.of[A]))

private def recSummonLabelsImpl(t: Type[?])(using Quotes): List[String] =
import quotes.reflect.*
t match
case '[EmptyTuple] => Nil
case '[head *: tail] =>
val headValue = Type.valueOfConstant[head].getOrElse(report.errorAndAbort("This was not a literal!")).toString()
headValue :: recSummonLabelsImpl(Type.of[tail])
case _ => report.errorAndAbort("This can be ONLY called on tuples of string singleton types!")

// TODO all of these could summon a generic TC[head] typeclass but it's harder so... later?
inline def summonDecoders[A]: List[Decoder[?]] = ${ summonDecodersImpl[A] }

private def summonDecodersImpl[A: Type](using Quotes): Expr[List[Decoder[?]]] =
import quotes.reflect.*
// report.info(s"Deriving for ${Type.show[A]}")
Expr.ofList(recSummonDecodersImpl(Type.of[A]))

private def recSummonDecodersImpl(t: Type[?])(using Quotes): List[Expr[Decoder[?]]] =
import quotes.reflect.*
t match
case '[EmptyTuple] => Nil
case '[head *: tail] =>
val exprOfDecoder = Expr.summon[Decoder[head]].getOrElse {
report.errorAndAbort(s"Decoder for ${Type.show[head]} was not found!")
}
exprOfDecoder :: recSummonDecodersImpl(Type.of[tail])
case _ => report.errorAndAbort("This can be ONLY called on tuples of types!")

inline def summonEncoders[A]: List[Encoder[?]] = ${ summonEncodersImpl[A] }

private def summonEncodersImpl[A: Type](using Quotes): Expr[List[Encoder[?]]] =
import quotes.reflect.*
Expr.ofList(recSummonEncodersImpl(Type.of[A]))

private def recSummonEncodersImpl(t: Type[?])(using Quotes): List[Expr[Encoder[?]]] =
import quotes.reflect.*
t match
case '[EmptyTuple] => Nil
case '[head *: tail] =>
val exprOfEncoder = Expr.summon[Encoder[head]].getOrElse {
report.errorAndAbort(s"Encoder for ${Type.show[head]} was not found!")
}
exprOfEncoder :: recSummonEncodersImpl(Type.of[tail])
case _ => report.errorAndAbort("This can be ONLY called on tuples!")

inline def summonJsonEncoders[A]: List[JsonEncoder[?]] = ${ summonJsonEncodersImpl[A] }

private def summonJsonEncodersImpl[A: Type](using Quotes): Expr[List[JsonEncoder[?]]] =
import quotes.reflect.*
Expr.ofList(recSummonJsonEncodersImpl(Type.of[A]))

private def recSummonJsonEncodersImpl(t: Type[?])(using Quotes): List[Expr[JsonEncoder[?]]] =
import quotes.reflect.*
t match
case '[EmptyTuple] => Nil
case '[head *: tail] =>
val exprOfJsonEncoder = Expr.summon[JsonEncoder[head]].getOrElse {
report.errorAndAbort(s"JsonEncoder for ${Type.show[head]} was not found!")
}
exprOfJsonEncoder :: recSummonJsonEncodersImpl(Type.of[tail])
case _ => report.errorAndAbort("This can be ONLY called on tuples!")

// inline def summonTypeclasses[A, TC[_]]: List[TC[Any]] = ${ summonTypeclassesImpl[A, TC] }

// private def summonTypeclassesImpl[A: Type, TC[_]: Type](using Quotes): Expr[List[TC[Any]]] =
// import quotes.reflect.*

// '{ List.empty[TC[Any]] }
inline def summonLabels[A <: Tuple]: List[String] =
val constTuple = constValueTuple[A]
val ev = summonInline[Tuple.Union[constTuple.type] <:< String]
ev.substituteCo(constTuple.toList)
private inline def summonTCList[A <: Tuple, TC[_]] =
val summoned = summonAll[Tuple.Map[A,TC]]
summoned.toList

inline def summonDecoders[A <: Tuple]: List[Decoder[?]] = summonTCList[A, Decoder].asInstanceOf[List[Decoder[?]]]
inline def summonEncoders[A <: Tuple]: List[Encoder[?]] = summonTCList[A, Encoder].asInstanceOf[List[Encoder[?]]]
inline def summonJsonEncoders[A <: Tuple]: List[JsonEncoder[?]] = summonTCList[A, JsonEncoder].asInstanceOf[List[JsonEncoder[?]]]
Loading