Skip to content

Commit

Permalink
Removed dependency from typelevel compiler (#49)
Browse files Browse the repository at this point in the history
* Removed dependency from typelevel compiler
* Fixed 2.11.x compilation
* Readme and improved build
  • Loading branch information
barambani committed Oct 29, 2018
1 parent d6323fb commit 542adab
Show file tree
Hide file tree
Showing 18 changed files with 131 additions and 101 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -2,7 +2,7 @@ sudo: false
dist: trusty
language: scala
scala:
- 2.12.4-bin-typelevel-4
- 2.12.7
- 2.11.11-bin-typelevel-4
jdk:
- oraclejdk8
Expand Down
5 changes: 2 additions & 3 deletions README.md
Expand Up @@ -16,9 +16,8 @@ LaserDisc is a(nother) Scala driver for [Redis](https://redis.io/), written in S
It differentiates itself from the others for having a core layer, which is made up of all the supported Redis commands
and the Redis Serialization Protocol ([RESP](https://redis.io/topics/protocol)), that is strongly typed and which makes
heavy use of [shapeless](https://github.com/milessabin/shapeless) and [refined](https://github.com/fthomas/refined) to
achieve this. It's also worth noting that the core - in order to be built - makes use of
[Typelevel's Scala 2.12](https://typelevel.org/scala) fork, since it requires the enhancements on implicit heuristics
and the surfacing of literal types. Finally, it also provides an implementation of RESP built using
achieve this. It's also worth noting that the core - in order to be built on scala 2.11.x - makes use of
[Typelevel's Scala 2.11](https://typelevel.org/scala) fork, since it requires the enhancements on implicit heuristics. Finally, it also provides an implementation of RESP built using
[scodec](http://scodec.org/).

On top of this, one or more clients can be implemented. The only one currently available out of the box is built using
Expand Down
74 changes: 48 additions & 26 deletions build.sbt
@@ -1,10 +1,15 @@
import sbtcrossproject.{CrossType, crossProject}
import sbtcrossproject.CrossPlugin.autoImport.crossProject
import sbtcrossproject.CrossType

val `scala 211` = "2.11.11-bin-typelevel-4"
val `scala 212` = "2.12.7"

val V = new {
val fs2 = "1.0.0"
val `kind-projector` = "0.9.8"
val kittens = "1.2.0"
val refined = "0.8.7" //FIXME can't upgrade see https://gist.github.com/sirocchj/64a00a28f5cc5776140c776c7db4e2e3
val refined = "0.9.2"
val refined211 = "0.8.7"
val scalacheck = "1.13.5"
val scalatest = "3.0.5"
val `scodec-bits` = "1.1.6"
Expand All @@ -17,14 +22,20 @@ val V = new {
val `fs2-core` = Def.setting("co.fs2" %%% "fs2-core" % V.fs2)
val `fs2-io` = Def.setting("co.fs2" %% "fs2-io" % V.fs2)
val kittens = Def.setting("org.typelevel" %%% "kittens" % V.kittens)
val refined = Def.setting("eu.timepit" %%% "refined" % V.refined)
val `scodec-bits` = Def.setting("org.scodec" %%% "scodec-bits" % V.`scodec-bits`)
val `scodec-core` = Def.setting("org.scodec" %%% "scodec-core" % V.`scodec-core`)
val `scodec-stream` = Def.setting("org.scodec" %%% "scodec-stream" % V.`scodec-stream`)
val shapeless = Def.setting("com.chuusai" %%% "shapeless" % V.shapeless)
val `log-effect-fs2` = Def.setting("io.laserdisc" %%% "log-effect-fs2" % V.`log-effect-fs2`)
val scalacheck = Def.setting("org.scalacheck" %%% "scalacheck" % V.scalacheck % Test)
val scalatest = Def.setting("org.scalatest" %%% "scalatest" % V.scalatest % Test)
val refined = Def.setting {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 11)) => "eu.timepit" %%% "refined" % V.refined211
case _ => "eu.timepit" %%% "refined" % V.refined
}
}


val `kind-projector-compiler-plugin` = Def.setting {
compilerPlugin("org.spire-math" % "kind-projector" % V.`kind-projector` cross CrossVersion.binary)
Expand All @@ -34,7 +45,15 @@ val `scalajs-compiler-plugin` = Def.setting {
}

val coreDeps = Def.Initialize.join {
Seq(`kind-projector-compiler-plugin`, refined, `scodec-bits`, `scodec-core`, shapeless, scalacheck, scalatest)
Seq(
`kind-projector-compiler-plugin`,
`scodec-bits`,
`scodec-core`,
shapeless,
refined,
scalacheck,
scalatest
)
}

val fs2Deps = Def.Initialize.join {
Expand Down Expand Up @@ -81,23 +100,24 @@ val externalApiMappings = Def.task {
}

val versionDependantScalacOptions = Def.setting {
def versionDependent(scalaVersion: String, flags: Seq[String]) = CrossVersion.partialVersion(scalaVersion) match {
case Some((2, major)) if major >= 12 =>
flags ++ Seq(
"-Xlint:constant", // Evaluation of a constant arithmetic expression results in an error.
"-Ywarn-extra-implicit", // Warn when more than one implicit parameter section is defined.
"-Ywarn-unused:explicits", // Warn if a parameter is unused.
"-Ywarn-unused:imports", // Warn if an import selector is not referenced.
"-Ywarn-unused:locals", // Warn if a local definition is unused.
"-Ywarn-unused:patvars", // Warn if a variable bound in a pattern is unused.
"-Ywarn-unused:privates", // Warn if a private member is unused.
"-Ywarn-value-discard" // Warn when non-Unit expression results are unused.
)
case _ =>
flags
.filterNot(_ == "-Xlint:missing-interpolator") //@implicitNotFound uses ${A} syntax w/o need for s interpolator
}

def versionDependent(scalaVersion: String, flags: Seq[String]) =
CrossVersion.partialVersion(scalaVersion) match {
case Some((2, major)) if major >= 12 =>
flags ++ Seq(
"-Xlint:constant", // Evaluation of a constant arithmetic expression results in an error.
"-Ywarn-extra-implicit", // Warn when more than one implicit parameter section is defined.
"-Ywarn-unused:explicits", // Warn if a parameter is unused.
"-Ywarn-unused:imports", // Warn if an import selector is not referenced.
"-Ywarn-unused:locals", // Warn if a local definition is unused.
"-Ywarn-unused:patvars", // Warn if a variable bound in a pattern is unused.
"-Ywarn-unused:privates", // Warn if a private member is unused.
"-Ywarn-value-discard" // Warn when non-Unit expression results are unused.
)
case _ =>
(flags ++ Seq("-Yinduction-heuristics", "-Yliteral-types"))
.filterNot(_ == "-Xlint:missing-interpolator") //@implicitNotFound uses ${A} syntax w/o need for s interpolator
}

val flags = Seq(
"-deprecation", // Emit warning and location for usages of deprecated APIs.
"-encoding",
Expand Down Expand Up @@ -136,8 +156,6 @@ val versionDependantScalacOptions = Def.setting {
"-Ywarn-nullary-override", // Warn when non-nullary `def f()' overrides nullary `def f'.
"-Ywarn-nullary-unit", // Warn when nullary methods return Unit.
"-Ywarn-numeric-widen", // Warn when numerics are widened.
"-Yinduction-heuristics", // Nobody wants recursive implicit searches that last forever, we need TLS for this
"-Yliteral-types" // Allow inferring singleton types, we need TLS for this in 2.12
)

versionDependent(scalaVersion.value, flags)
Expand All @@ -146,13 +164,17 @@ val versionDependantScalacOptions = Def.setting {
inThisBuild {
Def.settings(
organization := "io.laserdisc",
scalaOrganization := "org.typelevel",
scalaVersion := "2.12.4-bin-typelevel-4"
scalaVersion := `scala 212`
)
}

lazy val commonSettings = Seq(
crossScalaVersions := Seq("2.11.11-bin-typelevel-4", "2.12.4-bin-typelevel-4"),
scalaOrganization :=
(CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 11)) => "org.typelevel"
case _ => "org.scala-lang"
}),
crossScalaVersions := Seq(`scala 211`, `scala 212`),
scalacOptions ++= versionDependantScalacOptions.value,
Compile / console / scalacOptions --= Seq("-Ywarn-unused:imports", "-Xfatal-warnings"),
Test / console / scalacOptions := (Compile / console / scalacOptions).value
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/boilerplate/HashPExtra.scala.template
Expand Up @@ -23,7 +23,7 @@ trait HashPExtra { this: HashP =>
]

//HMSET
[..21#final def hmset[[#A1 <: XString, B1: Show#]](key: Key, [#field1: SingletonKey[A1], value1: B1#]): Protocol.Aux["OK"] = {
[..21#final def hmset[[#A1 <: XString, B1: Show#]](key: Key, [#field1: SingletonKey[A1], value1: B1#]): Protocol.Aux[OK] = {
[#val tagged1 = tag[A1](Symbol(field1.value))#
]
hmset(key, [#labelled.field[tagged1.type](value1)# :: ] :: HNil)
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/boilerplate/HyperLogLogPExtra.scala.template
Expand Up @@ -13,7 +13,7 @@ trait HyperLogLogPExtra { this: HyperLogLogP =>
]

//PFMERGE
[..20#final def pfmerge(sourceKey##1: Key, [#sourceKey2: Key#], destinationKey: Key): Protocol.Aux["OK"] =
[..20#final def pfmerge(sourceKey##1: Key, [#sourceKey2: Key#], destinationKey: Key): Protocol.Aux[OK] =
pfmerge(TwoOrMoreKeys.unsafeFrom(sourceKey##1 :: [#sourceKey2# :: ] :: Nil), destinationKey)#
]
}
2 changes: 1 addition & 1 deletion core/src/main/boilerplate/StringPExtra.scala.template
Expand Up @@ -19,7 +19,7 @@ trait StringPExtra { this: StringP =>
]

//MSET
[#final def mset[[#A1 <: XString, B1: Show#]]([#key1: SingletonKey[A1], value1: B1#]): Protocol.Aux["OK"] = {
[#final def mset[[#A1 <: XString, B1: Show#]]([#key1: SingletonKey[A1], value1: B1#]): Protocol.Aux[OK] = {
[#val tagged1 = tag[A1](Symbol(key1.value))#
]
mset([#labelled.field[tagged1.type](value1)# :: ] :: HNil)
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/scala-2.11/laserdisc/protocol.scala
@@ -1,7 +1,9 @@
package laserdisc

package object protocol {
implicit def eitherSyntaxBase[A, B](aOrB: A | B): EitherSyntaxBaseOps[A, B] = new EitherSyntaxBaseOps(aOrB)

implicit def eitherSyntaxBase[A, B](aOrB: A | B): EitherSyntaxBaseOps[A, B] =
new EitherSyntaxBaseOps(aOrB)
}

final private[laserdisc] class EitherSyntaxBaseOps[A, B](private val aOrB: A | B) extends AnyVal {
Expand Down
7 changes: 7 additions & 0 deletions core/src/main/scala/laserdisc/package.scala
@@ -1,6 +1,7 @@
import java.{lang => j}

import eu.timepit.refined.W
import eu.timepit.refined.auto._
import eu.timepit.refined.api._
import eu.timepit.refined.boolean.{And, Not, Or, True}
import eu.timepit.refined.char.Whitespace
Expand All @@ -23,6 +24,12 @@ package object laserdisc {
final type RESP = protocol.RESP
final type Show[A] = protocol.Show[A]

final type OK = String Refined Equal[W.`"OK"`.T]
final type PONG = String Refined Equal[W.`"PONG"`.T]

final val OK: OK = "OK"
final val PONG: PONG = "PONG"

//object forwarders
final val Protocol = protocol.Protocol
final val Read = protocol.Read
Expand Down
16 changes: 8 additions & 8 deletions core/src/main/scala/laserdisc/protocol/ConnectionP.scala
Expand Up @@ -4,22 +4,22 @@ package protocol
trait ConnectionP {
import Read.==>

private[this] implicit final val pongRead: SimpleString ==> "PONG" = Read.instancePF {
case SimpleString("PONG") => "PONG"
private[this] implicit final val pongRead: SimpleString ==> PONG = Read.instancePF {
case SimpleString("PONG") => PONG
}

final def auth(password: Key): Protocol.Aux["OK"] = Protocol("AUTH", password).as[SimpleString, "OK"]
final def auth(password: Key): Protocol.Aux[OK] = Protocol("AUTH", password).as[SimpleString, OK]

final def echo(message: Key): Protocol.Aux[Key] = Protocol("ECHO", message).as[NonNullBulkString, Key]

final val ping: Protocol.Aux["PONG"] = Protocol("PING", Nil).as[SimpleString, "PONG"]
final val ping: Protocol.Aux[PONG] = Protocol("PING", Nil).as[SimpleString, PONG]

final def ping(message: Key): Protocol.Aux[Key] = Protocol("PING", message).as[NonNullBulkString, Key]

final val quit: Protocol.Aux["OK"] = Protocol("QUIT", Nil).as[SimpleString, "OK"]
final val quit: Protocol.Aux[OK] = Protocol("QUIT", Nil).as[SimpleString, OK]

final def select(index: DbIndex): Protocol.Aux["OK"] = Protocol("SELECT", index).as[SimpleString, "OK"]
final def select(index: DbIndex): Protocol.Aux[OK] = Protocol("SELECT", index).as[SimpleString, OK]

final def swapdb(index1: DbIndex, index2: DbIndex): Protocol.Aux["OK"] =
Protocol("SWAPDB", index1 :: index2 :: Nil).as[SimpleString, "OK"]
final def swapdb(index1: DbIndex, index2: DbIndex): Protocol.Aux[OK] =
Protocol("SWAPDB", index1 :: index2 :: Nil).as[SimpleString, OK]
}
4 changes: 2 additions & 2 deletions core/src/main/scala/laserdisc/protocol/HashP.scala
Expand Up @@ -42,15 +42,15 @@ trait HashP {
implicit ev0: Length.Aux[L, N],
ev1: N >= _1,
ev2: LUBConstraint[L, FieldType[_, _]]
): Protocol.Aux["OK"] = Protocol("HMSET", key :: l).as[SimpleString, "OK"]
): Protocol.Aux[OK] = Protocol("HMSET", key :: l).as[SimpleString, OK]

final def hmset[P <: Product, L <: HList, N <: Nat](key: Key, product: P)(
implicit gen: LabelledGeneric.Aux[P, L],
ev0: Length.Aux[L, N],
ev1: N >= _1,
ev2: LUBConstraint[L, FieldType[_, _]],
ev3: RESPParamWrite[L]
): Protocol.Aux["OK"] = Protocol("HMSET", key :: gen.to(product)).as[SimpleString, "OK"]
): Protocol.Aux[OK] = Protocol("HMSET", key :: gen.to(product)).as[SimpleString, OK]

final def hscan(key: Key, cursor: NonNegLong): Protocol.Aux[ScanKV] =
Protocol("HSCAN", key :: cursor :: HNil).as[NonNilArray, ScanKV]
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/laserdisc/protocol/HyperLogLogP.scala
Expand Up @@ -8,8 +8,8 @@ trait HyperLogLogP {
final def pfcount(keys: OneOrMoreKeys): Protocol.Aux[NonNegInt] =
Protocol("PFCOUNT", keys.value).as[Integer, NonNegInt]

final def pfmerge(sourceKeys: TwoOrMoreKeys, destinationKey: Key): Protocol.Aux["OK"] =
Protocol("PFMERGE", destinationKey :: sourceKeys.value).as[SimpleString, "OK"]
final def pfmerge(sourceKeys: TwoOrMoreKeys, destinationKey: Key): Protocol.Aux[OK] =
Protocol("PFMERGE", destinationKey :: sourceKeys.value).as[SimpleString, OK]
}

trait AllHyperLogLogP extends HyperLogLogP with HyperLogLogPExtra
8 changes: 4 additions & 4 deletions core/src/main/scala/laserdisc/protocol/KeyP.scala
Expand Up @@ -135,11 +135,11 @@ trait KeyP {
final def renamenx(key: Key, newKey: Key): Protocol.Aux[Boolean] =
Protocol("RENAMENX", key :: newKey :: Nil).as[Integer, Boolean]

final def restore(key: Key, ttl: NonNegLong, serializedValue: NonNullBulkString): Protocol.Aux["OK"] =
Protocol("RESTORE", key :: ttl :: serializedValue :: HNil).as[SimpleString, "OK"]
final def restore(key: Key, ttl: NonNegLong, serializedValue: NonNullBulkString): Protocol.Aux[OK] =
Protocol("RESTORE", key :: ttl :: serializedValue :: HNil).as[SimpleString, OK]

final def restorereplace(key: Key, ttl: NonNegLong, serializedValue: NonNullBulkString): Protocol.Aux["OK"] =
Protocol("RESTORE", key :: ttl :: serializedValue :: "REPLACE" :: HNil).as[SimpleString, "OK"]
final def restorereplace(key: Key, ttl: NonNegLong, serializedValue: NonNullBulkString): Protocol.Aux[OK] =
Protocol("RESTORE", key :: ttl :: serializedValue :: "REPLACE" :: HNil).as[SimpleString, OK]

final def scan(cursor: NonNegLong): Protocol.Aux[Scan[Key]] = Protocol("SCAN", cursor).as[NonNilArray, Scan[Key]]

Expand Down
8 changes: 4 additions & 4 deletions core/src/main/scala/laserdisc/protocol/ListP.scala
Expand Up @@ -53,11 +53,11 @@ trait ListP {
final def lrem[A: Show](key: Key, count: Index, value: A): Protocol.Aux[NonNegInt] =
Protocol("LREM", key :: count :: value :: HNil).as[Integer, NonNegInt]

final def lset[A: Show](key: Key, index: Index, value: A): Protocol.Aux["OK"] =
Protocol("LSET", key :: index :: value :: HNil).as[SimpleString, "OK"]
final def lset[A: Show](key: Key, index: Index, value: A): Protocol.Aux[OK] =
Protocol("LSET", key :: index :: value :: HNil).as[SimpleString, OK]

final def ltrim(key: Key, start: Index, stop: Index): Protocol.Aux["OK"] =
Protocol("LTRIM", key :: start :: stop :: HNil).as[SimpleString, "OK"]
final def ltrim(key: Key, start: Index, stop: Index): Protocol.Aux[OK] =
Protocol("LTRIM", key :: start :: stop :: HNil).as[SimpleString, OK]

final def rpop[A](key: Key)(
implicit ev: NonNullBulkString ==> A
Expand Down
13 changes: 7 additions & 6 deletions core/src/main/scala/laserdisc/protocol/Read.scala
Expand Up @@ -72,8 +72,8 @@ trait LowPriorityReadInstances extends LowerPriorityReadInstances {
implicit final val simpleString2StringRead: SimpleString ==> String = Read.instance {
case SimpleString(s) => Some(s)
}
implicit final val simpleString2OKRead: SimpleString ==> "OK" = Read.instancePF {
case SimpleString("OK") => "OK"
implicit final val simpleString2OKRead: SimpleString ==> OK = Read.instancePF {
case SimpleString("OK") => OK
}
implicit final val simpleString2KeyRead: SimpleString ==> Key = Read.instancePF {
case SimpleString(Key(s)) => s
Expand Down Expand Up @@ -165,7 +165,7 @@ trait LowPriorityReadInstances extends LowerPriorityReadInstances {

implicit final def nonNilArray2Tuple2Read[A, B](
implicit RA: NonNullBulkString ==> A,
RB: NonNullBulkString ==> B,
RB: NonNullBulkString ==> B
): NonNilArray ==> (A, B) = Read.instancePF {
case NonNilArray(RA(key) +: RB(value) +: Seq()) => key -> value
}
Expand Down Expand Up @@ -243,9 +243,10 @@ trait LowPriorityReadInstances extends LowerPriorityReadInstances {
}

implicit final def nonNilArray2HCons[H, T <: HList](
implicit ev: H <:!< FieldType[_, _],
RH: NonNullBulkString ==> H,
RT: NonNilArray ==> T
implicit
ev: H <:!< FieldType[_, _],
RH: NonNullBulkString ==> H,
RT: NonNilArray ==> T
): NonNilArray ==> (H :: T) = Read.instance {
case NonNilArray(RH(h) +: rest) => RT.read(RESP.arr(rest)).map(h :: _)
}
Expand Down

0 comments on commit 542adab

Please sign in to comment.