Skip to content

Commit

Permalink
Update scalapb-json4s, scala-collection-compat and sbt-scalafmt (#144)
Browse files Browse the repository at this point in the history
Also reformat everything.
  • Loading branch information
Georgi Krastev authored Sep 16, 2021
1 parent d884759 commit bbe0616
Show file tree
Hide file tree
Showing 25 changed files with 247 additions and 320 deletions.
3 changes: 1 addition & 2 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@

align = more
align.preset = more
maxColumn = 140
4 changes: 2 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ lazy val `teleproto` = project
library.scalaTest % Test,
library.scalaTestPlusCheck % Test,
library.scalaCheck % Test,
"org.scala-lang.modules" %% "scala-collection-compat" % "2.4.4",
"org.scala-lang.modules" %% "scala-collection-compat" % "2.5.0",
"org.scala-lang" % "scala-reflect" % (ThisBuild / scalaVersion).value
)
)
Expand All @@ -35,7 +35,7 @@ lazy val `teleproto` = project
lazy val library = new {
object Version {
val scalaPB = scalapb.compiler.Version.scalapbVersion
val scalaPBJson = "0.11.1"
val scalaPBJson = "0.12.0"
val scalaCheck = "1.15.4"
val scalaTest = "3.2.9"
val scalaTestPlusCheck = "3.2.2.0"
Expand Down
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Formatting in scala
// See .scalafmt.conf for configuration details.
// Formatting takes place before the project is compiled.
addSbtPlugin("com.lucidchart" % "sbt-scalafmt" % "1.16")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.3")

// Use git in sbt, show git prompt and use versions from git.
// sbt> git <your git command>
Expand Down
9 changes: 3 additions & 6 deletions src/main/scala/io/moia/protos/teleproto/Format.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ package io.moia.protos.teleproto

import scala.annotation.implicitNotFound

/**
* Allows bijection from model to proto.
/** Allows bijection from model to proto.
*
* @tparam M the model type
* @tparam P the proto type
Expand All @@ -29,17 +28,15 @@ trait Format[M, P] extends Reader[P, M] with Writer[M, P]

object Format {

/**
* Create a format by passing in functions for reading and writing.
/** Create a format by passing in functions for reading and writing.
*/
def apply[M, P](reader: P => PbResult[M], writer: M => P): Format[M, P] =
new Format[M, P] {
override def write(model: M): P = writer(model)
override def read(protobuf: P): PbResult[M] = reader(protobuf)
}

/**
* A format can be combined by using an existing reader and writer.
/** A format can be combined by using an existing reader and writer.
* If both are available in implicit scope, the format can be created implicitly.
*/
implicit def fromReaderWriter[M, P](implicit reader: Reader[P, M], writer: Writer[M, P]): Format[M, P] =
Expand Down
26 changes: 9 additions & 17 deletions src/main/scala/io/moia/protos/teleproto/FormatImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ import scalapb.{GeneratedEnum, GeneratedOneof}

import scala.reflect.macros.blackbox

/**
* Compiler functions shared between both, reader and writer macros
/** Compiler functions shared between both, reader and writer macros
*/
@SuppressWarnings(Array("all"))
trait FormatImpl {
Expand Down Expand Up @@ -58,8 +57,7 @@ trait FormatImpl {
type Compiled = (Tree, Compatibility)
type CompatIssue = (Type, String)

/**
* Within a compiled hierarchy collects backward/forward compatibility issues.
/** Within a compiled hierarchy collects backward/forward compatibility issues.
*/
case class Compatibility(
surplusParameters: Iterable[CompatIssue],
Expand Down Expand Up @@ -89,14 +87,12 @@ trait FormatImpl {
val full: Compatibility = Compatibility(Nil, Nil, Nil)
}

/**
* From type `S[T]` extracts `T`.
/** From type `S[T]` extracts `T`.
*/
private[teleproto] def innerType(from: Type): Type =
from.typeArgs.headOption.getOrElse(abort(s"Type $from does not have type arguments"))

/**
* Fails if types are not a Protobuf case class and case class pair.
/** Fails if types are not a Protobuf case class and case class pair.
*/
private[teleproto] def ensureValidTypes(protobufType: Type, modelType: Type): Unit =
if (!checkClassTypes(protobufType, modelType)) {
Expand All @@ -113,8 +109,7 @@ trait FormatImpl {
private[teleproto] def checkHierarchyTypes(protobufType: Type, modelType: Type): Boolean =
isSealedTrait(modelType) && isSealedTrait(protobufType) && protobufType <:< typeOf[GeneratedOneof]

/**
* A ScalaPB enumeration can be mapped to a detached sealed trait with corresponding case objects and vice versa.
/** A ScalaPB enumeration can be mapped to a detached sealed trait with corresponding case objects and vice versa.
*/
private[teleproto] def checkEnumerationTypes(protobufType: Type, modelType: Type): Boolean =
isScalaPBEnumeration(protobufType) && isSealedTrait(modelType)
Expand All @@ -135,8 +130,7 @@ trait FormatImpl {
private[teleproto] def hasTraceAnnotation: Boolean =
c.internal.enclosingOwner.annotations.exists(_.tree.tpe.typeSymbol == symbolOf[trace])

/**
* If the enclosing owner (the `def` or `val` that invokes the macro) got the annotation `@trace` then send the given
/** If the enclosing owner (the `def` or `val` that invokes the macro) got the annotation `@trace` then send the given
* (compiled) tree as info message to the compiler shell.
*/
private[teleproto] def traceCompiled(tree: Tree): Tree = {
Expand Down Expand Up @@ -203,8 +197,7 @@ trait FormatImpl {
info
}

/**
* Always renders the same hash for a similar incompatibility.
/** Always renders the same hash for a similar incompatibility.
*/
private[teleproto] def compatibilitySignature(compatibility: Compatibility): String =
if (compatibility.hasIssues) {
Expand All @@ -217,16 +210,15 @@ trait FormatImpl {
MessageDigest
.getInstance("MD5")
.digest(baos.toByteArray)
.map(0xFF & _)
.map(0xff & _)
.map { "%02x".format(_) }
.take(3) // <- 6 characters
.mkString
} else {
""
}

/**
* Extracts literal signature value of @backward("signature") or @forward("signature").
/** Extracts literal signature value of @backward("signature") or @forward("signature").
*/
private[teleproto] def compatibilityAnnotation(tpe: Type): Option[String] =
c.internal.enclosingOwner.annotations.find(_.tree.tpe.typeSymbol == tpe.typeSymbol).flatMap { annotation =>
Expand Down
9 changes: 3 additions & 6 deletions src/main/scala/io/moia/protos/teleproto/Migration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,23 @@

package io.moia.protos.teleproto

/**
* Models a migration between a Protocol Buffers model in different versions `P` and `Q` that may never fail.
/** Models a migration between a Protocol Buffers model in different versions `P` and `Q` that may never fail.
* It's not specified by the definition if `P` is newer/older that `Q`. Both are possible.
* Just by application of `read` (`P` < `Q`) and `write` (`Q` < `P`) the direction is defined.
*
* Migrations can be (partly) generated by `ProtocolBuffers.migration[P, Q](...)`.
*/
final case class Migration[P, Q](migrate: P => Q) {

/**
* Create a reader directly from older version `P` to `M` if reader for the newer version `Q` exists:
/** Create a reader directly from older version `P` to `M` if reader for the newer version `Q` exists:
*
* - Use the migration from `P` to `Q`
* - Apply the result `Q` to the existing reader to `M`
*/
def reader[M](implicit newReader: Reader[Q, M]): Reader[P, M] =
(oldProtobuf: P) => newReader.read(migrate(oldProtobuf))

/**
* Create a writer directly from `M` to older version `Q` if writer for the newer version `P` exists:
/** Create a writer directly from `M` to older version `Q` if writer for the newer version `P` exists:
*
* - Write the `M` to a newer `P`
* - Use the migration from `P` to `Q`
Expand Down
38 changes: 18 additions & 20 deletions src/main/scala/io/moia/protos/teleproto/MigrationImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ class MigrationImpl(val c: blackbox.Context) extends FormatImpl {
s"Cannot create a migration from `$sourceType` to `$targetType`. Just migrations between a) case classes b) sealed traits from enums are possible."
)

/**
* Checks if source and target type are compatible in a way that the macro can assume a migration would make sense:
/** Checks if source and target type are compatible in a way that the macro can assume a migration would make sense:
* a) both are case classes (protobuf messages)
* b) both are sealed traits from ScalaPB enums
*/
Expand All @@ -50,8 +49,7 @@ class MigrationImpl(val c: blackbox.Context) extends FormatImpl {
classMigration || enumMigration
}

/**
* Checks if a migration from source to target type can be compiled without additional code.
/** Checks if a migration from source to target type can be compiled without additional code.
*/
private def isTrivial(sourceType: Type, targetType: Type): Boolean =
if (isProtobuf(sourceType) && isProtobuf(targetType))
Expand All @@ -63,8 +61,7 @@ class MigrationImpl(val c: blackbox.Context) extends FormatImpl {
else
false

/**
* Returns an expression that is a migration from source to target type.
/** Returns an expression that is a migration from source to target type.
* Should be used for type pairs that fulfill the `isExpected` predicate.
*
* Check for an implicit migration from source to target type in the scope.
Expand Down Expand Up @@ -99,8 +96,8 @@ class MigrationImpl(val c: blackbox.Context) extends FormatImpl {
s"${requiredMigrations.size} migration functions are required:"

val signatureInfo =
(signatureLengthInfo :: requiredMigrations.map(
required => s"- ${required.name}: `$sourceType => ${required.typeSignature}` (${required.explanation})"
(signatureLengthInfo :: requiredMigrations.map(required =>
s"- ${required.name}: `$sourceType => ${required.typeSignature}` (${required.explanation})"
)).mkString("\n")

// Validate the signature of the function application
Expand Down Expand Up @@ -173,8 +170,7 @@ class MigrationImpl(val c: blackbox.Context) extends FormatImpl {
// models a field in Q that requires a migration function
case class Required(name: String, typeSignature: Type, argIndex: Int, explanation: String) extends ParamMigration

/**
* Compares given source and target Protocol Buffers class types.
/** Compares given source and target Protocol Buffers class types.
* Returns the migration strategies for each param.
*
* If all returned parameter migrations are `Automatically` the whole migration is trivial.
Expand All @@ -186,8 +182,8 @@ class MigrationImpl(val c: blackbox.Context) extends FormatImpl {

// from the fields in P (source) create a map by name to the term symbol to select it in `pb.$field` where `pb` is the source
val sourceParamsMap: Map[String, TermSymbol] =
symbolsByName(sourceCons.paramLists.headOption.getOrElse(Nil)).map {
case (name, symbol) => name.toString -> symbol.asTerm
symbolsByName(sourceCons.paramLists.headOption.getOrElse(Nil)).map { case (name, symbol) =>
name.toString -> symbol.asTerm
}

// select the fields in Q as terms
Expand Down Expand Up @@ -224,8 +220,10 @@ class MigrationImpl(val c: blackbox.Context) extends FormatImpl {
case Some(from) if isExpected(from, to) =>
val migrationExpr = implicitMigration(from, to)

Automatically(q"$migrationExpr.migrate(pb.${targetParam.name})",
s"`$targetParam` can be copied with an implicit `Migration[$from, $to]`.") ::
Automatically(
q"$migrationExpr.migrate(pb.${targetParam.name})",
s"`$targetParam` can be copied with an implicit `Migration[$from, $to]`."
) ::
compareParams(rest, idx)

// field exists and both are option/collection values for matching collection types and migrations between both inner types are generally possible
Expand All @@ -245,8 +243,10 @@ class MigrationImpl(val c: blackbox.Context) extends FormatImpl {
// look for an implicit conversion
val conversion = c.inferImplicitView(q"pb.${targetParam.name}", from, to)
if (conversion.nonEmpty)
Automatically(q"$conversion(pb.${targetParam.name})",
s"`$targetParam` can be copied with conversion from `$from` to `$to`.") ::
Automatically(
q"$conversion(pb.${targetParam.name})",
s"`$targetParam` can be copied with conversion from `$from` to `$to`."
) ::
compareParams(rest, idx)
else
Required(name, to, idx, s"For`$targetParam` the type `$from` must be converted to `$to`.") ::
Expand Down Expand Up @@ -308,8 +308,7 @@ class MigrationImpl(val c: blackbox.Context) extends FormatImpl {
)
}

/**
* Checks if both types are collections/options, target collection can be assigned from source collection and if
/** Checks if both types are collections/options, target collection can be assigned from source collection and if
* the inner types are expected to be migrated.
*
* If so a migration for the inner types could be expected and source value can be mapped using that migration.
Expand All @@ -324,8 +323,7 @@ class MigrationImpl(val c: blackbox.Context) extends FormatImpl {
(bothOptions || (bothCollections && matchingCollections)) && matchingInnerTypes
}

/**
* Returns the options in the source (enum sealed trait) type that are not matched in the target type.
/** Returns the options in the source (enum sealed trait) type that are not matched in the target type.
*/
private def compareEnumerationOptions(sourceType: Type, targetType: Type): Set[Name] = {
def optionNames(tpe: Type) = tpe.typeSymbol.asClass.knownDirectSubclasses.filter(_.isModuleClass).map(_.name.decodedName)
Expand Down
12 changes: 4 additions & 8 deletions src/main/scala/io/moia/protos/teleproto/PbResult.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ package io.moia.protos.teleproto

import scala.util.{Failure, Success, Try}

/**
* Models the attempt to read a Protocol Buffers case class into business model type `T`.
/** Models the attempt to read a Protocol Buffers case class into business model type `T`.
*/
sealed trait PbResult[+T] {

Expand Down Expand Up @@ -61,8 +60,7 @@ object PbResult {
tryA.fold(PbFailure.fromThrowable, PbSuccess.apply)
}

/**
* Models the success to read a Protocol Buffers case class into business model type `T`.
/** Models the success to read a Protocol Buffers case class into business model type `T`.
*/
final case class PbSuccess[T](value: T) extends PbResult[T] {

Expand All @@ -86,8 +84,7 @@ final case class PbSuccess[T](value: T) extends PbResult[T] {
def toOption: Option[T] = Some(get)
}

/**
* Models the failure to read a Protocol Buffers case class into business model type `T`.
/** Models the failure to read a Protocol Buffers case class into business model type `T`.
* Provides error messages for one or more paths, e.g.
* The path messages could be
* /price Value must be a decimal number. <- Simple field at top-level
Expand Down Expand Up @@ -133,8 +130,7 @@ object PbFailure {
def fromThrowable(error: Throwable): PbFailure =
apply(error.getMessage)

/**
* Collects and combines all the errors of all failures in the given results.
/** Collects and combines all the errors of all failures in the given results.
* Please note: This method ignores all successes and collects just error messages from failures. It's intended
* to create an overall failure when one of the results is a failure. It doesn't make sense if all are successes.
*/
Expand Down
9 changes: 3 additions & 6 deletions src/main/scala/io/moia/protos/teleproto/ProtocolBuffers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ object ProtocolBuffers {
}
}

/**
* Compiles a generic reader instance from Protocol Buffers type `P` to business model type `M` if possible.
/** Compiles a generic reader instance from Protocol Buffers type `P` to business model type `M` if possible.
* See User's Guide for details.
*
* Example:
Expand All @@ -51,14 +50,12 @@ object ProtocolBuffers {
*/
def reader[P, M]: Reader[P, M] = macro ReaderImpl.reader_impl[P, M]

/**
* Compiles a generic writer instance from business model type `M` to Protocol Buffers type `P` if possible.
/** Compiles a generic writer instance from business model type `M` to Protocol Buffers type `P` if possible.
* See User's Guide for details.
*/
def writer[M, P]: Writer[M, P] = macro WriterImpl.writer_impl[M, P]

/**
* Constructs a migration from Protocol Buffer class `P` to PB class `Q`.
/** Constructs a migration from Protocol Buffer class `P` to PB class `Q`.
* The migration tries to copy/convert fields from a `P` to a new `Q` automatically.
*
* That is possible for matching names if value types `VP` and `VQ`
Expand Down
Loading

0 comments on commit bbe0616

Please sign in to comment.