From fd6a18d01218c52558508aca3424d4eb78be911c Mon Sep 17 00:00:00 2001 From: Jon Pretty Date: Fri, 10 Nov 2017 17:13:18 +0000 Subject: Include support for decomposing AnyVals, like case classes --- core/src/main/scala/magnolia.scala | 44 +++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 17 deletions(-) (limited to 'core/src/main/scala/magnolia.scala') diff --git a/core/src/main/scala/magnolia.scala b/core/src/main/scala/magnolia.scala index 8c3d823..c29c1fa 100644 --- a/core/src/main/scala/magnolia.scala +++ b/core/src/main/scala/magnolia.scala @@ -177,7 +177,11 @@ object Magnolia { val isCaseClass = classType.map(_.isCaseClass).getOrElse(false) val isCaseObject = classType.map(_.isModuleClass).getOrElse(false) val isSealedTrait = classType.map(_.isSealed).getOrElse(false) - val isValueClass = genericType <:< typeOf[AnyVal] + + val primitives = Set(typeOf[Double], typeOf[Float], typeOf[Short], typeOf[Byte], + typeOf[Int], typeOf[Long], typeOf[Char], typeOf[Boolean]) + + val isValueClass = genericType <:< typeOf[AnyVal] && !primitives.exists(_ =:= genericType) val resultType = appliedType(typeConstructor, genericType) @@ -188,13 +192,14 @@ object Magnolia { val className = obj.name.decodedName.toString val impl = q""" ${c.prefix}.combine($magnoliaObj.caseClass[$typeConstructor, $genericType]( - $className, true, new $arrayCls(0), _ => $obj) + $className, true, false, new $arrayCls(0), _ => $obj) ) """ Some(Typeclass(genericType, impl)) - } else if (isCaseClass) { + } else if (isCaseClass || isValueClass) { val caseClassParameters = genericType.decls.collect { - case m: MethodSymbol if m.isCaseAccessor => m.asMethod + case m: MethodSymbol if m.isCaseAccessor || (isValueClass && m.isParamAccessor) => + m.asMethod } val className = genericType.typeSymbol.name.decodedName.toString @@ -203,6 +208,7 @@ object Magnolia { paramType: c.Type, ref: c.TermName) + val caseParamsReversed: List[CaseParam] = caseClassParameters.foldLeft(List[CaseParam]()) { case (acc, param) => val paramName = param.name.decodedName.toString @@ -214,7 +220,7 @@ object Magnolia { val caseParamOpt = predefinedRef.map { backRef => CaseParam(param, q"()", paramType, backRef.ref) :: acc } - + caseParamOpt.getOrElse { val derivedImplicit = recurse(ProductType(paramName, genericType.toString), genericType, assignedName) { @@ -236,17 +242,19 @@ object Magnolia { val preAssignments = caseParams.map(_.typeclass) - val caseClassCompanion = genericType.companion - val constructorMethod = caseClassCompanion.decl(TermName("apply")).asMethod - val indexedConstructorParams = constructorMethod.paramLists.head.map(_.asTerm).zipWithIndex - - val defaults = indexedConstructorParams.map { - case (p, idx) => - if (p.isParamWithDefault) { - val method = TermName("apply$default$" + (idx + 1)) - q"_root_.scala.Some(${genericType.typeSymbol.companionSymbol.asTerm}.$method)" - } else q"_root_.scala.None" - } + val defaults = if(!isValueClass) { + val caseClassCompanion = genericType.companion + val constructorMethod = caseClassCompanion.decl(TermName("apply")).asMethod + val indexedConstructorParams = constructorMethod.paramLists.head.map(_.asTerm).zipWithIndex + + indexedConstructorParams.map { + case (p, idx) => + if (p.isParamWithDefault) { + val method = TermName("apply$default$" + (idx + 1)) + q"_root_.scala.Some(${genericType.typeSymbol.companionSymbol.asTerm}.$method)" + } else q"_root_.scala.None" + } + } else List(q"_root_.scala.None") val assignments = caseParams.zip(defaults).zipWithIndex.map { case ((CaseParam(param, typeclass, paramType, ref), defaultVal), idx) => @@ -268,6 +276,7 @@ object Magnolia { ${c.prefix}.combine($magnoliaObj.caseClass[$typeConstructor, $genericType]( $className, false, + $isValueClass, $paramsVal, ($fnVal: Param[$typeConstructor, $genericType] => Any) => new $genericType(..${caseParams.zipWithIndex.map { @@ -421,9 +430,10 @@ object Magnolia { * should not be called directly from users' code. */ def caseClass[Tc[_], T](name: String, obj: Boolean, + valClass: Boolean, params: Array[Param[Tc, T]], constructor: (Param[Tc, T] => Any) => T) = - new CaseClass[Tc, T](name, obj, params) { + new CaseClass[Tc, T](name, obj, valClass, params) { def construct[R](param: Param[Tc, T] => R): T = constructor(param) } } -- cgit v1.2.3