All Downloads are FREE. Search and download functionalities are using the official Maven repository.

argonaut.internal.Macros.scala Maven / Gradle / Ivy

The newest version!
package argonaut.internal

import argonaut._

object Macros extends MacrosCompat {
  def materializeCodecImpl[T: c.WeakTypeTag](c: Context): c.Expr[CodecJson[T]] = {
    import c.universe._
    val tpe = weakTypeOf[T]
    val encode = materializeEncodeImpl[T](c)
    val decode = materializeDecodeImpl[T](c)
    c.Expr[CodecJson[T]](q"""
    _root_.argonaut.CodecJson.derived[$tpe]($encode, $decode)
    """)
  }

  def materializeEncodeImpl[T: c.WeakTypeTag](c: Context): c.Expr[EncodeJson[T]] = {
    import c.universe._
    val tpe = weakTypeOf[T]

    val primaryConstructor = getDeclarations(c)(tpe).collectFirst{
      case m: MethodSymbol if m.isPrimaryConstructor => m
    }
    primaryConstructor match {
      case Some(constructor) => {
        val fieldNames: List[c.universe.Name] = getParameterLists(c)(constructor).flatten.map{field => 
          field.name
        }
        val decodedNames: List[String] = fieldNames.map(_.decodedName.toString)
        val fieldTypes: List[c.universe.Type] = getParameterLists(c)(constructor).flatten.map{field =>
          getDeclaration(c)(tpe, field.name).typeSignature
        }
        val fieldCount = fieldNames.size
        val invocations = fieldNames.map{fieldName => 
          val termName = createTermName(c)(fieldName.toString)
          q"toEncode.$termName"
        }
        val methodName = createTermName(c)("jencode" + (fieldCount.toString) + "L")
        val expr = c.Expr[EncodeJson[T]]{q"""
          _root_.argonaut.EncodeJson.$methodName[$tpe, ..$fieldTypes](toEncode => (..$invocations))(..$decodedNames)
        """}
        //println(expr)
        expr
      }
      case None => c.abort(c.enclosingPosition, "Could not identify primary constructor for " + tpe)
    }
  }

  def materializeDecodeImpl[T: c.WeakTypeTag](c: Context): c.Expr[DecodeJson[T]] = {
    import c.universe._
    val tpe = weakTypeOf[T]

    val primaryConstructor = getDeclarations(c)(tpe).collectFirst{
      case m: MethodSymbol if m.isPrimaryConstructor => m
    }
    primaryConstructor match {
      case Some(constructor) => {
        val fieldNames: List[c.universe.Name] = getParameterLists(c)(constructor).flatten.map{field => 
          field.name
        }
        val decodedNames: List[String] = fieldNames.map(_.decodedName.toString)
        val fieldTypes: List[c.universe.Type] = getParameterLists(c)(constructor).flatten.map{field =>
          getDeclaration(c)(tpe, field.name).typeSignature
        }
        val fieldCount = fieldNames.size
        val functionParameters = fieldNames.zip(fieldTypes).map{case (fieldName, fieldType) =>
          val termName = createTermName(c)(fieldName.toString)
          q"$termName: $fieldType"
        }
        val parameters = fieldNames.map{fieldName =>
          val termName = createTermName(c)(fieldName.toString)
          q"$termName"
        }
        val methodName = createTermName(c)("jdecode" + (fieldCount.toString) + "L")
        val expr = c.Expr[DecodeJson[T]]{q"""
          _root_.argonaut.DecodeJson.$methodName[..$fieldTypes, $tpe]((..$functionParameters) => new $tpe(..$parameters))(..$decodedNames)
        """}
        //println(expr)
        expr
      }
      case None => c.abort(c.enclosingPosition, "Could not identify primary constructor for " + tpe)
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy