From 5a4c804c535da98e696e49341f2ec66f73447df5 Mon Sep 17 00:00:00 2001 From: Roman-Statsura Date: Wed, 24 Apr 2024 00:02:52 +0400 Subject: [PATCH] Add readers and writers instances for some cats-collections --- build.sbt | 1 + .../tethys/cats/readers/CatsReaders.scala | 40 +++++++++++++++++- .../tethys/cats/writers/CatsWriters.scala | 39 ++++++++++++++++++ .../scala/tethys/cats/CatsSupportTests.scala | 41 +++++++++++++++++++ 4 files changed, 120 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 747f5c45..e8517086 100644 --- a/build.sbt +++ b/build.sbt @@ -103,6 +103,7 @@ lazy val cats = project.in(modules / "cats") name := "tethys-cats", libraryDependencies ++= Seq( "org.typelevel" %% "cats-core" % "2.10.0", + "org.typelevel" %% "cats-collections-core" % "0.9.8", ) ) .dependsOn(core) diff --git a/modules/cats/src/main/scala/tethys/cats/readers/CatsReaders.scala b/modules/cats/src/main/scala/tethys/cats/readers/CatsReaders.scala index 4c2031ad..94c6cca1 100644 --- a/modules/cats/src/main/scala/tethys/cats/readers/CatsReaders.scala +++ b/modules/cats/src/main/scala/tethys/cats/readers/CatsReaders.scala @@ -1,8 +1,19 @@ package tethys.cats.readers +import cats.{Hash, Order} +import cats.collections.{ + AvlSet, + BitSet, + Dequeue, + HashMap, + HashSet, + Heap, + PairingHeap, + TreeList +} import cats.data._ import tethys.readers.tokens.TokenIterator -import tethys.readers.{FieldName, ReaderError} +import tethys.readers.{FieldName, KeyReader, ReaderError} import tethys.JsonReader import tethys.JsonReader.iterableReader @@ -53,4 +64,31 @@ trait CatsReaders { } } + implicit val readerForBitSet: JsonReader[BitSet] = + JsonReader[Seq[Int]].map(seq => BitSet(seq: _*)) + + implicit def readerForCatsDequeue[T: JsonReader]: JsonReader[Dequeue[T]] = + JsonReader[Seq[T]].map(seq => Dequeue(seq: _*)) + + implicit def readerForCatsHashMap[K: KeyReader: Hash, V: JsonReader] + : JsonReader[HashMap[K, V]] = + JsonReader[Map[K, V]].map(m => HashMap(m.toSeq: _*)) + + implicit def readerForCatsHashSet[T: JsonReader: Hash] + : JsonReader[HashSet[T]] = + JsonReader[Seq[T]].map(HashSet.fromSeq(_)) + + implicit def readerForCatsHeap[T: JsonReader: Order]: JsonReader[Heap[T]] = + JsonReader[Seq[T]].map(Heap.fromIterable(_)) + + implicit def readerForPairingHeap[T: JsonReader: Order] + : JsonReader[PairingHeap[T]] = + JsonReader[Seq[T]].map(PairingHeap.fromIterable(_)) + + implicit def readerForTreeList[T: JsonReader]: JsonReader[TreeList[T]] = + JsonReader[List[T]].map(TreeList.fromList) + + implicit def readerForAvlSet[T: JsonReader: Order]: JsonReader[AvlSet[T]] = + JsonReader[List[T]].map(AvlSet.fromList(_)) + } diff --git a/modules/cats/src/main/scala/tethys/cats/writers/CatsWriters.scala b/modules/cats/src/main/scala/tethys/cats/writers/CatsWriters.scala index a14efa56..1f0c5c92 100644 --- a/modules/cats/src/main/scala/tethys/cats/writers/CatsWriters.scala +++ b/modules/cats/src/main/scala/tethys/cats/writers/CatsWriters.scala @@ -1,7 +1,19 @@ package tethys.cats.writers +import cats.Order +import cats.collections.{ + AvlSet, + BitSet, + Dequeue, + HashMap, + HashSet, + Heap, + PairingHeap, + TreeList +} import cats.data._ import tethys.JsonWriter +import tethys.writers.KeyWriter trait CatsWriters { implicit def writerForNev[T: JsonWriter]: JsonWriter[NonEmptyVector[T]] = @@ -18,4 +30,31 @@ trait CatsWriters { implicit def writerForNec[T: JsonWriter]: JsonWriter[NonEmptyChain[T]] = JsonWriter[Chain[T]].contramap(_.toChain) + + implicit val writerForBitSet: JsonWriter[BitSet] = + JsonWriter[Set[Int]].contramap(_.toSet) + + implicit def writerForCatsDequeue[T: JsonWriter]: JsonWriter[Dequeue[T]] = + JsonWriter[List[T]].contramap(_.toList) + + implicit def writerForCatsHashMap[K: KeyWriter, V: JsonWriter] + : JsonWriter[HashMap[K, V]] = + JsonWriter[Map[K, V]].contramap(_.toMap) + + implicit def writerForCatsHashSet[T: JsonWriter]: JsonWriter[HashSet[T]] = + JsonWriter[Set[T]].contramap(_.toSet) + + implicit def writerForCatsHeap[T: JsonWriter: Order]: JsonWriter[Heap[T]] = + JsonWriter[Seq[T]].contramap(_.toList) + + implicit def writerForPairingHeap[T: JsonWriter: Order] + : JsonWriter[PairingHeap[T]] = + JsonWriter[Seq[T]].contramap(_.toList) + + implicit def writerForTreeList[T: JsonWriter]: JsonWriter[TreeList[T]] = + JsonWriter[List[T]].contramap(_.toList) + + implicit def writerForAvlSet[T: JsonWriter]: JsonWriter[AvlSet[T]] = + JsonWriter[Seq[T]].contramap(_.toList) + } diff --git a/modules/cats/src/test/scala/tethys/cats/CatsSupportTests.scala b/modules/cats/src/test/scala/tethys/cats/CatsSupportTests.scala index 7bd0c36d..4072e74c 100644 --- a/modules/cats/src/test/scala/tethys/cats/CatsSupportTests.scala +++ b/modules/cats/src/test/scala/tethys/cats/CatsSupportTests.scala @@ -1,5 +1,15 @@ package tethys.cats +import cats.collections.{ + AvlSet, + BitSet, + Dequeue, + HashMap, + HashSet, + Heap, + PairingHeap, + TreeList +} import cats.data._ import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers @@ -15,6 +25,15 @@ class CatsSupportTests extends AnyFlatSpec with Matchers { val chain: Chain[Int] = Chain.fromIterableOnce(Seq(1, 2, 3)) val nec: NonEmptyChain[String] = NonEmptyChain.of("a", "b", "c") + val bitSet: BitSet = BitSet.apply(5, 1, 5, 4, 2, 3) + val dequeue: Dequeue[String] = Dequeue("a", "b", "c") + val hashMap: HashMap[String, Int] = HashMap("a" -> 1, "b" -> 2) + val hasSet: HashSet[Int] = HashSet(1, 2, 3) + val heap: Heap[Int] = Heap.fromIterable(Seq(1, 2, 3, 4)) + val pairingHeap: PairingHeap[Int] = PairingHeap.fromIterable(Seq(1, 2, 3)) + val treeList: TreeList[Int] = TreeList.fromList(List(1, 2, 3, 4)) + val avlSet: AvlSet[Int] = AvlSet.fromList(List(1, 2, 3)) + behavior of "CatsWriters" it should "write non-empty" in { nev.asTokenList shouldBe arr("a", "b") @@ -24,6 +43,17 @@ class CatsSupportTests extends AnyFlatSpec with Matchers { nec.asTokenList shouldBe arr("a", "b", "c") } + it should "write cats-collection" in { + bitSet.asTokenList shouldBe arr(1, 2, 3, 4, 5) + dequeue.asTokenList shouldBe arr("a", "b", "c") + hashMap.asTokenList shouldBe obj("a" -> 1, "b" -> 2) + hasSet.asTokenList shouldBe arr(1, 2, 3) + heap.asTokenList shouldBe arr(1, 2, 3, 4) + pairingHeap.asTokenList shouldBe arr(1, 2, 3) + treeList.asTokenList shouldBe arr(1, 2, 3, 4) + avlSet.asTokenList shouldBe arr(1, 2, 3) + } + behavior of "CatsReaders" it should "read non-empty" in { nev shouldBe arr("a", "b").tokensAs[NonEmptyVector[String]] @@ -41,4 +71,15 @@ class CatsSupportTests extends AnyFlatSpec with Matchers { nec shouldBe arr("a", "b", "c").tokensAs[NonEmptyChain[String]] assertThrows[ReaderError](Nil.tokensAs[NonEmptyChain[String]]) } + + it should "read cats-collection" in { + bitSet shouldBe arr(1, 2, 3, 4, 5).tokensAs[BitSet] + dequeue shouldBe arr("a", "b", "c").tokensAs[Dequeue[String]] + hashMap shouldBe obj("a" -> 1, "b" -> 2).tokensAs[HashMap[String, Int]] + hasSet shouldBe arr(1, 2, 3).tokensAs[HashSet[Int]] + heap shouldBe arr(1, 2, 3, 4).tokensAs[Heap[Int]] + pairingHeap shouldBe arr(1, 2, 3).tokensAs[PairingHeap[Int]] + treeList shouldBe arr(1, 2, 3, 4).tokensAs[TreeList[Int]] + avlSet shouldBe arr(1, 2, 3).tokensAs[AvlSet[Int]] + } }