Last active
February 11, 2020 13:56
-
-
Save mpilquist/767c83b70524f10bdcd1db92b1b2ef05 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/shared/src/main/scala/scodec/Codec.scala b/shared/src/main/scala/scodec/Codec.scala | |
index f3086f7..61e3e35 100644 | |
--- a/shared/src/main/scala/scodec/Codec.scala | |
+++ b/shared/src/main/scala/scodec/Codec.scala | |
@@ -1,10 +1,10 @@ | |
package scodec | |
-import shapeless._ | |
-import shapeless.labelled.FieldType | |
-import shapeless.ops.record._ | |
+import scala.deriving._ | |
+import scala.compiletime._ | |
-import scodec.bits.BitVector | |
+import scodec.bits.{BitVector, ByteVector} | |
+import scala.collection.mutable | |
/** | |
* Supports encoding a value of type `A` to a `BitVector` and decoding a `BitVector` to a value of `A`. | |
@@ -163,11 +163,6 @@ import scodec.bits.BitVector | |
* | |
* Full examples are available in the test directory of this project. | |
* | |
- * == Implicit Codecs == | |
- * | |
- * If authoring combinators that require implicit codec arguments, use `shapeless.Lazy[Codec[A]]` instead of | |
- * `Codec[A]`. This prevents the occurrence of diverging implicit expansion errors. | |
- * | |
* @groupname tuple Tuple Support | |
* @groupprio tuple 11 | |
* | |
@@ -202,44 +197,10 @@ trait Codec[A] extends GenCodec[A, A] { self => | |
} | |
/** | |
- * Transforms using two functions, `A => Attempt[B]` and `B => A`. | |
- * | |
- * The supplied functions form an injection from `B` to `A`. Hence, this method converts from | |
- * a larger to a smaller type. Hence, the name `narrow`. | |
- * @group combinators | |
- */ | |
- final def narrow[B](f: A => Attempt[B], g: B => A): Codec[B] = | |
- exmap(f, b => Attempt.successful(g(b))) | |
- | |
- /** | |
- * Transforms using two functions, `A => B` and `B => Attempt[A]`. | |
- * | |
- * The supplied functions form an injection from `A` to `B`. Hence, this method converts from | |
- * a smaller to a larger type. Hence, the name `widen`. | |
- * @group combinators | |
- */ | |
- final def widen[B](f: A => B, g: B => Attempt[A]): Codec[B] = | |
- exmap(a => Attempt.successful(f(a)), g) | |
- | |
- /** | |
- * Lifts this codec in to a codec of a singleton hlist. | |
- * @group hlist | |
- */ | |
- final def hlist: Codec[A :: HNil] = xmap(_ :: HNil, _.head) | |
- | |
- /** | |
- * Creates a `Codec[(A, B)]` that first encodes/decodes an `A` followed by a `B`. | |
- * @group tuple | |
- */ | |
- final def pairedWith[B](codecB: Codec[B]): Codec[(A, B)] = new codecs.TupleCodec(this, codecB) | |
- | |
- /** | |
- * Creates a `Codec[(A, B)]` that first encodes/decodes an `A` followed by a `B`. | |
- * | |
- * Operator alias for [[pairedWith]]. | |
+ * Lifts this codec in to a codec of a singleton tuple. | |
* @group tuple | |
*/ | |
- final def ~[B](codecB: Codec[B]): Codec[(A, B)] = pairedWith(codecB) | |
+ final def tuple: Codec[A *: Unit] = xmap(_ *: (), _.head) | |
/** | |
* Assuming `A` is `Unit`, creates a `Codec[B]` that: encodes the unit followed by a `B`; | |
@@ -248,7 +209,7 @@ trait Codec[A] extends GenCodec[A, A] { self => | |
* @group tuple | |
*/ | |
final def dropLeft[B](codecB: Codec[B])(implicit ev: Unit =:= A): Codec[B] = | |
- pairedWith(codecB).xmap[B]({ case (a, b) => b }, b => (ev(()), b)) | |
+ (this :: codecB).xmap[B]({ (_, b) => b }, b => (ev(()), b)) | |
/** | |
* Assuming `A` is `Unit`, creates a `Codec[B]` that: encodes the unit followed by a `B`; | |
@@ -266,7 +227,7 @@ trait Codec[A] extends GenCodec[A, A] { self => | |
* @group tuple | |
*/ | |
final def dropRight[B](codecB: Codec[B])(implicit ev: Unit =:= B): Codec[A] = | |
- pairedWith(codecB).xmap[A]({ case (a, b) => a }, a => (a, ev(()))) | |
+ (this :: codecB).xmap[A]({ (a, _) => a }, a => (a, ev(()))) | |
/** | |
* Assuming `B` is `Unit`, creates a `Codec[A]` that: encodes the `A` followed by a unit; | |
@@ -277,17 +238,6 @@ trait Codec[A] extends GenCodec[A, A] { self => | |
*/ | |
final def <~[B](codecB: Codec[B])(implicit ev: Unit =:= B): Codec[A] = dropRight(codecB) | |
- /** | |
- * Converts this codec to an `HList` based codec by flattening all left nested pairs. | |
- * For example, `flattenLeftPairs` on a `Codec[(((A, B), C), D)]` results in a | |
- * `Codec[A :: B :: C :: D :: HNil]`. This is particularly useful when combined | |
- * with `~`, `~>`, and `<~`. | |
- * | |
- * @group tuple | |
- */ | |
- final def flattenLeftPairs(implicit f: codecs.FlattenLeftPairs[A]): Codec[f.Out] = | |
- xmap(a => f.flatten(a), l => f.unflatten(l)) | |
- | |
/** | |
* Converts this to a `Codec[Unit]` that encodes using the specified zero value and | |
* decodes a unit value when this codec decodes an `A` successfully. | |
@@ -364,11 +314,11 @@ trait Codec[A] extends GenCodec[A, A] { self => | |
* | |
* @group combinators | |
*/ | |
- final def upcast[B >: A](implicit ta: Typeable[A]): Codec[B] = new Codec[B] { | |
+ final def upcast[B >: A](implicit ct: reflect.ClassTag[A]): Codec[B] = new Codec[B] { | |
def sizeBound: SizeBound = self.sizeBound | |
- def encode(b: B) = ta.cast(b) match { | |
- case Some(a) => self.encode(a) | |
- case None => Attempt.failure(Err(s"not a value of type ${ta.describe}")) | |
+ def encode(b: B) = b match { | |
+ case a: A => self.encode(a) | |
+ case _ => Attempt.failure(Err(s"not a value of type ${ct.runtimeClass.getSimpleName}")) | |
} | |
def decode(bv: BitVector) = self.decode(bv) | |
override def toString = self.toString | |
@@ -382,13 +332,13 @@ trait Codec[A] extends GenCodec[A, A] { self => | |
* | |
* @group combinators | |
*/ | |
- final def downcast[B <: A](implicit tb: Typeable[B]): Codec[B] = new Codec[B] { | |
+ final def downcast[B <: A](implicit ct: reflect.ClassTag[B]): Codec[B] = new Codec[B] { | |
def sizeBound: SizeBound = self.sizeBound | |
def encode(b: B) = self.encode(b) | |
def decode(bv: BitVector) = self.decode(bv).flatMap { result => | |
- tb.cast(result.value) match { | |
- case Some(b) => Attempt.successful(DecodeResult(b, result.remainder)) | |
- case None => Attempt.failure(Err(s"not a value of type ${tb.describe}")) | |
+ result.value match { | |
+ case b: B => Attempt.successful(DecodeResult(b, result.remainder)) | |
+ case _ => Attempt.failure(Err(s"not a value of type ${ct.runtimeClass.getSimpleName}")) | |
} | |
} | |
override def toString = self.toString | |
@@ -417,29 +367,29 @@ trait Codec[A] extends GenCodec[A, A] { self => | |
override def toString = str | |
} | |
- /** | |
- * Supports creation of a coproduct codec. See [[scodec.codecs.CoproductCodecBuilder]] for details. | |
- * @group coproduct | |
- */ | |
- def :+:[B]( | |
- left: Codec[B] | |
- ): codecs.CoproductCodecBuilder[B :+: A :+: CNil, Codec[B] :: Codec[A] :: HNil, B :+: A :+: CNil] = | |
- codecs.CoproductCodecBuilder(left :: self :: HNil) | |
- | |
- /** | |
- * Lifts this codec to a codec of a shapeless field -- allowing it to be used in records and unions. | |
- * @group combinators | |
- */ | |
- def toField[K]: Codec[FieldType[K, A]] = | |
- xmap[FieldType[K, A]](a => labelled.field[K](a), identity) | |
- | |
- /** | |
- * Lifts this codec to a codec of a shapeless field -- allowing it to be used in records and unions. | |
- * The specified key is pushed in to the context of any errors that are returned from the resulting codec. | |
- * @group combinators | |
- */ | |
- def toFieldWithContext[K <: Symbol](k: K): Codec[FieldType[K, A]] = | |
- toField[K].withContext(k.name) | |
+ // /** | |
+ // * Supports creation of a coproduct codec. See [[scodec.codecs.CoproductCodecBuilder]] for details. | |
+ // * @group coproduct | |
+ // */ | |
+ // def :+:[B]( | |
+ // left: Codec[B] | |
+ // ): codecs.CoproductCodecBuilder[B :+: A :+: CNil, Codec[B] :: Codec[A] :: HNil, B :+: A :+: CNil] = | |
+ // codecs.CoproductCodecBuilder(left :: self :: HNil) | |
+ | |
+ // /** | |
+ // * Lifts this codec to a codec of a shapeless field -- allowing it to be used in records and unions. | |
+ // * @group combinators | |
+ // */ | |
+ // def toField[K]: Codec[FieldType[K, A]] = | |
+ // xmap[FieldType[K, A]](a => labelled.field[K](a), identity) | |
+ | |
+ // /** | |
+ // * Lifts this codec to a codec of a shapeless field -- allowing it to be used in records and unions. | |
+ // * The specified key is pushed in to the context of any errors that are returned from the resulting codec. | |
+ // * @group combinators | |
+ // */ | |
+ // def toFieldWithContext[K <: Symbol](k: K): Codec[FieldType[K, A]] = | |
+ // toField[K].withContext(k.name) | |
override def decodeOnly[AA >: A]: Codec[AA] = { | |
val sup = super.decodeOnly[AA] | |
@@ -488,22 +438,6 @@ object Codec extends EncoderFunctions with DecoderFunctions { | |
override def decode(bits: BitVector) = decoder.decode(bits) | |
} | |
- /** | |
- * Gets an implicitly available codec for type `A`. | |
- * | |
- * If an implicit `Codec[A]` is not available, one might be able to be derived automatically. | |
- * Codecs can be derived for: | |
- * - case classes (and hlists and records), where each component type of the case class either has an | |
- * implicitly available codec or one can be automatically derived | |
- * - sealed class hierarchies (and coproducts and unions), where: | |
- * - the root type, `A`, has an implicitly available `Discriminated[A, D]` for some `D` | |
- * - each subtype has an implicitly available codec or can have one derived | |
- * - each subtype `X` has an implicitly available `Discriminator[A, X, D]` | |
- * | |
- * @group ctor | |
- */ | |
- def apply[A](implicit c: Lazy[Codec[A]]): Codec[A] = c.value | |
- | |
/** | |
* Provides a `Codec[A]` that delegates to a lazily evaluated `Codec[A]`. | |
* Typically used to consruct codecs for recursive structures. | |
@@ -527,70 +461,103 @@ object Codec extends EncoderFunctions with DecoderFunctions { | |
override def toString = s"lazily($c)" | |
} | |
- /** | |
- * Encodes the specified value to a bit vector using an implicitly available codec. | |
- * @group conv | |
- */ | |
- def encode[A](a: A)(implicit c: Lazy[Codec[A]]): Attempt[BitVector] = c.value.encode(a) | |
+ extension on [T <: Tuple, U <: Tuple](t: Codec[T])(given u: codecs.DropUnits[T] { type L = U }) { | |
+ def dropUnits: Codec[U] = t.xmap(u.removeUnits, u.addUnits) | |
+ } | |
- /** | |
- * Decodes the specified bit vector in to a value of type `A` using an implicitly available codec. | |
- * @group conv | |
- */ | |
- def decode[A](bits: BitVector)(implicit c: Lazy[Codec[A]]): Attempt[DecodeResult[A]] = | |
- c.value.decode(bits) | |
+ extension on [H, T <: Tuple](t: Codec[T]) { | |
+ /** | |
+ * Builds a `Codec[H *: T]` from a `Codec[H]` and a `Codec[T]` where `T` is a tuple type. | |
+ * That is, this operator is a codec-level tuple prepend operation. | |
+ * @param codec codec to prepend | |
+ * @group tuple | |
+ */ | |
+ def ::(h: Codec[H]): Codec[H *: T] = | |
+ new Codec[H *: T] { | |
+ def sizeBound = h.sizeBound + t.sizeBound | |
+ def encode(ht: H *: T) = encodeBoth(h, t)(ht.head, ht.tail) | |
+ def decode(bv: BitVector) = decodeBoth(h, t)(bv).map(_.map(_ *: _)) | |
+ override def toString = s"$h :: $t" | |
+ } | |
+ } | |
- /** | |
- * Supports derived codecs. | |
- * @group ctor | |
- */ | |
- implicit val deriveHNil: Codec[HNil] = | |
- codecs.HListCodec.hnilCodec | |
+ extension on [A, B](b: Codec[B]) { | |
+ /** | |
+ * When called on a `Codec[A]` where `A` is not a tuple, creates a new codec that encodes/decodes a tuple of `(B, A)`. | |
+ * For example, {{{uint8 :: utf8}}} has type `Codec[(Int, Int)]`. | |
+ * @group tuple | |
+ */ | |
+ def ::(a: Codec[A]): Codec[(A, B)] = | |
+ new Codec[(A, B)] { | |
+ def sizeBound = a.sizeBound + b.sizeBound | |
+ def encode(ab: (A, B)) = Codec.encodeBoth(a, b)(ab._1, ab._2) | |
+ def decode(bv: BitVector) = Codec.decodeBoth(a, b)(bv) | |
+ override def toString = s"$a :: $b" | |
+ } | |
+ } | |
- /** | |
- * Supports derived codecs. | |
- * @group ctor | |
- */ | |
- implicit def deriveProduct[H, T <: HList]( | |
- implicit headCodec: Lazy[Codec[H]], | |
- tailAux: Lazy[Codec[T]] | |
- ): Codec[H :: T] = | |
- headCodec.value :: tailAux.value | |
+ extension on [A, B <: Tuple](codecA: Codec[A]) { | |
+ /** | |
+ * Creates a new codec that encodes/decodes a tuple of `A :: B` given a function `A => Codec[B]`. | |
+ * This allows later parts of a tuple codec to be dependent on earlier values. | |
+ * @group tuple | |
+ */ | |
+ def flatPrepend(f: A => Codec[B]): Codec[A *: B] = | |
+ new Codec[A *: B] { | |
+ def sizeBound = codecA.sizeBound.atLeast | |
+ def encode(ab: A *: B) = encodeBoth(codecA, f(ab.head))(ab.head, ab.tail) | |
+ def decode(b: BitVector) = | |
+ (for { | |
+ a <- codecA | |
+ l <- f(a) | |
+ } yield a *: l).decode(b) | |
+ override def toString = s"flatPrepend($codecA, $f)" | |
+ } | |
+ | |
+ /** | |
+ * Creates a new codec that encodes/decodes a tuple of `A :: B` given a function `A => Codec[B]`. | |
+ * This allows later parts of a tuple codec to be dependent on earlier values. | |
+ * Operator alias for `flatPrepend`. | |
+ * @group tuple | |
+ */ | |
+ def >>:~(f: A => Codec[B]): Codec[A *: B] = codecA.flatPrepend(f) | |
+ } | |
- /** | |
- * Supports derived codecs. | |
- * @group ctor | |
- */ | |
- implicit def deriveRecord[KH <: Symbol, VH, TRec <: HList, KT <: HList]( | |
- implicit | |
- keys: Keys.Aux[FieldType[KH, VH] :: TRec, KH :: KT], | |
- headCodec: Lazy[Codec[VH]], | |
- tailAux: Lazy[Codec[TRec]] | |
- ): Codec[FieldType[KH, VH] :: TRec] = lazily { | |
- val headFieldCodec: Codec[FieldType[KH, VH]] = headCodec.value.toFieldWithContext(keys().head) | |
- headFieldCodec :: tailAux.value | |
+ extension on [B <: Tuple](rhs: Codec[B]) { | |
+ /** | |
+ * When called on a `Codec[L]` for some `L <: HList`, returns a new codec that encodes/decodes | |
+ * `B :: L` but only returns `L`. HList equivalent of `~>`. | |
+ * @group hlist | |
+ */ | |
+ def :~>:(lhs: Codec[Unit]): Codec[B] = lhs.dropLeft(rhs) | |
} | |
+ // /** | |
+ // * When called on a `Codec[A]`, returns a new codec that encodes/decodes `B :: A :: HNil`. | |
+ // * HList equivalent of `~>`. | |
+ // * @group hlist | |
+ // */ | |
+ // def :~>:[B](codecB: Codec[B])(implicit ev: Unit =:= B): Codec[A :: HNil] = | |
+ // codecB :~>: self.hlist | |
+ | |
- /** | |
- * Supports derived codecs. | |
- * @group ctor | |
- */ | |
- implicit def deriveLabelledGeneric[A, Rec <: HList]( | |
- implicit | |
- lgen: LabelledGeneric.Aux[A, Rec], | |
- auto: Lazy[Codec[Rec]] | |
- ): Codec[A] = auto.value.xmap(lgen.from, lgen.to) | |
- /** | |
- * Supports derived codecs. | |
- * @group ctor | |
- */ | |
- implicit def deriveCoproduct[A, D, C0 <: Coproduct]( | |
- implicit | |
- discriminated: codecs.Discriminated[A, D], | |
- auto: codecs.CoproductBuilderAuto[A] { type C = C0 }, | |
- auto2: codecs.CoproductBuilderAutoDiscriminators[A, C0, D] | |
- ): Codec[A] = auto.apply.auto | |
+ | |
+ | |
+ // def [H, T <: Tuple] (h: Codec[H]) :: (t: Codec[T]): Codec[H *: T] = | |
+ // new Codec[H *: T] { | |
+ // def sizeBound = h.sizeBound + t.sizeBound | |
+ // def encode(ht: H *: T) = Codec.encodeBoth(h, t)(ht.head, ht.tail) | |
+ // def decode(bv: BitVector) = Codec.decodeBoth(h, t)(bv).map(_.map(_ *: _)) | |
+ // override def toString = s"$h :: $t" | |
+ // } | |
+ | |
+ // def [A, B] (a: Codec[A]) :: (b: Codec[B])(given DummyImplicit): Codec[(A, B)] = | |
+ // new Codec[(A, B)] { | |
+ // def sizeBound = a.sizeBound + b.sizeBound | |
+ // def encode(ab: (A, B)) = Codec.encodeBoth(a, b)(ab._1, ab._2) | |
+ // def decode(bv: BitVector) = Codec.decodeBoth(a, b)(bv) | |
+ // override def toString = s"$a :: $b" | |
+ // } | |
/** | |
* Creates a coproduct codec builder for the specified type. | |
@@ -606,17 +573,123 @@ object Codec extends EncoderFunctions with DecoderFunctions { | |
}}} | |
* @group ctor | |
*/ | |
- def coproduct[A](implicit auto: codecs.CoproductBuilderAuto[A]): auto.Out = auto.apply | |
+ // def coproduct[A](implicit auto: codecs.CoproductBuilderAuto[A]): auto.Out = auto.apply | |
- /** | |
- * Transform typeclass instance. | |
- * @group inst | |
- */ | |
- implicit val transformInstance: Transform[Codec] = new Transform[Codec] { | |
- def exmap[A, B](codec: Codec[A], f: A => Attempt[B], g: B => Attempt[A]): Codec[B] = | |
- codec.exmap(f, g) | |
+ inline given derivedTuple[T <: Tuple] as Codec[T] = { | |
+ val codecs = summonCodecs[T].toArray.asInstanceOf[Array[Codec[_]]] | |
+ deriveProduct(codecs, _.toArray.iterator, p => Tuple.fromProduct(p).asInstanceOf[T]) | |
+ } | |
+ | |
+ inline def derived[A](given m: Mirror.Of[A]): Codec[A] = { | |
+ val elemCodecs = summonCodecs[m.MirroredElemTypes].toArray.asInstanceOf[Array[Codec[_]]] | |
+ val elemLabels = summonLabels[m.MirroredElemLabels] | |
+ val codecs = elemCodecs.zip(elemLabels).map { (c, l) => | |
+ c.withContext(l).asInstanceOf[Codec[_]] | |
+ } | |
+ inline m match { | |
+ case p: Mirror.ProductOf[A] => | |
+ deriveProduct(codecs, a => a.asInstanceOf[Product].productIterator, t => p.fromProduct(t).asInstanceOf[A]) | |
+ case s: Mirror.SumOf[A] => | |
+ deriveSum(s, codecs) | |
+ } | |
+ } | |
+ | |
+ private inline def summonOne[A]: A = summonFrom { case a: A => a } | |
+ | |
+ private inline def summonCodecs[T <: Tuple]: List[Codec[_]] = inline erasedValue[T] match { | |
+ case _: Unit => Nil | |
+ case _: (t *: ts) => summonOne[Codec[t]] :: summonCodecs[ts] | |
+ } | |
+ | |
+ private inline def summonLabels[T <: Tuple]: List[String] = inline erasedValue[T] match { | |
+ case _: Unit => Nil | |
+ case _: (t *: ts) => constValue[t].asInstanceOf[String] :: summonLabels[ts] | |
+ } | |
+ | |
+ private def deriveProduct[A](codecs: Array[Codec[_]], toElems: A => Iterator[Any], mk: Product => A): Codec[A] = { | |
+ new Codec[A] { | |
+ def sizeBound = codecs.foldLeft(SizeBound.exact(0))(_ + _.sizeBound) | |
+ def encode(a: A) = { | |
+ var i = 0 | |
+ val elems = toElems(a) | |
+ var result = BitVector.empty | |
+ var err: Err = null | |
+ while (i < codecs.size && (err eq null)) { | |
+ val elem = elems.next.asInstanceOf[Any] | |
+ val codec = codecs(i).asInstanceOf[Codec[Any]] | |
+ codec.encode(elem) match { | |
+ case Attempt.Successful(out) => | |
+ result = result ++ out | |
+ case Attempt.Failure(e) => err = e | |
+ } | |
+ i += 1 | |
+ } | |
+ if (err eq null) Attempt.successful(result) else Attempt.failure(err) | |
+ } | |
+ def decode(b: BitVector) = { | |
+ var i = 0 | |
+ val bldr = mutable.ArrayBuilder.make[AnyRef] | |
+ var buf = b | |
+ var err: Err = null | |
+ while (i < codecs.size && (err eq null)) { | |
+ val codec = codecs(i).asInstanceOf[Codec[AnyRef]] | |
+ codec.decode(buf) match { | |
+ case Attempt.Successful(DecodeResult(a, rem)) => | |
+ bldr += a | |
+ buf = rem | |
+ case Attempt.Failure(e) => err = e | |
+ } | |
+ i += 1 | |
+ } | |
+ if (err eq null) Attempt.successful(DecodeResult(mk(new ArrayProduct(bldr.result)), buf)) | |
+ else Attempt.failure(err) | |
+ } | |
+ } | |
+ } | |
+ | |
+ private def deriveSum[A]( | |
+ s: Mirror.SumOf[A], | |
+ elemCodecs: Array[Codec[_]], | |
+ ): Codec[A] = new Codec[A] { | |
+ private val discriminator = codecs.uint8 | |
+ def sizeBound = discriminator.sizeBound + SizeBound.choice(elemCodecs.map(_.sizeBound)) | |
+ def encode(a: A) = { | |
+ val idx = s.ordinal(a) | |
+ (discriminator :: elemCodecs(idx).asInstanceOf[Codec[A]]).encode(idx, a) | |
+ } | |
+ def decode(b: BitVector) = { | |
+ discriminator.flatMap(idx => elemCodecs(idx).asInstanceOf[Codec[A]]).decode(b) | |
+ } | |
+ } | |
+ | |
+ inline given derivedSingleton[A <: Singleton](given m: Mirror.Of[A]) as Codec[A] = { | |
+ inline m match { | |
+ case s: Mirror.Singleton => codecs.provide(s.fromProduct(null).asInstanceOf[A]) | |
+ } | |
+ } | |
+ | |
+ given Codec[Byte] = codecs.byte | |
+ given Codec[Short] = codecs.short16 | |
+ given Codec[Int] = codecs.int32 | |
+ given Codec[Long] = codecs.int64 | |
+ given Codec[Float] = codecs.float | |
+ given Codec[Double] = codecs.double | |
+ given Codec[String] = codecs.utf8_32 | |
+ given Codec[Boolean] = codecs.bool(8) | |
+ given Codec[BitVector] = codecs.variableSizeBitsLong(codecs.int64, codecs.bits) | |
+ given Codec[ByteVector] = codecs.variableSizeBytesLong(codecs.int64, codecs.bytes) | |
+ given Codec[java.util.UUID] = codecs.uuid | |
+ | |
+ given [A](given ccount: Codec[Int], ca: Codec[A]) as Codec[List[A]] = codecs.listOfN(ccount, ca) | |
+ given [A](given ccount: Codec[Int], ca: Codec[A]) as Codec[Vector[A]] = codecs.vectorOfN(ccount, ca) | |
+ given [A](given cguard: Codec[Boolean], ca: Codec[A]) as Codec[Option[A]] = codecs.optional(cguard, ca) | |
+ | |
+ given Transform[Codec] { | |
+ def [A, B](fa: Codec[A]).exmap(f: A => Attempt[B], g: B => Attempt[A]): Codec[B] = | |
+ fa.exmap(f, g) | |
+ } | |
- override def xmap[A, B](codec: Codec[A], f: A => B, g: B => A): Codec[B] = | |
- codec.xmap(f, g) | |
+ implicit class AsSyntax[A](private val self: Codec[A]) extends AnyVal { | |
+ def as[B](given t: Transformer[A, B]): Codec[B] = t(self) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment