# scodec / scodec

Scala combinator library for working with binary data

# scodec

Scala combinator library for working with binary data.

## Design Constraints

This library focuses on contract-first and pure functional encoding and decoding of binary data. The following design constraints are considered:

• Binary structure should mirror protocol definitions and be self-evident under casual reading
• Mapping binary structures to types should be statically verified
• Encoding and decoding should be purely functional
• Failures in encoding and decoding should provide descriptive errors
• Compiler plugin should not be used

As a result, the library is implemented as a combinator based DSL. Performance is considered but yields to the above design constraints.

## Acknowledgements

Scodec 1.x used Shapeless and is heavily influenced by scala.util.parsing.combinator. As of Scodec 2.x, the library only depends on the standard library.

The scodec channel on Gitter is a good place to go for help. Also consider using the scodec tag on StackOverflow.

## Introduction

The primary abstraction is a `Codec[A]`, which supports encoding a value of type `A` to a `BitVector` and decoding a `BitVector` to a value of type `A`.

The `codecs` objects provides a number of predefined codecs and combinators.

```    import scodec.*
import scodec.bits.*
import scodec.codecs.*

// Create a codec for an 8-bit unsigned int followed by an 8-bit unsigned int followed by a 16-bit unsigned int
val firstCodec = uint8 :: uint8 :: uint16

// Decode a bit vector using that codec
val result: Attempt[DecodeResult[(Int, Int, Int)]] = firstCodec.decode(hex"102a03ff".bits)
// Successful(DecodeResult(((16, 42), 1023), BitVector(empty)))

// Sum the result
val add3 = (_: Int) + (_: Int) + (_: Int)
val sum: Attempt[DecodeResult[Int]] = result.map(_.map(add3))
// Successful(DecodeResult(1081, BitVector(empty)))```

Automatic case class binding is supported via tuples:

```    case class Point(x: Int, y: Int, z: Int)

val pointCodec: Codec[Point] = (int8 :: int8 :: int8).as[Point]

val encoded: Attempt[BitVector] = pointCodec.encode(Point(-5, 10, 1))
// Successful(BitVector(24 bits, 0xfb0a01))

val decoded: Attempt[DecodeResult[Point]] = pointCodec.decode(0xfb0a01)
// Successful(DecodeResult(Point(-5, 10, 1), BitVector(empty)))```

Codecs can also be derived, resulting in usage like:

```    case class Point(x: Int, y: Int, z: Int) derives Codec

val encoded: Attempt[BitVector] = Codec.encode(Point(-5, 10, 1))
// Successful(BitVector(96 bits, 0x000000fb0000000a00000001))

val decoded: Attempt[DecodeResult[Point]] = Codec.decode[Point](0x000000fb0000000a00000001)
// Successful(DecodeResult(Point(-5, 10, 1), BitVector(empty)))```

New codecs can be created by either implementing the `Codec` trait though typically new codecs are created by applying one or more combinators to existing codecs.

See the guide for detailed documentation. Also, see ScalaDoc. Especially:

## Ecosystem

Many libraries have support for scodec:

## Examples

There are various examples in the test directory, including codecs for:

The scodec-protocols has production quality codecs for the above examples.

The bmsg library has a codec for the Bitcoin Cash and Bitcoin Core network protocol.

The scodec-msgpack library provides codecs for MessagePack.

The fs2-http project uses FS2, scodec, and shapeless to implement a minimal HTTP client and server.

The scodec-bson library implements BSON codecs and combinators.

## Testing Your Own Codecs

If you're creating your own `Codec` instances scodec publishes some of its own test tooling in the `scodec-testkit` module.

## Getting Binaries

See the releases page on the website.

## Building

This project uses sbt and requires node.js to be installed in order to run Scala.js tests. To build, run `sbt publish-local`.

## Code of Conduct

See the Code of Conduct.