Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package scodec
import scala.language.implicitConversions
import scalaz.{ \/, InvariantFunctor, Monoid, StateT }
import \/.left
import shapeless._
import scodec.bits.BitVector
/**
* 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.
*
* Note: the decode function can be lifted to a state action via `StateT[String \/ ?, BitVector, A]`. This type alias
* and associated constructor is provided by `[[DecodingContext]]`.
*
*
* @groupname tuple Tuple Support
* @groupprio tuple 11
* @groupname hlist HList Support
* @groupprio hlist 12
*/
trait Codec[A] extends GenCodec[A, A] { self =>
/**
* Maps to a codec of type `B` using two total functions, `A => B` and `B => A`.
* @group combinators
*/
final def xmap[B](f: A => B, g: B => A): Codec[B] = new Codec[B] {
def encode(b: B): String \/ BitVector = self.encode(g(b))
def decode(buffer: BitVector): String \/ (BitVector, B) = self.decode(buffer).map { case (rest, a) => (rest, f(a)) }
}
/**
* Maps to a `codec` of type `B`, where there is a partial function
* from `B` to `A`. The encoding will fail for any `B` that
* `g` maps to `None`.
* @group combinators
*/
final def pxmap[B](f: A => B, g: B => Option[A]): Codec[B] = new Codec[B] {
def encode(b: B): String \/ BitVector = g(b).map(self.encode).getOrElse(left(s"extraction failure: $b"))
def decode(buffer: BitVector): String \/ (BitVector, B) = self.decode(buffer).map { case (rest, a) => (rest, f(a)) }
}
/**
* Maps to a codec of type `B` using two total functions,
* `A => String \/ B` and `B => String \/ A`.
*
* f and g can then reject their argument and return an error.
*
* @group combinators
*/
final def exmap[B](f: A => String \/ B, g: B => String \/ A): Codec[B] = new Codec[B] {
def encode(b: B): String \/ BitVector = g(b) flatMap self.encode
def decode(buffer: BitVector): String \/ (BitVector, B) =
self.decode(buffer) flatMap { case (rest, a) => f(a).flatMap { b => \/.right((rest, b)) } }
}
/**
* Maps to a codec of type `B` using a total function on input to encode and a partial function on output from decode.
*
* The supplied functions form an injection from `B` to `A`. Hence, converting a `Codec[A]` to a `Codec[B]` converts from
* a larger to a smaller type. Hence, the name `narrow`.
*
* @group combinators
*/
final def narrow[B](f: A => String \/ B, g: B => A): Codec[B] =
exmap(f, \/.right compose g)
/**
* Maps to a codec of type `B` using a partial function on input to encode and a total function on output from decode.
*
* The supplied functions form an injection from `A` to `B`. Hence, converting a `Codec[A]` to a `Codec[B]` converts from
* a smaller to a larger type. Hence, the name `widen`.
* @group combinators
*/
final def widen[B](f: A => B, g: B => String \/ A): Codec[B] =
exmap(\/.right compose f, g)
/**
* Returns a new codec that encodes/decodes a value of type `B` by using an isomorphism between `A` and `B`.
*
* The isomorphism is provided by the implicit `CodecAsAux` instance.
*
* Typically used when `B` is a case class and `A` is an `HList` with the same shape as the elements of `B`.
*
* @group hlist
*/
final def as[B](implicit as: CodecAsAux[B, A]): Codec[B] = as(this)
/**
* 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]].
* @group tuple
*/
final def ~[B](codecB: Codec[B]): Codec[(A, B)] = pairedWith(codecB)
/**
* Creates a `Codec[B]` that: encodes the zero element of the `Monoid` of A` followed by a `B`;
* decodes an `A` followed by a `B` and discards the decoded `A`.
* @group tuple
*/
final def dropLeft[B](codecB: Codec[B])(implicit ma: Monoid[A]): Codec[B] =
pairedWith(codecB).xmap[B]({ case (a, b) => b }, b => (Monoid[A].zero, b))
/**
* Creates a `Codec[B]` that: encodes the zero element of the `Monoid` of A` followed by a `B`;
* decodes an `A` followed by a `B` and discards the decoded `A`.
*
* Operator alias of [[dropLeft]].
* @group tuple
*/
final def ~>[B](codecB: Codec[B])(implicit ma: Monoid[A]): Codec[B] = dropLeft(codecB)
/**
* Creates a `Codec[A]` that: encodes an `A` followed by the zero element of the `Monoid` of `B`;
* decodes an `A` followed by a `B` and discards the decoded `B`.
* @group tuple
*/
final def dropRight[B: Monoid](codecB: Codec[B]): Codec[A] =
pairedWith(codecB).xmap[A]({ case (a, b) => a }, a => (a, Monoid[B].zero))
/**
* Creates a `Codec[A]` that: encodes an `A` followed by the zero element of the `Monoid` of `B`;
* decodes an `A` followed by a `B` and discards the decoded `B`.
*
* Operator alias of [[dropRight]].
* @group tuple
*/
final def <~[B: Monoid](codecB: Codec[B]): Codec[A] = dropRight(codecB)
/**
* 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.
*
* @group combinators
*/
final def unit(zero: A): Codec[Unit] = xmap[Unit](_ => (), _ => zero)
/**
* Converts this to a `Codec[Unit]` that encodes using the zero value of the implicitly
* available `Monoid[A]` and decodes a unit value when this codec decodes an `A` successfully.
*
* @group combinators
*/
final def unitM(implicit ma: Monoid[A]): Codec[Unit] = unit(ma.zero)
/**
* Returns a new codec that encodes/decodes a value of type `(A, B)` where the codec of `B` is dependent on `A`.
* @group tuple
*/
final def flatZip[B](f: A => Codec[B]): Codec[(A, B)] = new Codec[(A, B)] {
override def encode(t: (A, B)) = Codec.encodeBoth(self, f(t._1))(t._1, t._2)
override def decode(buffer: BitVector) = (for {
a <- DecodingContext(self.decode)
b <- DecodingContext(f(a).decode)
} yield (a, b)).run(buffer)
}
/**
* Returns a new codec that encodes/decodes a value of type `(A, B)` where the codec of `B` is dependent on `A`.
* Operator alias for [[flatZip]].
* @group tuple
*/
final def >>~[B](f: A => Codec[B]): Codec[(A, B)] = flatZip(f)
final override def complete: Codec[A] = Codec(this, super.complete)
final override def compact: Codec[A] = Codec(super.compact, this)
/**
* Creates a new codec that is functionally equivalent to this codec but returns the specified string from `toString`.
* @group combinators
*/
final def withToString(str: String): Codec[A] = new Codec[A] {
override def encode(a: A) = self.encode(a)
override def decode(buffer: BitVector) = self.decode(buffer)
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] =
new codecs.CoproductCodecBuilder(left :: self :: HNil)
}
/**
* Typeclass that witnesses that a `Codec[A]` can be xmapped in to a `Codec[B]`.
*
* Implicit instances (forward and reverse) are provided between:
* - case classes and `HList`s of compatible shapes
* - singleton case classes and values of proper types
*
* Credit: Miles Sabin
*/
@annotation.implicitNotFound("""Could not prove that ${B} can be converted to/from ${A}.
Proof is automatically available between case classes and HLists that have the same shape, as singleton case classes and values of matching types.""")
abstract class CodecAsAux[B, A] {
def apply(ca: Codec[A]): Codec[B]
}
/** Companion for [[CodecAsAux]]. */
object CodecAsAux {
/** Provides a `CodecAsAux[B, A]` for case class `B` and HList `A`. */
implicit def mkAs[B, Repr, A](implicit gen: Generic.Aux[B, Repr], aToR: A =:= Repr, rToA: Repr =:= A): CodecAsAux[B, A] = new CodecAsAux[B, A] {
def apply(ca: Codec[A]): Codec[B] = {
val from: A => B = a => gen.from(a)
val to: B => A = b => gen.to(b)
ca.xmap(from, to)
}
}
/** Provides a `CodecAsAux[B, A]` for HList `B` and case class `A`. */
implicit def mkAsReverse[B, Repr, A](implicit gen: Generic.Aux[A, Repr], bToR: B =:= Repr, rToB: Repr =:= B): CodecAsAux[B, A] = new CodecAsAux[B, A] {
def apply(ca: Codec[A]): Codec[B] = {
val from: A => B = a => gen.to(a)
val to: B => A = b => gen.from(b)
ca.xmap(from, to)
}
}
/** Provides a `CodecAsAux[B, A]` for singleton case class `B` and value `A`. */
implicit def mkAsSingleton[B, Repr, A](implicit gen: Generic.Aux[B, Repr], aToR: (A :: HNil) =:= Repr, rToA: Repr =:= (A :: HNil)): CodecAsAux[B, A] = new CodecAsAux[B, A] {
def apply(ca: Codec[A]): Codec[B] = {
val from: A => B = a => gen.from(a :: HNil)
val to: B => A = b => gen.to(b).head
ca.xmap(from, to)
}
}
/** Provides a `CodecAsAux[B, A]` for value `B` and singleton case class `A`. */
implicit def mkAsSingletonReverse[B, Repr, A](implicit gen: Generic.Aux[A, Repr], bToR: (B :: HNil) =:= Repr, rToB: Repr =:= (B :: HNil)): CodecAsAux[B, A] = new CodecAsAux[B, A] {
def apply(ca: Codec[A]): Codec[B] = {
val from: A => B = a => gen.to(a).head
val to: B => A = b => gen.from(b :: HNil)
ca.xmap(from, to)
}
}
}
/** Companion for [[Codec]]. */
object Codec extends EncoderFunctions with DecoderFunctions {
/** Creates a codec from encoder and decoder functions. */
def apply[A](encoder: A => String \/ BitVector, decoder: BitVector => String \/ (BitVector, A)): Codec[A] = new Codec[A] {
override def encode(a: A) = encoder(a)
override def decode(bits: BitVector) = decoder(bits)
}
/** Creates a codec from an encoder and a decoder. */
def apply[A](encoder: Encoder[A], decoder: Decoder[A]): Codec[A] = new Codec[A] {
override def encode(a: A) = encoder.encode(a)
override def decode(bits: BitVector) = decoder.decode(bits)
}
/** Gets the implicitly available codec for type `A`. */
def apply[A: Codec]: Codec[A] = implicitly[Codec[A]]
val invariantFunctorInstance: InvariantFunctor[Codec] = new InvariantFunctor[Codec] {
def xmap[A, B](c: Codec[A], f: A => B, g: B => A) = c.xmap(f, g)
}
}