Supports encoding a value of type A
to a BitVector
and decoding a BitVector
to a value of A
.
Not every value of A
can be encoded to a bit vector and similarly, not every bit vector can be decoded to a value
of type A
. Hence, both encode and decode return either an error or the result. Furthermore, decode returns the
remaining bits in the bit vector that it did not use in decoding.
There are various ways to create instances of Codec
. The trait can be implemented directly or one of the
constructor methods in the companion can be used (e.g., apply
). Most of the methods on Codec
create return a new codec that has been transformed in some way. For example, the xmap method
converts a Codec[A]
to a Codec[B]
given two functions, A => B
and B => A
.
One of the simplest transformation methods is def withContext(context: String): Codec[A]
, which
pushes the specified context string in to any errors (i.e., Err
s) returned from encode or decode.
See the methods on this trait for additional transformation types.
See the codecs package object for pre-defined codecs for many common data types and combinators for building larger codecs out of smaller ones.
Tuple Codecs
The ::
operator supports combining a Codec[A]
and a Codec[B]
in to a Codec[(A, B)]
.
For example:
val codec: Codec[(Int, Int, Int)] = uint8 :: uint8 :: uint8
There are various methods on Codec
that only work on Codec[A]
for some A <: Tuple
. Besides the aforementioned
::
method, they include methods like ++
, flatPrepend
, flatConcat
, etc. One particularly useful method is
dropUnits
, which removes any Unit
values from the tuple.
Given a Codec[(X0, X1, ..., Xn)]
and a case class with types X0
to Xn
in the same order,
the codec can be turned in to a case class codec via the as
method. For example:
case class Point(x: Int, y: Int, z: Int)
val threeInts: Codec[(Int, Int, Int)] = uint8 :: uint8 :: uint8
val point: Codec[Point] = threeInts.as[Point]
flatZip
Sometimes when combining codecs, a latter codec depends on a formerly decoded value.
The flatZip
method is important in these types of situations -- it represents a dependency between
the left hand side and right hand side. Its signature is def flatZip[B](f: A => Codec[B]): Codec[(A, B)]
.
This is similar to flatMap
except the return type is Codec[(A, B)]
instead of Decoder[B]
.
Consider a binary format of an 8-bit unsigned integer indicating the number of bytes following it.
To implement this with flatZip
, we could write:
val x: Codec[(Int, ByteVector)] = uint8.flatZip { numBytes => bytes(numBytes) }
val y: Codec[ByteVector] = x.xmap[ByteVector]({ case (_, bv) => bv }, bv => (bv.size, bv))
In this example, x
is a Codec[(Int, ByteVector)]
but we do not need the size directly in the model
because it is redundant with the size stored in the ByteVector
. Hence, we remove the Int
by
xmap
-ping over x
. The notion of removing redundant data from models comes up frequently.
Note: there is a combinator that expresses this pattern more succinctly -- variableSizeBytes(uint8, bytes)
.
flatPrepend
When the function passed to flatZip
returns a Codec[B]
where B <: Tuple
, you end up creating
right nested tuples instead of a extending the arity of a single tuple. To do the latter, there's
flatPrepend
. It has the signature:
def flatPrepend[B <: Tuple](f: A => Codec[B]): Codec[A *: B]
It forms a codec of A
consed on to B
when called on a Codec[A]
and passed a function A => Codec[B]
.
Note that the specified function must return a tuple codec. Implementing our example from earlier
using flatPrepend
:
val x: Codec[(Int, ByteVector)] = uint8.flatPrepend { numBytes => bytes(numBytes).tuple }
In this example, bytes(numBytes)
returns a Codec[ByteVector]
so we called .tuple
on it to lift it
in to a Codec[ByteVector *: Unit]
.
There are similar methods for flat appending and flat concating.
Derived Codecs
Codecs for case classes and sealed class hierarchies can often be automatically derived.
Consider this example:
case class Point(x: Int, y: Int, z: Int) derives Codec
Codec[Point].encode(Point(1, 2, 3))
In this example, no explicit codec was defined for Point
and instead, one was derived as a result
of the derives Codec
clause. Derivation of a codec for a case class requires each element of the case class to
have a given codec of the corresponding type. In this case, each element was an Int
and there is
a Codec[Int]
given in the companion of Codec
.
Derived codecs include the name of each element in any errors produced when encoding/decoding the element.
This works similarly for ADTs / sealed class hierarchies. The binary form is represented as a single unsigned 8-bit integer representing the ordinal of the sum, followed by the derived form of the product.
Full examples are available in the test directory of this project.
- Companion
- object
Value members
Concrete methods
Builds a Codec[A ++ B]
from a Codec[A]
and a Codec[B]
where A
and B
are tuples.
That is, this operator is a codec-level tuple concat operation.
Builds a Codec[A ++ B]
from a Codec[A]
and a Codec[B]
where A
and B
are tuples.
That is, this operator is a codec-level tuple concat operation.
- Value Params
- codecA
codec to concat
codecB :+ codecA
returns a new codec that encodes/decodes the tuple B
followed by an A
.
That is, this operator is a codec-level tuple append operation.
codecB :+ codecA
returns a new codec that encodes/decodes the tuple B
followed by an A
.
That is, this operator is a codec-level tuple append operation.
Builds a Codec[A *: B]
from a Codec[A]
and a Codec[B]
where B
is a tuple type.
That is, this operator is a codec-level tuple prepend operation.
Builds a Codec[A *: B]
from a Codec[A]
and a Codec[B]
where B
is a tuple type.
That is, this operator is a codec-level tuple prepend operation.
- Value Params
- codec
codec to prepend
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,
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)]
.
uint8 :: utf8 }}}
Assuming B
is Unit
, creates a Codec[A]
that: encodes the A
followed by a unit;
decodes an A
followed by a unit and discards the decoded unit.
Assuming B
is Unit
, creates a Codec[A]
that: encodes the A
followed by a unit;
decodes an A
followed by a unit and discards the decoded unit.
Operator alias of dropRight.
Transforms this codec to a Codec[B]
if A
is isomorphic to B
.
Transforms this codec to a Codec[B]
if A
is isomorphic to B
.
This is most commonly used to convert a tuple codec to a case class:
- Example
case class Point(x: Int, y: Int, z: Int) val c: Codec[(Int, Int, Int)] = int8 :: int8 :: int8 val p: Codec[Point] = c.as[Point]
Similar to flatZip
except the A
type is not visible in the resulting type -- the binary
effects of the Codec[A]
still occur though.
Similar to flatZip
except the A
type is not visible in the resulting type -- the binary
effects of the Codec[A]
still occur though.
Example usage:
case class Flags(x: Boolean, y: Boolean, z: Boolean)
(bool :: bool :: bool :: ignore(5)).consume { flgs =>
conditional(flgs.x, uint8) :: conditional(flgs.y, uint8) :: conditional(flgs.z, uint8)
} {
case (x, y, z) => Flags(x.isDefined, y.isDefined, z.isDefined) }
}
Safely lifts this codec to a codec of a subtype.
Safely lifts this codec to a codec of a subtype.
When a supertype of B
that is not a supertype of A
is decoded,
an decoding error is returned.
Assuming A
is Unit
, creates a Codec[B]
that: encodes the unit followed by a B
;
decodes a unit followed by a B
and discards the decoded unit.
Assuming A
is Unit
, creates a Codec[B]
that: encodes the unit followed by a B
;
decodes a unit followed by a B
and discards the decoded unit.
Assuming B
is Unit
, creates a Codec[A]
that: encodes the A
followed by a unit;
decodes an A
followed by a unit and discards the decoded unit.
Assuming B
is Unit
, creates a Codec[A]
that: encodes the A
followed by a unit;
decodes an A
followed by a unit and discards the decoded unit.
Transforms using two functions, A => Attempt[B]
and B => Attempt[A]
.
Transforms using two functions, A => Attempt[B]
and B => Attempt[A]
.
When called on a Codec[A]
for some A <: Tuple
, returns a new codec that encodes/decodes
the tuple A
followed by the value B
, where the latter is encoded/decoded with the codec
returned from applying A
to f
.
When called on a Codec[A]
for some A <: Tuple
, returns a new codec that encodes/decodes
the tuple A
followed by the value B
, where the latter is encoded/decoded with the codec
returned from applying A
to f
.
When called on a Codec[A]
for some A <: Tuple
, returns a new codec that encodes/decodes
the tuple A
followed by the tuple B
, where the latter is encoded/decoded with the codec
returned from applying A
to f
.
When called on a Codec[A]
for some A <: Tuple
, returns a new codec that encodes/decodes
the tuple A
followed by the tuple B
, where the latter is encoded/decoded with the codec
returned from applying A
to 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.
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.
Returns a new codec that encodes/decodes a value of type (A, B)
where the codec of B
is dependent on A
.
Returns a new codec that encodes/decodes a value of type (A, B)
where the codec of B
is dependent on A
.
Lifts this codec in to a codec of a singleton tuple.
Lifts this codec in to a codec of a singleton tuple.
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.
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.
Safely lifts this codec to a codec of a supertype.
Safely lifts this codec to a codec of a supertype.
When a subtype of B
that is not a subtype of A
is passed to encode,
an encoding error is returned.
Creates a new codec that is functionally equivalent to this codec but pushes the specified context string in to any errors returned from encode or decode.
Creates a new codec that is functionally equivalent to this codec but pushes the specified context string in to any errors returned from encode or decode.
Creates a new codec that is functionally equivalent to this codec but returns the specified string from toString
.
Creates a new codec that is functionally equivalent to this codec but returns the specified string from toString
.
Transforms using the isomorphism described by two functions, A => B
and B => A
.
Transforms using the isomorphism described by two functions, A => B
and B => A
.
Assuming A
is Unit
, creates a Codec[B]
that: encodes the unit followed by a B
;
decodes a unit followed by a B
and discards the decoded unit.
Assuming A
is Unit
, creates a Codec[B]
that: encodes the unit followed by a B
;
decodes a unit followed by a B
and discards the decoded unit.
Operator alias of dropLeft.
Deprecated methods
Inherited methods
Repeatedly decodes values of type A
from the specified vector and returns a collection of the specified type.
Terminates when no more bits are available in the vector or when limit
is defined and that many records have been
decoded. Exits upon first decoding error.
Repeatedly decodes values of type A
from the specified vector and returns a collection of the specified type.
Terminates when no more bits are available in the vector or when limit
is defined and that many records have been
decoded. Exits upon first decoding error.
- Inherited from
- Decoder
Converts this encoder to an Encoder[B]
using the supplied B => A
.
Converts this encoder to an Encoder[B]
using the supplied B => A
.
- Inherited from
- Encoder
Attempts to decode a value of type A
from the specified bit vector.
Attempts to decode a value of type A
from the specified bit vector.
- Value Params
- bits
bits to decode
- Returns
error if value could not be decoded or the remaining bits and the decoded value
- Inherited from
- Decoder
Repeatedly decodes values of type A
from the specified vector, converts each value to a B
and appends it to an accumulator of type
B
using the supplied zero
value and append
function. Terminates when no more bits are available in the vector. Exits upon first decoding error.
Repeatedly decodes values of type A
from the specified vector, converts each value to a B
and appends it to an accumulator of type
B
using the supplied zero
value and append
function. Terminates when no more bits are available in the vector. Exits upon first decoding error.
- Returns
tuple consisting of the terminating error if any and the accumulated value
- Inherited from
- Decoder
Attempts to decode a value of type A
from the specified bit vector and discards the remaining bits.
Attempts to decode a value of type A
from the specified bit vector and discards the remaining bits.
- Value Params
- bits
bits to decode
- Returns
error if value could not be decoded or the decoded value
- Inherited from
- Decoder
Converts this encoder to an Encoder[B]
using the supplied B => Attempt[A]
.
Converts this encoder to an Encoder[B]
using the supplied B => Attempt[A]
.
- Inherited from
- Encoder
Converts this decoder to a Decoder[B]
using the supplied A => Attempt[B]
.
Converts this decoder to a Decoder[B]
using the supplied A => Attempt[B]
.
- Inherited from
- Decoder
Attempts to encode the specified value in to a bit vector.
Attempts to encode the specified value in to a bit vector.
- Value Params
- value
value to encode
- Returns
error or binary encoding of the value
- Inherited from
- Encoder
Encodes all elements of the specified sequence and concatenates the results, or returns the first encountered error.
Encodes all elements of the specified sequence and concatenates the results, or returns the first encountered error.
- Inherited from
- Encoder
Converts this to a codec that fails decoding with an error.
Converts this to a codec that fails decoding with an error.
- Inherited from
- Encoder
Converts this decoder to a Decoder[B]
using the supplied A => Decoder[B]
.
Converts this decoder to a Decoder[B]
using the supplied A => Decoder[B]
.
- Inherited from
- Decoder
Converts this decoder to a Decoder[B]
using the supplied A => B
.
Converts this decoder to a Decoder[B]
using the supplied A => B
.
- Inherited from
- Decoder
Converts this encoder to an Encoder[B]
using the supplied partial
function from B
to A
. The encoding will fail for any B
that
f
maps to None
.
Converts this encoder to an Encoder[B]
using the supplied partial
function from B
to A
. The encoding will fail for any B
that
f
maps to None
.
- Inherited from
- Encoder