diff --git a/project.scala b/project.scala index 91af199..5575473 100644 --- a/project.scala +++ b/project.scala @@ -1,6 +1,6 @@ //> using scala 3.9.0-RC6 -//> using dep com.halotukozak::made::0.3.1 +//> using dep com.halotukozak::made::0.4.0 //> using test.dep org.scalameta::munit::1.3.5 //> using test.dep org.scalameta::munit-scalacheck::1.3.0 diff --git a/src/mcodec/Derivation.scala b/src/mcodec/Derivation.scala index 4dafc2d..3427c33 100644 --- a/src/mcodec/Derivation.scala +++ b/src/mcodec/Derivation.scala @@ -24,8 +24,8 @@ trait Derivation: compiletime.constValueTuple[m.ElemLabels].toArrayOf[String], compiletime.summonAll[Tuple.Map[m.ElemTypes, MCodec]].toArrayOf[MCodec[Any]](using containsOnly.refl), m.elems - .mapAs[MadeFieldElem][[e] =>> Option[Any]]([e <: MadeFieldElem] => elem => elem.default) - .toArrayOf[Option[Any]], + .mapAs[MadeFieldElem][[e] =>> Any | NotExists]([e <: MadeFieldElem] => elem => elem.default) + .toArrayOf[Any | NotExists], m.elems.hasAnnotations[optionalParam].toArrayOf[Boolean], isOptionFlags[m.ElemTypes].toArray, m.elems.hasAnnotations[halotukozak.mcodec.annotation.transientDefault].toArrayOf[Boolean], diff --git a/src/mcodec/DerivedCodecs.scala b/src/mcodec/DerivedCodecs.scala index 5743fd7..9c4ae00 100644 --- a/src/mcodec/DerivedCodecs.scala +++ b/src/mcodec/DerivedCodecs.scala @@ -1,5 +1,7 @@ package halotukozak.mcodec +import halotukozak.made.NotExists + final class Deferred[T] extends MCodec[T]: private[mcodec] var underlying: MCodec[T] | Null = compiletime.uninitialized @@ -15,7 +17,7 @@ final class ProductCodec[T]( typeName: String, labels: Array[String], childCodecsByName: => Array[MCodec[Any]], - defaults: Array[Option[Any]], + defaults: Array[Any | NotExists], optionalFlags: Array[Boolean], isOption: Array[Boolean], transientDefaultFlags: Array[Boolean], @@ -36,7 +38,7 @@ final class ProductCodec[T]( // `forced` (the IgnoreTransientDefaults marker) disables the transient-default omission. private def isOmitted(i: Int, p: Product, forced: Boolean): Boolean = ((optionalFlags(i) || isOption(i)) && (p.productElement(i) == None)) || - (!forced && transientDefaultFlags(i) && defaults(i).contains(p.productElement(i))) + (!forced && transientDefaultFlags(i) && defaults(i) != null && defaults(i) == p.productElement(i)) private[mcodec] def writtenFieldCount(value: T, forced: Boolean): Int = val p = value.asInstanceOf[Product] @@ -88,10 +90,10 @@ final class ProductCodec[T]( while i < labels.length do if !seen(i) then values(i) = defaults(i) match - case Some(d) => d - case None => + case NotExists => if optionalFlags(i) || isOption(i) then None else throw new MissingField(s"missing field: ${labels(i)}") + case d => d i += 1 fromArray(values) catch case rf: ReadFailure => throw rf.withRootType(typeName) diff --git a/test/mcodec/MirrorAdapterTest.scala b/test/mcodec/MirrorAdapterTest.scala index edcc8ad..9e0148a 100644 --- a/test/mcodec/MirrorAdapterTest.scala +++ b/test/mcodec/MirrorAdapterTest.scala @@ -9,7 +9,6 @@ class MirrorAdapterTest extends munit.FunSuite: test("Made.derived resolves in-project and the enriched mirror is readable"): val m = Made.derived[User] val (nameElem, ageElem) = m.elems - // Made 0.1.1: `Label` is a type member, read via constValue. assertEquals(compiletime.constValue[nameElem.Label], "user_name") - assertEquals(nameElem.default, None) - assertEquals(ageElem.default, Some(18)) + assertEquals(nameElem.default, NotExists) + assertEquals(ageElem.default, 18)