From 43af6f6bffd25c21e789a337e915333b3200f3c2 Mon Sep 17 00:00:00 2001 From: Rodolfo Hansen Date: Sat, 1 Nov 2014 17:07:26 -0500 Subject: [PATCH 1/2] Have an implicit instance for Equivalent classes, (A === B) --- core/src/main/scala/Pickler.scala | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/main/scala/Pickler.scala b/core/src/main/scala/Pickler.scala index f45ea56..ea3dab9 100644 --- a/core/src/main/scala/Pickler.scala +++ b/core/src/main/scala/Pickler.scala @@ -1,6 +1,7 @@ package gkit import scalaz._ +import Leibniz.=== import scalaz.syntax.std.option._ import scalaz.syntax.either._ @@ -13,6 +14,11 @@ trait Pickler[A, B] { def unpickle(b: B, path: List[String] = Nil): String \/ A + implicit def leibPickler[A, B](implicit f: A === B): Pickler[A, B] = new Pickler[A, B] { + def pickle(a: A): B = f(a) + def unpickle(b: B, path: List[String]): String \/ A = Leibniz.symm[Nothing, Any, A, B](f)(b).right + } + class Typecheck[A] { def apply[B, C](b: B, path: List[String])(f: A => C) (implicit tpble: Typeable[A], tm: Manifest[A]): String \/ C = { From 0d01aa9143f5fcba3fe21005f3e15262c796f19c Mon Sep 17 00:00:00 2001 From: Rodolfo Hansen Date: Tue, 4 Nov 2014 10:57:35 -0600 Subject: [PATCH 2/2] Facilitate the usage of Leibniz and Liskov picklers. --- core/src/main/scala/Pickler.scala | 25 ++++++++++++++----- mongo/src/main/scala/BSONPickler.scala | 15 +---------- mongo/src/main/scala/package.scala | 6 ++++- play-gjson/src/main/scala/JSONPickler.scala | 5 +++- .../src/main/scala/PicklerInstances.scala | 1 + 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/core/src/main/scala/Pickler.scala b/core/src/main/scala/Pickler.scala index ea3dab9..1d15cfb 100644 --- a/core/src/main/scala/Pickler.scala +++ b/core/src/main/scala/Pickler.scala @@ -2,6 +2,7 @@ package gkit import scalaz._ import Leibniz.=== +import Liskov.<~< import scalaz.syntax.std.option._ import scalaz.syntax.either._ @@ -14,18 +15,30 @@ trait Pickler[A, B] { def unpickle(b: B, path: List[String] = Nil): String \/ A +} + +object Pickler extends LowerPriorityPickler { implicit def leibPickler[A, B](implicit f: A === B): Pickler[A, B] = new Pickler[A, B] { def pickle(a: A): B = f(a) def unpickle(b: B, path: List[String]): String \/ A = Leibniz.symm[Nothing, Any, A, B](f)(b).right } - class Typecheck[A] { - def apply[B, C](b: B, path: List[String])(f: A => C) - (implicit tpble: Typeable[A], tm: Manifest[A]): String \/ C = { - def errMsg = s"""type mismatch at `${path.mkString(".")}': expected: ${tm.runtimeClass.getName}, found: ${b.toString}""" - b.cast[A].cata(f(_).right, errMsg.left) - } +} + +trait LowerPriorityPickler { + implicit def liskovPickler[A, B](implicit f: A <~< B, tpble: Typeable[A], tm: Manifest[A]): Pickler[A, B] = new Pickler[A, B] { + def pickle(a: A): B = f(a) + def unpickle(b: B, path: List[String]): String \/ A = + typecheck[A](b, path)(identity) } def typecheck[A]: Typecheck[A] = new Typecheck[A] } + +class Typecheck[A] { + def apply[B, C](b: B, path: List[String])(f: A => C) + (implicit tpble: Typeable[A], tm: Manifest[A]): String \/ C = { + def errMsg = s"""type mismatch at `${path.mkString(".")}': expected: ${tm.runtimeClass.getName}, found: ${b.toString}""" + b.cast[A].cata(f(_).right, errMsg.left) + } +} diff --git a/mongo/src/main/scala/BSONPickler.scala b/mongo/src/main/scala/BSONPickler.scala index b021b1d..7451d9f 100644 --- a/mongo/src/main/scala/BSONPickler.scala +++ b/mongo/src/main/scala/BSONPickler.scala @@ -17,9 +17,8 @@ import scalaz.syntax.traverse._ import shapeless._ import shapeless.record._ -trait BSONPickler[A] extends Pickler[A, BSONValue] - object BSONPickler { + import Pickler._ implicit def apply[A](implicit ev: LabelledTypeClass[BSONPickler]): BSONPickler[A] = macro GenericMacros.deriveLabelledInstance[BSONPickler, A] @@ -56,18 +55,6 @@ object BSONPickler { typecheck[BSONDateTime](v, path)(dt => new DateTime(dt.value)) } - implicit def BSONObjectIDPickler: BSONPickler[BSONObjectID] = new BSONPickler[BSONObjectID] { - def pickle(boid: BSONObjectID): BSONValue = boid - def unpickle(v: BSONValue, path: List[String]): String \/ BSONObjectID = - typecheck[BSONObjectID](v, path)(identity) - } - - implicit def BSONDocumentPickler: BSONPickler[BSONDocument] = new BSONPickler[BSONDocument] { - def pickle(doc: BSONDocument): BSONValue = doc - def unpickle(v: BSONValue, path: List[String]): String \/ BSONDocument = - typecheck[BSONDocument](v, path)(identity) - } - implicit def OptionBSONPickler[T](implicit bp: BSONPickler[T]): BSONPickler[Option[T]] = new BSONPickler[Option[T]] { def pickle(t: Option[T]): BSONValue = t.map(bp.pickle).getOrElse(BSONUndefined) def unpickle(v: BSONValue, path: List[String]): String \/ Option[T] = diff --git a/mongo/src/main/scala/package.scala b/mongo/src/main/scala/package.scala index 0121be0..218b11a 100644 --- a/mongo/src/main/scala/package.scala +++ b/mongo/src/main/scala/package.scala @@ -1,3 +1,7 @@ package gkit -package object mongo extends QueryPicklerInstances with GeneratorInstances +import reactivemongo.bson.BSONValue + +package object mongo extends QueryPicklerInstances with GeneratorInstances { + type BSONPickler[A] = Pickler[A, BSONValue] +} diff --git a/play-gjson/src/main/scala/JSONPickler.scala b/play-gjson/src/main/scala/JSONPickler.scala index 76e9453..18e534b 100644 --- a/play-gjson/src/main/scala/JSONPickler.scala +++ b/play-gjson/src/main/scala/JSONPickler.scala @@ -17,9 +17,12 @@ import scalaz.syntax.traverse._ import shapeless._ import shapeless.record._ -trait JSONPickler[A] extends Pickler[A, JsValue] +object `package` { + type JSONPickler[A] = Pickler[A, JsValue] +} object JSONPickler { + import Pickler._ implicit def apply[A](implicit ev: LabelledTypeClass[JSONPickler]): JSONPickler[A] = macro GenericMacros.deriveLabelledInstance[JSONPickler, A] diff --git a/play-gresource-mongo/src/main/scala/PicklerInstances.scala b/play-gresource-mongo/src/main/scala/PicklerInstances.scala index b910316..c52bbfe 100644 --- a/play-gresource-mongo/src/main/scala/PicklerInstances.scala +++ b/play-gresource-mongo/src/main/scala/PicklerInstances.scala @@ -11,6 +11,7 @@ import scalaz.syntax.either._ import scalaz.syntax.std.option._ trait PicklerInstances { + import gkit.Pickler._ implicit def BSONObjectIDPickler: JSONPickler[BSONObjectID] = new JSONPickler[BSONObjectID] {