Git Product home page Git Product logo

codec's Introduction

Build Status

Codec

Codec is an opinionated library for cats-friendly pure (reversible) conversions between types, with possible errors represented with Either.

It's cross-built for Scala and Scala.js, and can also be used for other free-of-effect conversions to reach functional composability.

Motivation

Use partial functions, track the errors

Often it's useful to do some validation alongside conversion, like in String => Int.

However, this function throws when malformed input is given. Hence String => Either[Throwable, Int], being a total function, should fit better.

In this case, error is reflected in type system. It keeps things pure. We go further, forcing the error to be of type CodecError, so that later it's easy to track where it comes from, especially in asynchronous environment.

This uni-direction type is called fluence.codec.PureCodec.Func for a fixed CodecError error type. Any other error type could be used by extending fluence.codec.MonadicalEitherArrow[Error].

Bidirection type A <=> B is composed from two Funcs and is called Bijection.

Lawful composition

A type Func[A, B], being something like A => Either[E, B], is not very composable on it's own, so we implemented cats.arrow.ArrowChoice[Func] for it. You may use cats.syntax.compose._ or anything like that to receive andThen and other lawful functions.

Bijection[A, B] is more complex type, so it has only Compose[Bijection] typeclass. Finally you can do something like this:

import cats.syntax.compose._
import fluence.codec.PureCodec

val intToBytes: PureCodec[Int, Array[Byte]] = PureCodec[Int, String] andThen PureCodec[String, Array[Byte]]

Errors are handled in monad-like "fail-fast" fashion.

Benefit from different Monads

In general, functional types conversion could be lazy or eager, be performed in current thread or another. This choice should not affect the logic of conversion, as it's pure.

PureCodec may use any monad to preform execution upon, retaining its nature. The most simple case is strict eager evaluation:

import cats.Id

val resEagerSync: Either[CodecError, Array[Byte]] = intToBytes.runF[Id](33)

You may use any monad, like Task, Coeval, Eval, IO...

Minimal dependencies

codec-core depends only on cats. Each particular codec set is moved into separate module.

Cross compile

In case of complex algorithms, it's worthy to share codebase between platforms. We cross-compile all the codecs possible both to Scala and Scala.js.

Installation

// Bintray repo is used so far. Migration to Maven Central is planned
resolvers += Resolver.bintrayRepo("fluencelabs", "releases")

val codecV = "0.0.4"

libraryDependencies ++= Seq(
  "one.fluence" %%% "codec-core" % codecV, // basic types
  "one.fluence" %%% "codec-bits" % codecV, // scodec-bits conversions for ByteVector 
  "one.fluence" %%% "codec-circe" % codecV, // json handling with circe
  "one.fluence" %%% "codec-protobuf" % codecV, // ByteString conversions for both scala and scala.js
  "one.fluence" %% "codec-kryo" % codecV // typesafe kryo codecs, only for scala
)

Example

  import cats.syntax.compose._
  import fluence.codec.PureCodec
  import fluence.codec.circe.CirceCodecs._
  import io.circe.{Decoder, Encoder, Json}
  import scodec.bits.ByteVector
  import fluence.codec.bits.BitsCodecs._

  // Simple class
  case class User(id: Int, name: String)

  // Encode and decode with circe
  implicit val encoder: Encoder[User] =
    user  Json.obj("id"  Encoder.encodeInt(user.id), "name"  Encoder.encodeString(user.name))

  implicit val decoder: Decoder[User] = cursor 
    for {
      id  cursor.downField("id").as[Int]
      name  cursor.downField("name").as[String]
    } yield User(id, name)

  // Get codec for encoder/decoder
  implicit val userJson: PureCodec[User, Json] = circeJsonCodec(encoder, decoder)

  // A trivial string to bytes codec; never use it in production!
  implicit val stringCodec: PureCodec[String, Array[Byte]] =
    PureCodec.liftB(_.getBytes, bs  new String(bs))

  // Convert user to byte vector and vice versa
  implicit val userJsonVec: PureCodec[User, ByteVector] =
    PureCodec[User, Json] andThen
      PureCodec[Json, String] andThen
      PureCodec[String, Array[Byte]] andThen
      PureCodec[Array[Byte], ByteVector]

  // Try it with an instance
  val user = User(234, "Hey Bob")

  // unsafe() is to be used in tests only; it throws!
  println(userJsonVec.direct.unsafe(user).toBase64)
  
  // eyJpZCI6MjM0LCJuYW1lIjoiSGV5IEJvYiJ9

For more real-world examples, see Fluence.

Roadmap

  • connect[A, B, C] to compose several Funcs or Bijections
  • sbt-tut for docs
  • Implement more codecs
  • Enhance Func api with shortcuts to EitherT methods
  • Consider improving performance: EitherT is not so fast (at least yet)

License

Fluence is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License v3 (AGPLv3) as published by the Free Software Foundation.

Fluence includes some external modules that carry their own licensing.

codec's People

Contributors

alari avatar diemyst avatar ricogit avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

gitter-badger

codec's Issues

Bring generic protobuf codecs here

We have them already somewhere in main fluence codebase.

Also we need to ensure that that codecs are safe and could never throw (I bet they can now). So better tests coverage is required.

Pump circe dependency to 0.10.0-xx

Circe 0.9 depends on cats 1.0.1, whilst 1.1.0 is already released and used by a lot of other libraries.

We need to upgrade circe to avoid conflicting dependencies.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.