<commit_before>package com.avast.cactus

import org.scalactic.Accumulation._
import org.scalactic._

import scala.collection.generic.CanBuildFrom
import scala.collection.{TraversableLike, mutable}
import scala.language.experimental.macros
import scala.language.{higherKinds, implicitConversions}
import scala.reflect.ClassTag
import scala.reflect.macros._

//noinspection TypeAnnotation
object CactusMacros {

  private[cactus] type AnnotationsMap = Map[String, Map[String, String]]

  private[cactus] val Debug = false

  private val OptPattern = "Option\\[(.*)\\]".r

  private[cactus] object ClassesNames {

    object Protobuf {
      val ProtocolStringList = "com.google.protobuf.ProtocolStringList"
      val ListValue = "com.google.protobuf.ListValue"
      val ByteString = "com.google.protobuf.ByteString"
      val MessageLite = "com.google.protobuf.MessageLite"
      val GeneratedMessageV3 = "com.google.protobuf.GeneratedMessageV3"
    }

    object Scala {
      val AnyVal = "scala.AnyVal"
      val TraversableLike = "scala.collection.TraversableLike"
    }

    object Java {
      val String = "java.lang.String"
      val Map = "java.util.Map"
      val Iterable = "java.lang.Iterable"
    }

  }

  private val JavaPrimitiveTypes = Set(
    classOf[java.lang.Boolean].getName,
    classOf[java.lang.Byte].getName,
    classOf[java.lang.Character].getName,
    classOf[java.lang.Short].getName,
    classOf[java.lang.Integer].getName,
    classOf[java.lang.Long].getName,
    classOf[java.lang.Double].getName,
    classOf[java.lang.Float].getName,
    classOf[java.lang.String].getName // consider String as primitive
  )

  def CollAToCollB[A, B, T[X] <: TraversableLike[X, T[X]]](fieldPath: String, coll: T[A])(implicit cbf: CanBuildFrom[T[A], B, T[B]], aToBConverter: Converter[A, B]): T[B] Or EveryCactusFailure = {
    coll.map((e: A) => aToBConverter.apply(fieldPath)(e).toOr).combined.map { (c: TraversableOnce[B]) =>
      cbf.apply().++=(c).result()
    }
  }

  def AToB[A, B](fieldPath: String)(a: A)(implicit aToBConverter: Converter[A, B]): B Or EveryCactusFailure = {
    aToBConverter.apply(fieldPath)(a).toOr
  }

  def asCaseClassMethod[CaseClass: c.WeakTypeTag](c: whitebox.Context)(conv: c.Tree, gpbCt: c.Tree): c.Expr[ResultOrErrors[CaseClass]] = {
    import c.universe._

    // unpack the implicit ClassTag tree
    val caseClassType = weakTypeOf[CaseClass]
    val gpbType = extractSymbolFromClassTag(c)(gpbCt)

    val variable = getVariable(c)
    val variableName = variable.symbol.asTerm.fullName.split('.').last

    c.Expr[ResultOrErrors[CaseClass]] {
      q" implicitly[com.avast.cactus.Converter[$gpbType, $caseClassType]].apply($variableName)($variable) "
    }
  }

  def asGpbMethod[Gpb: c.WeakTypeTag](c: whitebox.Context)(conv: c.Tree, caseClassCt: c.Tree): c.Expr[ResultOrErrors[Gpb]] = {
    import c.universe._

    // unpack the implicit ClassTag tree
    val caseClassType = extractSymbolFromClassTag(c)(caseClassCt)
    val gpbType = weakTypeOf[Gpb]

    val variable = getVariable(c)
    val variableName = variable.symbol.asTerm.fullName.split('.').last

    c.Expr[ResultOrErrors[Gpb]] {
      q" implicitly[com.avast.cactus.Converter[$caseClassType, $gpbType]].apply($variableName)($variable) "
    }
  }

  def deriveConverter[From: c.WeakTypeTag, To: c.WeakTypeTag](c: whitebox.Context): c.Expr[Converter[From, To]] = {
    import c.universe._

    val fromType = weakTypeOf[From]
    val toType = weakTypeOf[To]

    def isCaseClass(t: Symbol): Boolean = {
      t.isClass && t.asClass.isCaseClass
    }

    if (isCaseClass(fromType.typeSymbol) && isProtoBuf(c)(toType)) {
      deriveCaseClassToGpbConverter[From, To](c)
    } else {
      if (isCaseClass(toType.typeSymbol) && isProtoBuf(c)(fromType)) {
        deriveGpbToCaseClassConverter[From, To](c)
      } else {
        c.abort(c.enclosingPosition, s"Could not generate converter from $fromType to $toType")
      }
    }
  }

