From ea531600c741b03914e241bcc62f2f64ee1d289c Mon Sep 17 00:00:00 2001 From: Tim Spence Date: Wed, 19 May 2021 10:05:47 +0100 Subject: [PATCH 1/3] Derive Show with field labels --- .../scala-3.0.0-RC3/cats/derived/all.scala | 3 +- .../scala-3.0.0-RC3/cats/derived/show.scala | 31 +++++++++++++++++++ .../cats/derived/ShowTests.scala | 9 ++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 core/src/main/scala-3.0.0-RC3/cats/derived/show.scala create mode 100644 core/src/test/scala-3.0.0-RC3/cats/derived/ShowTests.scala diff --git a/core/src/main/scala-3.0.0-RC3/cats/derived/all.scala b/core/src/main/scala-3.0.0-RC3/cats/derived/all.scala index 151ad7ef..1dfb8ff1 100644 --- a/core/src/main/scala-3.0.0-RC3/cats/derived/all.scala +++ b/core/src/main/scala-3.0.0-RC3/cats/derived/all.scala @@ -10,4 +10,5 @@ object all extends HashDerivation, FunctorDerivation, FoldableDerivation, - TraverseDerivation + TraverseDerivation, + ShowDerivation diff --git a/core/src/main/scala-3.0.0-RC3/cats/derived/show.scala b/core/src/main/scala-3.0.0-RC3/cats/derived/show.scala new file mode 100644 index 00000000..1b137cea --- /dev/null +++ b/core/src/main/scala-3.0.0-RC3/cats/derived/show.scala @@ -0,0 +1,31 @@ +package cats.derived + +import cats.Show +import shapeless3.deriving.{Continue, K0, Labelling} + +object show extends ShowDerivation + +trait ShowDerivation: + + extension (F: Show.type) + inline def derived[A](using gen: K0.Generic[A]): Show[A] = gen.derive(productShow, coproductShow) + + given productShow[A](using inst : => K0.ProductInstances[Show, A], l: Labelling[A]): Show[A] with + def show(a: A) = { + var idx = 0 + val x = inst.foldLeft[StringBuilder](a)(new StringBuilder(s"${l.label}("))( + [t] => (acc: StringBuilder, sh: Show[t], t0: t) => { + //elemLabels is backed by an array so this should be fast + val res = Continue(acc.append(s"${l.elemLabels(idx)}=${sh.show(t0)}, ")) + idx = idx + 1 + res + } + ) + x.delete(x.length - 2, x.length).append(")") + x.toString() + } + + given coproductShow[A](using inst: => K0.CoproductInstances[Show, A]): Show[A] with + def show(a: A) = inst.fold[String](a)( + [t] => (sh: Show[t], t0: t) => sh.show(t0) + ) diff --git a/core/src/test/scala-3.0.0-RC3/cats/derived/ShowTests.scala b/core/src/test/scala-3.0.0-RC3/cats/derived/ShowTests.scala new file mode 100644 index 00000000..5e1066d3 --- /dev/null +++ b/core/src/test/scala-3.0.0-RC3/cats/derived/ShowTests.scala @@ -0,0 +1,9 @@ +package cats.derived + +import alleycats._ +import cats._ +import cats.derived.all._ + +class ShowTests { // + case class Foo(i: Int, b: Option[String]) derives Show +} From e85c7be5d777e02d394fa4c9359115b14f4e494b Mon Sep 17 00:00:00 2001 From: Tim Spence Date: Wed, 19 May 2021 13:46:42 +0100 Subject: [PATCH 2/3] Make show safe for empty products --- core/src/main/scala-3.0.0-RC3/cats/derived/show.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala-3.0.0-RC3/cats/derived/show.scala b/core/src/main/scala-3.0.0-RC3/cats/derived/show.scala index 1b137cea..aa31d62a 100644 --- a/core/src/main/scala-3.0.0-RC3/cats/derived/show.scala +++ b/core/src/main/scala-3.0.0-RC3/cats/derived/show.scala @@ -13,15 +13,18 @@ trait ShowDerivation: given productShow[A](using inst : => K0.ProductInstances[Show, A], l: Labelling[A]): Show[A] with def show(a: A) = { var idx = 0 + var removeTrailingComma = false val x = inst.foldLeft[StringBuilder](a)(new StringBuilder(s"${l.label}("))( [t] => (acc: StringBuilder, sh: Show[t], t0: t) => { //elemLabels is backed by an array so this should be fast val res = Continue(acc.append(s"${l.elemLabels(idx)}=${sh.show(t0)}, ")) + removeTrailingComma = true idx = idx + 1 res } ) - x.delete(x.length - 2, x.length).append(")") + if(removeTrailingComma) {x.delete(x.length - 2, x.length)} + x.append(")") x.toString() } From 0cc9642817d2e0e2a67cfec8f5cfcea6f9077525 Mon Sep 17 00:00:00 2001 From: Tim Spence Date: Wed, 19 May 2021 14:12:45 +0100 Subject: [PATCH 3/3] Use SAM functions to avoid anonymous class generation --- .../src/main/scala-3.0.0-RC3/cats/derived/show.scala | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/core/src/main/scala-3.0.0-RC3/cats/derived/show.scala b/core/src/main/scala-3.0.0-RC3/cats/derived/show.scala index aa31d62a..3dc77013 100644 --- a/core/src/main/scala-3.0.0-RC3/cats/derived/show.scala +++ b/core/src/main/scala-3.0.0-RC3/cats/derived/show.scala @@ -10,25 +10,23 @@ trait ShowDerivation: extension (F: Show.type) inline def derived[A](using gen: K0.Generic[A]): Show[A] = gen.derive(productShow, coproductShow) - given productShow[A](using inst : => K0.ProductInstances[Show, A], l: Labelling[A]): Show[A] with - def show(a: A) = { + given productShow[A](using inst : => K0.ProductInstances[Show, A], l: Labelling[A]): Show[A] = + (a: A) => { var idx = 0 - var removeTrailingComma = false val x = inst.foldLeft[StringBuilder](a)(new StringBuilder(s"${l.label}("))( [t] => (acc: StringBuilder, sh: Show[t], t0: t) => { //elemLabels is backed by an array so this should be fast val res = Continue(acc.append(s"${l.elemLabels(idx)}=${sh.show(t0)}, ")) - removeTrailingComma = true idx = idx + 1 res } ) - if(removeTrailingComma) {x.delete(x.length - 2, x.length)} + if(idx > 0) {x.delete(x.length - 2, x.length)} x.append(")") x.toString() } - given coproductShow[A](using inst: => K0.CoproductInstances[Show, A]): Show[A] with - def show(a: A) = inst.fold[String](a)( + given coproductShow[A](using inst: => K0.CoproductInstances[Show, A]): Show[A] = + (a: A) => inst.fold[String](a)( [t] => (sh: Show[t], t0: t) => sh.show(t0) )