Skip to content

Commit eb80bde

Browse files
author
Matthieu Leclercq
committed
Rework summonTagged (endpoints4s#566)
Do not wrap the value to encode in a (potentially long) tuple. Instead summonTagged returns a schema for `A` and its ordinal
1 parent 9bbeaac commit eb80bde

File tree

1 file changed

+12
-28
lines changed
  • json-schema/json-schema-generic/src/main/scala-3/endpoints4s/generic

1 file changed

+12
-28
lines changed

json-schema/json-schema-generic/src/main/scala-3/endpoints4s/generic/JsonSchemas.scala

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ trait JsonSchemas extends algebra.JsonSchemas:
9898
* trait’s `ClassTag`.
9999
*/
100100
inline def genericTagged[A](using sumOf: Mirror.SumOf[A]): Tagged[A] =
101-
summonTagged[sumOf.MirroredElemTypes, sumOf.MirroredElemLabels](0).asInstanceOf[Tagged[sumOf.MirroredElemTypes]] // FIXME Remove asInstanceOf
102-
.xmap[A](tuple => last(tuple).asInstanceOf[A])(a => asTuple(sumOf.ordinal(a), a).asInstanceOf[sumOf.MirroredElemTypes])
101+
summonTagged[A, sumOf.MirroredElemTypes, sumOf.MirroredElemLabels](0).asInstanceOf[Tagged[(Int, A)]] // FIXME Remove asInstanceOf
102+
.xmap[A]{case (_, a) => a}(a => sumOf.ordinal(a) -> a)
103103
.pipe(tagged => summonName[A].fold(tagged)(tagged.named))
104104
.withDiscriminator(summonDiscriminator[A])
105105
.pipe(tagged => summonDescription[A].fold(tagged)(tagged.withDescription))
@@ -212,18 +212,6 @@ trait JsonSchemas extends algebra.JsonSchemas:
212212
case _ => defaultDiscriminatorName
213213
}
214214

215-
/** Retrieve the last element of a tuple */
216-
private def last(tuple: Tuple): Any =
217-
tuple match
218-
case h *: EmptyTuple => h
219-
case () *: t => last(t)
220-
221-
/** Build a tuple with `n` elements, the last one containing the value `a` */
222-
private def asTuple[A](n: Int, a: A): Tuple =
223-
n match
224-
case 0 => a *: EmptyTuple
225-
case _ => () *: asTuple(n - 1, a)
226-
227215
/** Summon the [[Record]] schema of a concrete type of a sealed trait.
228216
* If there is a given instance of `GenericJsonSchema.GenericRecord[A]`,
229217
* it is used as the schema, otherwise we derive the schema.
@@ -235,33 +223,29 @@ trait JsonSchemas extends algebra.JsonSchemas:
235223
}
236224

237225
/** Summon a [[Tagged]] schema for the alternatives `Types`.
226+
* @tparam A The sum type
238227
* @tparam Types List of record types (e.g. `(Circle, Rectangle)`)
239228
* @tparam Labels List of record labels’ types (e.g. `("Circle".type, "Rectangle".type)`)
240229
* @param i Index of the head alternative
241-
*
242-
* We encode the ordinal `i` of each alternative as a tuple containing `i - 1` `Unit`
243-
* followed by the actual value.
244230
*/
245-
private[generic] inline def summonTagged[Types <: Tuple, Labels <: Tuple](i: Int): Tagged[Types] =
231+
private[generic] inline def summonTagged[A, Types <: Tuple, Labels <: Tuple](i: Int): Tagged[(Int, A)] =
246232
inline erasedValue[(Types, Labels)] match
247233
// Last alternative
248234
case _: (head *: EmptyTuple, labelHead *: EmptyTuple) =>
249235
summonTaggedRecord[head].asInstanceOf[Record[head]] // FIXME Remove asInstanceOf
250-
.tagged(constValue[labelHead].asInstanceOf[String]) // TODO Remove asInstanceOf
251-
.xmap[head *: EmptyTuple](h => h *: EmptyTuple) { case h *: EmptyTuple => h }
252-
.asInstanceOf[Tagged[Types]] // FIXME Remove asInstanceOf
236+
.tagged(constValue[labelHead].asInstanceOf[String])
237+
.xmap(h => i -> h.asInstanceOf[A]) { case (_, h) => h.asInstanceOf[head] }
253238
case _: (head *: tail, labelHead *: labelsTail) =>
254239
summonTaggedRecord[head].asInstanceOf[Record[head]] // FIXME Remove asInstanceOf
255-
.tagged(constValue[labelHead].asInstanceOf[String]) // TODO Remove asInstanceOf
256-
.orElse(summonTagged[tail, labelsTail](i + 1).asInstanceOf[Tagged[tail]]) // FIXME Remove asInstanceOf
240+
.tagged(constValue[labelHead].asInstanceOf[String])
241+
.orElse(summonTagged[A, tail, labelsTail](i + 1).asInstanceOf[Tagged[(Int, tail)]]) // FIXME Remove asInstanceOf
257242
.xmap {
258-
case Left(h) => h *: EmptyTuple
259-
case Right(t) => () *: t
243+
case Left(h) => i -> h.asInstanceOf[A]
244+
case Right(t) => t.asInstanceOf[(Int, A)]
260245
} {
261-
case h *: EmptyTuple => Left(h.asInstanceOf[head])
262-
case () *: t => Right(t.asInstanceOf[tail])
246+
case (`i`, h) => Left(h.asInstanceOf[head])
247+
case t => Right(t.asInstanceOf[(Int, tail)])
263248
}
264-
.asInstanceOf[Tagged[Types]]
265249

266250
extension [A <: Product](schema: JsonSchema[A])
267251
/**

0 commit comments

Comments
 (0)