  private def deriveGpbToCaseClassConverter[GpbClass: c.WeakTypeTag, CaseClass: c.WeakTypeTag](c: whitebox.Context): c.Expr[Converter[GpbClass, CaseClass]] = {<commit_msg>Minor logging improvement<commit_after>package com.avast.cactus

import org.scalactic.Accumulation._
import org.scalactic._

import scala.collection.generic.CanBuildFrom
import scala.collection.{TraversableLike, mutable}
import scala.language.experimental.macros
import scala.language.{higherKinds, implicitConversions}
import scala.reflect.ClassTag
import scala.reflect.macros._

//noinspection TypeAnnotation
object CactusMacros {

  private[cactus] type AnnotationsMap = Map[String, Map[String, String]]

  private[cactus] val Debug = false

  private val OptPattern = "Option\\[(.*)\\]".r

  private[cactus] object ClassesNames {

    object Protobuf {
      val ProtocolStringList = "com.google.protobuf.ProtocolStringList"
      val ListValue = "com.google.protobuf.ListValue"
      val ByteString = "com.google.protobuf.ByteString"
      val MessageLite = "com.google.protobuf.MessageLite"
      val GeneratedMessageV3 = "com.google.protobuf.GeneratedMessageV3"
    }

    object Scala {
      val AnyVal = "scala.AnyVal"
      val TraversableLike = "scala.collection.TraversableLike"
    }

    object Java {
      val String = "java.lang.String"
      val Map = "java.util.Map"
      val Iterable = "java.lang.Iterable"
    }

  }

  private val JavaPrimitiveTypes = Set(
    classOf[java.lang.Boolean].getName,
    classOf[java.lang.Byte].getName,
    classOf[java.lang.Character].getName,
    classOf[java.lang.Short].getName,
    classOf[java.lang.Integer].getName,
    classOf[java.lang.Long].getName,
    classOf[java.lang.Double].getName,
    classOf[java.lang.Float].getName,
    classOf[java.lang.String].getName // consider String as primitive
  )

  def CollAToCollB[A, B, T[X] <: TraversableLike[X, T[X]]](fieldPath: String, coll: T[A])(implicit cbf: CanBuildFrom[T[A], B, T[B]], aToBConverter: Converter[A, B]): T[B] Or EveryCactusFailure = {
    coll.map((e: A) => aToBConverter.apply(fieldPath)(e).toOr).combined.map { (c: TraversableOnce[B]) =>
      cbf.apply().++=(c).result()
    }
  }

  def AToB[A, B](fieldPath: String)(a: A)(implicit aToBConverter: Converter[A, B]): B Or EveryCactusFailure = {
    aToBConverter.apply(fieldPath)(a).toOr
  }

  def asCaseClassMethod[CaseClass: c.WeakTypeTag](c: whitebox.Context)(conv: c.Tree, gpbCt: c.Tree): c.Expr[ResultOrErrors[CaseClass]] = {
    import c.universe._

    // unpack the implicit ClassTag tree
    val caseClassType = weakTypeOf[CaseClass]
    val gpbType = extractSymbolFromClassTag(c)(gpbCt)

    val variable = getVariable(c)
    val variableName = variable.symbol.asTerm.fullName.split('.').last

    c.Expr[ResultOrErrors[CaseClass]] {
      q" implicitly[com.avast.cactus.Converter[$gpbType, $caseClassType]].apply($variableName)($variable) "
    }
  }

  def asGpbMethod[Gpb: c.WeakTypeTag](c: whitebox.Context)(conv: c.Tree, caseClassCt: c.Tree): c.Expr[ResultOrErrors[Gpb]] = {
    import c.universe._

    // unpack the implicit ClassTag tree
    val caseClassType = extractSymbolFromClassTag(c)(caseClassCt)
    val gpbType = weakTypeOf[Gpb]

    val variable = getVariable(c)
    val variableName = variable.symbol.asTerm.fullName.split('.').last

    c.Expr[ResultOrErrors[Gpb]] {
      q" implicitly[com.avast.cactus.Converter[$caseClassType, $gpbType]].apply($variableName)($variable) "
    }
  }

  def deriveConverter[From: c.WeakTypeTag, To: c.WeakTypeTag](c: whitebox.Context): c.Expr[Converter[From, To]] = {
    import c.universe._

    val fromType = weakTypeOf[From]
    val toType = weakTypeOf[To]

    def isCaseClass(t: Symbol): Boolean = {
      t.isClass && t.asClass.isCaseClass
    }

    val res = if (isCaseClass(fromType.typeSymbol) && isProtoBuf(c)(toType)) {
      deriveCaseClassToGpbConverter[From, To](c)
    } else {
      if (isCaseClass(toType.typeSymbol) && isProtoBuf(c)(fromType)) {
        deriveGpbToCaseClassConverter[From, To](c)
      } else {
        c.abort(c.enclosingPosition, s"Could not generate converter from $fromType to $toType")
      }
    }

    if (Debug) {
      println(s"Returning:\n$res")
    }

    res
  }

  private def deriveGpbToCaseClassConverter[GpbClass: c.WeakTypeTag, CaseClass: c.WeakTypeTag](c: whitebox.Context): c.Expr[Converter[GpbClass, CaseClass]] = {
{'fraction_non_alphanumeric': 0.1326946107784431, 'fraction_numerical': 0.00047904191616766467, 'mean_word_length': 3.9443457667258732, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '11537', 'n_tokens_mistral': 2894, 'n_tokens_neox': 2802, 'n_words': 498}