Introduction

Module: Maven Central

The fs2-data-cbor-json module provides pipes to convert streams between CBOR and JSON representations in both directions.

CBOR to JSON

The library implements decoding of CBOR item streams into JSON token streams.

import fs2._
import fs2.data.cbor
import fs2.data.cbor.low.CborItem

import scodec.bits._

Stream
  .emits(List(
    CborItem.PositiveInt(hex"cafebabe"),
    CborItem.StartArray(3),
    CborItem.TextString("Some string"),
    CborItem.TextString("Some other string"),
    CborItem.False
  ))
  .through(cbor.json.decodeItems[Fallible])
  .compile
  .toList
// res0: Either[Throwable, List[data.json.Token]] = Right(
//   value = List(
//     NumberValue(value = "3405691582"),
//     StartArray,
//     StringValue(value = "Some string"),
//     StringValue(value = "Some other string"),
//     FalseValue,
//     EndArray
//   )
// )

CBOR is more expressive than JSON and allows to express more kind of data, so not all CBOR item streams can be successfully converted, or some information loss might occur.

In particular restrictions are:

To convert to JSON, some tags are understood by the pipe, namely:

import fs2.data.cbor.Tags

Stream
  .emits(List(
    CborItem.Tag(Tags.ExpectedBase64Encoding),
    CborItem.StartArray(2),
    CborItem.ByteString(hex"cafebabe"),
    CborItem.ByteString(hex"ff"),
    CborItem.Tag(Tags.PositiveBigNum),
    CborItem.ByteString(hex"1234567890abcdef")
  ))
  .through(cbor.json.decodeItems[Fallible])
  .compile
  .toList
// res1: Either[Throwable, List[data.json.Token]] = Right(
//   value = List(
//     StartArray,
//     StringValue(value = "yv66vg=="),
//     StringValue(value = "/w=="),
//     EndArray,
//     NumberValue(value = "1311768467294899695")
//   )
// )

JSON to CBOR

Conversely, you can convert a stream of JSON tokens into a stream CBOR items. The pipe tries to encode the elements using the smallest CBOR type that can hold the value. However, some simplications are made:

import fs2.data.json
import fs2.data.json.Token

Stream
  .emits(List(
    Token.StartArray,
    Token.StringValue("a string"),
    Token.NumberValue("1.34"),
    Token.StartObject,
    Token.Key("a"),
    Token.TrueValue,
    Token.Key("b"),
    Token.NullValue,
    Token.EndObject,
    Token.EndArray
  ))
  .through(json.cbor.encodeItems)
  .compile
  .toList
// res2: cats.package.Id[List[CborItem]] = List(
//   StartIndefiniteArray,
//   TextString(string = "a string"),
//   Tag(tag = 4L),
//   StartArray(size = 2L),
//   NegativeInt(
//     bytes = Chunk(
//       bytes = View(
//         at = scodec.bits.ByteVector$AtArray@3f91a48f,
//         offset = 0L,
//         size = 1L
//       )
//     )
//   ),
//   PositiveInt(
//     bytes = Chunk(
//       bytes = View(
//         at = scodec.bits.ByteVector$AtArray@8ca44fa,
//         offset = 0L,
//         size = 2L
//       )
//     )
//   ),
//   StartIndefiniteMap,
//   TextString(string = "a"),
//   True,
//   TextString(string = "b"),
//   Null,
//   Break,
//   Break
// )