Skip to content

Commit

Permalink
Idiomatic scala 3 implicits
Browse files Browse the repository at this point in the history
  • Loading branch information
RustedBones committed Nov 16, 2023
1 parent e4a2c99 commit f8f7f68
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 53 deletions.
51 changes: 51 additions & 0 deletions guava/src/main/scala-2/magnolify/guava/FunnelImplicits.scala
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
16 changes: 16 additions & 0 deletions guava/src/main/scala-2/magnolify/guava/GuavaMacros.scala
Original file line number Diff line number Diff line change
@@ -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
Expand Down
45 changes: 45 additions & 0 deletions guava/src/main/scala-3/magnolify/guava/FunnelImplicits.scala
Original file line number Diff line number Diff line change
@@ -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
16 changes: 16 additions & 0 deletions guava/src/main/scala-3/magnolify/guava/GuavaMacros.scala
Original file line number Diff line number Diff line change
@@ -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
Expand Down
50 changes: 0 additions & 50 deletions guava/src/main/scala/magnolify/guava/FunnelImplicits.scala

This file was deleted.

50 changes: 50 additions & 0 deletions guava/src/main/scala/magnolify/guava/FunnelInstances.scala
Original file line number Diff line number Diff line change
@@ -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)
}
}
10 changes: 7 additions & 3 deletions guava/src/test/scala/magnolify/guava/ScopeTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]
}
}

0 comments on commit f8f7f68

Please sign in to comment.