diff --git a/guava/src/main/scala-2/magnolify/guava/FunnelImplicits.scala b/guava/src/main/scala-2/magnolify/guava/FunnelImplicits.scala new file mode 100644 index 000000000..6cd690603 --- /dev/null +++ b/guava/src/main/scala-2/magnolify/guava/FunnelImplicits.scala @@ -0,0 +1,51 @@ +/* + * Copyright 2023 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package magnolify.guava + +import com.google.common.hash.{Funnel, PrimitiveSink} + +trait FunnelImplicits { + import FunnelImplicits.* + def Funnel[T](implicit fnl: Funnel[T]): Funnel[T] = fnl + + implicit val intFunnel: Funnel[Int] = FunnelInstances.intFunnel() + implicit val longFunnel: Funnel[Long] = FunnelInstances.longFunnel() + implicit val bytesFunnel: Funnel[Array[Byte]] = FunnelInstances.bytesFunnel() + implicit val booleanFunnel: Funnel[Boolean] = FunnelInstances.booleanFunnel() + implicit val byteFunnel: Funnel[Byte] = FunnelInstances.byteFunnel() + implicit val charFunnel: Funnel[Char] = FunnelInstances.charFunnel() + implicit val shortFunnel: Funnel[Short] = FunnelInstances.shortFunnel() + + implicit def charSequenceFunnel[T <: CharSequence]: Funnel[T] = + FunnelInstances.charSequenceFunnel[T] + + // There is an implicit Option[T] => Iterable[T] + implicit def iterableFunnel[T, C[_]](implicit + fnl: Funnel[T], + ti: C[T] => Iterable[T] + ): Funnel[C[T]] = FunnelInstances.iterableFunnel(fnl).contramap(ti) + + implicit def funnelOps[T](fnl: Funnel[T]): FunnelOps[T] = new FunnelOps(fnl) +} + +object FunnelImplicits extends FunnelImplicits { + final class FunnelOps[T](val fnl: Funnel[T]) extends AnyVal { + def contramap[U](f: U => T): Funnel[U] = new Funnel[U] { + override def funnel(from: U, into: PrimitiveSink): Unit = fnl.funnel(f(from), into) + } + } +} diff --git a/guava/src/main/scala-2/magnolify/guava/GuavaMacros.scala b/guava/src/main/scala-2/magnolify/guava/GuavaMacros.scala index 96f6822f7..cd4814f6c 100644 --- a/guava/src/main/scala-2/magnolify/guava/GuavaMacros.scala +++ b/guava/src/main/scala-2/magnolify/guava/GuavaMacros.scala @@ -1,3 +1,19 @@ +/* + * Copyright 2023 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package magnolify.guava import com.google.common.hash.Funnel diff --git a/guava/src/main/scala-3/magnolify/guava/FunnelImplicits.scala b/guava/src/main/scala-3/magnolify/guava/FunnelImplicits.scala new file mode 100644 index 000000000..28f4e1eab --- /dev/null +++ b/guava/src/main/scala-3/magnolify/guava/FunnelImplicits.scala @@ -0,0 +1,45 @@ +/* + * Copyright 2023 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package magnolify.guava + +import com.google.common.hash.{Funnel, PrimitiveSink} + +trait FunnelImplicits: + def Funnel[T](using fnl: Funnel[T]): Funnel[T] = fnl + + given intFunnel: Funnel[Int] = FunnelInstances.intFunnel() + given longFunnel: Funnel[Long] = FunnelInstances.longFunnel() + given bytesFunnel: Funnel[Array[Byte]] = FunnelInstances.bytesFunnel() + given booleanFunnel: Funnel[Boolean] = FunnelInstances.booleanFunnel() + given byteFunnel: Funnel[Byte] = FunnelInstances.byteFunnel() + given charFunnel: Funnel[Char] = FunnelInstances.charFunnel() + given shortFunnel: Funnel[Short] = FunnelInstances.shortFunnel() + + given charSequenceFunnel[T <: CharSequence]: Funnel[T] = + FunnelInstances.charSequenceFunnel[T] + + // There is an implicit Option[T] => Iterable[T] + given iterableFunnel[T, C[_]](using + fnl: Funnel[T], + ti: C[T] => Iterable[T] + ): Funnel[C[T]] = FunnelInstances.iterableFunnel(fnl).contramap(ti) + + extension [T](fnl: Funnel[T]) + def contramap[U](f: U => T): Funnel[U] = new Funnel[U]: + override def funnel(from: U, into: PrimitiveSink): Unit = fnl.funnel(f(from), into) + +object FunnelImplicits extends FunnelImplicits diff --git a/guava/src/main/scala-3/magnolify/guava/GuavaMacros.scala b/guava/src/main/scala-3/magnolify/guava/GuavaMacros.scala index 322916002..bb123d138 100644 --- a/guava/src/main/scala-3/magnolify/guava/GuavaMacros.scala +++ b/guava/src/main/scala-3/magnolify/guava/GuavaMacros.scala @@ -1,3 +1,19 @@ +/* + * Copyright 2023 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package magnolify.guava import com.google.common.hash.Funnel diff --git a/guava/src/main/scala/magnolify/guava/FunnelImplicits.scala b/guava/src/main/scala/magnolify/guava/FunnelImplicits.scala deleted file mode 100644 index 98c2b9757..000000000 --- a/guava/src/main/scala/magnolify/guava/FunnelImplicits.scala +++ /dev/null @@ -1,50 +0,0 @@ -package magnolify.guava - -import com.google.common.hash.{Funnel, Funnels, PrimitiveSink} - -import scala.annotation.nowarn -trait FunnelImplicits { - import FunnelImplicits.* - - private def funnel[T](f: (PrimitiveSink, T) => Any): Funnel[T] = new Funnel[T] { - override def funnel(from: T, into: PrimitiveSink): Unit = f(into, from): @nowarn - } - - implicit val intFunnel: Funnel[Int] = Funnels.integerFunnel().asInstanceOf[Funnel[Int]] - implicit val longFunnel: Funnel[Long] = Funnels.longFunnel().asInstanceOf[Funnel[Long]] - implicit val bytesFunnel: Funnel[Array[Byte]] = Funnels.byteArrayFunnel() - implicit val booleanFunnel: Funnel[Boolean] = funnel[Boolean](_.putBoolean(_)) - implicit val byteFunnel: Funnel[Byte] = funnel[Byte](_.putByte(_)) - implicit val charFunnel: Funnel[Char] = funnel[Char](_.putChar(_)) - implicit val shortFunnel: Funnel[Short] = funnel[Short](_.putShort(_)) - - implicit def charSequenceFunnel[T <: CharSequence]: Funnel[T] = - Funnels.unencodedCharsFunnel().asInstanceOf[Funnel[T]] - - // There is an implicit Option[T] => Iterable[T] - implicit def iterableFunnel[T, C[_]](implicit - fnl: Funnel[T], - ti: C[T] => Iterable[T] - ): Funnel[C[T]] = - funnel { (sink, from) => - var i = 0 - ti(from).foreach { x => - fnl.funnel(x, sink) - i += 1 - } - // inject size to distinguish `None`, `Some("")`, and `List("", "", ...)` - sink.putInt(i) - } - - def Funnel[T](implicit fnl: Funnel[T]): Funnel[T] = fnl - - implicit def funnelOps[T](fnl: Funnel[T]): FunnelOps[T] = new FunnelOps(fnl) -} - -object FunnelImplicits extends FunnelImplicits { - final class FunnelOps[T](val fnl: Funnel[T]) extends AnyVal { - def contramap[U](f: U => T): Funnel[U] = new Funnel[U] { - override def funnel(from: U, into: PrimitiveSink): Unit = fnl.funnel(f(from), into) - } - } -} diff --git a/guava/src/main/scala/magnolify/guava/FunnelInstances.scala b/guava/src/main/scala/magnolify/guava/FunnelInstances.scala new file mode 100644 index 000000000..0a360479d --- /dev/null +++ b/guava/src/main/scala/magnolify/guava/FunnelInstances.scala @@ -0,0 +1,50 @@ +/* + * Copyright 2023 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package magnolify.guava + +import com.google.common.hash.{Funnel, Funnels, PrimitiveSink} + +import scala.annotation.nowarn + +object FunnelInstances { + + private def funnel[T](f: (PrimitiveSink, T) => Any): Funnel[T] = new Funnel[T] { + override def funnel(from: T, into: PrimitiveSink): Unit = f(into, from): @nowarn + } + + // respect naming convention from Funnels + def intFunnel(): Funnel[Int] = Funnels.integerFunnel().asInstanceOf[Funnel[Int]] + def longFunnel(): Funnel[Long] = Funnels.longFunnel().asInstanceOf[Funnel[Long]] + def bytesFunnel(): Funnel[Array[Byte]] = Funnels.byteArrayFunnel() + def booleanFunnel(): Funnel[Boolean] = funnel[Boolean](_.putBoolean(_)) + def byteFunnel(): Funnel[Byte] = funnel[Byte](_.putByte(_)) + def charFunnel(): Funnel[Char] = funnel[Char](_.putChar(_)) + def shortFunnel(): Funnel[Short] = funnel[Short](_.putShort(_)) + + def charSequenceFunnel[T <: CharSequence]: Funnel[T] = + Funnels.unencodedCharsFunnel().asInstanceOf[Funnel[T]] + def iterableFunnel[T](fnl: Funnel[T]): Funnel[Iterable[T]] = + funnel { (sink, xs) => + var i = 0 + xs.foreach { x => + fnl.funnel(x, sink) + i += 1 + } + // inject size to distinguish `None`, `Some("")`, and `List("", "", ...)` + sink.putInt(i) + } +} diff --git a/guava/src/test/scala/magnolify/guava/ScopeTest.scala b/guava/src/test/scala/magnolify/guava/ScopeTest.scala index db2daabc0..1d074723e 100644 --- a/guava/src/test/scala/magnolify/guava/ScopeTest.scala +++ b/guava/src/test/scala/magnolify/guava/ScopeTest.scala @@ -20,14 +20,18 @@ import com.google.common.hash.Funnel import magnolify.test.Simple.* object ScopeTest { - import magnolify.guava.FunnelImplicits.* - object Auto extends magnolify.guava.AutoDerivations { + object Auto { + import magnolify.guava.auto.genFunnel + import magnolify.guava.auto.intFunnel + import magnolify.guava.auto.longFunnel implicitly[Funnel[Integers]] } object Semi { - import magnolify.guava.semiauto.* + import magnolify.guava.semiauto.genFunnel + import magnolify.guava.semiauto.intFunnel + import magnolify.guava.semiauto.longFunnel genFunnel[Integers] } }