From be35b8e8fb77b8dec4cb053d14f3a1cad7711bd6 Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Tue, 28 Sep 2021 11:29:13 -0500 Subject: [PATCH 1/3] update dependencies --- build.sbt | 14 ++++++-------- project/build.properties | 2 +- project/plugins.sbt | 4 ++-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/build.sbt b/build.sbt index 891f15600..a136f00e0 100644 --- a/build.sbt +++ b/build.sbt @@ -16,21 +16,19 @@ inThisBuild(List( startYear := Option(2021), )) -lazy val CatsEffect2V = "2.5.1" -lazy val CatsEffect3V = "3.1.1" -lazy val TwitterUtilsLatestV = "21.5.0" +lazy val CatsEffect2V = "2.5.4" +lazy val CatsEffect3V = "3.2.9" +lazy val TwitterUtilsLatestV = "21.8.0" lazy val TwitterUtils19_4V = "19.4.0" lazy val CatsTaglessV = "0.14.0" lazy val SCALA_2_13 = "2.13.6" -lazy val SCALA_2_12 = "2.12.14" -lazy val SCALA_3 = "3.0.0" +lazy val SCALA_2_12 = "2.12.15" lazy val Scala2Versions = Seq(SCALA_2_13, SCALA_2_12) -lazy val Scala2And3 = Seq(SCALA_2_13, SCALA_2_12, SCALA_3) lazy val scala2CompilerPlugins: Seq[ModuleID] = Seq( - compilerPlugin("org.typelevel" % "kind-projector" % "0.13.0" cross CrossVersion.full) + compilerPlugin("org.typelevel" % "kind-projector" % "0.13.2" cross CrossVersion.full) ) def dedupKindProjectorOptions(opts: Seq[String]): Seq[String] = @@ -246,7 +244,7 @@ lazy val examples = (projectMatrix in file("examples")) .settings( libraryDependencies ++= { Seq( - "org.typelevel" %% "cats-tagless-macros" % "0.14.0", + "org.typelevel" %% "cats-tagless-macros" % CatsTaglessV, ) ++ (if (scalaVersion.value.startsWith("2")) scala2CompilerPlugins else Nil) }, publish / skip := true, diff --git a/project/build.properties b/project/build.properties index 67d27a1df..10fd9eee0 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.5.3 +sbt.version=1.5.5 diff --git a/project/plugins.sbt b/project/plugins.sbt index ee00b9f59..efeb62a15 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,4 @@ addSbtPlugin("io.github.davidgregory084" % "sbt-tpolecat" % "0.1.20") -addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.7") +addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.9") addSbtPlugin("com.eed3si9n" % "sbt-projectmatrix" % "0.8.0") -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.5.1") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.7.0") From a9f90296259f271e6394ca05079a4f44ab88676f Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Tue, 28 Sep 2021 11:49:22 -0500 Subject: [PATCH 2/3] add Scalafix rule to add cats-tagless instances for use with asyncMapK running the Scalafix rule after generating Finagle code with Scrooge will result in implicit instances being added to the companion objects of the generated Finagle service traits. --- README.md | 53 +- build.sbt | 60 + project/plugins.sbt | 1 + scalafix/README.md | 33 + .../scala/example/thrift/SimpleRequest.scala | 445 +++++++ .../scala/example/thrift/SimpleResponse.scala | 445 +++++++ .../thrift/SimpleService$FinagleClient.scala | 141 +++ .../thrift/SimpleService$FinagleService.scala | 107 ++ .../scala/example/thrift/SimpleService.scala | 1074 ++++++++++++++++ scalafix/input/src/main/thrift/Simple.thrift | 13 + .../scala/example/thrift/SimpleRequest.scala | 443 +++++++ .../scala/example/thrift/SimpleResponse.scala | 443 +++++++ .../thrift/SimpleService$FinagleClient.scala | 138 +++ .../thrift/SimpleService$FinagleService.scala | 104 ++ .../scala/example/thrift/SimpleService.scala | 1078 +++++++++++++++++ scalafix/regenerate-inputs.sh | 63 + .../META-INF/services/scalafix.v1.Rule | 1 + .../scalafix/AddCatsTaglessInstances.scala | 77 ++ .../AddCatsTaglessInstancesTest.scala | 45 + .../dwolla/scrooge/scalafix/RuleSuite.scala | 8 + 20 files changed, 4768 insertions(+), 4 deletions(-) create mode 100644 scalafix/README.md create mode 100644 scalafix/input/src/main/scala/example/thrift/SimpleRequest.scala create mode 100644 scalafix/input/src/main/scala/example/thrift/SimpleResponse.scala create mode 100644 scalafix/input/src/main/scala/example/thrift/SimpleService$FinagleClient.scala create mode 100644 scalafix/input/src/main/scala/example/thrift/SimpleService$FinagleService.scala create mode 100644 scalafix/input/src/main/scala/example/thrift/SimpleService.scala create mode 100644 scalafix/input/src/main/thrift/Simple.thrift create mode 100644 scalafix/output/src/main/scala/example/thrift/SimpleRequest.scala create mode 100644 scalafix/output/src/main/scala/example/thrift/SimpleResponse.scala create mode 100644 scalafix/output/src/main/scala/example/thrift/SimpleService$FinagleClient.scala create mode 100644 scalafix/output/src/main/scala/example/thrift/SimpleService$FinagleService.scala create mode 100644 scalafix/output/src/main/scala/example/thrift/SimpleService.scala create mode 100755 scalafix/regenerate-inputs.sh create mode 100644 scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule create mode 100644 scalafix/rules/src/main/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstances.scala create mode 100644 scalafix/rules/src/test/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstancesTest.scala create mode 100644 scalafix/tests/src/test/scala/com/dwolla/scrooge/scalafix/RuleSuite.scala diff --git a/README.md b/README.md index 295812086..90c64ac94 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ object FooService { } ``` +These implicit instances can be automatically added to the code generated by Scrooge by running the `AddCatsTaglessInstances` scalafix rule! See below for more detail. + Now you can safely convert your `Future`-based implementation into one in `F[_] : Async`: ```scala @@ -64,10 +66,8 @@ trait FooScroogeService[F[_]] { } object FooScroogeService { - // these implicits won't be generated by scrooge—but we're working on that! - // for now you'll have to add them yourself, either here or somewhere in the - // implicit scope available to the calls shown below under "Finagle Clients" - // and "Finagle Servers" + // Let Scalafix generate these instances for you! + // Follow the instructions in the `Scalafix Rule` section below. implicit def FooScroogeServiceReaderT[F[_]]: FooScroogeService[ReaderT[F, FooScroogeService[F], *]] = Derive.readerT[FooScroogeService, F] implicit val FooScroogeServiceFunctorK: FunctorK[FooScroogeService] = Derive.functorK[FooScroogeService] @@ -100,6 +100,43 @@ val fooImpl: FooScroogeService[IO] = new FooScroogeService[IO] { val thriftServer: IO[Nothing] = ThriftServer("address", fooImpl) ``` +## Scalafix Rule + +Add Scalafix to your project's build by [following the instructions](https://scalacenter.github.io/scalafix/docs/users/installation.html#sbt): + +1. Add the Scalafix plugin to the project by adding this to `project/plugins.sbt`: + ```scala + addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.31") + ``` + +2. Enable SemanticDB by adding this to `build.sbt`: + ```scala + ThisBuild / semanticdbEnabled := true + ThisBuild / semanticdbVersion := scalafixSemanticdb.revision + ThisBuild / scalafixScalaBinaryVersion := CrossVersion.binaryScalaVersion(scalaVersion.value) + ThisBuild / scalafixDependencies += "com.dwolla" %% "finagle-tagless-scalafix" % "0.0.4" + ``` + +3. Run the Scalafix rule automatically after generating the Thrift sources by adding this to `build.sbt`: + ```scala + Compile / scalafix / unmanagedSources := (Compile / sources).value + Compile / compile := Def.taskDyn { + val compileOutput = (Compile / compile).value + + Def.task { + (Compile / scalafix).toTask(" AddCatsTaglessInstances").value + compileOutput + } + }.value + libraryDependencies ++= { + val catsTaglessV = "0.14.0" + Seq( + "org.typelevel" %% "cats-tagless-core" % catsTaglessV, + "org.typelevel" %% "cats-tagless-macros" % catsTaglessV, + ) + } + ``` + ## Artifacts The Group ID for each artifact is `"com.dwolla"`. All artifacts are published to Maven Central. @@ -153,6 +190,14 @@ The Group ID for each artifact is `"com.dwolla"`. All artifacts are published to Cats Effect 3 +"finagle-tagless-scalafix" +Automatically adds implicit instances needed by `asyncMapK` to the companion objects of Finagle services generated by Scrooge +All + + +N/A + + "async-utils-twitter-19-4-ce2" Implementation for Twitter Future
(with "com.twitter" %% "util-core" % "19.4.0") Cats Effect 2 diff --git a/build.sbt b/build.sbt index a136f00e0..a33a6eec0 100644 --- a/build.sbt +++ b/build.sbt @@ -21,6 +21,7 @@ lazy val CatsEffect3V = "3.2.9" lazy val TwitterUtilsLatestV = "21.8.0" lazy val TwitterUtils19_4V = "19.4.0" lazy val CatsTaglessV = "0.14.0" +lazy val libthriftV = "0.10.0" lazy val SCALA_2_13 = "2.13.6" lazy val SCALA_2_12 = "2.12.15" @@ -252,6 +253,63 @@ lazy val examples = (projectMatrix in file("examples")) .jvmPlatform(scalaVersions = Scala2Versions) .dependsOn(`async-utils`) +lazy val `scalafix-rules` = (projectMatrix in file("scalafix/rules")) + .jvmPlatform(scalaVersions = Scala2Versions) + .settings( + moduleName := "finagle-tagless-scalafix", + libraryDependencies ++= Seq( + "ch.epfl.scala" %% "scalafix-core" % _root_.scalafix.sbt.BuildInfo.scalafixVersion, + + ), + scalacOptions ~= { _.filterNot(_ == "-Xfatal-warnings") }, + ) + +lazy val `scalafix-input` = (project in file("scalafix/input")) + .settings( + publish / skip := true, + scalaVersion := Scala2Versions.head, + libraryDependencies ++= Seq( + "com.twitter" %% "scrooge-core" % TwitterUtilsLatestV, + "com.twitter" %% "finagle-thrift" % TwitterUtilsLatestV, + "org.apache.thrift" % "libthrift" % libthriftV, + ), + scalacOptions += "-nowarn", + scalacOptions ~= { _.filterNot(_ == "-Xfatal-warnings") }, + semanticdbEnabled := true, + semanticdbVersion := scalafixSemanticdb.revision, + ) + .disablePlugins(ScalafixPlugin) + +lazy val `scalafix-output` = (project in file("scalafix/output")) + .settings( + publish / skip := true, + scalaVersion := Scala2Versions.head, + libraryDependencies ++= Seq( + "com.twitter" %% "scrooge-core" % TwitterUtilsLatestV, + "com.twitter" %% "finagle-thrift" % TwitterUtilsLatestV, + "org.apache.thrift" % "libthrift" % libthriftV, + "org.typelevel" %% "cats-tagless-core" % CatsTaglessV, + "org.typelevel" %% "cats-tagless-macros" % CatsTaglessV, + ), + scalacOptions += "-nowarn", + scalacOptions ~= { _.filterNot(_ == "-Xfatal-warnings") }, + ) + .disablePlugins(ScalafixPlugin) + +lazy val `scalafix-tests` = (projectMatrix in file("scalafix/tests")) + .jvmPlatform(scalaVersions = Scala2Versions) + .settings( + publish / skip := true, + libraryDependencies += "ch.epfl.scala" % "scalafix-testkit" % _root_.scalafix.sbt.BuildInfo.scalafixVersion % Test cross CrossVersion.full, + scalafixTestkitOutputSourceDirectories := (`scalafix-output` / Compile / unmanagedSourceDirectories).value, + scalafixTestkitInputSourceDirectories := (`scalafix-input` / Compile / unmanagedSourceDirectories).value, + scalafixTestkitInputClasspath := (`scalafix-input` / Compile / fullClasspath).value, + scalafixTestkitInputScalacOptions := (`scalafix-input` / Compile / scalacOptions).value, + scalafixTestkitInputScalaVersion := (`scalafix-input` / Compile / scalaVersion).value, + ) + .dependsOn(`scalafix-rules`) + .enablePlugins(ScalafixTestkitPlugin) + lazy val `async-utils-root` = (project in file(".")) .aggregate( Seq( @@ -259,6 +317,8 @@ lazy val `async-utils-root` = (project in file(".")) `async-utils`, `async-utils-twitter`, `async-utils-finagle`, + `scalafix-rules`, + `scalafix-tests`, examples, ).flatMap(_.projectRefs): _* ) diff --git a/project/plugins.sbt b/project/plugins.sbt index efeb62a15..be56e573e 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,3 +2,4 @@ addSbtPlugin("io.github.davidgregory084" % "sbt-tpolecat" % "0.1.20") addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.9") addSbtPlugin("com.eed3si9n" % "sbt-projectmatrix" % "0.8.0") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.7.0") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.31") diff --git a/scalafix/README.md b/scalafix/README.md new file mode 100644 index 000000000..6060ad285 --- /dev/null +++ b/scalafix/README.md @@ -0,0 +1,33 @@ +# Scalafix Notes + +## Scrooge Updates + +Scrooge updates roughly monthly, and occasionally the updates introduce +breaking changes in the generated code. (For example, between the `21.5.0` +and `21.8.0` versions, [a new abstract method was added to the `ValidatingThriftStructCodec3`](https://github.com/twitter/scrooge/commit/fdb8f8f2d9cc30d6ca06b117fe7a82003f330ba8#diff-1fb7ff7b4c7a64ec907dfa620403b5b190f9829f3d5e6e0d57d07685dd53411f) +trait, which implementations generated by the older version will be missing.) + +As a result, the files in `scalafix/input/src/main/scala/example/thrift` and +`scalafix/output/src/main/scala/example/thrift` may need to be regenerated when +the Scrooge version is updated by running the `regenerate-inputs.sh` script with +the new Scrooge version as the first parameter. + +```bash +./regenerate-inputs.sh 21.8.0 +``` + +Then edit `scalafix/output/src/main/scala/example/thrift/SimpleService.scala` and replace the +blank line at the end of the `SimpleService` object with these lines: + +```scala + + + implicit def SimpleServiceInReaderT[F[_]]: SimpleService[({type Λ[β0] = _root_.cats.data.ReaderT[F, SimpleService[F], β0]})#Λ] = + _root_.cats.tagless.Derive.readerT[SimpleService, F] + + implicit val SimpleServiceFunctorK: _root_.cats.tagless.FunctorK[SimpleService] = _root_.cats.tagless.Derive.functorK[SimpleService] + + +``` + +(Newlines and whitespace matter to the tests!) diff --git a/scalafix/input/src/main/scala/example/thrift/SimpleRequest.scala b/scalafix/input/src/main/scala/example/thrift/SimpleRequest.scala new file mode 100644 index 000000000..1efeda4d8 --- /dev/null +++ b/scalafix/input/src/main/scala/example/thrift/SimpleRequest.scala @@ -0,0 +1,445 @@ +/* +rule = AddCatsTaglessInstances + */ +/** + * Generated by Scrooge + * version: 21.8.0 + * rev: 75b832815f5da5328f0225e2ab3e06a14afb3446 + * built at: 20210813-170828 + */ +package example.thrift + +import com.twitter.io.Buf +import com.twitter.scrooge.{ + InvalidFieldsException, + LazyTProtocol, + StructBuilder, + StructBuilderFactory, + TFieldBlob, + ThriftStruct, + ThriftStructCodec3, + ThriftStructField, + ThriftStructFieldInfo, + ThriftStructMetaData, + ValidatingThriftStruct, + ValidatingThriftStructCodec3 +} +import org.apache.thrift.protocol._ +import org.apache.thrift.transport.TMemoryBuffer +import scala.collection.immutable.{Map => immutable$Map} +import scala.collection.mutable.Builder +import scala.reflect.{ClassTag, classTag} + + +object SimpleRequest extends ValidatingThriftStructCodec3[SimpleRequest] with StructBuilderFactory[SimpleRequest] { + private[this] val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols() + + val Struct: TStruct = new TStruct("SimpleRequest") + val IdField: TField = new TField("id", TType.STRING, 1) + val IdFieldManifest: Manifest[String] = manifest[String] + + /** + * Field information in declaration order. + */ + lazy val fieldInfos: scala.List[ThriftStructFieldInfo] = scala.List[ThriftStructFieldInfo]( + new ThriftStructFieldInfo( + IdField, + false, + true, + IdFieldManifest, + _root_.scala.None, + _root_.scala.None, + immutable$Map.empty[String, String], + immutable$Map.empty[String, String], + None, + _root_.scala.Option("empty") + ) + ) + + + val structAnnotations: immutable$Map[String, String] = + immutable$Map.empty[String, String] + + private val fieldTypes: IndexedSeq[ClassTag[_]] = IndexedSeq[ClassTag[_]]( + classTag[String].asInstanceOf[ClassTag[_]] + ) + + private[this] val structFields: Seq[ThriftStructField[SimpleRequest]] = Seq[ThriftStructField[SimpleRequest]]( + new ThriftStructField[SimpleRequest]( + IdField, + _root_.scala.Some(IdFieldManifest), + classOf[SimpleRequest]) { + def getValue[R](struct: SimpleRequest): R = struct.id.asInstanceOf[R] + } + ) + + override lazy val metaData: ThriftStructMetaData[SimpleRequest] = + ThriftStructMetaData(this, structFields, fieldInfos, Nil, structAnnotations) + + /** + * Checks that all required fields are non-null. + */ + def validate(_item: SimpleRequest): Unit = { + if (_item.id eq null) throw new TProtocolException("Required field id cannot be null") + } + + /** + * Checks that the struct is a valid as a new instance. If there are any missing required or + * construction required fields, return a non-empty list. + */ + def validateNewInstance(item: SimpleRequest): scala.Seq[com.twitter.scrooge.validation.Issue] = { + val buf = scala.collection.mutable.ListBuffer.empty[com.twitter.scrooge.validation.Issue] + + if (item.id eq null) + buf += com.twitter.scrooge.validation.MissingRequiredField(fieldInfos.apply(0)) + buf ++= validateField(item.id) + buf.toList + } + + /** + * Validate that all validation annotations on the struct meet the criteria defined in the + * corresponding [[com.twitter.scrooge.validation.ThriftConstraintValidator]]. + */ + def validateInstanceValue(item: SimpleRequest): Set[com.twitter.scrooge.validation.ThriftValidationViolation] = { + val thriftValidator = com.twitter.scrooge.ThriftValidator() + val violations = scala.collection.mutable.Set.empty[com.twitter.scrooge.validation.ThriftValidationViolation] + val fieldInfo0 = fieldInfos.apply(0) + violations ++= validateFieldValue(fieldInfo0.tfield.name, item.id, fieldInfo0.fieldAnnotations, thriftValidator) + violations.toSet + } + + def withoutPassthroughFields(original: SimpleRequest): SimpleRequest = + new Immutable( + id = original.id + ) + + lazy val unsafeEmpty: SimpleRequest = { + val id: String = "empty" + + new Immutable( + id, + _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + ) + } + + def newBuilder(): StructBuilder[SimpleRequest] = new SimpleRequestStructBuilder(_root_.scala.None, fieldTypes) + + override def encode(_item: SimpleRequest, _oproto: TProtocol): Unit = { + _item.write(_oproto) + } + + + override def decode(_iprot: TProtocol): SimpleRequest = { + if (_iprot.isInstanceOf[LazyTProtocol]) { + decodeInternal(_iprot, true) + } else { + decodeInternal(_iprot, false) + } + } + + private[thrift] def eagerDecode(_iprot: TProtocol): SimpleRequest = { + decodeInternal(_iprot, false) + } + + private[this] def decodeInternal(_iprot: TProtocol, lazily: Boolean): SimpleRequest = { + var idOffset: Int = -1 + var id: String = null + var _got_id = false + + var _passthroughFields: Builder[(Short, TFieldBlob), immutable$Map[Short, TFieldBlob]] = null + var _done = false + val _start_offset = if (lazily) _iprot.asInstanceOf[LazyTProtocol].offset else -1 + + _iprot.readStructBegin() + do { + val _field = _iprot.readFieldBegin() + val _fieldType = _field.`type` + if (_fieldType == TType.STOP) { + _done = true + } else { + _field.id match { + case 1 => + _root_.com.twitter.scrooge.internal.TProtocols.validateFieldType(TType.STRING, _fieldType, "id") + if (lazily) + idOffset = _iprot.asInstanceOf[LazyTProtocol].offsetSkipString() + else + id = _iprot.readString() + _got_id = true + case _ => + _passthroughFields = _root_.com.twitter.scrooge.internal.TProtocols.readPassthroughField(_iprot, _field, _passthroughFields) + } + _iprot.readFieldEnd() + } + } while (!_done) + _iprot.readStructEnd() + + if (!_got_id) _root_.com.twitter.scrooge.internal.TProtocols.throwMissingRequiredField("SimpleRequest", "id") + + val _passthroughFieldsResult = + if (_passthroughFields eq null) _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + else _passthroughFields.result() + if (lazily) { + val _lazyProt = _iprot.asInstanceOf[LazyTProtocol] + new LazyImmutable( + _lazyProt, + _lazyProt.buffer, + _start_offset, + _lazyProt.offset, + idOffset, + _passthroughFieldsResult + ) + } else { + new Immutable( + id, + _passthroughFieldsResult + ) + } + } + + def apply( + id: String + ): SimpleRequest = + new Immutable( + id + ) + + def unapply(_item: SimpleRequest): _root_.scala.Option[String] = _root_.scala.Some(_item.id) + + + + object Immutable extends ThriftStructCodec3[SimpleRequest] { + override def encode(_item: SimpleRequest, _oproto: TProtocol): Unit = { _item.write(_oproto) } + override def decode(_iprot: TProtocol): SimpleRequest = SimpleRequest.decode(_iprot) + override lazy val metaData: ThriftStructMetaData[SimpleRequest] = SimpleRequest.metaData + } + + /** + * The default read-only implementation of SimpleRequest. You typically should not need to + * directly reference this class; instead, use the SimpleRequest.apply method to construct + * new instances. + */ + class Immutable( + val id: String, + override val _passthroughFields: immutable$Map[Short, TFieldBlob]) + extends SimpleRequest { + def this( + id: String + ) = this( + id, + immutable$Map.empty[Short, TFieldBlob] + ) + } + + /** + * This is another Immutable, this however keeps strings as lazy values that are lazily decoded from the backing + * array byte on read. + */ + private[this] class LazyImmutable( + _proto: LazyTProtocol, + _buf: Array[Byte], + _start_offset: Int, + _end_offset: Int, + idOffset: Int, + override val _passthroughFields: immutable$Map[Short, TFieldBlob]) + extends SimpleRequest { + + override def write(_oprot: TProtocol): Unit = { + if (_oprot.isInstanceOf[LazyTProtocol]) { + _oprot.asInstanceOf[LazyTProtocol].writeRaw(_buf, _start_offset, _end_offset - _start_offset) + } else { + super.write(_oprot) + } + } + + lazy val id: String = + if (idOffset == -1) + null + else { + _proto.decodeString(_buf, idOffset) + } + + /** + * Override the super hash code to make it a lazy val rather than def. + * + * Calculating the hash code can be expensive, caching it where possible + * can provide significant performance wins. (Key in a hash map for instance) + * Usually not safe since the normal constructor will accept a mutable map or + * set as an arg + * Here however we control how the class is generated from serialized data. + * With the class private and the contract that we throw away our mutable references + * having the hash code lazy here is safe. + */ + override lazy val hashCode: Int = super.hashCode + } + +} + +/** + * Prefer the companion object's [[example.thrift.SimpleRequest.apply]] + * for construction if you don't need to specify passthrough fields. + */ +trait SimpleRequest + extends ThriftStruct + with _root_.scala.Product1[String] + with ValidatingThriftStruct[SimpleRequest] + with java.io.Serializable +{ + import SimpleRequest._ + + def id: String + + def _passthroughFields: immutable$Map[Short, TFieldBlob] = immutable$Map.empty + + def _1: String = id + + + /** + * Gets a field value encoded as a binary blob using TCompactProtocol. If the specified field + * is present in the passthrough map, that value is returned. Otherwise, if the specified field + * is known and not optional and set to None, then the field is serialized and returned. + */ + def getFieldBlob(_fieldId: Short): _root_.scala.Option[TFieldBlob] = { + val passedthroughValue = _passthroughFields.get(_fieldId) + if (passedthroughValue.isDefined) { + passedthroughValue + } else { + val _protos = _root_.com.twitter.scrooge.internal.TProtocols() + val _buff = new TMemoryBuffer(32) + val _oprot = new TCompactProtocol(_buff) + + val _fieldOpt: _root_.scala.Option[TField] = _fieldId match { + case 1 => + if (id ne null) { + _oprot.writeString(id) + _root_.scala.Some(SimpleRequest.IdField) + } else { + _root_.scala.None + } + case _ => _root_.scala.None + } + if (_fieldOpt.isDefined) { + _root_.scala.Some(TFieldBlob(_fieldOpt.get, Buf.ByteArray.Owned(_buff.getArray))) + } else { + _root_.scala.None + } + } + } + + + /** + * Collects TCompactProtocol-encoded field values according to `getFieldBlob` into a map. + */ + def getFieldBlobs(ids: TraversableOnce[Short]): immutable$Map[Short, TFieldBlob] = + (ids.flatMap { id => getFieldBlob(id).map { fieldBlob => (id, fieldBlob) } }).toMap + + /** + * Sets a field using a TCompactProtocol-encoded binary blob. If the field is a known + * field, the blob is decoded and the field is set to the decoded value. If the field + * is unknown and passthrough fields are enabled, then the blob will be stored in + * _passthroughFields. + */ + def setField(_blob: TFieldBlob): SimpleRequest = { + val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols() + var id: String = this.id + var _passthroughFields = this._passthroughFields + val _iprot = _blob.read + _blob.id match { + case 1 => + id = _iprot.readString() + case _ => _passthroughFields += _root_.scala.Tuple2(_blob.id, _blob) + } + new Immutable( + id, + _passthroughFields + ) + } + + /** + * If the specified field is optional, it is set to None. Otherwise, if the field is + * known, it is reverted to its default value; if the field is unknown, it is removed + * from the passthroughFields map, if present. + */ + def unsetField(_fieldId: Short): SimpleRequest = { + var id: String = this.id + + _fieldId match { + case 1 => + id = null + case _ => + } + new Immutable( + id, + _passthroughFields - _fieldId + ) + } + + /** + * If the specified field is optional, it is set to None. Otherwise, if the field is + * known, it is reverted to its default value; if the field is unknown, it is removed + * from the passthroughFields map, if present. + */ + def unsetId: SimpleRequest = unsetField(1) + + + override def write(_oprot: TProtocol): Unit = { + SimpleRequest.validate(this) + val _protos = _root_.com.twitter.scrooge.internal.TProtocols() + _oprot.writeStructBegin(Struct) + if (id ne null) { + _oprot.writeFieldBegin(IdField) + _oprot.writeString(id) + _oprot.writeFieldEnd() + } + _root_.com.twitter.scrooge.internal.TProtocols.finishWritingStruct(_oprot, _passthroughFields) + } + + def copy( + id: String = this.id, + _passthroughFields: immutable$Map[Short, TFieldBlob] = this._passthroughFields + ): SimpleRequest = + new Immutable( + id, + _passthroughFields + ) + + override def canEqual(other: Any): Boolean = other.isInstanceOf[SimpleRequest] + + private[this] def _equals(other: SimpleRequest): Boolean = + this.productArity == other.productArity && + this.productIterator.sameElements(other.productIterator) && + this._passthroughFields == other._passthroughFields + + override def equals(other: Any): Boolean = + canEqual(other) && _equals(other.asInstanceOf[SimpleRequest]) + + override def hashCode: Int = { + _root_.scala.runtime.ScalaRunTime._hashCode(this) + } + + override def toString: String = _root_.scala.runtime.ScalaRunTime._toString(this) + + override def productPrefix: String = "SimpleRequest" + + def _codec: ValidatingThriftStructCodec3[SimpleRequest] = SimpleRequest + + def newBuilder(): StructBuilder[SimpleRequest] = new SimpleRequestStructBuilder(_root_.scala.Some(this), fieldTypes) +} + +private[thrift] class SimpleRequestStructBuilder(instance: _root_.scala.Option[SimpleRequest], fieldTypes: IndexedSeq[ClassTag[_]]) + extends StructBuilder[SimpleRequest](fieldTypes) { + + def build(): SimpleRequest = { + val _fieldArray = fieldArray // shadow variable + if (instance.isDefined) { + val instanceValue = instance.get + SimpleRequest( + if (_fieldArray(0) == null) instanceValue.id else _fieldArray(0).asInstanceOf[String] + ) + } else { + if (genericArrayOps(_fieldArray).contains(null)) throw new InvalidFieldsException(structBuildError("SimpleRequest")) + SimpleRequest( + _fieldArray(0).asInstanceOf[String] + ) + } + } +} diff --git a/scalafix/input/src/main/scala/example/thrift/SimpleResponse.scala b/scalafix/input/src/main/scala/example/thrift/SimpleResponse.scala new file mode 100644 index 000000000..4845afdf5 --- /dev/null +++ b/scalafix/input/src/main/scala/example/thrift/SimpleResponse.scala @@ -0,0 +1,445 @@ +/* +rule = AddCatsTaglessInstances + */ +/** + * Generated by Scrooge + * version: 21.8.0 + * rev: 75b832815f5da5328f0225e2ab3e06a14afb3446 + * built at: 20210813-170828 + */ +package example.thrift + +import com.twitter.io.Buf +import com.twitter.scrooge.{ + InvalidFieldsException, + LazyTProtocol, + StructBuilder, + StructBuilderFactory, + TFieldBlob, + ThriftStruct, + ThriftStructCodec3, + ThriftStructField, + ThriftStructFieldInfo, + ThriftStructMetaData, + ValidatingThriftStruct, + ValidatingThriftStructCodec3 +} +import org.apache.thrift.protocol._ +import org.apache.thrift.transport.TMemoryBuffer +import scala.collection.immutable.{Map => immutable$Map} +import scala.collection.mutable.Builder +import scala.reflect.{ClassTag, classTag} + + +object SimpleResponse extends ValidatingThriftStructCodec3[SimpleResponse] with StructBuilderFactory[SimpleResponse] { + private[this] val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols() + + val Struct: TStruct = new TStruct("SimpleResponse") + val IdField: TField = new TField("id", TType.STRING, 1) + val IdFieldManifest: Manifest[String] = manifest[String] + + /** + * Field information in declaration order. + */ + lazy val fieldInfos: scala.List[ThriftStructFieldInfo] = scala.List[ThriftStructFieldInfo]( + new ThriftStructFieldInfo( + IdField, + false, + true, + IdFieldManifest, + _root_.scala.None, + _root_.scala.None, + immutable$Map.empty[String, String], + immutable$Map.empty[String, String], + None, + _root_.scala.Option("empty") + ) + ) + + + val structAnnotations: immutable$Map[String, String] = + immutable$Map.empty[String, String] + + private val fieldTypes: IndexedSeq[ClassTag[_]] = IndexedSeq[ClassTag[_]]( + classTag[String].asInstanceOf[ClassTag[_]] + ) + + private[this] val structFields: Seq[ThriftStructField[SimpleResponse]] = Seq[ThriftStructField[SimpleResponse]]( + new ThriftStructField[SimpleResponse]( + IdField, + _root_.scala.Some(IdFieldManifest), + classOf[SimpleResponse]) { + def getValue[R](struct: SimpleResponse): R = struct.id.asInstanceOf[R] + } + ) + + override lazy val metaData: ThriftStructMetaData[SimpleResponse] = + ThriftStructMetaData(this, structFields, fieldInfos, Nil, structAnnotations) + + /** + * Checks that all required fields are non-null. + */ + def validate(_item: SimpleResponse): Unit = { + if (_item.id eq null) throw new TProtocolException("Required field id cannot be null") + } + + /** + * Checks that the struct is a valid as a new instance. If there are any missing required or + * construction required fields, return a non-empty list. + */ + def validateNewInstance(item: SimpleResponse): scala.Seq[com.twitter.scrooge.validation.Issue] = { + val buf = scala.collection.mutable.ListBuffer.empty[com.twitter.scrooge.validation.Issue] + + if (item.id eq null) + buf += com.twitter.scrooge.validation.MissingRequiredField(fieldInfos.apply(0)) + buf ++= validateField(item.id) + buf.toList + } + + /** + * Validate that all validation annotations on the struct meet the criteria defined in the + * corresponding [[com.twitter.scrooge.validation.ThriftConstraintValidator]]. + */ + def validateInstanceValue(item: SimpleResponse): Set[com.twitter.scrooge.validation.ThriftValidationViolation] = { + val thriftValidator = com.twitter.scrooge.ThriftValidator() + val violations = scala.collection.mutable.Set.empty[com.twitter.scrooge.validation.ThriftValidationViolation] + val fieldInfo0 = fieldInfos.apply(0) + violations ++= validateFieldValue(fieldInfo0.tfield.name, item.id, fieldInfo0.fieldAnnotations, thriftValidator) + violations.toSet + } + + def withoutPassthroughFields(original: SimpleResponse): SimpleResponse = + new Immutable( + id = original.id + ) + + lazy val unsafeEmpty: SimpleResponse = { + val id: String = "empty" + + new Immutable( + id, + _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + ) + } + + def newBuilder(): StructBuilder[SimpleResponse] = new SimpleResponseStructBuilder(_root_.scala.None, fieldTypes) + + override def encode(_item: SimpleResponse, _oproto: TProtocol): Unit = { + _item.write(_oproto) + } + + + override def decode(_iprot: TProtocol): SimpleResponse = { + if (_iprot.isInstanceOf[LazyTProtocol]) { + decodeInternal(_iprot, true) + } else { + decodeInternal(_iprot, false) + } + } + + private[thrift] def eagerDecode(_iprot: TProtocol): SimpleResponse = { + decodeInternal(_iprot, false) + } + + private[this] def decodeInternal(_iprot: TProtocol, lazily: Boolean): SimpleResponse = { + var idOffset: Int = -1 + var id: String = null + var _got_id = false + + var _passthroughFields: Builder[(Short, TFieldBlob), immutable$Map[Short, TFieldBlob]] = null + var _done = false + val _start_offset = if (lazily) _iprot.asInstanceOf[LazyTProtocol].offset else -1 + + _iprot.readStructBegin() + do { + val _field = _iprot.readFieldBegin() + val _fieldType = _field.`type` + if (_fieldType == TType.STOP) { + _done = true + } else { + _field.id match { + case 1 => + _root_.com.twitter.scrooge.internal.TProtocols.validateFieldType(TType.STRING, _fieldType, "id") + if (lazily) + idOffset = _iprot.asInstanceOf[LazyTProtocol].offsetSkipString() + else + id = _iprot.readString() + _got_id = true + case _ => + _passthroughFields = _root_.com.twitter.scrooge.internal.TProtocols.readPassthroughField(_iprot, _field, _passthroughFields) + } + _iprot.readFieldEnd() + } + } while (!_done) + _iprot.readStructEnd() + + if (!_got_id) _root_.com.twitter.scrooge.internal.TProtocols.throwMissingRequiredField("SimpleResponse", "id") + + val _passthroughFieldsResult = + if (_passthroughFields eq null) _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + else _passthroughFields.result() + if (lazily) { + val _lazyProt = _iprot.asInstanceOf[LazyTProtocol] + new LazyImmutable( + _lazyProt, + _lazyProt.buffer, + _start_offset, + _lazyProt.offset, + idOffset, + _passthroughFieldsResult + ) + } else { + new Immutable( + id, + _passthroughFieldsResult + ) + } + } + + def apply( + id: String + ): SimpleResponse = + new Immutable( + id + ) + + def unapply(_item: SimpleResponse): _root_.scala.Option[String] = _root_.scala.Some(_item.id) + + + + object Immutable extends ThriftStructCodec3[SimpleResponse] { + override def encode(_item: SimpleResponse, _oproto: TProtocol): Unit = { _item.write(_oproto) } + override def decode(_iprot: TProtocol): SimpleResponse = SimpleResponse.decode(_iprot) + override lazy val metaData: ThriftStructMetaData[SimpleResponse] = SimpleResponse.metaData + } + + /** + * The default read-only implementation of SimpleResponse. You typically should not need to + * directly reference this class; instead, use the SimpleResponse.apply method to construct + * new instances. + */ + class Immutable( + val id: String, + override val _passthroughFields: immutable$Map[Short, TFieldBlob]) + extends SimpleResponse { + def this( + id: String + ) = this( + id, + immutable$Map.empty[Short, TFieldBlob] + ) + } + + /** + * This is another Immutable, this however keeps strings as lazy values that are lazily decoded from the backing + * array byte on read. + */ + private[this] class LazyImmutable( + _proto: LazyTProtocol, + _buf: Array[Byte], + _start_offset: Int, + _end_offset: Int, + idOffset: Int, + override val _passthroughFields: immutable$Map[Short, TFieldBlob]) + extends SimpleResponse { + + override def write(_oprot: TProtocol): Unit = { + if (_oprot.isInstanceOf[LazyTProtocol]) { + _oprot.asInstanceOf[LazyTProtocol].writeRaw(_buf, _start_offset, _end_offset - _start_offset) + } else { + super.write(_oprot) + } + } + + lazy val id: String = + if (idOffset == -1) + null + else { + _proto.decodeString(_buf, idOffset) + } + + /** + * Override the super hash code to make it a lazy val rather than def. + * + * Calculating the hash code can be expensive, caching it where possible + * can provide significant performance wins. (Key in a hash map for instance) + * Usually not safe since the normal constructor will accept a mutable map or + * set as an arg + * Here however we control how the class is generated from serialized data. + * With the class private and the contract that we throw away our mutable references + * having the hash code lazy here is safe. + */ + override lazy val hashCode: Int = super.hashCode + } + +} + +/** + * Prefer the companion object's [[example.thrift.SimpleResponse.apply]] + * for construction if you don't need to specify passthrough fields. + */ +trait SimpleResponse + extends ThriftStruct + with _root_.scala.Product1[String] + with ValidatingThriftStruct[SimpleResponse] + with java.io.Serializable +{ + import SimpleResponse._ + + def id: String + + def _passthroughFields: immutable$Map[Short, TFieldBlob] = immutable$Map.empty + + def _1: String = id + + + /** + * Gets a field value encoded as a binary blob using TCompactProtocol. If the specified field + * is present in the passthrough map, that value is returned. Otherwise, if the specified field + * is known and not optional and set to None, then the field is serialized and returned. + */ + def getFieldBlob(_fieldId: Short): _root_.scala.Option[TFieldBlob] = { + val passedthroughValue = _passthroughFields.get(_fieldId) + if (passedthroughValue.isDefined) { + passedthroughValue + } else { + val _protos = _root_.com.twitter.scrooge.internal.TProtocols() + val _buff = new TMemoryBuffer(32) + val _oprot = new TCompactProtocol(_buff) + + val _fieldOpt: _root_.scala.Option[TField] = _fieldId match { + case 1 => + if (id ne null) { + _oprot.writeString(id) + _root_.scala.Some(SimpleResponse.IdField) + } else { + _root_.scala.None + } + case _ => _root_.scala.None + } + if (_fieldOpt.isDefined) { + _root_.scala.Some(TFieldBlob(_fieldOpt.get, Buf.ByteArray.Owned(_buff.getArray))) + } else { + _root_.scala.None + } + } + } + + + /** + * Collects TCompactProtocol-encoded field values according to `getFieldBlob` into a map. + */ + def getFieldBlobs(ids: TraversableOnce[Short]): immutable$Map[Short, TFieldBlob] = + (ids.flatMap { id => getFieldBlob(id).map { fieldBlob => (id, fieldBlob) } }).toMap + + /** + * Sets a field using a TCompactProtocol-encoded binary blob. If the field is a known + * field, the blob is decoded and the field is set to the decoded value. If the field + * is unknown and passthrough fields are enabled, then the blob will be stored in + * _passthroughFields. + */ + def setField(_blob: TFieldBlob): SimpleResponse = { + val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols() + var id: String = this.id + var _passthroughFields = this._passthroughFields + val _iprot = _blob.read + _blob.id match { + case 1 => + id = _iprot.readString() + case _ => _passthroughFields += _root_.scala.Tuple2(_blob.id, _blob) + } + new Immutable( + id, + _passthroughFields + ) + } + + /** + * If the specified field is optional, it is set to None. Otherwise, if the field is + * known, it is reverted to its default value; if the field is unknown, it is removed + * from the passthroughFields map, if present. + */ + def unsetField(_fieldId: Short): SimpleResponse = { + var id: String = this.id + + _fieldId match { + case 1 => + id = null + case _ => + } + new Immutable( + id, + _passthroughFields - _fieldId + ) + } + + /** + * If the specified field is optional, it is set to None. Otherwise, if the field is + * known, it is reverted to its default value; if the field is unknown, it is removed + * from the passthroughFields map, if present. + */ + def unsetId: SimpleResponse = unsetField(1) + + + override def write(_oprot: TProtocol): Unit = { + SimpleResponse.validate(this) + val _protos = _root_.com.twitter.scrooge.internal.TProtocols() + _oprot.writeStructBegin(Struct) + if (id ne null) { + _oprot.writeFieldBegin(IdField) + _oprot.writeString(id) + _oprot.writeFieldEnd() + } + _root_.com.twitter.scrooge.internal.TProtocols.finishWritingStruct(_oprot, _passthroughFields) + } + + def copy( + id: String = this.id, + _passthroughFields: immutable$Map[Short, TFieldBlob] = this._passthroughFields + ): SimpleResponse = + new Immutable( + id, + _passthroughFields + ) + + override def canEqual(other: Any): Boolean = other.isInstanceOf[SimpleResponse] + + private[this] def _equals(other: SimpleResponse): Boolean = + this.productArity == other.productArity && + this.productIterator.sameElements(other.productIterator) && + this._passthroughFields == other._passthroughFields + + override def equals(other: Any): Boolean = + canEqual(other) && _equals(other.asInstanceOf[SimpleResponse]) + + override def hashCode: Int = { + _root_.scala.runtime.ScalaRunTime._hashCode(this) + } + + override def toString: String = _root_.scala.runtime.ScalaRunTime._toString(this) + + override def productPrefix: String = "SimpleResponse" + + def _codec: ValidatingThriftStructCodec3[SimpleResponse] = SimpleResponse + + def newBuilder(): StructBuilder[SimpleResponse] = new SimpleResponseStructBuilder(_root_.scala.Some(this), fieldTypes) +} + +private[thrift] class SimpleResponseStructBuilder(instance: _root_.scala.Option[SimpleResponse], fieldTypes: IndexedSeq[ClassTag[_]]) + extends StructBuilder[SimpleResponse](fieldTypes) { + + def build(): SimpleResponse = { + val _fieldArray = fieldArray // shadow variable + if (instance.isDefined) { + val instanceValue = instance.get + SimpleResponse( + if (_fieldArray(0) == null) instanceValue.id else _fieldArray(0).asInstanceOf[String] + ) + } else { + if (genericArrayOps(_fieldArray).contains(null)) throw new InvalidFieldsException(structBuildError("SimpleResponse")) + SimpleResponse( + _fieldArray(0).asInstanceOf[String] + ) + } + } +} diff --git a/scalafix/input/src/main/scala/example/thrift/SimpleService$FinagleClient.scala b/scalafix/input/src/main/scala/example/thrift/SimpleService$FinagleClient.scala new file mode 100644 index 000000000..2d638895a --- /dev/null +++ b/scalafix/input/src/main/scala/example/thrift/SimpleService$FinagleClient.scala @@ -0,0 +1,141 @@ +/* +rule = AddCatsTaglessInstances + */ +/** + * Generated by Scrooge + * version: 21.8.0 + * rev: 75b832815f5da5328f0225e2ab3e06a14afb3446 + * built at: 20210813-170828 + */ +package example.thrift + +import com.twitter.finagle.{service => ctfs} +import com.twitter.finagle.stats.{NullStatsReceiver, StatsReceiver} +import com.twitter.finagle.thrift.{Protocols, RichClientParam, ThriftClientRequest} +import com.twitter.util.Future +import org.apache.thrift.TApplicationException +import org.apache.thrift.protocol._ + + +@javax.annotation.Generated(value = Array("com.twitter.scrooge.Compiler")) +class SimpleService$FinagleClient( + val service: com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + val clientParam: RichClientParam) + extends SimpleService[Future] { + + @deprecated("Use com.twitter.finagle.thrift.RichClientParam", "2017-08-16") + def this( + service: com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + protocolFactory: TProtocolFactory = Protocols.binaryFactory(), + serviceName: String = "SimpleService", + stats: StatsReceiver = NullStatsReceiver, + responseClassifier: ctfs.ResponseClassifier = ctfs.ResponseClassifier.Default + ) = this( + service, + RichClientParam( + protocolFactory, + serviceName, + clientStats = stats, + responseClassifier = responseClassifier + ) + ) + + import SimpleService._ + + def serviceName: String = clientParam.serviceName + + override def asClosable: _root_.com.twitter.util.Closable = service + + private[this] def protocolFactory: TProtocolFactory = clientParam.restrictedProtocolFactory + + private[this] val tlReusableBuffer: _root_.com.twitter.scrooge.TReusableBuffer = + clientParam.createThriftReusableBuffer() + + protected def encodeRequest(name: String, args: _root_.com.twitter.scrooge.ThriftStruct): ThriftClientRequest = { + val memoryBuffer = tlReusableBuffer.get() + try { + val oprot = protocolFactory.getProtocol(memoryBuffer) + + oprot.writeMessageBegin(new TMessage(name, TMessageType.CALL, 0)) + args.write(oprot) + oprot.writeMessageEnd() + oprot.getTransport.flush() + val bytes = _root_.java.util.Arrays.copyOfRange( + memoryBuffer.getArray(), + 0, + memoryBuffer.length() + ) + new ThriftClientRequest(bytes, false) + } finally { + tlReusableBuffer.reset() + } + } + + protected def decodeResponse[T <: _root_.com.twitter.scrooge.ThriftStruct]( + resBytes: Array[Byte], + codec: _root_.com.twitter.scrooge.ThriftStructCodec[T] + ): _root_.com.twitter.util.Try[T] = + _root_.com.twitter.finagle.thrift.service.ThriftCodec.decodeResponse(resBytes, codec, protocolFactory, serviceName) + + // ----- end boilerplate. + + private[this] def stats: StatsReceiver = clientParam.clientStats + private[this] def responseClassifier: ctfs.ResponseClassifier = clientParam.responseClassifier + + private[this] val scopedStats: StatsReceiver = if (serviceName != "") stats.scope(serviceName) else stats + private[this] object __stats_makeRequest { + val RequestsCounter: _root_.com.twitter.finagle.stats.Counter = scopedStats.scope("MakeRequest").counter("requests") + val SuccessCounter: _root_.com.twitter.finagle.stats.Counter = scopedStats.scope("MakeRequest").counter("success") + val FailuresCounter: _root_.com.twitter.finagle.stats.Counter = scopedStats.scope("MakeRequest").counter("failures") + val FailuresScope: StatsReceiver = scopedStats.scope("MakeRequest").scope("failures") + } + val MakeRequestSimpleServiceReplyDeserializer: Array[Byte] => _root_.com.twitter.util.Try[example.thrift.SimpleResponse] = { + response: Array[Byte] => { + decodeResponse(response, MakeRequest.Result).flatMap { result: MakeRequest.Result => + val firstException = result.firstException() + if (firstException.isDefined) { + _root_.com.twitter.util.Throw(_root_.com.twitter.finagle.SourcedException.setServiceName(firstException.get, serviceName)) + } else if (result.successField.isDefined) { + _root_.com.twitter.util.Return(result.successField.get) + } else { + _root_.com.twitter.util.Throw(_root_.com.twitter.scrooge.internal.ApplicationExceptions.missingResult("MakeRequest")) + } + } + } + } + + def makeRequest(request: example.thrift.SimpleRequest): Future[example.thrift.SimpleResponse] = { + __stats_makeRequest.RequestsCounter.incr() + val inputArgs = MakeRequest.Args(request) + + val serdeCtx = new _root_.com.twitter.finagle.thrift.ClientDeserializeCtx[example.thrift.SimpleResponse](inputArgs, MakeRequestSimpleServiceReplyDeserializer) + _root_.com.twitter.finagle.context.Contexts.local.let( + _root_.com.twitter.finagle.thrift.ClientDeserializeCtx.Key, + serdeCtx, + _root_.com.twitter.finagle.thrift.Headers.Request.Key, + _root_.com.twitter.finagle.thrift.Headers.Request.newValues + ) { + serdeCtx.rpcName("MakeRequest") + val start = System.nanoTime + val serialized = encodeRequest("MakeRequest", inputArgs) + serdeCtx.serializationTime(System.nanoTime - start) + this.service(serialized).flatMap { response => + Future.const(serdeCtx.deserialize(response)) + }.respond { response => + val classified = responseClassifier.applyOrElse( + ctfs.ReqRep(inputArgs, response), + ctfs.ResponseClassifier.Default) + if (classified.isInstanceOf[ctfs.ResponseClass.Successful]) { + __stats_makeRequest.SuccessCounter.incr() + } else if (classified.isInstanceOf[ctfs.ResponseClass.Failed]) { + __stats_makeRequest.FailuresCounter.incr() + if (response.isThrow) { + _root_.com.twitter.finagle.SourcedException.setServiceName(response.throwable, serviceName) + __stats_makeRequest.FailuresScope.counter( + _root_.com.twitter.util.Throwables.mkString(response.throwable): _*).incr() + } + } // Last ResponseClass is Ignorable, which we do not need to record + } + } + } +} diff --git a/scalafix/input/src/main/scala/example/thrift/SimpleService$FinagleService.scala b/scalafix/input/src/main/scala/example/thrift/SimpleService$FinagleService.scala new file mode 100644 index 000000000..7584afc2e --- /dev/null +++ b/scalafix/input/src/main/scala/example/thrift/SimpleService$FinagleService.scala @@ -0,0 +1,107 @@ +/* +rule = AddCatsTaglessInstances + */ +/** + * Generated by Scrooge + * version: 21.8.0 + * rev: 75b832815f5da5328f0225e2ab3e06a14afb3446 + * built at: 20210813-170828 + */ +package example.thrift + +import com.twitter.finagle.{ + Filter => _, + Service => _, + thrift => _, + _ +} +import com.twitter.finagle.stats.{NullStatsReceiver, StatsReceiver} +import com.twitter.finagle.thrift.RichServerParam +import com.twitter.io.Buf +import com.twitter.util.Future +import org.apache.thrift.protocol._ +import org.apache.thrift.TApplicationException +import org.apache.thrift.transport.TMemoryInputTransport + + +@javax.annotation.Generated(value = Array("com.twitter.scrooge.Compiler")) +class SimpleService$FinagleService( + iface: SimpleService[Future], + serverParam: RichServerParam +) extends com.twitter.finagle.Service[Array[Byte], Array[Byte]] { + import SimpleService._ + + @deprecated("Use com.twitter.finagle.thrift.RichServerParam", "2017-08-16") + def this( + iface: SimpleService[Future], + protocolFactory: TProtocolFactory, + stats: StatsReceiver = NullStatsReceiver, + maxThriftBufferSize: Int = Thrift.param.maxThriftBufferSize, + serviceName: String = "SimpleService" + ) = this(iface, RichServerParam(protocolFactory, serviceName, maxThriftBufferSize, stats)) + + @deprecated("Use com.twitter.finagle.thrift.RichServerParam", "2017-08-16") + def this( + iface: SimpleService[Future], + protocolFactory: TProtocolFactory, + stats: StatsReceiver, + maxThriftBufferSize: Int + ) = this(iface, protocolFactory, stats, maxThriftBufferSize, "SimpleService") + + @deprecated("Use com.twitter.finagle.thrift.RichServerParam", "2017-08-16") + def this( + iface: SimpleService[Future], + protocolFactory: TProtocolFactory + ) = this(iface, protocolFactory, NullStatsReceiver, Thrift.param.maxThriftBufferSize) + + def serviceName: String = serverParam.serviceName + private[this] val filters: Filter = new Filter(serverParam) + + private[this] def protocolFactory: TProtocolFactory = serverParam.restrictedProtocolFactory + + protected val serviceMap: _root_.scala.collection.mutable.HashMap[String, _root_.com.twitter.finagle.Service[(TProtocol, Int), Array[Byte]]] = + new _root_.scala.collection.mutable.HashMap[String, _root_.com.twitter.finagle.Service[(TProtocol, Int), Array[Byte]]]() + + protected def addService(name: String, service: _root_.com.twitter.finagle.Service[(TProtocol, Int), Array[Byte]]): Unit = { + serviceMap(name) = service + } + + final def apply(request: Array[Byte]): Future[Array[Byte]] = { + val iprot = protocolFactory.getProtocol(new TMemoryInputTransport(request)) + + try { + val msg = iprot.readMessageBegin() + val svcOpt = serviceMap.get(msg.name) + if (svcOpt.isDefined) { + svcOpt.get.apply((iprot, msg.seqid)) + } else { + TProtocolUtil.skip(iprot, TType.STRUCT) + invalidMethodNameFuture(msg) + } + } catch { + case e: Exception => Future.exception(e) + } + } + + private[this] def invalidMethodNameFuture(msg: TMessage): Future[Array[Byte]] = { + Future.value(Buf.ByteArray.Owned.extract( + filters.exception(msg.name, msg.seqid, TApplicationException.UNKNOWN_METHOD, + "Invalid method name: '" + msg.name + "'"))) + } + // ---- end boilerplate. + + addService("MakeRequest", { + val methodService = new _root_.com.twitter.finagle.Service[MakeRequest.Args, MakeRequest.SuccessType] { + def apply(args: MakeRequest.Args): Future[MakeRequest.SuccessType] = { + val trace = _root_.com.twitter.finagle.tracing.Trace() + if (trace.isActivelyTracing) { + trace.recordRpc("MakeRequest") + trace.recordBinary("srv/thrift_endpoint", "example.thrift.SimpleService#makeRequest()") + } + iface.makeRequest(args.request) + } + } + + filters.makeRequest.andThen(methodService) + }) +} diff --git a/scalafix/input/src/main/scala/example/thrift/SimpleService.scala b/scalafix/input/src/main/scala/example/thrift/SimpleService.scala new file mode 100644 index 000000000..0b301a2e3 --- /dev/null +++ b/scalafix/input/src/main/scala/example/thrift/SimpleService.scala @@ -0,0 +1,1074 @@ +/* +rule = AddCatsTaglessInstances + */ +/** + * Generated by Scrooge + * version: 21.8.0 + * rev: 75b832815f5da5328f0225e2ab3e06a14afb3446 + * built at: 20210813-170828 + */ +package example.thrift + +import com.twitter.scrooge._ +import com.twitter.finagle.{ + service => ctfs, + Filter => finagle$Filter, + Service => finagle$Service, + thrift => _, + _ +} +import com.twitter.finagle.stats.{Counter, StatsReceiver} +import com.twitter.finagle.thrift.{ + Protocols, + RichClientParam, + RichServerParam, + ServerToReqRep, + ThriftClientRequest, + ToThriftService +} +import com.twitter.util.{Future, Return, Throw, Throwables} +import com.twitter.io.Buf +import org.apache.thrift.protocol._ +import org.apache.thrift.TApplicationException +import scala.collection.mutable.Builder +import scala.collection.immutable.{Map => immutable$Map, Set => immutable$Set} +import scala.language.higherKinds +import scala.reflect.{ClassTag, classTag} + + +@javax.annotation.Generated(value = Array("com.twitter.scrooge.Compiler")) +trait SimpleService[+MM[_]] extends _root_.com.twitter.finagle.thrift.ThriftService { + + def makeRequest(request: example.thrift.SimpleRequest): MM[example.thrift.SimpleResponse] + + /** + * Used to close the underlying `Service`. + * Not a user-defined API. + */ + def asClosable: _root_.com.twitter.util.Closable = _root_.com.twitter.util.Closable.nop +} + + +object SimpleService extends _root_.com.twitter.finagle.thrift.GeneratedThriftService { self => + + val annotations: immutable$Map[String, String] = immutable$Map.empty + + val methods: immutable$Set[ThriftMethod] = immutable$Set( + self.MakeRequest + ) + + trait ServicePerEndpoint + extends ToThriftService + with _root_.com.twitter.finagle.thrift.service.Filterable[ServicePerEndpoint] { + def makeRequest : _root_.com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType] + + def withMakeRequest(makeRequest : _root_.com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType]): ServicePerEndpoint = this + + /** + * Prepends the given type-agnostic `Filter` to all of the `Services` + * and returns a copy of the `ServicePerEndpoint` now including the filter. + */ + def filtered(filter: _root_.com.twitter.finagle.Filter.TypeAgnostic): ServicePerEndpoint = + ServicePerEndpoint.apply(makeRequest).filtered(filter) + + /** + * Converts the `ServicePerEndpoint` to a `GeneratedThriftService`. + * @see _root_.com.twitter.scrooge.ToThriftService + */ + def toThriftService: _root_.com.twitter.finagle.thrift.ThriftService = MethodPerEndpoint(this) + + /** + * Used to close the underlying `Service`. + * Not a user-defined API. + */ + def asClosable: _root_.com.twitter.util.Closable = _root_.com.twitter.util.Closable.nop + } + + trait ReqRepServicePerEndpoint + extends ToThriftService + with _root_.com.twitter.finagle.thrift.service.Filterable[ReqRepServicePerEndpoint] { + def makeRequest : _root_.com.twitter.finagle.Service[com.twitter.scrooge.Request[self.MakeRequest.Args], _root_.com.twitter.scrooge.Response[self.MakeRequest.SuccessType]] + + def withMakeRequest(makeRequest : _root_.com.twitter.finagle.Service[com.twitter.scrooge.Request[self.MakeRequest.Args], _root_.com.twitter.scrooge.Response[self.MakeRequest.SuccessType]]): ReqRepServicePerEndpoint = this + + /** + * Prepends the given type-agnostic `Filter` to all of the `Services` + * and returns a copy of the `ServicePerEndpoint` now including the filter. + */ + def filtered(filter: com.twitter.finagle.Filter.TypeAgnostic): ReqRepServicePerEndpoint = + ReqRepServicePerEndpoint.apply(makeRequest).filtered(filter) + + /** + * Converts the `ServicePerEndpoint` to a `GeneratedThriftService`. + * @see _root_.com.twitter.scrooge.ToThriftService + */ + def toThriftService: _root_.com.twitter.finagle.thrift.ThriftService = ReqRepMethodPerEndpoint(this) + + /** + * Used to close the underlying `Service`. + * Not a user-defined API. + */ + def asClosable: _root_.com.twitter.util.Closable = _root_.com.twitter.util.Closable.nop + } + + @deprecated("Use ServicePerEndpoint", "2017-11-07") + trait BaseServiceIface extends ToThriftService { + def makeRequest : com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType] + + def toThriftService: _root_.com.twitter.finagle.thrift.ThriftService = new MethodIface(this) + } + + object ServicePerEndpoint { + + def apply( + makeRequest : _root_.com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType] + ): ServicePerEndpoint = new ServicePerEndpointImpl(makeRequest) + + private final class ServicePerEndpointImpl( + override val makeRequest : _root_.com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType] + ) extends ServicePerEndpoint { + + override def withMakeRequest( + makeRequest : _root_.com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType] + ): ServicePerEndpoint = + new ServicePerEndpointImpl(makeRequest) + + override def filtered(filter: _root_.com.twitter.finagle.Filter.TypeAgnostic): ServicePerEndpoint = + new ServicePerEndpointImpl( + makeRequest = filter.toFilter.andThen(makeRequest) + ) + + override def asClosable: _root_.com.twitter.util.Closable = + _root_.com.twitter.util.Closable.all( + this.makeRequest + ) + } + } + + object ReqRepServicePerEndpoint { + + def apply( + makeRequest : _root_.com.twitter.finagle.Service[_root_.com.twitter.scrooge.Request[self.MakeRequest.Args], _root_.com.twitter.scrooge.Response[self.MakeRequest.SuccessType]] + ): ReqRepServicePerEndpoint = + new ReqRepServicePerEndpointImpl(makeRequest) + + private final class ReqRepServicePerEndpointImpl( + override val makeRequest : _root_.com.twitter.finagle.Service[_root_.com.twitter.scrooge.Request[self.MakeRequest.Args], _root_.com.twitter.scrooge.Response[self.MakeRequest.SuccessType]] + ) extends ReqRepServicePerEndpoint { + + override def withMakeRequest( + makeRequest : _root_.com.twitter.finagle.Service[com.twitter.scrooge.Request[self.MakeRequest.Args], _root_.com.twitter.scrooge.Response[self.MakeRequest.SuccessType]] + ): ReqRepServicePerEndpoint = + new ReqRepServicePerEndpointImpl(makeRequest) + + override def filtered(filter: com.twitter.finagle.Filter.TypeAgnostic): ReqRepServicePerEndpoint = + new ReqRepServicePerEndpointImpl( + makeRequest = filter.toFilter.andThen(makeRequest) + ) + + override def asClosable: _root_.com.twitter.util.Closable = + _root_.com.twitter.util.Closable.all( + this.makeRequest + ) + } + } + + def unsafeBuildFromMethods(methods: immutable$Map[ThriftMethod, _root_.com.twitter.finagle.Service[_root_.com.twitter.scrooge.Request[_], _root_.com.twitter.scrooge.Response[_]]]): ReqRepServicePerEndpoint = { + val makeRequest = { + val makeRequestOpt = methods.get(self.MakeRequest) + if (makeRequestOpt.isEmpty) throw new IllegalArgumentException(_root_.java.lang.String.format("No implementation found for method MakeRequest in %s", methods.keySet)) + makeRequestOpt.get.asInstanceOf[self.MakeRequest.ReqRepServicePerEndpointServiceType] + } + + ReqRepServicePerEndpoint(makeRequest) + } + + @deprecated("Use ServicePerEndpoint", "2017-11-07") + case class ServiceIface( + makeRequest : com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType] + ) extends BaseServiceIface + with _root_.com.twitter.finagle.thrift.service.Filterable[ServiceIface] { + + /** + * Prepends the given type-agnostic `Filter` to all of the `Services` + * and returns a copy of the `ServiceIface` now including the filter. + */ + def filtered(filter: com.twitter.finagle.Filter.TypeAgnostic): ServiceIface = + copy( + makeRequest = filter.toFilter.andThen(makeRequest) + ) + } + + implicit object ServicePerEndpointBuilder + extends _root_.com.twitter.finagle.thrift.service.ServicePerEndpointBuilder[ServicePerEndpoint] { + override def serviceClass: Class[ServicePerEndpoint] = classOf[ServicePerEndpoint] + def servicePerEndpoint( + thriftService: _root_.com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + clientParam: RichClientParam + ): ServicePerEndpoint = + ServicePerEndpoint( + makeRequest = _root_.com.twitter.finagle.thrift.service.ThriftServicePerEndpoint( + self.MakeRequest, + thriftService, + clientParam + ) + ) + } + + implicit object ReqRepServicePerEndpointBuilder + extends _root_.com.twitter.finagle.thrift.service.ReqRepServicePerEndpointBuilder[ReqRepServicePerEndpoint] { + override def serviceClass: Class[ReqRepServicePerEndpoint] = classOf[ReqRepServicePerEndpoint] + def servicePerEndpoint( + thriftService: _root_.com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + clientParam: RichClientParam + ): ReqRepServicePerEndpoint = + ReqRepServicePerEndpoint( + makeRequest = _root_.com.twitter.finagle.thrift.service.ThriftReqRepServicePerEndpoint(self.MakeRequest, thriftService, clientParam) + ) + } + + @deprecated("Use ServicePerEndpointBuilder", "2017-11-07") + implicit object ServiceIfaceBuilder + extends com.twitter.finagle.thrift.ServiceIfaceBuilder[ServiceIface] { + override def serviceClass: Class[ServiceIface] = classOf[ServiceIface] + def newServiceIface( + binaryService: com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + clientParam: RichClientParam + ): ServiceIface = + ServiceIface( + makeRequest = _root_.com.twitter.finagle.thrift.service.ThriftServicePerEndpoint( + self.MakeRequest, + binaryService, + clientParam + ) + ) + } + + object MakeRequest extends ThriftMethod { + + object Args extends ValidatingThriftStructCodec3[Args] with StructBuilderFactory[Args] { + private[this] val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols() + + val Struct: TStruct = new TStruct("makeRequest_args") + val RequestField: TField = new TField("request", TType.STRUCT, 1) + val RequestFieldManifest: Manifest[example.thrift.SimpleRequest] = manifest[example.thrift.SimpleRequest] + + /** + * Field information in declaration order. + */ + lazy val fieldInfos: scala.List[ThriftStructFieldInfo] = scala.List[ThriftStructFieldInfo]( + new ThriftStructFieldInfo( + RequestField, + false, + true, + RequestFieldManifest, + _root_.scala.None, + _root_.scala.None, + immutable$Map.empty[String, String], + immutable$Map.empty[String, String], + None, + _root_.scala.Option(example.thrift.SimpleRequest.unsafeEmpty) + ) + ) + + + val structAnnotations: immutable$Map[String, String] = + immutable$Map.empty[String, String] + + private val fieldTypes: IndexedSeq[ClassTag[_]] = IndexedSeq[ClassTag[_]]( + classTag[example.thrift.SimpleRequest].asInstanceOf[ClassTag[_]] + ) + + private[this] val structFields: Seq[ThriftStructField[Args]] = Seq[ThriftStructField[Args]]( + new ThriftStructField[Args]( + RequestField, + _root_.scala.Some(RequestFieldManifest), + classOf[Args]) { + def getValue[R](struct: Args): R = struct.request.asInstanceOf[R] + } + ) + + override lazy val metaData: ThriftStructMetaData[Args] = + ThriftStructMetaData(this, structFields, fieldInfos, Nil, structAnnotations) + + /** + * Checks that all required fields are non-null. + */ + def validate(_item: Args): Unit = { + if (_item.request eq null) throw new TProtocolException("Required field request cannot be null") + } + + /** + * Checks that the struct is a valid as a new instance. If there are any missing required or + * construction required fields, return a non-empty list. + */ + def validateNewInstance(item: Args): scala.Seq[com.twitter.scrooge.validation.Issue] = { + val buf = scala.collection.mutable.ListBuffer.empty[com.twitter.scrooge.validation.Issue] + + if (item.request eq null) + buf += com.twitter.scrooge.validation.MissingRequiredField(fieldInfos.apply(0)) + buf ++= validateField(item.request) + buf.toList + } + + /** + * Validate that all validation annotations on the struct meet the criteria defined in the + * corresponding [[com.twitter.scrooge.validation.ThriftConstraintValidator]]. + */ + def validateInstanceValue(item: Args): Set[com.twitter.scrooge.validation.ThriftValidationViolation] = { + val thriftValidator = com.twitter.scrooge.ThriftValidator() + val violations = scala.collection.mutable.Set.empty[com.twitter.scrooge.validation.ThriftValidationViolation] + val fieldInfo0 = fieldInfos.apply(0) + violations ++= validateFieldValue(fieldInfo0.tfield.name, item.request, fieldInfo0.fieldAnnotations, thriftValidator) + violations.toSet + } + + def withoutPassthroughFields(original: Args): Args = + new Args( + request = + { + val field = original.request + example.thrift.SimpleRequest.withoutPassthroughFields(field) + } + ) + + lazy val unsafeEmpty: Args = { + val request: example.thrift.SimpleRequest = example.thrift.SimpleRequest.unsafeEmpty + + new Args( + request, + _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + ) + } + + def newBuilder(): StructBuilder[Args] = new ArgsStructBuilder(_root_.scala.None, fieldTypes) + + override def encode(_item: Args, _oproto: TProtocol): Unit = { + _item.write(_oproto) + } + + + override def decode(_iprot: TProtocol): Args = { + decodeInternal(_iprot, false) + } + + private[this] def decodeInternal(_iprot: TProtocol, lazily: Boolean): Args = { + var request: example.thrift.SimpleRequest = null + var _got_request = false + + var _passthroughFields: Builder[(Short, TFieldBlob), immutable$Map[Short, TFieldBlob]] = null + var _done = false + + _iprot.readStructBegin() + do { + val _field = _iprot.readFieldBegin() + val _fieldType = _field.`type` + if (_fieldType == TType.STOP) { + _done = true + } else { + _field.id match { + case 1 => + _root_.com.twitter.scrooge.internal.TProtocols.validateFieldType(TType.STRUCT, _fieldType, "request") + request = example.thrift.SimpleRequest.decode(_iprot) + _got_request = true + case _ => + _passthroughFields = _root_.com.twitter.scrooge.internal.TProtocols.readPassthroughField(_iprot, _field, _passthroughFields) + } + _iprot.readFieldEnd() + } + } while (!_done) + _iprot.readStructEnd() + + if (!_got_request) _root_.com.twitter.scrooge.internal.TProtocols.throwMissingRequiredField("Args", "request") + + val _passthroughFieldsResult = + if (_passthroughFields eq null) _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + else _passthroughFields.result() + new Args( + request, + _passthroughFieldsResult + ) + } + + def apply( + request: example.thrift.SimpleRequest + ): Args = + new Args( + request + ) + + def unapply(_item: Args): _root_.scala.Option[example.thrift.SimpleRequest] = _root_.scala.Some(_item.request) + + + + } + + class Args( + val request: example.thrift.SimpleRequest, + val _passthroughFields: immutable$Map[Short, TFieldBlob]) + extends ThriftStruct + with _root_.scala.Product1[example.thrift.SimpleRequest] + with ValidatingThriftStruct[Args] + with java.io.Serializable + { + import Args._ + + def this( + request: example.thrift.SimpleRequest + ) = this( + request, + immutable$Map.empty + ) + + def _1: example.thrift.SimpleRequest = request + + + + override def write(_oprot: TProtocol): Unit = { + Args.validate(this) + val _protos = _root_.com.twitter.scrooge.internal.TProtocols() + _oprot.writeStructBegin(Struct) + if (request ne null) { + _oprot.writeFieldBegin(RequestField) + request.write(_oprot) + _oprot.writeFieldEnd() + } + _root_.com.twitter.scrooge.internal.TProtocols.finishWritingStruct(_oprot, _passthroughFields) + } + + def copy( + request: example.thrift.SimpleRequest = this.request, + _passthroughFields: immutable$Map[Short, TFieldBlob] = this._passthroughFields + ): Args = + new Args( + request, + _passthroughFields + ) + + override def canEqual(other: Any): Boolean = other.isInstanceOf[Args] + + private[this] def _equals(other: Args): Boolean = + this.productArity == other.productArity && + this.productIterator.sameElements(other.productIterator) && + this._passthroughFields == other._passthroughFields + + override def equals(other: Any): Boolean = + canEqual(other) && _equals(other.asInstanceOf[Args]) + + override def hashCode: Int = { + _root_.scala.runtime.ScalaRunTime._hashCode(this) + } + + override def toString: String = _root_.scala.runtime.ScalaRunTime._toString(this) + + override def productPrefix: String = "Args" + + def _codec: ValidatingThriftStructCodec3[Args] = Args + + def newBuilder(): StructBuilder[Args] = new ArgsStructBuilder(_root_.scala.Some(this), fieldTypes) + } + + private[thrift] class ArgsStructBuilder(instance: _root_.scala.Option[Args], fieldTypes: IndexedSeq[ClassTag[_]]) + extends StructBuilder[Args](fieldTypes) { + + def build(): Args = { + val _fieldArray = fieldArray // shadow variable + if (instance.isDefined) { + val instanceValue = instance.get + Args( + if (_fieldArray(0) == null) instanceValue.request else _fieldArray(0).asInstanceOf[example.thrift.SimpleRequest] + ) + } else { + if (genericArrayOps(_fieldArray).contains(null)) throw new InvalidFieldsException(structBuildError("Args")) + Args( + _fieldArray(0).asInstanceOf[example.thrift.SimpleRequest] + ) + } + } + } + + type SuccessType = example.thrift.SimpleResponse + + object Result extends ValidatingThriftStructCodec3[Result] with StructBuilderFactory[Result] { + private[this] val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols() + + val Struct: TStruct = new TStruct("makeRequest_result") + val SuccessField: TField = new TField("success", TType.STRUCT, 0) + val SuccessFieldManifest: Manifest[example.thrift.SimpleResponse] = manifest[example.thrift.SimpleResponse] + + /** + * Field information in declaration order. + */ + lazy val fieldInfos: scala.List[ThriftStructFieldInfo] = scala.List[ThriftStructFieldInfo]( + new ThriftStructFieldInfo( + SuccessField, + true, + false, + SuccessFieldManifest, + _root_.scala.None, + _root_.scala.None, + immutable$Map.empty[String, String], + immutable$Map.empty[String, String], + None, + _root_.scala.Option(example.thrift.SimpleResponse.unsafeEmpty) + ) + ) + + + val structAnnotations: immutable$Map[String, String] = + immutable$Map.empty[String, String] + + private val fieldTypes: IndexedSeq[ClassTag[_]] = IndexedSeq[ClassTag[_]]( + classTag[_root_.scala.Option[example.thrift.SimpleResponse]].asInstanceOf[ClassTag[_]] + ) + + private[this] val structFields: Seq[ThriftStructField[Result]] = Seq[ThriftStructField[Result]]( + new ThriftStructField[Result]( + SuccessField, + _root_.scala.Some(SuccessFieldManifest), + classOf[Result]) { + def getValue[R](struct: Result): R = struct.success.asInstanceOf[R] + } + ) + + override lazy val metaData: ThriftStructMetaData[Result] = + ThriftStructMetaData(this, structFields, fieldInfos, Nil, structAnnotations) + + /** + * Checks that all required fields are non-null. + */ + def validate(_item: Result): Unit = { + } + + /** + * Checks that the struct is a valid as a new instance. If there are any missing required or + * construction required fields, return a non-empty list. + */ + def validateNewInstance(item: Result): scala.Seq[com.twitter.scrooge.validation.Issue] = { + val buf = scala.collection.mutable.ListBuffer.empty[com.twitter.scrooge.validation.Issue] + + buf ++= validateField(item.success) + buf.toList + } + + /** + * Validate that all validation annotations on the struct meet the criteria defined in the + * corresponding [[com.twitter.scrooge.validation.ThriftConstraintValidator]]. + */ + def validateInstanceValue(item: Result): Set[com.twitter.scrooge.validation.ThriftValidationViolation] = { + val thriftValidator = com.twitter.scrooge.ThriftValidator() + val violations = scala.collection.mutable.Set.empty[com.twitter.scrooge.validation.ThriftValidationViolation] + val fieldInfo0 = fieldInfos.apply(0) + violations ++= validateFieldValue(fieldInfo0.tfield.name, item.success, fieldInfo0.fieldAnnotations, thriftValidator) + violations.toSet + } + + def withoutPassthroughFields(original: Result): Result = + new Result( + success = + { + val field = original.success + field.map { field => + example.thrift.SimpleResponse.withoutPassthroughFields(field) + } + } + ) + + lazy val unsafeEmpty: Result = { + val success: _root_.scala.Option[example.thrift.SimpleResponse] = _root_.scala.None + + new Result( + success, + _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + ) + } + + def newBuilder(): StructBuilder[Result] = new ResultStructBuilder(_root_.scala.None, fieldTypes) + + override def encode(_item: Result, _oproto: TProtocol): Unit = { + _item.write(_oproto) + } + + + override def decode(_iprot: TProtocol): Result = { + decodeInternal(_iprot, false) + } + + private[this] def decodeInternal(_iprot: TProtocol, lazily: Boolean): Result = { + var success: Option[example.thrift.SimpleResponse] = None + + var _passthroughFields: Builder[(Short, TFieldBlob), immutable$Map[Short, TFieldBlob]] = null + var _done = false + + _iprot.readStructBegin() + do { + val _field = _iprot.readFieldBegin() + val _fieldType = _field.`type` + if (_fieldType == TType.STOP) { + _done = true + } else { + _field.id match { + case 0 => + _root_.com.twitter.scrooge.internal.TProtocols.validateFieldType(TType.STRUCT, _fieldType, "success") + success = _root_.scala.Some(example.thrift.SimpleResponse.decode(_iprot)) + case _ => + _passthroughFields = _root_.com.twitter.scrooge.internal.TProtocols.readPassthroughField(_iprot, _field, _passthroughFields) + } + _iprot.readFieldEnd() + } + } while (!_done) + _iprot.readStructEnd() + + + val _passthroughFieldsResult = + if (_passthroughFields eq null) _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + else _passthroughFields.result() + new Result( + success, + _passthroughFieldsResult + ) + } + + def apply( + success: _root_.scala.Option[example.thrift.SimpleResponse] = _root_.scala.None + ): Result = + new Result( + success + ) + + def unapply(_item: Result): _root_.scala.Option[_root_.scala.Option[example.thrift.SimpleResponse]] = _root_.scala.Some(_item.success) + + + + } + + class Result( + val success: _root_.scala.Option[example.thrift.SimpleResponse], + val _passthroughFields: immutable$Map[Short, TFieldBlob]) + extends ThriftResponse[example.thrift.SimpleResponse] with ThriftStruct + with _root_.scala.Product1[Option[example.thrift.SimpleResponse]] + with ValidatingThriftStruct[Result] + with java.io.Serializable + { + import Result._ + + def this( + success: _root_.scala.Option[example.thrift.SimpleResponse] = _root_.scala.None + ) = this( + success, + immutable$Map.empty + ) + + def _1: _root_.scala.Option[example.thrift.SimpleResponse] = success + + def successField: Option[example.thrift.SimpleResponse] = success + def exceptionFields: Iterable[Option[com.twitter.scrooge.ThriftException]] = Nil + + + override def write(_oprot: TProtocol): Unit = { + Result.validate(this) + val _protos = _root_.com.twitter.scrooge.internal.TProtocols() + _oprot.writeStructBegin(Struct) + if (success.isDefined) { + _oprot.writeFieldBegin(SuccessField) + success.get.write(_oprot) + _oprot.writeFieldEnd() + } + _root_.com.twitter.scrooge.internal.TProtocols.finishWritingStruct(_oprot, _passthroughFields) + } + + def copy( + success: _root_.scala.Option[example.thrift.SimpleResponse] = this.success, + _passthroughFields: immutable$Map[Short, TFieldBlob] = this._passthroughFields + ): Result = + new Result( + success, + _passthroughFields + ) + + override def canEqual(other: Any): Boolean = other.isInstanceOf[Result] + + private[this] def _equals(other: Result): Boolean = + this.productArity == other.productArity && + this.productIterator.sameElements(other.productIterator) && + this._passthroughFields == other._passthroughFields + + override def equals(other: Any): Boolean = + canEqual(other) && _equals(other.asInstanceOf[Result]) + + override def hashCode: Int = { + _root_.scala.runtime.ScalaRunTime._hashCode(this) + } + + override def toString: String = _root_.scala.runtime.ScalaRunTime._toString(this) + + override def productPrefix: String = "Result" + + def _codec: ValidatingThriftStructCodec3[Result] = Result + + def newBuilder(): StructBuilder[Result] = new ResultStructBuilder(_root_.scala.Some(this), fieldTypes) + } + + private[thrift] class ResultStructBuilder(instance: _root_.scala.Option[Result], fieldTypes: IndexedSeq[ClassTag[_]]) + extends StructBuilder[Result](fieldTypes) { + + def build(): Result = { + val _fieldArray = fieldArray // shadow variable + if (instance.isDefined) { + val instanceValue = instance.get + Result( + if (_fieldArray(0) == null) instanceValue.success else _fieldArray(0).asInstanceOf[_root_.scala.Option[example.thrift.SimpleResponse]] + ) + } else { + if (genericArrayOps(_fieldArray).contains(null)) throw new InvalidFieldsException(structBuildError("Result")) + Result( + _fieldArray(0).asInstanceOf[_root_.scala.Option[example.thrift.SimpleResponse]] + ) + } + } + } + + val annotations: immutable$Map[String, String] = immutable$Map.empty + + type FunctionType = Function1[Args,Future[example.thrift.SimpleResponse]] + type ReqRepFunctionType = Function1[_root_.com.twitter.scrooge.Request[Args],Future[_root_.com.twitter.scrooge.Response[example.thrift.SimpleResponse]]] + + type ServicePerEndpointServiceType = _root_.com.twitter.finagle.Service[Args, SuccessType] + type ReqRepServicePerEndpointServiceType = _root_.com.twitter.finagle.Service[_root_.com.twitter.scrooge.Request[Args], _root_.com.twitter.scrooge.Response[SuccessType]] + + def toServicePerEndpointService(f: FunctionType): ServicePerEndpointServiceType = + _root_.com.twitter.finagle.Service.mk { args: Args => + f(args) + } + + def toReqRepServicePerEndpointService(f: ReqRepFunctionType): ReqRepServicePerEndpointServiceType = + _root_.com.twitter.finagle.Service.mk[_root_.com.twitter.scrooge.Request[Args], _root_.com.twitter.scrooge.Response[SuccessType]] { request: _root_.com.twitter.scrooge.Request[Args] => + f(request) + } + + + val name: String = "MakeRequest" + val serviceName: String = "SimpleService" + val argsCodec: Args.type = Args + val responseCodec: Result.type = Result + val oneway: Boolean = false + } + + // Compatibility aliases. + val makeRequest$args: MakeRequest.Args.type = MakeRequest.Args + type makeRequest$args = MakeRequest.Args + + val makeRequest$result: MakeRequest.Result.type = MakeRequest.Result + type makeRequest$result = MakeRequest.Result + + + trait MethodPerEndpoint + extends SimpleService[Future] { + + def makeRequest(request: example.thrift.SimpleRequest): Future[example.thrift.SimpleResponse] + } + + object MethodPerEndpoint { + + def apply(servicePerEndpoint: ServicePerEndpoint): MethodPerEndpoint = { + new MethodPerEndpointImpl(servicePerEndpoint) {} + } + + /** + * Use `MethodPerEndpoint.apply()` instead of this constructor. + */ + class MethodPerEndpointImpl protected (servicePerEndpoint: ServicePerEndpoint) + extends MethodPerEndpoint { + def makeRequest(request: example.thrift.SimpleRequest): Future[example.thrift.SimpleResponse] = + servicePerEndpoint.makeRequest(self.MakeRequest.Args(request)) + + override def asClosable: _root_.com.twitter.util.Closable = + servicePerEndpoint.asClosable + } + } + + object ReqRepMethodPerEndpoint { + + def apply(servicePerEndpoint: ReqRepServicePerEndpoint): MethodPerEndpoint = + new ReqRepMethodPerEndpointImpl(servicePerEndpoint) { } + + /** + * Use `ReqRepMethodPerEndpoint.apply()` instead of this constructor. + */ + class ReqRepMethodPerEndpointImpl protected (servicePerEndpoint: ReqRepServicePerEndpoint) + extends MethodPerEndpoint { + + def makeRequest(request: example.thrift.SimpleRequest): Future[example.thrift.SimpleResponse] = { + val requestCtx = _root_.com.twitter.finagle.context.Contexts.local.getOrElse(_root_.com.twitter.finagle.thrift.Headers.Request.Key, () => _root_.com.twitter.finagle.thrift.Headers.Request.newValues) + val scroogeRequest = _root_.com.twitter.scrooge.Request(requestCtx.values, self.MakeRequest.Args(request)) + servicePerEndpoint.makeRequest(scroogeRequest).transform(_root_.com.twitter.finagle.thrift.service.ThriftReqRepServicePerEndpoint.transformResult) + } + + override def asClosable: _root_.com.twitter.util.Closable = + servicePerEndpoint.asClosable + } + } + + @deprecated("Use MethodPerEndpoint", "2017-11-07") + class MethodIface(serviceIface: BaseServiceIface) + extends FutureIface { + def makeRequest(request: example.thrift.SimpleRequest): Future[example.thrift.SimpleResponse] = + serviceIface.makeRequest(self.MakeRequest.Args(request)) + } + + implicit object MethodPerEndpointBuilder + extends _root_.com.twitter.finagle.thrift.service.MethodPerEndpointBuilder[ServicePerEndpoint, MethodPerEndpoint] { + def methodPerEndpoint(servicePerEndpoint: ServicePerEndpoint): MethodPerEndpoint = + MethodPerEndpoint(servicePerEndpoint) + } + + @deprecated("Use MethodPerEndpointBuilder", "2018-01-12") + implicit object ThriftServiceBuilder + extends _root_.com.twitter.finagle.thrift.service.ThriftServiceBuilder[ServicePerEndpoint, SimpleService[Future]] { + def build(servicePerEndpoint: ServicePerEndpoint): MethodPerEndpoint = + MethodPerEndpoint(servicePerEndpoint) + } + + implicit object ReqRepMethodPerEndpointBuilder + extends _root_.com.twitter.finagle.thrift.service.ReqRepMethodPerEndpointBuilder[ReqRepServicePerEndpoint, MethodPerEndpoint] { + def methodPerEndpoint(servicePerEndpoint: ReqRepServicePerEndpoint): MethodPerEndpoint = + ReqRepMethodPerEndpoint(servicePerEndpoint) + } + + @deprecated("Use MethodPerEndpointBuilder", "2017-11-07") + implicit object MethodIfaceBuilder + extends com.twitter.finagle.thrift.MethodIfaceBuilder[ServiceIface, SimpleService[Future]] { + def newMethodIface(serviceIface: ServiceIface): MethodIface = + new MethodIface(serviceIface) + } + + @deprecated("Use MethodPerEndpoint", "2017-11-07") + trait FutureIface + extends SimpleService[Future] { + + def makeRequest(request: example.thrift.SimpleRequest): Future[example.thrift.SimpleResponse] + } + + class FinagledClient( + service: com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + clientParam: RichClientParam) + extends SimpleService$FinagleClient(service, clientParam) + with FutureIface + with MethodPerEndpoint { + + @deprecated("Use com.twitter.finagle.thrift.RichClientParam", "2017-08-16") + def this( + service: com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + protocolFactory: org.apache.thrift.protocol.TProtocolFactory = Protocols.binaryFactory(), + serviceName: String = "SimpleService", + stats: com.twitter.finagle.stats.StatsReceiver = com.twitter.finagle.stats.NullStatsReceiver, + responseClassifier: ctfs.ResponseClassifier = ctfs.ResponseClassifier.Default + ) = this( + service, + RichClientParam( + protocolFactory, + serviceName, + clientStats = stats, + responseClassifier = responseClassifier + ) + ) + + @deprecated("Use com.twitter.finagle.thrift.RichClientParam", "2017-08-16") + def this( + service: com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + protocolFactory: org.apache.thrift.protocol.TProtocolFactory, + serviceName: String, + stats: com.twitter.finagle.stats.StatsReceiver + ) = this( + service, + RichClientParam( + protocolFactory, + serviceName, + clientStats = stats + ) + ) + } + + class FinagledService( + iface: SimpleService[Future], + serverParam: RichServerParam) + extends SimpleService$FinagleService(iface, serverParam) { + + @deprecated("Use com.twitter.finagle.thrift.RichServerParam", "2017-08-16") + def this( + iface: SimpleService[Future], + protocolFactory: org.apache.thrift.protocol.TProtocolFactory, + serviceName: String = "SimpleService" + ) = this(iface, RichServerParam(protocolFactory, serviceName)) + } + + class Filter(serverParam: RichServerParam) { + private[this] def protocolFactory: TProtocolFactory = serverParam.restrictedProtocolFactory + + private[this] def serviceName: String = serverParam.serviceName + private[this] def responseClassifier: ctfs.ResponseClassifier = serverParam.responseClassifier + private[this] def stats: StatsReceiver = serverParam.serverStats + private[this] def perEndpointStats: Boolean = serverParam.perEndpointStats && !stats.isNull + + private[this] val tlReusableBuffer: TReusableBuffer = TReusableBuffer(maxThriftBufferSize = serverParam.maxThriftBufferSize) + + private[thrift] def exception(name: String, seqid: Int, code: Int, message: String): Buf = { + val x = new TApplicationException(code, message) + val memoryBuffer = tlReusableBuffer.get() + try { + val oprot = protocolFactory.getProtocol(memoryBuffer) + + oprot.writeMessageBegin(new TMessage(name, TMessageType.EXCEPTION, seqid)) + x.write(oprot) + oprot.writeMessageEnd() + oprot.getTransport.flush() + + // make a copy of the array of bytes to construct a new buffer because memoryBuffer is reusable + Buf.ByteArray.Shared(memoryBuffer.getArray(), 0, memoryBuffer.length()) + } finally { + tlReusableBuffer.reset() + } + } + + private[this] def reply(name: String, seqid: Int, result: ThriftStruct): Buf = { + val memoryBuffer = tlReusableBuffer.get() + try { + val oprot = protocolFactory.getProtocol(memoryBuffer) + val start = System.nanoTime + oprot.writeMessageBegin(new TMessage(name, TMessageType.REPLY, seqid)) + result.write(oprot) + oprot.writeMessageEnd() + val trace = _root_.com.twitter.finagle.tracing.Trace() + if (trace.isActivelyTracing) { + trace.recordBinary("srv/response_serialization_ns", System.nanoTime - start) + } + oprot.getTransport.flush() + + // make a copy of the array of bytes to construct a new buffer because memoryBuffer is reusable + Buf.ByteArray.Shared(memoryBuffer.getArray(), 0, memoryBuffer.length()) + } finally { + tlReusableBuffer.reset() + } + } + + private[this] def recordResponse(reqRep: ctfs.ReqRep, methodStats: _root_.com.twitter.finagle.thrift.ThriftMethodStats): Unit = { + ServerToReqRep.setCtx(reqRep) + val classified = responseClassifier.applyOrElse(reqRep, ctfs.ResponseClassifier.Default) + if (classified.isInstanceOf[ctfs.ResponseClass.Successful]) { + methodStats.successCounter.incr() + } else if (classified.isInstanceOf[ctfs.ResponseClass.Failed]) { + methodStats.failuresCounter.incr() + if (reqRep.response.isThrow) { + methodStats.failuresScope.counter(Throwables.mkString(reqRep.response.throwable): _*).incr() + } + } // Last ResponseClass is Ignorable, which we do not need to record + } + + final protected def perMethodStatsFilter( + method: ThriftMethod + ): finagle$Filter[(TProtocol, Int), Array[Byte], (TProtocol, Int), RichResponse[method.Args, method.Result]] = { + val methodStats = if (perEndpointStats) { + _root_.com.twitter.finagle.thrift.ThriftMethodStats((if (serviceName != "") stats.scope(serviceName) else stats).scope(method.name)) + } else { + _root_.com.twitter.finagle.thrift.ThriftMethodStats.Null + } + + new finagle$Filter[(TProtocol, Int), Array[Byte], (TProtocol, Int), RichResponse[method.Args, method.Result]] { + def apply( + req: (TProtocol, Int), + service: finagle$Service[(TProtocol, Int), RichResponse[method.Args, method.Result]] + ): Future[Array[Byte]] = { + methodStats.requestsCounter.incr() + service(req).transform { response => + if (response.isReturn) { + val value = response.apply() + if (value.isInstanceOf[SuccessfulResponse[method.Args, method.Result]]) { + val succResp = value.asInstanceOf[SuccessfulResponse[method.Args, method.Result]] + recordResponse(ctfs.ReqRep(succResp.input, _root_.com.twitter.util.Return(succResp.result.successField.get)), methodStats) + } else if (value.isInstanceOf[ProtocolExceptionResponse[method.Args, method.Result]]) { + val protExResp = value.asInstanceOf[ProtocolExceptionResponse[method.Args, method.Result]] + recordResponse(ctfs.ReqRep(protExResp.input, _root_.com.twitter.util.Throw(protExResp.exception)), methodStats) + } else if (value.isInstanceOf[ThriftExceptionResponse[method.Args, method.Result]]) { + val thriftExResp = value.asInstanceOf[ThriftExceptionResponse[method.Args, method.Result]] + val rep: Throwable = if (thriftExResp.ex.isInstanceOf[ThriftException]) { + _root_.com.twitter.finagle.SourcedException.setServiceName(thriftExResp.ex, serviceName) + } else { + _root_.com.twitter.scrooge.internal.ApplicationExceptions.missingResult(serviceName) + } + recordResponse(ctfs.ReqRep(thriftExResp.input, _root_.com.twitter.util.Throw(rep)), methodStats) + } + Future.value(Buf.ByteArray.Owned.extract(value.response)) + } else { // Throw[_] + recordResponse(ctfs.ReqRep(req, response), methodStats) + Future.const(response.asInstanceOf[Throw[Array[Byte]]]) + } + } + } + } + } + // ---- end boilerplate. + + val makeRequest: finagle$Filter[(TProtocol, Int), Array[Byte], MakeRequest.Args, MakeRequest.SuccessType] = { + val statsFilter: finagle$Filter[(TProtocol, Int), Array[Byte], (TProtocol, Int), RichResponse[MakeRequest.Args, MakeRequest.Result]] = perMethodStatsFilter(MakeRequest) + + val protocolExnFilter = new SimpleFilter[(TProtocol, Int), RichResponse[MakeRequest.Args, MakeRequest.Result]] { + def apply( + request: (TProtocol, Int), + service: _root_.com.twitter.finagle.Service[(TProtocol, Int), RichResponse[MakeRequest.Args, MakeRequest.Result]] + ): Future[RichResponse[MakeRequest.Args, MakeRequest.Result]] = { + val iprot = request._1 + val seqid = request._2 + val res = service(request) + res.transform(resTry => { + if (resTry.isThrow && resTry.throwable.isInstanceOf[TProtocolException]) { + val underlyingException = resTry.throwable + iprot.readMessageEnd() + Future.value( + ProtocolExceptionResponse( + null, + exception("MakeRequest", seqid, TApplicationException.PROTOCOL_ERROR, underlyingException.getMessage), + new TApplicationException(TApplicationException.PROTOCOL_ERROR, underlyingException.getMessage))) + } else { + res + } + }) + } + } + + val serdeFilter = new finagle$Filter[(TProtocol, Int), RichResponse[MakeRequest.Args, MakeRequest.Result], MakeRequest.Args, MakeRequest.SuccessType] { + def apply( + request: (TProtocol, Int), + service: _root_.com.twitter.finagle.Service[MakeRequest.Args, MakeRequest.SuccessType] + ): Future[RichResponse[MakeRequest.Args, MakeRequest.Result]] = { + val iprot = request._1 + val seqid = request._2 + val start = System.nanoTime + val args = MakeRequest.Args.decode(iprot) + iprot.readMessageEnd() + val trace = _root_.com.twitter.finagle.tracing.Trace() + if (trace.isActivelyTracing) { + trace.recordBinary("srv/request_deserialization_ns", System.nanoTime - start) + } + _root_.com.twitter.finagle.context.Contexts.local.let( + _root_.com.twitter.finagle.thrift.MethodMetadata.Key, + _root_.com.twitter.finagle.thrift.MethodMetadata(MakeRequest)) { + service(args) + }.transform(resTry => { + if (resTry.isReturn) { + val methodResult = MakeRequest.Result(success = Some(resTry.apply())) + Future.value( + SuccessfulResponse( + args, + reply("MakeRequest", seqid, methodResult), + methodResult)) + } else { // Throw[_] + Future.const(resTry.asInstanceOf[Throw[RichResponse[MakeRequest.Args, MakeRequest.Result]]]) + } + }) + } + } + statsFilter.andThen(protocolExnFilter).andThen(serdeFilter) + } + } + +} diff --git a/scalafix/input/src/main/thrift/Simple.thrift b/scalafix/input/src/main/thrift/Simple.thrift new file mode 100644 index 000000000..83e04d275 --- /dev/null +++ b/scalafix/input/src/main/thrift/Simple.thrift @@ -0,0 +1,13 @@ +namespace java example.thrift + +struct SimpleRequest { + 1: required string id; +} + +struct SimpleResponse { + 1: required string id; +} + +service SimpleService { + SimpleResponse MakeRequest(1: required SimpleRequest request) +} diff --git a/scalafix/output/src/main/scala/example/thrift/SimpleRequest.scala b/scalafix/output/src/main/scala/example/thrift/SimpleRequest.scala new file mode 100644 index 000000000..6cbd1025e --- /dev/null +++ b/scalafix/output/src/main/scala/example/thrift/SimpleRequest.scala @@ -0,0 +1,443 @@ +/** + * Generated by Scrooge + * version: 21.8.0 + * rev: 75b832815f5da5328f0225e2ab3e06a14afb3446 + * built at: 20210813-170828 + */ +package example.thrift + +import com.twitter.io.Buf +import com.twitter.scrooge.{ + InvalidFieldsException, + LazyTProtocol, + StructBuilder, + StructBuilderFactory, + TFieldBlob, + ThriftStruct, + ThriftStructCodec3, + ThriftStructField, + ThriftStructFieldInfo, + ThriftStructMetaData, + ValidatingThriftStruct, + ValidatingThriftStructCodec3 +} +import org.apache.thrift.protocol._ +import org.apache.thrift.transport.TMemoryBuffer +import scala.collection.immutable.{Map => immutable$Map} +import scala.collection.mutable.Builder +import scala.reflect.{ClassTag, classTag} + + +object SimpleRequest extends ValidatingThriftStructCodec3[SimpleRequest] with StructBuilderFactory[SimpleRequest] { + private[this] val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols() + + val Struct: TStruct = new TStruct("SimpleRequest") + val IdField: TField = new TField("id", TType.STRING, 1) + val IdFieldManifest: Manifest[String] = manifest[String] + + /** + * Field information in declaration order. + */ + lazy val fieldInfos: scala.List[ThriftStructFieldInfo] = scala.List[ThriftStructFieldInfo]( + new ThriftStructFieldInfo( + IdField, + false, + true, + IdFieldManifest, + _root_.scala.None, + _root_.scala.None, + immutable$Map.empty[String, String], + immutable$Map.empty[String, String], + None, + _root_.scala.Option("empty") + ) + ) + + + val structAnnotations: immutable$Map[String, String] = + immutable$Map.empty[String, String] + + private val fieldTypes: IndexedSeq[ClassTag[_]] = IndexedSeq[ClassTag[_]]( + classTag[String].asInstanceOf[ClassTag[_]] + ) + + private[this] val structFields: Seq[ThriftStructField[SimpleRequest]] = Seq[ThriftStructField[SimpleRequest]]( + new ThriftStructField[SimpleRequest]( + IdField, + _root_.scala.Some(IdFieldManifest), + classOf[SimpleRequest]) { + def getValue[R](struct: SimpleRequest): R = struct.id.asInstanceOf[R] + } + ) + + override lazy val metaData: ThriftStructMetaData[SimpleRequest] = + ThriftStructMetaData(this, structFields, fieldInfos, Nil, structAnnotations) + + /** + * Checks that all required fields are non-null. + */ + def validate(_item: SimpleRequest): Unit = { + if (_item.id eq null) throw new TProtocolException("Required field id cannot be null") + } + + /** + * Checks that the struct is a valid as a new instance. If there are any missing required or + * construction required fields, return a non-empty list. + */ + def validateNewInstance(item: SimpleRequest): scala.Seq[com.twitter.scrooge.validation.Issue] = { + val buf = scala.collection.mutable.ListBuffer.empty[com.twitter.scrooge.validation.Issue] + + if (item.id eq null) + buf += com.twitter.scrooge.validation.MissingRequiredField(fieldInfos.apply(0)) + buf ++= validateField(item.id) + buf.toList + } + + /** + * Validate that all validation annotations on the struct meet the criteria defined in the + * corresponding [[com.twitter.scrooge.validation.ThriftConstraintValidator]]. + */ + def validateInstanceValue(item: SimpleRequest): Set[com.twitter.scrooge.validation.ThriftValidationViolation] = { + val thriftValidator = com.twitter.scrooge.ThriftValidator() + val violations = scala.collection.mutable.Set.empty[com.twitter.scrooge.validation.ThriftValidationViolation] + val fieldInfo0 = fieldInfos.apply(0) + violations ++= validateFieldValue(fieldInfo0.tfield.name, item.id, fieldInfo0.fieldAnnotations, thriftValidator) + violations.toSet + } + + def withoutPassthroughFields(original: SimpleRequest): SimpleRequest = + new Immutable( + id = original.id + ) + + lazy val unsafeEmpty: SimpleRequest = { + val id: String = "empty" + + new Immutable( + id, + _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + ) + } + + def newBuilder(): StructBuilder[SimpleRequest] = new SimpleRequestStructBuilder(_root_.scala.None, fieldTypes) + + override def encode(_item: SimpleRequest, _oproto: TProtocol): Unit = { + _item.write(_oproto) + } + + + override def decode(_iprot: TProtocol): SimpleRequest = { + if (_iprot.isInstanceOf[LazyTProtocol]) { + decodeInternal(_iprot, true) + } else { + decodeInternal(_iprot, false) + } + } + + private[thrift] def eagerDecode(_iprot: TProtocol): SimpleRequest = { + decodeInternal(_iprot, false) + } + + private[this] def decodeInternal(_iprot: TProtocol, lazily: Boolean): SimpleRequest = { + var idOffset: Int = -1 + var id: String = null + var _got_id = false + + var _passthroughFields: Builder[(Short, TFieldBlob), immutable$Map[Short, TFieldBlob]] = null + var _done = false + val _start_offset = if (lazily) _iprot.asInstanceOf[LazyTProtocol].offset else -1 + + _iprot.readStructBegin() + do { + val _field = _iprot.readFieldBegin() + val _fieldType = _field.`type` + if (_fieldType == TType.STOP) { + _done = true + } else { + _field.id match { + case 1 => + _root_.com.twitter.scrooge.internal.TProtocols.validateFieldType(TType.STRING, _fieldType, "id") + if (lazily) + idOffset = _iprot.asInstanceOf[LazyTProtocol].offsetSkipString() + else + id = _iprot.readString() + _got_id = true + case _ => + _passthroughFields = _root_.com.twitter.scrooge.internal.TProtocols.readPassthroughField(_iprot, _field, _passthroughFields) + } + _iprot.readFieldEnd() + } + } while (!_done) + _iprot.readStructEnd() + + if (!_got_id) _root_.com.twitter.scrooge.internal.TProtocols.throwMissingRequiredField("SimpleRequest", "id") + + val _passthroughFieldsResult = + if (_passthroughFields eq null) _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + else _passthroughFields.result() + if (lazily) { + val _lazyProt = _iprot.asInstanceOf[LazyTProtocol] + new LazyImmutable( + _lazyProt, + _lazyProt.buffer, + _start_offset, + _lazyProt.offset, + idOffset, + _passthroughFieldsResult + ) + } else { + new Immutable( + id, + _passthroughFieldsResult + ) + } + } + + def apply( + id: String + ): SimpleRequest = + new Immutable( + id + ) + + def unapply(_item: SimpleRequest): _root_.scala.Option[String] = _root_.scala.Some(_item.id) + + + + object Immutable extends ThriftStructCodec3[SimpleRequest] { + override def encode(_item: SimpleRequest, _oproto: TProtocol): Unit = { _item.write(_oproto) } + override def decode(_iprot: TProtocol): SimpleRequest = SimpleRequest.decode(_iprot) + override lazy val metaData: ThriftStructMetaData[SimpleRequest] = SimpleRequest.metaData + } + + /** + * The default read-only implementation of SimpleRequest. You typically should not need to + * directly reference this class; instead, use the SimpleRequest.apply method to construct + * new instances. + */ + class Immutable( + val id: String, + override val _passthroughFields: immutable$Map[Short, TFieldBlob]) + extends SimpleRequest { + def this( + id: String + ) = this( + id, + immutable$Map.empty[Short, TFieldBlob] + ) + } + + /** + * This is another Immutable, this however keeps strings as lazy values that are lazily decoded from the backing + * array byte on read. + */ + private[this] class LazyImmutable( + _proto: LazyTProtocol, + _buf: Array[Byte], + _start_offset: Int, + _end_offset: Int, + idOffset: Int, + override val _passthroughFields: immutable$Map[Short, TFieldBlob]) + extends SimpleRequest { + + override def write(_oprot: TProtocol): Unit = { + if (_oprot.isInstanceOf[LazyTProtocol]) { + _oprot.asInstanceOf[LazyTProtocol].writeRaw(_buf, _start_offset, _end_offset - _start_offset) + } else { + super.write(_oprot) + } + } + + lazy val id: String = + if (idOffset == -1) + null + else { + _proto.decodeString(_buf, idOffset) + } + + /** + * Override the super hash code to make it a lazy val rather than def. + * + * Calculating the hash code can be expensive, caching it where possible + * can provide significant performance wins. (Key in a hash map for instance) + * Usually not safe since the normal constructor will accept a mutable map or + * set as an arg + * Here however we control how the class is generated from serialized data. + * With the class private and the contract that we throw away our mutable references + * having the hash code lazy here is safe. + */ + override lazy val hashCode: Int = super.hashCode + } + +} + +/** + * Prefer the companion object's [[example.thrift.SimpleRequest.apply]] + * for construction if you don't need to specify passthrough fields. + */ +trait SimpleRequest + extends ThriftStruct + with _root_.scala.Product1[String] + with ValidatingThriftStruct[SimpleRequest] + with java.io.Serializable +{ + import SimpleRequest._ + + def id: String + + def _passthroughFields: immutable$Map[Short, TFieldBlob] = immutable$Map.empty + + def _1: String = id + + + /** + * Gets a field value encoded as a binary blob using TCompactProtocol. If the specified field + * is present in the passthrough map, that value is returned. Otherwise, if the specified field + * is known and not optional and set to None, then the field is serialized and returned. + */ + def getFieldBlob(_fieldId: Short): _root_.scala.Option[TFieldBlob] = { + val passedthroughValue = _passthroughFields.get(_fieldId) + if (passedthroughValue.isDefined) { + passedthroughValue + } else { + val _protos = _root_.com.twitter.scrooge.internal.TProtocols() + val _buff = new TMemoryBuffer(32) + val _oprot = new TCompactProtocol(_buff) + + val _fieldOpt: _root_.scala.Option[TField] = _fieldId match { + case 1 => + if (id ne null) { + _oprot.writeString(id) + _root_.scala.Some(SimpleRequest.IdField) + } else { + _root_.scala.None + } + case _ => _root_.scala.None + } + if (_fieldOpt.isDefined) { + _root_.scala.Some(TFieldBlob(_fieldOpt.get, Buf.ByteArray.Owned(_buff.getArray))) + } else { + _root_.scala.None + } + } + } + + + /** + * Collects TCompactProtocol-encoded field values according to `getFieldBlob` into a map. + */ + def getFieldBlobs(ids: TraversableOnce[Short]): immutable$Map[Short, TFieldBlob] = + (ids.flatMap { id => getFieldBlob(id).map { fieldBlob => (id, fieldBlob) } }).toMap + + /** + * Sets a field using a TCompactProtocol-encoded binary blob. If the field is a known + * field, the blob is decoded and the field is set to the decoded value. If the field + * is unknown and passthrough fields are enabled, then the blob will be stored in + * _passthroughFields. + */ + def setField(_blob: TFieldBlob): SimpleRequest = { + val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols() + var id: String = this.id + var _passthroughFields = this._passthroughFields + val _iprot = _blob.read + _blob.id match { + case 1 => + id = _iprot.readString() + case _ => _passthroughFields += _root_.scala.Tuple2(_blob.id, _blob) + } + new Immutable( + id, + _passthroughFields + ) + } + + /** + * If the specified field is optional, it is set to None. Otherwise, if the field is + * known, it is reverted to its default value; if the field is unknown, it is removed + * from the passthroughFields map, if present. + */ + def unsetField(_fieldId: Short): SimpleRequest = { + var id: String = this.id + + _fieldId match { + case 1 => + id = null + case _ => + } + new Immutable( + id, + _passthroughFields - _fieldId + ) + } + + /** + * If the specified field is optional, it is set to None. Otherwise, if the field is + * known, it is reverted to its default value; if the field is unknown, it is removed + * from the passthroughFields map, if present. + */ + def unsetId: SimpleRequest = unsetField(1) + + + override def write(_oprot: TProtocol): Unit = { + SimpleRequest.validate(this) + val _protos = _root_.com.twitter.scrooge.internal.TProtocols() + _oprot.writeStructBegin(Struct) + if (id ne null) { + _oprot.writeFieldBegin(IdField) + _oprot.writeString(id) + _oprot.writeFieldEnd() + } + _root_.com.twitter.scrooge.internal.TProtocols.finishWritingStruct(_oprot, _passthroughFields) + } + + def copy( + id: String = this.id, + _passthroughFields: immutable$Map[Short, TFieldBlob] = this._passthroughFields + ): SimpleRequest = + new Immutable( + id, + _passthroughFields + ) + + override def canEqual(other: Any): Boolean = other.isInstanceOf[SimpleRequest] + + private[this] def _equals(other: SimpleRequest): Boolean = + this.productArity == other.productArity && + this.productIterator.sameElements(other.productIterator) && + this._passthroughFields == other._passthroughFields + + override def equals(other: Any): Boolean = + canEqual(other) && _equals(other.asInstanceOf[SimpleRequest]) + + override def hashCode: Int = { + _root_.scala.runtime.ScalaRunTime._hashCode(this) + } + + override def toString: String = _root_.scala.runtime.ScalaRunTime._toString(this) + + override def productPrefix: String = "SimpleRequest" + + def _codec: ValidatingThriftStructCodec3[SimpleRequest] = SimpleRequest + + def newBuilder(): StructBuilder[SimpleRequest] = new SimpleRequestStructBuilder(_root_.scala.Some(this), fieldTypes) +} + +private[thrift] class SimpleRequestStructBuilder(instance: _root_.scala.Option[SimpleRequest], fieldTypes: IndexedSeq[ClassTag[_]]) + extends StructBuilder[SimpleRequest](fieldTypes) { + + def build(): SimpleRequest = { + val _fieldArray = fieldArray // shadow variable + if (instance.isDefined) { + val instanceValue = instance.get + SimpleRequest( + if (_fieldArray(0) == null) instanceValue.id else _fieldArray(0).asInstanceOf[String] + ) + } else { + if (genericArrayOps(_fieldArray).contains(null)) throw new InvalidFieldsException(structBuildError("SimpleRequest")) + SimpleRequest( + _fieldArray(0).asInstanceOf[String] + ) + } + } +} + diff --git a/scalafix/output/src/main/scala/example/thrift/SimpleResponse.scala b/scalafix/output/src/main/scala/example/thrift/SimpleResponse.scala new file mode 100644 index 000000000..53b3b0865 --- /dev/null +++ b/scalafix/output/src/main/scala/example/thrift/SimpleResponse.scala @@ -0,0 +1,443 @@ +/** + * Generated by Scrooge + * version: 21.8.0 + * rev: 75b832815f5da5328f0225e2ab3e06a14afb3446 + * built at: 20210813-170828 + */ +package example.thrift + +import com.twitter.io.Buf +import com.twitter.scrooge.{ + InvalidFieldsException, + LazyTProtocol, + StructBuilder, + StructBuilderFactory, + TFieldBlob, + ThriftStruct, + ThriftStructCodec3, + ThriftStructField, + ThriftStructFieldInfo, + ThriftStructMetaData, + ValidatingThriftStruct, + ValidatingThriftStructCodec3 +} +import org.apache.thrift.protocol._ +import org.apache.thrift.transport.TMemoryBuffer +import scala.collection.immutable.{Map => immutable$Map} +import scala.collection.mutable.Builder +import scala.reflect.{ClassTag, classTag} + + +object SimpleResponse extends ValidatingThriftStructCodec3[SimpleResponse] with StructBuilderFactory[SimpleResponse] { + private[this] val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols() + + val Struct: TStruct = new TStruct("SimpleResponse") + val IdField: TField = new TField("id", TType.STRING, 1) + val IdFieldManifest: Manifest[String] = manifest[String] + + /** + * Field information in declaration order. + */ + lazy val fieldInfos: scala.List[ThriftStructFieldInfo] = scala.List[ThriftStructFieldInfo]( + new ThriftStructFieldInfo( + IdField, + false, + true, + IdFieldManifest, + _root_.scala.None, + _root_.scala.None, + immutable$Map.empty[String, String], + immutable$Map.empty[String, String], + None, + _root_.scala.Option("empty") + ) + ) + + + val structAnnotations: immutable$Map[String, String] = + immutable$Map.empty[String, String] + + private val fieldTypes: IndexedSeq[ClassTag[_]] = IndexedSeq[ClassTag[_]]( + classTag[String].asInstanceOf[ClassTag[_]] + ) + + private[this] val structFields: Seq[ThriftStructField[SimpleResponse]] = Seq[ThriftStructField[SimpleResponse]]( + new ThriftStructField[SimpleResponse]( + IdField, + _root_.scala.Some(IdFieldManifest), + classOf[SimpleResponse]) { + def getValue[R](struct: SimpleResponse): R = struct.id.asInstanceOf[R] + } + ) + + override lazy val metaData: ThriftStructMetaData[SimpleResponse] = + ThriftStructMetaData(this, structFields, fieldInfos, Nil, structAnnotations) + + /** + * Checks that all required fields are non-null. + */ + def validate(_item: SimpleResponse): Unit = { + if (_item.id eq null) throw new TProtocolException("Required field id cannot be null") + } + + /** + * Checks that the struct is a valid as a new instance. If there are any missing required or + * construction required fields, return a non-empty list. + */ + def validateNewInstance(item: SimpleResponse): scala.Seq[com.twitter.scrooge.validation.Issue] = { + val buf = scala.collection.mutable.ListBuffer.empty[com.twitter.scrooge.validation.Issue] + + if (item.id eq null) + buf += com.twitter.scrooge.validation.MissingRequiredField(fieldInfos.apply(0)) + buf ++= validateField(item.id) + buf.toList + } + + /** + * Validate that all validation annotations on the struct meet the criteria defined in the + * corresponding [[com.twitter.scrooge.validation.ThriftConstraintValidator]]. + */ + def validateInstanceValue(item: SimpleResponse): Set[com.twitter.scrooge.validation.ThriftValidationViolation] = { + val thriftValidator = com.twitter.scrooge.ThriftValidator() + val violations = scala.collection.mutable.Set.empty[com.twitter.scrooge.validation.ThriftValidationViolation] + val fieldInfo0 = fieldInfos.apply(0) + violations ++= validateFieldValue(fieldInfo0.tfield.name, item.id, fieldInfo0.fieldAnnotations, thriftValidator) + violations.toSet + } + + def withoutPassthroughFields(original: SimpleResponse): SimpleResponse = + new Immutable( + id = original.id + ) + + lazy val unsafeEmpty: SimpleResponse = { + val id: String = "empty" + + new Immutable( + id, + _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + ) + } + + def newBuilder(): StructBuilder[SimpleResponse] = new SimpleResponseStructBuilder(_root_.scala.None, fieldTypes) + + override def encode(_item: SimpleResponse, _oproto: TProtocol): Unit = { + _item.write(_oproto) + } + + + override def decode(_iprot: TProtocol): SimpleResponse = { + if (_iprot.isInstanceOf[LazyTProtocol]) { + decodeInternal(_iprot, true) + } else { + decodeInternal(_iprot, false) + } + } + + private[thrift] def eagerDecode(_iprot: TProtocol): SimpleResponse = { + decodeInternal(_iprot, false) + } + + private[this] def decodeInternal(_iprot: TProtocol, lazily: Boolean): SimpleResponse = { + var idOffset: Int = -1 + var id: String = null + var _got_id = false + + var _passthroughFields: Builder[(Short, TFieldBlob), immutable$Map[Short, TFieldBlob]] = null + var _done = false + val _start_offset = if (lazily) _iprot.asInstanceOf[LazyTProtocol].offset else -1 + + _iprot.readStructBegin() + do { + val _field = _iprot.readFieldBegin() + val _fieldType = _field.`type` + if (_fieldType == TType.STOP) { + _done = true + } else { + _field.id match { + case 1 => + _root_.com.twitter.scrooge.internal.TProtocols.validateFieldType(TType.STRING, _fieldType, "id") + if (lazily) + idOffset = _iprot.asInstanceOf[LazyTProtocol].offsetSkipString() + else + id = _iprot.readString() + _got_id = true + case _ => + _passthroughFields = _root_.com.twitter.scrooge.internal.TProtocols.readPassthroughField(_iprot, _field, _passthroughFields) + } + _iprot.readFieldEnd() + } + } while (!_done) + _iprot.readStructEnd() + + if (!_got_id) _root_.com.twitter.scrooge.internal.TProtocols.throwMissingRequiredField("SimpleResponse", "id") + + val _passthroughFieldsResult = + if (_passthroughFields eq null) _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + else _passthroughFields.result() + if (lazily) { + val _lazyProt = _iprot.asInstanceOf[LazyTProtocol] + new LazyImmutable( + _lazyProt, + _lazyProt.buffer, + _start_offset, + _lazyProt.offset, + idOffset, + _passthroughFieldsResult + ) + } else { + new Immutable( + id, + _passthroughFieldsResult + ) + } + } + + def apply( + id: String + ): SimpleResponse = + new Immutable( + id + ) + + def unapply(_item: SimpleResponse): _root_.scala.Option[String] = _root_.scala.Some(_item.id) + + + + object Immutable extends ThriftStructCodec3[SimpleResponse] { + override def encode(_item: SimpleResponse, _oproto: TProtocol): Unit = { _item.write(_oproto) } + override def decode(_iprot: TProtocol): SimpleResponse = SimpleResponse.decode(_iprot) + override lazy val metaData: ThriftStructMetaData[SimpleResponse] = SimpleResponse.metaData + } + + /** + * The default read-only implementation of SimpleResponse. You typically should not need to + * directly reference this class; instead, use the SimpleResponse.apply method to construct + * new instances. + */ + class Immutable( + val id: String, + override val _passthroughFields: immutable$Map[Short, TFieldBlob]) + extends SimpleResponse { + def this( + id: String + ) = this( + id, + immutable$Map.empty[Short, TFieldBlob] + ) + } + + /** + * This is another Immutable, this however keeps strings as lazy values that are lazily decoded from the backing + * array byte on read. + */ + private[this] class LazyImmutable( + _proto: LazyTProtocol, + _buf: Array[Byte], + _start_offset: Int, + _end_offset: Int, + idOffset: Int, + override val _passthroughFields: immutable$Map[Short, TFieldBlob]) + extends SimpleResponse { + + override def write(_oprot: TProtocol): Unit = { + if (_oprot.isInstanceOf[LazyTProtocol]) { + _oprot.asInstanceOf[LazyTProtocol].writeRaw(_buf, _start_offset, _end_offset - _start_offset) + } else { + super.write(_oprot) + } + } + + lazy val id: String = + if (idOffset == -1) + null + else { + _proto.decodeString(_buf, idOffset) + } + + /** + * Override the super hash code to make it a lazy val rather than def. + * + * Calculating the hash code can be expensive, caching it where possible + * can provide significant performance wins. (Key in a hash map for instance) + * Usually not safe since the normal constructor will accept a mutable map or + * set as an arg + * Here however we control how the class is generated from serialized data. + * With the class private and the contract that we throw away our mutable references + * having the hash code lazy here is safe. + */ + override lazy val hashCode: Int = super.hashCode + } + +} + +/** + * Prefer the companion object's [[example.thrift.SimpleResponse.apply]] + * for construction if you don't need to specify passthrough fields. + */ +trait SimpleResponse + extends ThriftStruct + with _root_.scala.Product1[String] + with ValidatingThriftStruct[SimpleResponse] + with java.io.Serializable +{ + import SimpleResponse._ + + def id: String + + def _passthroughFields: immutable$Map[Short, TFieldBlob] = immutable$Map.empty + + def _1: String = id + + + /** + * Gets a field value encoded as a binary blob using TCompactProtocol. If the specified field + * is present in the passthrough map, that value is returned. Otherwise, if the specified field + * is known and not optional and set to None, then the field is serialized and returned. + */ + def getFieldBlob(_fieldId: Short): _root_.scala.Option[TFieldBlob] = { + val passedthroughValue = _passthroughFields.get(_fieldId) + if (passedthroughValue.isDefined) { + passedthroughValue + } else { + val _protos = _root_.com.twitter.scrooge.internal.TProtocols() + val _buff = new TMemoryBuffer(32) + val _oprot = new TCompactProtocol(_buff) + + val _fieldOpt: _root_.scala.Option[TField] = _fieldId match { + case 1 => + if (id ne null) { + _oprot.writeString(id) + _root_.scala.Some(SimpleResponse.IdField) + } else { + _root_.scala.None + } + case _ => _root_.scala.None + } + if (_fieldOpt.isDefined) { + _root_.scala.Some(TFieldBlob(_fieldOpt.get, Buf.ByteArray.Owned(_buff.getArray))) + } else { + _root_.scala.None + } + } + } + + + /** + * Collects TCompactProtocol-encoded field values according to `getFieldBlob` into a map. + */ + def getFieldBlobs(ids: TraversableOnce[Short]): immutable$Map[Short, TFieldBlob] = + (ids.flatMap { id => getFieldBlob(id).map { fieldBlob => (id, fieldBlob) } }).toMap + + /** + * Sets a field using a TCompactProtocol-encoded binary blob. If the field is a known + * field, the blob is decoded and the field is set to the decoded value. If the field + * is unknown and passthrough fields are enabled, then the blob will be stored in + * _passthroughFields. + */ + def setField(_blob: TFieldBlob): SimpleResponse = { + val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols() + var id: String = this.id + var _passthroughFields = this._passthroughFields + val _iprot = _blob.read + _blob.id match { + case 1 => + id = _iprot.readString() + case _ => _passthroughFields += _root_.scala.Tuple2(_blob.id, _blob) + } + new Immutable( + id, + _passthroughFields + ) + } + + /** + * If the specified field is optional, it is set to None. Otherwise, if the field is + * known, it is reverted to its default value; if the field is unknown, it is removed + * from the passthroughFields map, if present. + */ + def unsetField(_fieldId: Short): SimpleResponse = { + var id: String = this.id + + _fieldId match { + case 1 => + id = null + case _ => + } + new Immutable( + id, + _passthroughFields - _fieldId + ) + } + + /** + * If the specified field is optional, it is set to None. Otherwise, if the field is + * known, it is reverted to its default value; if the field is unknown, it is removed + * from the passthroughFields map, if present. + */ + def unsetId: SimpleResponse = unsetField(1) + + + override def write(_oprot: TProtocol): Unit = { + SimpleResponse.validate(this) + val _protos = _root_.com.twitter.scrooge.internal.TProtocols() + _oprot.writeStructBegin(Struct) + if (id ne null) { + _oprot.writeFieldBegin(IdField) + _oprot.writeString(id) + _oprot.writeFieldEnd() + } + _root_.com.twitter.scrooge.internal.TProtocols.finishWritingStruct(_oprot, _passthroughFields) + } + + def copy( + id: String = this.id, + _passthroughFields: immutable$Map[Short, TFieldBlob] = this._passthroughFields + ): SimpleResponse = + new Immutable( + id, + _passthroughFields + ) + + override def canEqual(other: Any): Boolean = other.isInstanceOf[SimpleResponse] + + private[this] def _equals(other: SimpleResponse): Boolean = + this.productArity == other.productArity && + this.productIterator.sameElements(other.productIterator) && + this._passthroughFields == other._passthroughFields + + override def equals(other: Any): Boolean = + canEqual(other) && _equals(other.asInstanceOf[SimpleResponse]) + + override def hashCode: Int = { + _root_.scala.runtime.ScalaRunTime._hashCode(this) + } + + override def toString: String = _root_.scala.runtime.ScalaRunTime._toString(this) + + override def productPrefix: String = "SimpleResponse" + + def _codec: ValidatingThriftStructCodec3[SimpleResponse] = SimpleResponse + + def newBuilder(): StructBuilder[SimpleResponse] = new SimpleResponseStructBuilder(_root_.scala.Some(this), fieldTypes) +} + +private[thrift] class SimpleResponseStructBuilder(instance: _root_.scala.Option[SimpleResponse], fieldTypes: IndexedSeq[ClassTag[_]]) + extends StructBuilder[SimpleResponse](fieldTypes) { + + def build(): SimpleResponse = { + val _fieldArray = fieldArray // shadow variable + if (instance.isDefined) { + val instanceValue = instance.get + SimpleResponse( + if (_fieldArray(0) == null) instanceValue.id else _fieldArray(0).asInstanceOf[String] + ) + } else { + if (genericArrayOps(_fieldArray).contains(null)) throw new InvalidFieldsException(structBuildError("SimpleResponse")) + SimpleResponse( + _fieldArray(0).asInstanceOf[String] + ) + } + } +} + diff --git a/scalafix/output/src/main/scala/example/thrift/SimpleService$FinagleClient.scala b/scalafix/output/src/main/scala/example/thrift/SimpleService$FinagleClient.scala new file mode 100644 index 000000000..37b706dff --- /dev/null +++ b/scalafix/output/src/main/scala/example/thrift/SimpleService$FinagleClient.scala @@ -0,0 +1,138 @@ +/** + * Generated by Scrooge + * version: 21.8.0 + * rev: 75b832815f5da5328f0225e2ab3e06a14afb3446 + * built at: 20210813-170828 + */ +package example.thrift + +import com.twitter.finagle.{service => ctfs} +import com.twitter.finagle.stats.{NullStatsReceiver, StatsReceiver} +import com.twitter.finagle.thrift.{Protocols, RichClientParam, ThriftClientRequest} +import com.twitter.util.Future +import org.apache.thrift.TApplicationException +import org.apache.thrift.protocol._ + + +@javax.annotation.Generated(value = Array("com.twitter.scrooge.Compiler")) +class SimpleService$FinagleClient( + val service: com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + val clientParam: RichClientParam) + extends SimpleService[Future] { + + @deprecated("Use com.twitter.finagle.thrift.RichClientParam", "2017-08-16") + def this( + service: com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + protocolFactory: TProtocolFactory = Protocols.binaryFactory(), + serviceName: String = "SimpleService", + stats: StatsReceiver = NullStatsReceiver, + responseClassifier: ctfs.ResponseClassifier = ctfs.ResponseClassifier.Default + ) = this( + service, + RichClientParam( + protocolFactory, + serviceName, + clientStats = stats, + responseClassifier = responseClassifier + ) + ) + + import SimpleService._ + + def serviceName: String = clientParam.serviceName + + override def asClosable: _root_.com.twitter.util.Closable = service + + private[this] def protocolFactory: TProtocolFactory = clientParam.restrictedProtocolFactory + + private[this] val tlReusableBuffer: _root_.com.twitter.scrooge.TReusableBuffer = + clientParam.createThriftReusableBuffer() + + protected def encodeRequest(name: String, args: _root_.com.twitter.scrooge.ThriftStruct): ThriftClientRequest = { + val memoryBuffer = tlReusableBuffer.get() + try { + val oprot = protocolFactory.getProtocol(memoryBuffer) + + oprot.writeMessageBegin(new TMessage(name, TMessageType.CALL, 0)) + args.write(oprot) + oprot.writeMessageEnd() + oprot.getTransport.flush() + val bytes = _root_.java.util.Arrays.copyOfRange( + memoryBuffer.getArray(), + 0, + memoryBuffer.length() + ) + new ThriftClientRequest(bytes, false) + } finally { + tlReusableBuffer.reset() + } + } + + protected def decodeResponse[T <: _root_.com.twitter.scrooge.ThriftStruct]( + resBytes: Array[Byte], + codec: _root_.com.twitter.scrooge.ThriftStructCodec[T] + ): _root_.com.twitter.util.Try[T] = + _root_.com.twitter.finagle.thrift.service.ThriftCodec.decodeResponse(resBytes, codec, protocolFactory, serviceName) + + // ----- end boilerplate. + + private[this] def stats: StatsReceiver = clientParam.clientStats + private[this] def responseClassifier: ctfs.ResponseClassifier = clientParam.responseClassifier + + private[this] val scopedStats: StatsReceiver = if (serviceName != "") stats.scope(serviceName) else stats + private[this] object __stats_makeRequest { + val RequestsCounter: _root_.com.twitter.finagle.stats.Counter = scopedStats.scope("MakeRequest").counter("requests") + val SuccessCounter: _root_.com.twitter.finagle.stats.Counter = scopedStats.scope("MakeRequest").counter("success") + val FailuresCounter: _root_.com.twitter.finagle.stats.Counter = scopedStats.scope("MakeRequest").counter("failures") + val FailuresScope: StatsReceiver = scopedStats.scope("MakeRequest").scope("failures") + } + val MakeRequestSimpleServiceReplyDeserializer: Array[Byte] => _root_.com.twitter.util.Try[example.thrift.SimpleResponse] = { + response: Array[Byte] => { + decodeResponse(response, MakeRequest.Result).flatMap { result: MakeRequest.Result => + val firstException = result.firstException() + if (firstException.isDefined) { + _root_.com.twitter.util.Throw(_root_.com.twitter.finagle.SourcedException.setServiceName(firstException.get, serviceName)) + } else if (result.successField.isDefined) { + _root_.com.twitter.util.Return(result.successField.get) + } else { + _root_.com.twitter.util.Throw(_root_.com.twitter.scrooge.internal.ApplicationExceptions.missingResult("MakeRequest")) + } + } + } + } + + def makeRequest(request: example.thrift.SimpleRequest): Future[example.thrift.SimpleResponse] = { + __stats_makeRequest.RequestsCounter.incr() + val inputArgs = MakeRequest.Args(request) + + val serdeCtx = new _root_.com.twitter.finagle.thrift.ClientDeserializeCtx[example.thrift.SimpleResponse](inputArgs, MakeRequestSimpleServiceReplyDeserializer) + _root_.com.twitter.finagle.context.Contexts.local.let( + _root_.com.twitter.finagle.thrift.ClientDeserializeCtx.Key, + serdeCtx, + _root_.com.twitter.finagle.thrift.Headers.Request.Key, + _root_.com.twitter.finagle.thrift.Headers.Request.newValues + ) { + serdeCtx.rpcName("MakeRequest") + val start = System.nanoTime + val serialized = encodeRequest("MakeRequest", inputArgs) + serdeCtx.serializationTime(System.nanoTime - start) + this.service(serialized).flatMap { response => + Future.const(serdeCtx.deserialize(response)) + }.respond { response => + val classified = responseClassifier.applyOrElse( + ctfs.ReqRep(inputArgs, response), + ctfs.ResponseClassifier.Default) + if (classified.isInstanceOf[ctfs.ResponseClass.Successful]) { + __stats_makeRequest.SuccessCounter.incr() + } else if (classified.isInstanceOf[ctfs.ResponseClass.Failed]) { + __stats_makeRequest.FailuresCounter.incr() + if (response.isThrow) { + _root_.com.twitter.finagle.SourcedException.setServiceName(response.throwable, serviceName) + __stats_makeRequest.FailuresScope.counter( + _root_.com.twitter.util.Throwables.mkString(response.throwable): _*).incr() + } + } // Last ResponseClass is Ignorable, which we do not need to record + } + } + } +} diff --git a/scalafix/output/src/main/scala/example/thrift/SimpleService$FinagleService.scala b/scalafix/output/src/main/scala/example/thrift/SimpleService$FinagleService.scala new file mode 100644 index 000000000..193afa047 --- /dev/null +++ b/scalafix/output/src/main/scala/example/thrift/SimpleService$FinagleService.scala @@ -0,0 +1,104 @@ +/** + * Generated by Scrooge + * version: 21.8.0 + * rev: 75b832815f5da5328f0225e2ab3e06a14afb3446 + * built at: 20210813-170828 + */ +package example.thrift + +import com.twitter.finagle.{ + Filter => _, + Service => _, + thrift => _, + _ +} +import com.twitter.finagle.stats.{NullStatsReceiver, StatsReceiver} +import com.twitter.finagle.thrift.RichServerParam +import com.twitter.io.Buf +import com.twitter.util.Future +import org.apache.thrift.protocol._ +import org.apache.thrift.TApplicationException +import org.apache.thrift.transport.TMemoryInputTransport + + +@javax.annotation.Generated(value = Array("com.twitter.scrooge.Compiler")) +class SimpleService$FinagleService( + iface: SimpleService[Future], + serverParam: RichServerParam +) extends com.twitter.finagle.Service[Array[Byte], Array[Byte]] { + import SimpleService._ + + @deprecated("Use com.twitter.finagle.thrift.RichServerParam", "2017-08-16") + def this( + iface: SimpleService[Future], + protocolFactory: TProtocolFactory, + stats: StatsReceiver = NullStatsReceiver, + maxThriftBufferSize: Int = Thrift.param.maxThriftBufferSize, + serviceName: String = "SimpleService" + ) = this(iface, RichServerParam(protocolFactory, serviceName, maxThriftBufferSize, stats)) + + @deprecated("Use com.twitter.finagle.thrift.RichServerParam", "2017-08-16") + def this( + iface: SimpleService[Future], + protocolFactory: TProtocolFactory, + stats: StatsReceiver, + maxThriftBufferSize: Int + ) = this(iface, protocolFactory, stats, maxThriftBufferSize, "SimpleService") + + @deprecated("Use com.twitter.finagle.thrift.RichServerParam", "2017-08-16") + def this( + iface: SimpleService[Future], + protocolFactory: TProtocolFactory + ) = this(iface, protocolFactory, NullStatsReceiver, Thrift.param.maxThriftBufferSize) + + def serviceName: String = serverParam.serviceName + private[this] val filters: Filter = new Filter(serverParam) + + private[this] def protocolFactory: TProtocolFactory = serverParam.restrictedProtocolFactory + + protected val serviceMap: _root_.scala.collection.mutable.HashMap[String, _root_.com.twitter.finagle.Service[(TProtocol, Int), Array[Byte]]] = + new _root_.scala.collection.mutable.HashMap[String, _root_.com.twitter.finagle.Service[(TProtocol, Int), Array[Byte]]]() + + protected def addService(name: String, service: _root_.com.twitter.finagle.Service[(TProtocol, Int), Array[Byte]]): Unit = { + serviceMap(name) = service + } + + final def apply(request: Array[Byte]): Future[Array[Byte]] = { + val iprot = protocolFactory.getProtocol(new TMemoryInputTransport(request)) + + try { + val msg = iprot.readMessageBegin() + val svcOpt = serviceMap.get(msg.name) + if (svcOpt.isDefined) { + svcOpt.get.apply((iprot, msg.seqid)) + } else { + TProtocolUtil.skip(iprot, TType.STRUCT) + invalidMethodNameFuture(msg) + } + } catch { + case e: Exception => Future.exception(e) + } + } + + private[this] def invalidMethodNameFuture(msg: TMessage): Future[Array[Byte]] = { + Future.value(Buf.ByteArray.Owned.extract( + filters.exception(msg.name, msg.seqid, TApplicationException.UNKNOWN_METHOD, + "Invalid method name: '" + msg.name + "'"))) + } + // ---- end boilerplate. + + addService("MakeRequest", { + val methodService = new _root_.com.twitter.finagle.Service[MakeRequest.Args, MakeRequest.SuccessType] { + def apply(args: MakeRequest.Args): Future[MakeRequest.SuccessType] = { + val trace = _root_.com.twitter.finagle.tracing.Trace() + if (trace.isActivelyTracing) { + trace.recordRpc("MakeRequest") + trace.recordBinary("srv/thrift_endpoint", "example.thrift.SimpleService#makeRequest()") + } + iface.makeRequest(args.request) + } + } + + filters.makeRequest.andThen(methodService) + }) +} \ No newline at end of file diff --git a/scalafix/output/src/main/scala/example/thrift/SimpleService.scala b/scalafix/output/src/main/scala/example/thrift/SimpleService.scala new file mode 100644 index 000000000..708f3e2c7 --- /dev/null +++ b/scalafix/output/src/main/scala/example/thrift/SimpleService.scala @@ -0,0 +1,1078 @@ +/** + * Generated by Scrooge + * version: 21.8.0 + * rev: 75b832815f5da5328f0225e2ab3e06a14afb3446 + * built at: 20210813-170828 + */ +package example.thrift + +import com.twitter.scrooge._ +import com.twitter.finagle.{ + service => ctfs, + Filter => finagle$Filter, + Service => finagle$Service, + thrift => _, + _ +} +import com.twitter.finagle.stats.{Counter, StatsReceiver} +import com.twitter.finagle.thrift.{ + Protocols, + RichClientParam, + RichServerParam, + ServerToReqRep, + ThriftClientRequest, + ToThriftService +} +import com.twitter.util.{Future, Return, Throw, Throwables} +import com.twitter.io.Buf +import org.apache.thrift.protocol._ +import org.apache.thrift.TApplicationException +import scala.collection.mutable.Builder +import scala.collection.immutable.{Map => immutable$Map, Set => immutable$Set} +import scala.language.higherKinds +import scala.reflect.{ClassTag, classTag} + + +@javax.annotation.Generated(value = Array("com.twitter.scrooge.Compiler")) +trait SimpleService[+MM[_]] extends _root_.com.twitter.finagle.thrift.ThriftService { + + def makeRequest(request: example.thrift.SimpleRequest): MM[example.thrift.SimpleResponse] + + /** + * Used to close the underlying `Service`. + * Not a user-defined API. + */ + def asClosable: _root_.com.twitter.util.Closable = _root_.com.twitter.util.Closable.nop +} + + +object SimpleService extends _root_.com.twitter.finagle.thrift.GeneratedThriftService { self => + + val annotations: immutable$Map[String, String] = immutable$Map.empty + + val methods: immutable$Set[ThriftMethod] = immutable$Set( + self.MakeRequest + ) + + trait ServicePerEndpoint + extends ToThriftService + with _root_.com.twitter.finagle.thrift.service.Filterable[ServicePerEndpoint] { + def makeRequest : _root_.com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType] + + def withMakeRequest(makeRequest : _root_.com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType]): ServicePerEndpoint = this + + /** + * Prepends the given type-agnostic `Filter` to all of the `Services` + * and returns a copy of the `ServicePerEndpoint` now including the filter. + */ + def filtered(filter: _root_.com.twitter.finagle.Filter.TypeAgnostic): ServicePerEndpoint = + ServicePerEndpoint.apply(makeRequest).filtered(filter) + + /** + * Converts the `ServicePerEndpoint` to a `GeneratedThriftService`. + * @see _root_.com.twitter.scrooge.ToThriftService + */ + def toThriftService: _root_.com.twitter.finagle.thrift.ThriftService = MethodPerEndpoint(this) + + /** + * Used to close the underlying `Service`. + * Not a user-defined API. + */ + def asClosable: _root_.com.twitter.util.Closable = _root_.com.twitter.util.Closable.nop + } + + trait ReqRepServicePerEndpoint + extends ToThriftService + with _root_.com.twitter.finagle.thrift.service.Filterable[ReqRepServicePerEndpoint] { + def makeRequest : _root_.com.twitter.finagle.Service[com.twitter.scrooge.Request[self.MakeRequest.Args], _root_.com.twitter.scrooge.Response[self.MakeRequest.SuccessType]] + + def withMakeRequest(makeRequest : _root_.com.twitter.finagle.Service[com.twitter.scrooge.Request[self.MakeRequest.Args], _root_.com.twitter.scrooge.Response[self.MakeRequest.SuccessType]]): ReqRepServicePerEndpoint = this + + /** + * Prepends the given type-agnostic `Filter` to all of the `Services` + * and returns a copy of the `ServicePerEndpoint` now including the filter. + */ + def filtered(filter: com.twitter.finagle.Filter.TypeAgnostic): ReqRepServicePerEndpoint = + ReqRepServicePerEndpoint.apply(makeRequest).filtered(filter) + + /** + * Converts the `ServicePerEndpoint` to a `GeneratedThriftService`. + * @see _root_.com.twitter.scrooge.ToThriftService + */ + def toThriftService: _root_.com.twitter.finagle.thrift.ThriftService = ReqRepMethodPerEndpoint(this) + + /** + * Used to close the underlying `Service`. + * Not a user-defined API. + */ + def asClosable: _root_.com.twitter.util.Closable = _root_.com.twitter.util.Closable.nop + } + + @deprecated("Use ServicePerEndpoint", "2017-11-07") + trait BaseServiceIface extends ToThriftService { + def makeRequest : com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType] + + def toThriftService: _root_.com.twitter.finagle.thrift.ThriftService = new MethodIface(this) + } + + object ServicePerEndpoint { + + def apply( + makeRequest : _root_.com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType] + ): ServicePerEndpoint = new ServicePerEndpointImpl(makeRequest) + + private final class ServicePerEndpointImpl( + override val makeRequest : _root_.com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType] + ) extends ServicePerEndpoint { + + override def withMakeRequest( + makeRequest : _root_.com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType] + ): ServicePerEndpoint = + new ServicePerEndpointImpl(makeRequest) + + override def filtered(filter: _root_.com.twitter.finagle.Filter.TypeAgnostic): ServicePerEndpoint = + new ServicePerEndpointImpl( + makeRequest = filter.toFilter.andThen(makeRequest) + ) + + override def asClosable: _root_.com.twitter.util.Closable = + _root_.com.twitter.util.Closable.all( + this.makeRequest + ) + } + } + + object ReqRepServicePerEndpoint { + + def apply( + makeRequest : _root_.com.twitter.finagle.Service[_root_.com.twitter.scrooge.Request[self.MakeRequest.Args], _root_.com.twitter.scrooge.Response[self.MakeRequest.SuccessType]] + ): ReqRepServicePerEndpoint = + new ReqRepServicePerEndpointImpl(makeRequest) + + private final class ReqRepServicePerEndpointImpl( + override val makeRequest : _root_.com.twitter.finagle.Service[_root_.com.twitter.scrooge.Request[self.MakeRequest.Args], _root_.com.twitter.scrooge.Response[self.MakeRequest.SuccessType]] + ) extends ReqRepServicePerEndpoint { + + override def withMakeRequest( + makeRequest : _root_.com.twitter.finagle.Service[com.twitter.scrooge.Request[self.MakeRequest.Args], _root_.com.twitter.scrooge.Response[self.MakeRequest.SuccessType]] + ): ReqRepServicePerEndpoint = + new ReqRepServicePerEndpointImpl(makeRequest) + + override def filtered(filter: com.twitter.finagle.Filter.TypeAgnostic): ReqRepServicePerEndpoint = + new ReqRepServicePerEndpointImpl( + makeRequest = filter.toFilter.andThen(makeRequest) + ) + + override def asClosable: _root_.com.twitter.util.Closable = + _root_.com.twitter.util.Closable.all( + this.makeRequest + ) + } + } + + def unsafeBuildFromMethods(methods: immutable$Map[ThriftMethod, _root_.com.twitter.finagle.Service[_root_.com.twitter.scrooge.Request[_], _root_.com.twitter.scrooge.Response[_]]]): ReqRepServicePerEndpoint = { + val makeRequest = { + val makeRequestOpt = methods.get(self.MakeRequest) + if (makeRequestOpt.isEmpty) throw new IllegalArgumentException(_root_.java.lang.String.format("No implementation found for method MakeRequest in %s", methods.keySet)) + makeRequestOpt.get.asInstanceOf[self.MakeRequest.ReqRepServicePerEndpointServiceType] + } + + ReqRepServicePerEndpoint(makeRequest) + } + + @deprecated("Use ServicePerEndpoint", "2017-11-07") + case class ServiceIface( + makeRequest : com.twitter.finagle.Service[self.MakeRequest.Args, self.MakeRequest.SuccessType] + ) extends BaseServiceIface + with _root_.com.twitter.finagle.thrift.service.Filterable[ServiceIface] { + + /** + * Prepends the given type-agnostic `Filter` to all of the `Services` + * and returns a copy of the `ServiceIface` now including the filter. + */ + def filtered(filter: com.twitter.finagle.Filter.TypeAgnostic): ServiceIface = + copy( + makeRequest = filter.toFilter.andThen(makeRequest) + ) + } + + implicit object ServicePerEndpointBuilder + extends _root_.com.twitter.finagle.thrift.service.ServicePerEndpointBuilder[ServicePerEndpoint] { + override def serviceClass: Class[ServicePerEndpoint] = classOf[ServicePerEndpoint] + def servicePerEndpoint( + thriftService: _root_.com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + clientParam: RichClientParam + ): ServicePerEndpoint = + ServicePerEndpoint( + makeRequest = _root_.com.twitter.finagle.thrift.service.ThriftServicePerEndpoint( + self.MakeRequest, + thriftService, + clientParam + ) + ) + } + + implicit object ReqRepServicePerEndpointBuilder + extends _root_.com.twitter.finagle.thrift.service.ReqRepServicePerEndpointBuilder[ReqRepServicePerEndpoint] { + override def serviceClass: Class[ReqRepServicePerEndpoint] = classOf[ReqRepServicePerEndpoint] + def servicePerEndpoint( + thriftService: _root_.com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + clientParam: RichClientParam + ): ReqRepServicePerEndpoint = + ReqRepServicePerEndpoint( + makeRequest = _root_.com.twitter.finagle.thrift.service.ThriftReqRepServicePerEndpoint(self.MakeRequest, thriftService, clientParam) + ) + } + + @deprecated("Use ServicePerEndpointBuilder", "2017-11-07") + implicit object ServiceIfaceBuilder + extends com.twitter.finagle.thrift.ServiceIfaceBuilder[ServiceIface] { + override def serviceClass: Class[ServiceIface] = classOf[ServiceIface] + def newServiceIface( + binaryService: com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + clientParam: RichClientParam + ): ServiceIface = + ServiceIface( + makeRequest = _root_.com.twitter.finagle.thrift.service.ThriftServicePerEndpoint( + self.MakeRequest, + binaryService, + clientParam + ) + ) + } + + object MakeRequest extends ThriftMethod { + + object Args extends ValidatingThriftStructCodec3[Args] with StructBuilderFactory[Args] { + private[this] val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols() + + val Struct: TStruct = new TStruct("makeRequest_args") + val RequestField: TField = new TField("request", TType.STRUCT, 1) + val RequestFieldManifest: Manifest[example.thrift.SimpleRequest] = manifest[example.thrift.SimpleRequest] + + /** + * Field information in declaration order. + */ + lazy val fieldInfos: scala.List[ThriftStructFieldInfo] = scala.List[ThriftStructFieldInfo]( + new ThriftStructFieldInfo( + RequestField, + false, + true, + RequestFieldManifest, + _root_.scala.None, + _root_.scala.None, + immutable$Map.empty[String, String], + immutable$Map.empty[String, String], + None, + _root_.scala.Option(example.thrift.SimpleRequest.unsafeEmpty) + ) + ) + + + val structAnnotations: immutable$Map[String, String] = + immutable$Map.empty[String, String] + + private val fieldTypes: IndexedSeq[ClassTag[_]] = IndexedSeq[ClassTag[_]]( + classTag[example.thrift.SimpleRequest].asInstanceOf[ClassTag[_]] + ) + + private[this] val structFields: Seq[ThriftStructField[Args]] = Seq[ThriftStructField[Args]]( + new ThriftStructField[Args]( + RequestField, + _root_.scala.Some(RequestFieldManifest), + classOf[Args]) { + def getValue[R](struct: Args): R = struct.request.asInstanceOf[R] + } + ) + + override lazy val metaData: ThriftStructMetaData[Args] = + ThriftStructMetaData(this, structFields, fieldInfos, Nil, structAnnotations) + + /** + * Checks that all required fields are non-null. + */ + def validate(_item: Args): Unit = { + if (_item.request eq null) throw new TProtocolException("Required field request cannot be null") + } + + /** + * Checks that the struct is a valid as a new instance. If there are any missing required or + * construction required fields, return a non-empty list. + */ + def validateNewInstance(item: Args): scala.Seq[com.twitter.scrooge.validation.Issue] = { + val buf = scala.collection.mutable.ListBuffer.empty[com.twitter.scrooge.validation.Issue] + + if (item.request eq null) + buf += com.twitter.scrooge.validation.MissingRequiredField(fieldInfos.apply(0)) + buf ++= validateField(item.request) + buf.toList + } + + /** + * Validate that all validation annotations on the struct meet the criteria defined in the + * corresponding [[com.twitter.scrooge.validation.ThriftConstraintValidator]]. + */ + def validateInstanceValue(item: Args): Set[com.twitter.scrooge.validation.ThriftValidationViolation] = { + val thriftValidator = com.twitter.scrooge.ThriftValidator() + val violations = scala.collection.mutable.Set.empty[com.twitter.scrooge.validation.ThriftValidationViolation] + val fieldInfo0 = fieldInfos.apply(0) + violations ++= validateFieldValue(fieldInfo0.tfield.name, item.request, fieldInfo0.fieldAnnotations, thriftValidator) + violations.toSet + } + + def withoutPassthroughFields(original: Args): Args = + new Args( + request = + { + val field = original.request + example.thrift.SimpleRequest.withoutPassthroughFields(field) + } + ) + + lazy val unsafeEmpty: Args = { + val request: example.thrift.SimpleRequest = example.thrift.SimpleRequest.unsafeEmpty + + new Args( + request, + _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + ) + } + + def newBuilder(): StructBuilder[Args] = new ArgsStructBuilder(_root_.scala.None, fieldTypes) + + override def encode(_item: Args, _oproto: TProtocol): Unit = { + _item.write(_oproto) + } + + + override def decode(_iprot: TProtocol): Args = { + decodeInternal(_iprot, false) + } + + private[this] def decodeInternal(_iprot: TProtocol, lazily: Boolean): Args = { + var request: example.thrift.SimpleRequest = null + var _got_request = false + + var _passthroughFields: Builder[(Short, TFieldBlob), immutable$Map[Short, TFieldBlob]] = null + var _done = false + + _iprot.readStructBegin() + do { + val _field = _iprot.readFieldBegin() + val _fieldType = _field.`type` + if (_fieldType == TType.STOP) { + _done = true + } else { + _field.id match { + case 1 => + _root_.com.twitter.scrooge.internal.TProtocols.validateFieldType(TType.STRUCT, _fieldType, "request") + request = example.thrift.SimpleRequest.decode(_iprot) + _got_request = true + case _ => + _passthroughFields = _root_.com.twitter.scrooge.internal.TProtocols.readPassthroughField(_iprot, _field, _passthroughFields) + } + _iprot.readFieldEnd() + } + } while (!_done) + _iprot.readStructEnd() + + if (!_got_request) _root_.com.twitter.scrooge.internal.TProtocols.throwMissingRequiredField("Args", "request") + + val _passthroughFieldsResult = + if (_passthroughFields eq null) _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + else _passthroughFields.result() + new Args( + request, + _passthroughFieldsResult + ) + } + + def apply( + request: example.thrift.SimpleRequest + ): Args = + new Args( + request + ) + + def unapply(_item: Args): _root_.scala.Option[example.thrift.SimpleRequest] = _root_.scala.Some(_item.request) + + + + } + + class Args( + val request: example.thrift.SimpleRequest, + val _passthroughFields: immutable$Map[Short, TFieldBlob]) + extends ThriftStruct + with _root_.scala.Product1[example.thrift.SimpleRequest] + with ValidatingThriftStruct[Args] + with java.io.Serializable + { + import Args._ + + def this( + request: example.thrift.SimpleRequest + ) = this( + request, + immutable$Map.empty + ) + + def _1: example.thrift.SimpleRequest = request + + + + override def write(_oprot: TProtocol): Unit = { + Args.validate(this) + val _protos = _root_.com.twitter.scrooge.internal.TProtocols() + _oprot.writeStructBegin(Struct) + if (request ne null) { + _oprot.writeFieldBegin(RequestField) + request.write(_oprot) + _oprot.writeFieldEnd() + } + _root_.com.twitter.scrooge.internal.TProtocols.finishWritingStruct(_oprot, _passthroughFields) + } + + def copy( + request: example.thrift.SimpleRequest = this.request, + _passthroughFields: immutable$Map[Short, TFieldBlob] = this._passthroughFields + ): Args = + new Args( + request, + _passthroughFields + ) + + override def canEqual(other: Any): Boolean = other.isInstanceOf[Args] + + private[this] def _equals(other: Args): Boolean = + this.productArity == other.productArity && + this.productIterator.sameElements(other.productIterator) && + this._passthroughFields == other._passthroughFields + + override def equals(other: Any): Boolean = + canEqual(other) && _equals(other.asInstanceOf[Args]) + + override def hashCode: Int = { + _root_.scala.runtime.ScalaRunTime._hashCode(this) + } + + override def toString: String = _root_.scala.runtime.ScalaRunTime._toString(this) + + override def productPrefix: String = "Args" + + def _codec: ValidatingThriftStructCodec3[Args] = Args + + def newBuilder(): StructBuilder[Args] = new ArgsStructBuilder(_root_.scala.Some(this), fieldTypes) + } + + private[thrift] class ArgsStructBuilder(instance: _root_.scala.Option[Args], fieldTypes: IndexedSeq[ClassTag[_]]) + extends StructBuilder[Args](fieldTypes) { + + def build(): Args = { + val _fieldArray = fieldArray // shadow variable + if (instance.isDefined) { + val instanceValue = instance.get + Args( + if (_fieldArray(0) == null) instanceValue.request else _fieldArray(0).asInstanceOf[example.thrift.SimpleRequest] + ) + } else { + if (genericArrayOps(_fieldArray).contains(null)) throw new InvalidFieldsException(structBuildError("Args")) + Args( + _fieldArray(0).asInstanceOf[example.thrift.SimpleRequest] + ) + } + } + } + + type SuccessType = example.thrift.SimpleResponse + + object Result extends ValidatingThriftStructCodec3[Result] with StructBuilderFactory[Result] { + private[this] val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols() + + val Struct: TStruct = new TStruct("makeRequest_result") + val SuccessField: TField = new TField("success", TType.STRUCT, 0) + val SuccessFieldManifest: Manifest[example.thrift.SimpleResponse] = manifest[example.thrift.SimpleResponse] + + /** + * Field information in declaration order. + */ + lazy val fieldInfos: scala.List[ThriftStructFieldInfo] = scala.List[ThriftStructFieldInfo]( + new ThriftStructFieldInfo( + SuccessField, + true, + false, + SuccessFieldManifest, + _root_.scala.None, + _root_.scala.None, + immutable$Map.empty[String, String], + immutable$Map.empty[String, String], + None, + _root_.scala.Option(example.thrift.SimpleResponse.unsafeEmpty) + ) + ) + + + val structAnnotations: immutable$Map[String, String] = + immutable$Map.empty[String, String] + + private val fieldTypes: IndexedSeq[ClassTag[_]] = IndexedSeq[ClassTag[_]]( + classTag[_root_.scala.Option[example.thrift.SimpleResponse]].asInstanceOf[ClassTag[_]] + ) + + private[this] val structFields: Seq[ThriftStructField[Result]] = Seq[ThriftStructField[Result]]( + new ThriftStructField[Result]( + SuccessField, + _root_.scala.Some(SuccessFieldManifest), + classOf[Result]) { + def getValue[R](struct: Result): R = struct.success.asInstanceOf[R] + } + ) + + override lazy val metaData: ThriftStructMetaData[Result] = + ThriftStructMetaData(this, structFields, fieldInfos, Nil, structAnnotations) + + /** + * Checks that all required fields are non-null. + */ + def validate(_item: Result): Unit = { + } + + /** + * Checks that the struct is a valid as a new instance. If there are any missing required or + * construction required fields, return a non-empty list. + */ + def validateNewInstance(item: Result): scala.Seq[com.twitter.scrooge.validation.Issue] = { + val buf = scala.collection.mutable.ListBuffer.empty[com.twitter.scrooge.validation.Issue] + + buf ++= validateField(item.success) + buf.toList + } + + /** + * Validate that all validation annotations on the struct meet the criteria defined in the + * corresponding [[com.twitter.scrooge.validation.ThriftConstraintValidator]]. + */ + def validateInstanceValue(item: Result): Set[com.twitter.scrooge.validation.ThriftValidationViolation] = { + val thriftValidator = com.twitter.scrooge.ThriftValidator() + val violations = scala.collection.mutable.Set.empty[com.twitter.scrooge.validation.ThriftValidationViolation] + val fieldInfo0 = fieldInfos.apply(0) + violations ++= validateFieldValue(fieldInfo0.tfield.name, item.success, fieldInfo0.fieldAnnotations, thriftValidator) + violations.toSet + } + + def withoutPassthroughFields(original: Result): Result = + new Result( + success = + { + val field = original.success + field.map { field => + example.thrift.SimpleResponse.withoutPassthroughFields(field) + } + } + ) + + lazy val unsafeEmpty: Result = { + val success: _root_.scala.Option[example.thrift.SimpleResponse] = _root_.scala.None + + new Result( + success, + _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + ) + } + + def newBuilder(): StructBuilder[Result] = new ResultStructBuilder(_root_.scala.None, fieldTypes) + + override def encode(_item: Result, _oproto: TProtocol): Unit = { + _item.write(_oproto) + } + + + override def decode(_iprot: TProtocol): Result = { + decodeInternal(_iprot, false) + } + + private[this] def decodeInternal(_iprot: TProtocol, lazily: Boolean): Result = { + var success: Option[example.thrift.SimpleResponse] = None + + var _passthroughFields: Builder[(Short, TFieldBlob), immutable$Map[Short, TFieldBlob]] = null + var _done = false + + _iprot.readStructBegin() + do { + val _field = _iprot.readFieldBegin() + val _fieldType = _field.`type` + if (_fieldType == TType.STOP) { + _done = true + } else { + _field.id match { + case 0 => + _root_.com.twitter.scrooge.internal.TProtocols.validateFieldType(TType.STRUCT, _fieldType, "success") + success = _root_.scala.Some(example.thrift.SimpleResponse.decode(_iprot)) + case _ => + _passthroughFields = _root_.com.twitter.scrooge.internal.TProtocols.readPassthroughField(_iprot, _field, _passthroughFields) + } + _iprot.readFieldEnd() + } + } while (!_done) + _iprot.readStructEnd() + + + val _passthroughFieldsResult = + if (_passthroughFields eq null) _root_.com.twitter.scrooge.internal.TProtocols.NoPassthroughFields + else _passthroughFields.result() + new Result( + success, + _passthroughFieldsResult + ) + } + + def apply( + success: _root_.scala.Option[example.thrift.SimpleResponse] = _root_.scala.None + ): Result = + new Result( + success + ) + + def unapply(_item: Result): _root_.scala.Option[_root_.scala.Option[example.thrift.SimpleResponse]] = _root_.scala.Some(_item.success) + + + + } + + class Result( + val success: _root_.scala.Option[example.thrift.SimpleResponse], + val _passthroughFields: immutable$Map[Short, TFieldBlob]) + extends ThriftResponse[example.thrift.SimpleResponse] with ThriftStruct + with _root_.scala.Product1[Option[example.thrift.SimpleResponse]] + with ValidatingThriftStruct[Result] + with java.io.Serializable + { + import Result._ + + def this( + success: _root_.scala.Option[example.thrift.SimpleResponse] = _root_.scala.None + ) = this( + success, + immutable$Map.empty + ) + + def _1: _root_.scala.Option[example.thrift.SimpleResponse] = success + + def successField: Option[example.thrift.SimpleResponse] = success + def exceptionFields: Iterable[Option[com.twitter.scrooge.ThriftException]] = Nil + + + override def write(_oprot: TProtocol): Unit = { + Result.validate(this) + val _protos = _root_.com.twitter.scrooge.internal.TProtocols() + _oprot.writeStructBegin(Struct) + if (success.isDefined) { + _oprot.writeFieldBegin(SuccessField) + success.get.write(_oprot) + _oprot.writeFieldEnd() + } + _root_.com.twitter.scrooge.internal.TProtocols.finishWritingStruct(_oprot, _passthroughFields) + } + + def copy( + success: _root_.scala.Option[example.thrift.SimpleResponse] = this.success, + _passthroughFields: immutable$Map[Short, TFieldBlob] = this._passthroughFields + ): Result = + new Result( + success, + _passthroughFields + ) + + override def canEqual(other: Any): Boolean = other.isInstanceOf[Result] + + private[this] def _equals(other: Result): Boolean = + this.productArity == other.productArity && + this.productIterator.sameElements(other.productIterator) && + this._passthroughFields == other._passthroughFields + + override def equals(other: Any): Boolean = + canEqual(other) && _equals(other.asInstanceOf[Result]) + + override def hashCode: Int = { + _root_.scala.runtime.ScalaRunTime._hashCode(this) + } + + override def toString: String = _root_.scala.runtime.ScalaRunTime._toString(this) + + override def productPrefix: String = "Result" + + def _codec: ValidatingThriftStructCodec3[Result] = Result + + def newBuilder(): StructBuilder[Result] = new ResultStructBuilder(_root_.scala.Some(this), fieldTypes) + } + + private[thrift] class ResultStructBuilder(instance: _root_.scala.Option[Result], fieldTypes: IndexedSeq[ClassTag[_]]) + extends StructBuilder[Result](fieldTypes) { + + def build(): Result = { + val _fieldArray = fieldArray // shadow variable + if (instance.isDefined) { + val instanceValue = instance.get + Result( + if (_fieldArray(0) == null) instanceValue.success else _fieldArray(0).asInstanceOf[_root_.scala.Option[example.thrift.SimpleResponse]] + ) + } else { + if (genericArrayOps(_fieldArray).contains(null)) throw new InvalidFieldsException(structBuildError("Result")) + Result( + _fieldArray(0).asInstanceOf[_root_.scala.Option[example.thrift.SimpleResponse]] + ) + } + } + } + + val annotations: immutable$Map[String, String] = immutable$Map.empty + + type FunctionType = Function1[Args,Future[example.thrift.SimpleResponse]] + type ReqRepFunctionType = Function1[_root_.com.twitter.scrooge.Request[Args],Future[_root_.com.twitter.scrooge.Response[example.thrift.SimpleResponse]]] + + type ServicePerEndpointServiceType = _root_.com.twitter.finagle.Service[Args, SuccessType] + type ReqRepServicePerEndpointServiceType = _root_.com.twitter.finagle.Service[_root_.com.twitter.scrooge.Request[Args], _root_.com.twitter.scrooge.Response[SuccessType]] + + def toServicePerEndpointService(f: FunctionType): ServicePerEndpointServiceType = + _root_.com.twitter.finagle.Service.mk { args: Args => + f(args) + } + + def toReqRepServicePerEndpointService(f: ReqRepFunctionType): ReqRepServicePerEndpointServiceType = + _root_.com.twitter.finagle.Service.mk[_root_.com.twitter.scrooge.Request[Args], _root_.com.twitter.scrooge.Response[SuccessType]] { request: _root_.com.twitter.scrooge.Request[Args] => + f(request) + } + + + val name: String = "MakeRequest" + val serviceName: String = "SimpleService" + val argsCodec: Args.type = Args + val responseCodec: Result.type = Result + val oneway: Boolean = false + } + + // Compatibility aliases. + val makeRequest$args: MakeRequest.Args.type = MakeRequest.Args + type makeRequest$args = MakeRequest.Args + + val makeRequest$result: MakeRequest.Result.type = MakeRequest.Result + type makeRequest$result = MakeRequest.Result + + + trait MethodPerEndpoint + extends SimpleService[Future] { + + def makeRequest(request: example.thrift.SimpleRequest): Future[example.thrift.SimpleResponse] + } + + object MethodPerEndpoint { + + def apply(servicePerEndpoint: ServicePerEndpoint): MethodPerEndpoint = { + new MethodPerEndpointImpl(servicePerEndpoint) {} + } + + /** + * Use `MethodPerEndpoint.apply()` instead of this constructor. + */ + class MethodPerEndpointImpl protected (servicePerEndpoint: ServicePerEndpoint) + extends MethodPerEndpoint { + def makeRequest(request: example.thrift.SimpleRequest): Future[example.thrift.SimpleResponse] = + servicePerEndpoint.makeRequest(self.MakeRequest.Args(request)) + + override def asClosable: _root_.com.twitter.util.Closable = + servicePerEndpoint.asClosable + } + } + + object ReqRepMethodPerEndpoint { + + def apply(servicePerEndpoint: ReqRepServicePerEndpoint): MethodPerEndpoint = + new ReqRepMethodPerEndpointImpl(servicePerEndpoint) { } + + /** + * Use `ReqRepMethodPerEndpoint.apply()` instead of this constructor. + */ + class ReqRepMethodPerEndpointImpl protected (servicePerEndpoint: ReqRepServicePerEndpoint) + extends MethodPerEndpoint { + + def makeRequest(request: example.thrift.SimpleRequest): Future[example.thrift.SimpleResponse] = { + val requestCtx = _root_.com.twitter.finagle.context.Contexts.local.getOrElse(_root_.com.twitter.finagle.thrift.Headers.Request.Key, () => _root_.com.twitter.finagle.thrift.Headers.Request.newValues) + val scroogeRequest = _root_.com.twitter.scrooge.Request(requestCtx.values, self.MakeRequest.Args(request)) + servicePerEndpoint.makeRequest(scroogeRequest).transform(_root_.com.twitter.finagle.thrift.service.ThriftReqRepServicePerEndpoint.transformResult) + } + + override def asClosable: _root_.com.twitter.util.Closable = + servicePerEndpoint.asClosable + } + } + + @deprecated("Use MethodPerEndpoint", "2017-11-07") + class MethodIface(serviceIface: BaseServiceIface) + extends FutureIface { + def makeRequest(request: example.thrift.SimpleRequest): Future[example.thrift.SimpleResponse] = + serviceIface.makeRequest(self.MakeRequest.Args(request)) + } + + implicit object MethodPerEndpointBuilder + extends _root_.com.twitter.finagle.thrift.service.MethodPerEndpointBuilder[ServicePerEndpoint, MethodPerEndpoint] { + def methodPerEndpoint(servicePerEndpoint: ServicePerEndpoint): MethodPerEndpoint = + MethodPerEndpoint(servicePerEndpoint) + } + + @deprecated("Use MethodPerEndpointBuilder", "2018-01-12") + implicit object ThriftServiceBuilder + extends _root_.com.twitter.finagle.thrift.service.ThriftServiceBuilder[ServicePerEndpoint, SimpleService[Future]] { + def build(servicePerEndpoint: ServicePerEndpoint): MethodPerEndpoint = + MethodPerEndpoint(servicePerEndpoint) + } + + implicit object ReqRepMethodPerEndpointBuilder + extends _root_.com.twitter.finagle.thrift.service.ReqRepMethodPerEndpointBuilder[ReqRepServicePerEndpoint, MethodPerEndpoint] { + def methodPerEndpoint(servicePerEndpoint: ReqRepServicePerEndpoint): MethodPerEndpoint = + ReqRepMethodPerEndpoint(servicePerEndpoint) + } + + @deprecated("Use MethodPerEndpointBuilder", "2017-11-07") + implicit object MethodIfaceBuilder + extends com.twitter.finagle.thrift.MethodIfaceBuilder[ServiceIface, SimpleService[Future]] { + def newMethodIface(serviceIface: ServiceIface): MethodIface = + new MethodIface(serviceIface) + } + + @deprecated("Use MethodPerEndpoint", "2017-11-07") + trait FutureIface + extends SimpleService[Future] { + + def makeRequest(request: example.thrift.SimpleRequest): Future[example.thrift.SimpleResponse] + } + + class FinagledClient( + service: com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + clientParam: RichClientParam) + extends SimpleService$FinagleClient(service, clientParam) + with FutureIface + with MethodPerEndpoint { + + @deprecated("Use com.twitter.finagle.thrift.RichClientParam", "2017-08-16") + def this( + service: com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + protocolFactory: org.apache.thrift.protocol.TProtocolFactory = Protocols.binaryFactory(), + serviceName: String = "SimpleService", + stats: com.twitter.finagle.stats.StatsReceiver = com.twitter.finagle.stats.NullStatsReceiver, + responseClassifier: ctfs.ResponseClassifier = ctfs.ResponseClassifier.Default + ) = this( + service, + RichClientParam( + protocolFactory, + serviceName, + clientStats = stats, + responseClassifier = responseClassifier + ) + ) + + @deprecated("Use com.twitter.finagle.thrift.RichClientParam", "2017-08-16") + def this( + service: com.twitter.finagle.Service[ThriftClientRequest, Array[Byte]], + protocolFactory: org.apache.thrift.protocol.TProtocolFactory, + serviceName: String, + stats: com.twitter.finagle.stats.StatsReceiver + ) = this( + service, + RichClientParam( + protocolFactory, + serviceName, + clientStats = stats + ) + ) + } + + class FinagledService( + iface: SimpleService[Future], + serverParam: RichServerParam) + extends SimpleService$FinagleService(iface, serverParam) { + + @deprecated("Use com.twitter.finagle.thrift.RichServerParam", "2017-08-16") + def this( + iface: SimpleService[Future], + protocolFactory: org.apache.thrift.protocol.TProtocolFactory, + serviceName: String = "SimpleService" + ) = this(iface, RichServerParam(protocolFactory, serviceName)) + } + + class Filter(serverParam: RichServerParam) { + private[this] def protocolFactory: TProtocolFactory = serverParam.restrictedProtocolFactory + + private[this] def serviceName: String = serverParam.serviceName + private[this] def responseClassifier: ctfs.ResponseClassifier = serverParam.responseClassifier + private[this] def stats: StatsReceiver = serverParam.serverStats + private[this] def perEndpointStats: Boolean = serverParam.perEndpointStats && !stats.isNull + + private[this] val tlReusableBuffer: TReusableBuffer = TReusableBuffer(maxThriftBufferSize = serverParam.maxThriftBufferSize) + + private[thrift] def exception(name: String, seqid: Int, code: Int, message: String): Buf = { + val x = new TApplicationException(code, message) + val memoryBuffer = tlReusableBuffer.get() + try { + val oprot = protocolFactory.getProtocol(memoryBuffer) + + oprot.writeMessageBegin(new TMessage(name, TMessageType.EXCEPTION, seqid)) + x.write(oprot) + oprot.writeMessageEnd() + oprot.getTransport.flush() + + // make a copy of the array of bytes to construct a new buffer because memoryBuffer is reusable + Buf.ByteArray.Shared(memoryBuffer.getArray(), 0, memoryBuffer.length()) + } finally { + tlReusableBuffer.reset() + } + } + + private[this] def reply(name: String, seqid: Int, result: ThriftStruct): Buf = { + val memoryBuffer = tlReusableBuffer.get() + try { + val oprot = protocolFactory.getProtocol(memoryBuffer) + val start = System.nanoTime + oprot.writeMessageBegin(new TMessage(name, TMessageType.REPLY, seqid)) + result.write(oprot) + oprot.writeMessageEnd() + val trace = _root_.com.twitter.finagle.tracing.Trace() + if (trace.isActivelyTracing) { + trace.recordBinary("srv/response_serialization_ns", System.nanoTime - start) + } + oprot.getTransport.flush() + + // make a copy of the array of bytes to construct a new buffer because memoryBuffer is reusable + Buf.ByteArray.Shared(memoryBuffer.getArray(), 0, memoryBuffer.length()) + } finally { + tlReusableBuffer.reset() + } + } + + private[this] def recordResponse(reqRep: ctfs.ReqRep, methodStats: _root_.com.twitter.finagle.thrift.ThriftMethodStats): Unit = { + ServerToReqRep.setCtx(reqRep) + val classified = responseClassifier.applyOrElse(reqRep, ctfs.ResponseClassifier.Default) + if (classified.isInstanceOf[ctfs.ResponseClass.Successful]) { + methodStats.successCounter.incr() + } else if (classified.isInstanceOf[ctfs.ResponseClass.Failed]) { + methodStats.failuresCounter.incr() + if (reqRep.response.isThrow) { + methodStats.failuresScope.counter(Throwables.mkString(reqRep.response.throwable): _*).incr() + } + } // Last ResponseClass is Ignorable, which we do not need to record + } + + final protected def perMethodStatsFilter( + method: ThriftMethod + ): finagle$Filter[(TProtocol, Int), Array[Byte], (TProtocol, Int), RichResponse[method.Args, method.Result]] = { + val methodStats = if (perEndpointStats) { + _root_.com.twitter.finagle.thrift.ThriftMethodStats((if (serviceName != "") stats.scope(serviceName) else stats).scope(method.name)) + } else { + _root_.com.twitter.finagle.thrift.ThriftMethodStats.Null + } + + new finagle$Filter[(TProtocol, Int), Array[Byte], (TProtocol, Int), RichResponse[method.Args, method.Result]] { + def apply( + req: (TProtocol, Int), + service: finagle$Service[(TProtocol, Int), RichResponse[method.Args, method.Result]] + ): Future[Array[Byte]] = { + methodStats.requestsCounter.incr() + service(req).transform { response => + if (response.isReturn) { + val value = response.apply() + if (value.isInstanceOf[SuccessfulResponse[method.Args, method.Result]]) { + val succResp = value.asInstanceOf[SuccessfulResponse[method.Args, method.Result]] + recordResponse(ctfs.ReqRep(succResp.input, _root_.com.twitter.util.Return(succResp.result.successField.get)), methodStats) + } else if (value.isInstanceOf[ProtocolExceptionResponse[method.Args, method.Result]]) { + val protExResp = value.asInstanceOf[ProtocolExceptionResponse[method.Args, method.Result]] + recordResponse(ctfs.ReqRep(protExResp.input, _root_.com.twitter.util.Throw(protExResp.exception)), methodStats) + } else if (value.isInstanceOf[ThriftExceptionResponse[method.Args, method.Result]]) { + val thriftExResp = value.asInstanceOf[ThriftExceptionResponse[method.Args, method.Result]] + val rep: Throwable = if (thriftExResp.ex.isInstanceOf[ThriftException]) { + _root_.com.twitter.finagle.SourcedException.setServiceName(thriftExResp.ex, serviceName) + } else { + _root_.com.twitter.scrooge.internal.ApplicationExceptions.missingResult(serviceName) + } + recordResponse(ctfs.ReqRep(thriftExResp.input, _root_.com.twitter.util.Throw(rep)), methodStats) + } + Future.value(Buf.ByteArray.Owned.extract(value.response)) + } else { // Throw[_] + recordResponse(ctfs.ReqRep(req, response), methodStats) + Future.const(response.asInstanceOf[Throw[Array[Byte]]]) + } + } + } + } + } + // ---- end boilerplate. + + val makeRequest: finagle$Filter[(TProtocol, Int), Array[Byte], MakeRequest.Args, MakeRequest.SuccessType] = { + val statsFilter: finagle$Filter[(TProtocol, Int), Array[Byte], (TProtocol, Int), RichResponse[MakeRequest.Args, MakeRequest.Result]] = perMethodStatsFilter(MakeRequest) + + val protocolExnFilter = new SimpleFilter[(TProtocol, Int), RichResponse[MakeRequest.Args, MakeRequest.Result]] { + def apply( + request: (TProtocol, Int), + service: _root_.com.twitter.finagle.Service[(TProtocol, Int), RichResponse[MakeRequest.Args, MakeRequest.Result]] + ): Future[RichResponse[MakeRequest.Args, MakeRequest.Result]] = { + val iprot = request._1 + val seqid = request._2 + val res = service(request) + res.transform(resTry => { + if (resTry.isThrow && resTry.throwable.isInstanceOf[TProtocolException]) { + val underlyingException = resTry.throwable + iprot.readMessageEnd() + Future.value( + ProtocolExceptionResponse( + null, + exception("MakeRequest", seqid, TApplicationException.PROTOCOL_ERROR, underlyingException.getMessage), + new TApplicationException(TApplicationException.PROTOCOL_ERROR, underlyingException.getMessage))) + } else { + res + } + }) + } + } + + val serdeFilter = new finagle$Filter[(TProtocol, Int), RichResponse[MakeRequest.Args, MakeRequest.Result], MakeRequest.Args, MakeRequest.SuccessType] { + def apply( + request: (TProtocol, Int), + service: _root_.com.twitter.finagle.Service[MakeRequest.Args, MakeRequest.SuccessType] + ): Future[RichResponse[MakeRequest.Args, MakeRequest.Result]] = { + val iprot = request._1 + val seqid = request._2 + val start = System.nanoTime + val args = MakeRequest.Args.decode(iprot) + iprot.readMessageEnd() + val trace = _root_.com.twitter.finagle.tracing.Trace() + if (trace.isActivelyTracing) { + trace.recordBinary("srv/request_deserialization_ns", System.nanoTime - start) + } + _root_.com.twitter.finagle.context.Contexts.local.let( + _root_.com.twitter.finagle.thrift.MethodMetadata.Key, + _root_.com.twitter.finagle.thrift.MethodMetadata(MakeRequest)) { + service(args) + }.transform(resTry => { + if (resTry.isReturn) { + val methodResult = MakeRequest.Result(success = Some(resTry.apply())) + Future.value( + SuccessfulResponse( + args, + reply("MakeRequest", seqid, methodResult), + methodResult)) + } else { // Throw[_] + Future.const(resTry.asInstanceOf[Throw[RichResponse[MakeRequest.Args, MakeRequest.Result]]]) + } + }) + } + } + statsFilter.andThen(protocolExnFilter).andThen(serdeFilter) + } + } + + + implicit def SimpleServiceInReaderT[F[_]]: SimpleService[({type Λ[β0] = _root_.cats.data.ReaderT[F, SimpleService[F], β0]})#Λ] = + _root_.cats.tagless.Derive.readerT[SimpleService, F] + + implicit val SimpleServiceFunctorK: _root_.cats.tagless.FunctorK[SimpleService] = _root_.cats.tagless.Derive.functorK[SimpleService] + + +} diff --git a/scalafix/regenerate-inputs.sh b/scalafix/regenerate-inputs.sh new file mode 100755 index 000000000..0b7fb0269 --- /dev/null +++ b/scalafix/regenerate-inputs.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +set -o errexit -o nounset -o pipefail +IFS=$'\n\t' + +GENERATED_SOURCES="src/main/scala/example/thrift" + +set -x + +SCROOGE_VERSION=$1 + +cd input +find "${GENERATED_SOURCES}" -name "*.scala" -delete +mkdir -p project +echo sbt.version=1.5.5 > project/build.properties +cat << __EOF__ > project/plugins.sbt +addSbtPlugin("com.twitter" % "scrooge-sbt-plugin" % "${SCROOGE_VERSION}") +__EOF__ + +cat << __EOF__ > build.sbt +scalaVersion := "2.13.6" +libraryDependencies ++= { + val finagleV = "${SCROOGE_VERSION}" + + Seq( + "com.twitter" %% "scrooge-core" % finagleV, + "com.twitter" %% "finagle-thrift" % finagleV, + "org.apache.thrift" % "libthrift" % "0.10.0", + ) +} +(Compile / scroogeBuildOptions) += com.twitter.scrooge.backend.WithFinagle +(Compile / scroogeThriftOutputFolder) := file("src/main/scala") +__EOF__ + +sbt compile +find "../output/${GENERATED_SOURCES}" -name "*.scala" -delete +cp "${GENERATED_SOURCES}"/* "../output/${GENERATED_SOURCES}/" +find src/main/scala -name "*.scala" -print0 | \ + xargs -0 -n1 \ + sed -i '' -e '1 i\ +/*rule = AddCatsTaglessInstances*/ +' +rm -rf build.sbt project + +set +x + +WHITE_BACKGROUND="\e[47m" +NORMAL_TEXT="\e[0m" +BOLD_TEXT="\e[1m" +RED_TEXT="\e[31m" +GREEN_TEXT="\e[32m" + +cat << __EOF__ +Now edit $(echo -e "${BOLD_TEXT}${RED_TEXT}")scalafix/output/"${GENERATED_SOURCES}"/SimpleService.scala$(echo -e "${NORMAL_TEXT}") and replace the +blank line at the end of the SimpleService object with these lines:$(echo -e "${WHITE_BACKGROUND}${GREEN_TEXT}") + + + implicit def SimpleServiceInReaderT[F[_]]: SimpleService[({type Λ[β0] = _root_.cats.data.ReaderT[F, SimpleService[F], β0]})#Λ] = + _root_.cats.tagless.Derive.readerT[SimpleService, F] + + implicit val SimpleServiceFunctorK: _root_.cats.tagless.FunctorK[SimpleService] = _root_.cats.tagless.Derive.functorK[SimpleService] + +$(echo -e "${NORMAL_TEXT}") +__EOF__ diff --git a/scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule b/scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule new file mode 100644 index 000000000..c494d686c --- /dev/null +++ b/scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule @@ -0,0 +1 @@ +com.dwolla.scrooge.scalafix.AddCatsTaglessInstances diff --git a/scalafix/rules/src/main/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstances.scala b/scalafix/rules/src/main/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstances.scala new file mode 100644 index 000000000..18028388c --- /dev/null +++ b/scalafix/rules/src/main/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstances.scala @@ -0,0 +1,77 @@ +package com.dwolla.scrooge.scalafix + +import scalafix.v1._ + +import scala.meta._ + +class AddCatsTaglessInstances extends SemanticRule("AddCatsTaglessInstances") { + override def fix(implicit doc: SemanticDocument): Patch = + Patch.fromIterable(addImplicitsToCompanionObjects) + + private def buildThriftServiceFromTrait(alg: Defn.Trait) + (implicit doc: SemanticDocument): ThriftService = { + val name = alg.name.value + + val companion = + doc + .tree + .collect { + case obj@Defn.Object(_, Term.Name(`name`), _) => obj + } + .headOption + + ThriftService(alg, companion) + } + + private def addImplicitsToCompanionObjects(implicit doc: SemanticDocument): List[Patch] = + doc + .tree + .collect { + case TraitWithTypeConstructor(name) => name + } + .map(buildThriftServiceFromTrait) + .map(_.toPatch) +} + +object TraitWithTypeConstructor { + def unapply(subtree: Tree): Option[Defn.Trait] = + PartialFunction.condOpt(subtree) { + case term@Defn.Trait(_, _, List(Type.Param(_, _, List(_: Type.Param), _, _, _)), _, _) => term + } +} + +case class ThriftService(alg: Defn.Trait, + companion: Option[Defn.Object]) { + def code: String = + s""" implicit def ${alg.name}InReaderT[F[_]]: ${alg.name}[({type Λ[β0] = _root_.cats.data.ReaderT[F, ${alg.name}[F], β0]})#Λ] = + | _root_.cats.tagless.Derive.readerT[${alg.name}, F] + | + | implicit val ${alg.name}FunctorK: _root_.cats.tagless.FunctorK[${alg.name}] = _root_.cats.tagless.Derive.functorK[${alg.name}] + | + |""".stripMargin + + def toPatch: Patch = + companion match { + case None => + val companionString = + s"""| + |object ${alg.name} { + |$code + |}""".stripMargin + + Patch.addRight(alg, companionString) + case Some(companion) => + companion.tokens.last match { + case brace@Token.RightBrace() => Patch.addLeft(brace, + s""" + |$code + |""".stripMargin) + case other => Patch.addRight(other, + s""" { + |$code + | + |}""".stripMargin) + } + } + +} diff --git a/scalafix/rules/src/test/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstancesTest.scala b/scalafix/rules/src/test/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstancesTest.scala new file mode 100644 index 000000000..5557da691 --- /dev/null +++ b/scalafix/rules/src/test/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstancesTest.scala @@ -0,0 +1,45 @@ +package com.dwolla.scrooge.scalafix + +import scalafix.Patch + +import scala.meta._ + +object AddCatsTaglessInstancesTest extends App { + + val input = + f"""trait SimpleService[F[_]] + |object SimpleService extends _root_.com.twitter.finagle.thrift.GeneratedThriftService { self => + | val annotations: immutable$$Map[String, String] = immutable$$Map.empty + |} + |trait Bar + |trait Baz[F] + |trait Boo[+MM[_]] + |""".stripMargin + + val tree: Tree = input.parse[Source].get + + val symbols: List[Defn.Trait] = + tree + .collect { + case TraitWithTypeConstructor(name) => name + } + + val thriftServices = + symbols + .map { alg => + val name = alg.name.value + + val companion = + tree + .collect { + case obj@Defn.Object(_, Term.Name(`name`), _) => obj + } + .headOption + + ThriftService(alg, companion) + } + + val patches = thriftServices.map(_.toPatch) + + println(Patch.fromIterable(patches)) +} diff --git a/scalafix/tests/src/test/scala/com/dwolla/scrooge/scalafix/RuleSuite.scala b/scalafix/tests/src/test/scala/com/dwolla/scrooge/scalafix/RuleSuite.scala new file mode 100644 index 000000000..db06df376 --- /dev/null +++ b/scalafix/tests/src/test/scala/com/dwolla/scrooge/scalafix/RuleSuite.scala @@ -0,0 +1,8 @@ +package com.dwolla.scrooge.scalafix + +import scalafix.testkit._ +import org.scalatest.FunSuiteLike + +class RuleSuite extends AbstractSemanticRuleSuite with FunSuiteLike { + runAllTests() +} From dbfa8e7579c06658ccbe3628ad56804632e2fd7c Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Wed, 29 Sep 2021 17:37:45 -0500 Subject: [PATCH 3/3] only add cats-tagless instances if they don't already exist on the companion object --- scalafix/README.md | 3 - .../scala/example/thrift/SimpleService.scala | 3 - scalafix/regenerate-inputs.sh | 2 +- .../scalafix/AddCatsTaglessInstances.scala | 130 ++++++++++++++---- .../AddCatsTaglessInstancesTest.scala | 5 + 5 files changed, 109 insertions(+), 34 deletions(-) diff --git a/scalafix/README.md b/scalafix/README.md index 6060ad285..eb850ff3b 100644 --- a/scalafix/README.md +++ b/scalafix/README.md @@ -21,13 +21,10 @@ blank line at the end of the `SimpleService` object with these lines: ```scala - implicit def SimpleServiceInReaderT[F[_]]: SimpleService[({type Λ[β0] = _root_.cats.data.ReaderT[F, SimpleService[F], β0]})#Λ] = _root_.cats.tagless.Derive.readerT[SimpleService, F] implicit val SimpleServiceFunctorK: _root_.cats.tagless.FunctorK[SimpleService] = _root_.cats.tagless.Derive.functorK[SimpleService] - - ``` (Newlines and whitespace matter to the tests!) diff --git a/scalafix/output/src/main/scala/example/thrift/SimpleService.scala b/scalafix/output/src/main/scala/example/thrift/SimpleService.scala index 708f3e2c7..bc3ec4961 100644 --- a/scalafix/output/src/main/scala/example/thrift/SimpleService.scala +++ b/scalafix/output/src/main/scala/example/thrift/SimpleService.scala @@ -1068,11 +1068,8 @@ object SimpleService extends _root_.com.twitter.finagle.thrift.GeneratedThriftSe } } - implicit def SimpleServiceInReaderT[F[_]]: SimpleService[({type Λ[β0] = _root_.cats.data.ReaderT[F, SimpleService[F], β0]})#Λ] = _root_.cats.tagless.Derive.readerT[SimpleService, F] implicit val SimpleServiceFunctorK: _root_.cats.tagless.FunctorK[SimpleService] = _root_.cats.tagless.Derive.functorK[SimpleService] - - } diff --git a/scalafix/regenerate-inputs.sh b/scalafix/regenerate-inputs.sh index 0b7fb0269..b045547d3 100755 --- a/scalafix/regenerate-inputs.sh +++ b/scalafix/regenerate-inputs.sh @@ -31,7 +31,7 @@ libraryDependencies ++= { (Compile / scroogeThriftOutputFolder) := file("src/main/scala") __EOF__ -sbt compile +sbt scroogeGen find "../output/${GENERATED_SOURCES}" -name "*.scala" -delete cp "${GENERATED_SOURCES}"/* "../output/${GENERATED_SOURCES}/" find src/main/scala -name "*.scala" -print0 | \ diff --git a/scalafix/rules/src/main/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstances.scala b/scalafix/rules/src/main/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstances.scala index 18028388c..949412552 100644 --- a/scalafix/rules/src/main/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstances.scala +++ b/scalafix/rules/src/main/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstances.scala @@ -33,45 +33,121 @@ class AddCatsTaglessInstances extends SemanticRule("AddCatsTaglessInstances") { .map(_.toPatch) } -object TraitWithTypeConstructor { - def unapply(subtree: Tree): Option[Defn.Trait] = - PartialFunction.condOpt(subtree) { - case term@Defn.Trait(_, _, List(Type.Param(_, _, List(_: Type.Param), _, _, _)), _, _) => term - } -} - case class ThriftService(alg: Defn.Trait, companion: Option[Defn.Object]) { - def code: String = - s""" implicit def ${alg.name}InReaderT[F[_]]: ${alg.name}[({type Λ[β0] = _root_.cats.data.ReaderT[F, ${alg.name}[F], β0]})#Λ] = - | _root_.cats.tagless.Derive.readerT[${alg.name}, F] - | - | implicit val ${alg.name}FunctorK: _root_.cats.tagless.FunctorK[${alg.name}] = _root_.cats.tagless.Derive.functorK[${alg.name}] - | - |""".stripMargin + private def allInstances: List[ImplicitInstance] = List( + ImplicitInstance.AlgebraInKleisli(alg.name.value), + ImplicitInstance.FunctorK(alg.name.value), + ) + + private def code(instances: List[ImplicitInstance]): String = + instances.map(_.code).mkString("", "\n", "\n") def toPatch: Patch = companion match { case None => val companionString = s"""| - |object ${alg.name} { - |$code + |object ${alg.name} { + |${code(allInstances)} |}""".stripMargin Patch.addRight(alg, companionString) case Some(companion) => - companion.tokens.last match { - case brace@Token.RightBrace() => Patch.addLeft(brace, - s""" - |$code - |""".stripMargin) - case other => Patch.addRight(other, - s""" { - |$code - | - |}""".stripMargin) - } + val algName = alg.name.value + + val existingInstances = companion.collect { + case ImplicitDefAlgInReaderT(`algName`) => ImplicitInstance.AlgebraInKleisli(algName) + case ImplicitValFunctorK(`algName`) => ImplicitInstance.FunctorK(algName) + }.toSet[ImplicitInstance] + + val instancesToAdd = allInstances.filterNot(existingInstances) + + if (instancesToAdd.isEmpty) Patch.empty + else + companion.tokens.last match { + case brace@Token.RightBrace() => + Patch.addLeft(brace, code(instancesToAdd)) + case other => Patch.addRight(other, + s""" { + |${code(instancesToAdd)} + |}""".stripMargin) + } } +} + +sealed trait ImplicitInstance { + def code: String +} +object ImplicitInstance { + case class AlgebraInKleisli(name: String) extends ImplicitInstance { + def code: String = + s""" implicit def ${name}InReaderT[F[_]]: $name[({type Λ[β0] = _root_.cats.data.ReaderT[F, $name[F], β0]})#Λ] = + | _root_.cats.tagless.Derive.readerT[$name, F] + |""".stripMargin + } + case class FunctorK(name: String) extends ImplicitInstance { + def code: String = + s" implicit val ${name}FunctorK: _root_.cats.tagless.FunctorK[$name] = _root_.cats.tagless.Derive.functorK[$name]" + } +} + +object TraitWithTypeConstructor { + def unapply(subtree: Tree): Option[Defn.Trait] = + PartialFunction.condOpt(subtree) { + case term@Defn.Trait(_, _, TypeParamWithSingleHole(_), _, _) => term + } +} + +object TypeParamWithSingleHole { + def unapply(list: List[Type.Param]): Option[String] = + PartialFunction.condOpt(list) { + case List(Type.Param(_, Type.Name(name), List(_: Type.Param), _, _, _)) => name + } +} + +object SingleTypeParameter { + def unapply(tree: List[Type.Param]): Option[String] = + PartialFunction.condOpt(tree) { + case List(Type.Param(_, Type.Name(name), List(), _, _, _)) => name + } +} + +object ImplicitValFunctorK { + def unapply(tree: Defn.Val): Option[String] = + PartialFunction.condOpt(tree) { + case Defn.Val(List(Mod.Implicit()), _, Some(FunctorK(name)), _) => name + } +} + +object ImplicitDefAlgInReaderT { + def unapply(tree: Defn.Def): Option[String] = + PartialFunction.condOpt(tree) { + case Defn.Def(List(Mod.Implicit()), _, TypeParamWithSingleHole(passedEffect), _, Some(Type.Apply(Type.Name(algName), TypeProjectionOfReaderT(effect, alg))), _) if passedEffect == effect && algName == alg => + algName + } +} + +object TypeProjectionOfReaderT { + def unapply(tree: List[Type]): Option[(String, String)] = + PartialFunction.condOpt(tree) { + case List(Type.Project(Type.Refine(_, List(Defn.Type(_, _, SingleTypeParameter(projType), ReaderT(kleisliEffect, algName, outputType)))), _)) if projType == outputType => + (kleisliEffect, algName) + } +} + +object ReaderT { + def unapply(tree: Type.Apply): Option[(String, String, String)] = + PartialFunction.condOpt(tree) { + case Type.Apply(Type.Select(_, Type.Name("ReaderT")), List(Type.Name(kleisliEffect), Type.Apply(Type.Name(algName), List(Type.Name(algEffect))), Type.Name(outputType))) if kleisliEffect == algEffect => + (kleisliEffect, algName, outputType) + } +} + +object FunctorK { + def unapply(tree: Type.Apply): Option[String] = + PartialFunction.condOpt(tree) { + case Type.Apply(Type.Select(_, Type.Name("FunctorK")), List(Type.Name(name))) => name + } } diff --git a/scalafix/rules/src/test/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstancesTest.scala b/scalafix/rules/src/test/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstancesTest.scala index 5557da691..19987474a 100644 --- a/scalafix/rules/src/test/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstancesTest.scala +++ b/scalafix/rules/src/test/scala/com/dwolla/scrooge/scalafix/AddCatsTaglessInstancesTest.scala @@ -10,6 +10,11 @@ object AddCatsTaglessInstancesTest extends App { f"""trait SimpleService[F[_]] |object SimpleService extends _root_.com.twitter.finagle.thrift.GeneratedThriftService { self => | val annotations: immutable$$Map[String, String] = immutable$$Map.empty + | + | implicit def SimpleServiceInReaderT[F[_]]: SimpleService[({type Λ[β0] = _root_.cats.data.ReaderT[F, SimpleService[F], β0]})#Λ] = + | _root_.cats.tagless.Derive.readerT[SimpleService, F] + | + | implicit val SimpleServiceFunctorK: _root_.cats.tagless.FunctorK[SimpleService] = _root_.cats.tagless.Derive.functorK[SimpleService] |} |trait Bar |trait Baz[F]