2

I have a class looking like this,

case class Foo ( bar: Int, foos: Vector[Foo] )

to define a Codec[Foo], I tried this,

def fc = shapeless.Lazy((int32 ~~ vector(fc)).widenOpt( (Foo.apply _).tupled, Foo.unapply _ ))

But this did not work, since scodec throws StackOverflowError. What is the right way of doing this ?

Sheng
  • 1,697
  • 4
  • 19
  • 33

1 Answers1

3

You'll need the scodec.codecs.lazily combinator to build recursive codecs (not shapeless.lazily). For example:

scala> def fc: Codec[Foo] = lazily((int32 :: vector(fc)).as[Foo])
fc: scodec.Codec[Foo]

scala> val res = fc.encode(Foo(1, Vector(Foo(2, Vector.empty)))).require
res: scodec.bits.BitVector = BitVector(64 bits, 0x0000000100000002)

scala> fc.decode(res)
res2: scodec.Attempt[scodec.DecodeResult[Foo]] = Successful(DecodeResult(Foo(1,Vector(Foo(2,Vector()))),BitVector(empty)))

In scodec 1.8.2 and prior, deriving this codec, instead of defining it explicitly, results in an error at compile time, due to the derivation continuing recursively forever. As of 1.8.3, this codec can be automatically derived without issue.

For an example of a recursive tree, see this example from scodec source.

mpilquist
  • 3,855
  • 21
  • 22
  • thanks for the suggestion. I tried it, but still ended up with SOE . In fact, even the original definition I gave did not cause compile error, it is only when I tried to print it in the console during runtime, the process crashed with SOE – Sheng Sep 25 '15 at 22:14
  • would be great if scodec can provide some sort of example describing how to create a Codec for a tree alike data structure. I think my problem boils down to that. – Sheng Sep 25 '15 at 22:28
  • but this throws SOE in the runtime. def fc: Codec[Foo] = { import shapeless._; lazily((int32 :: vector(fc)).as[Foo]) } what's the difference ? – Sheng Sep 25 '15 at 23:03
  • I was confusing `scodec.codecs.lazily` with `shapeless.lazily`, thank you. it works. – Sheng Sep 26 '15 at 00:06