fancadescala/scodec/src/main/scala/tf/bug/fancadescodec/Codecs.scala

160 lines
5.8 KiB
Scala

package tf.bug.fancadescodec
import scodec._
import scodec.bits.{BitVector, ByteVector}
import scodec.codecs._
object Codecs {
lazy val low: Codec[Unit] = constant(BitVector.low(1L))
lazy val high: Codec[Unit] = constant(BitVector.high(1L))
def optionC[A](b: Boolean, c: Codec[A]): Codec[Option[A]] =
optional(provide(b), c)
lazy val fancadeString: Codec[String] = variableSizeBytes(uint8L, utf8)
lazy val cartridgeMagic: Codec[Unit] = constant(ByteVector(0x1B, 0x00))
lazy val entriesMagic: Codec[Unit] = constant(ByteVector(0x2C, 0x02))
lazy val cartridge: Codec[Cartridge] =
(
cartridgeMagic ~>
fancadeString ::
fancadeString ::
fancadeString ::
(entriesMagic ~> vectorOfN(uint16L, entry)).hlist
).as[Cartridge]
lazy val boundary: Codec[Boundary] =
(uint16L :: uint16L :: uint16L).as[Boundary]
lazy val position: Codec[Position] =
(uint16L :: uint16L :: uint16L).as[Position]
lazy val face: Codec[Vector[Int]] = fixedSizeBytes(8L * 8L * 8L, vector(uint8L))
lazy val faces: Codec[Faces] =
(face :: face :: face :: face :: face :: face).as[Faces]
lazy val obj: Codec[Obj] = uint16L.xmap(Obj(_), _.id)
lazy val world: Codec[World] = boundary.flatPrepend { b =>
vectorOfN(provide(b.sizeLR * b.sizeDU * b.sizeNF), obj).hlist
}.as[World]
lazy val wires: Codec[Vector[Wire]] = vectorOfN(uint16L, wire)
lazy val wire: Codec[Wire] =
(position :: position :: position :: position.hlist).as[Wire]
lazy val metadatas: Codec[Vector[Metadata]] = vectorOfN(uint16L, metadata)
lazy val metadata: Codec[Metadata] =
discriminated[Metadata].by(uint16L)
.subcaseP(0x0100) {
case bool: Metadata.Bool => bool
} (metadataBool)
.subcaseP(0x0201) {
case pss: Metadata.PlaySoundSample => pss
} (metadataPlaySoundSample)
.subcaseP(0x0400) {
case num: Metadata.Number => num
} (metadataNumber)
.subcaseP(0x0500) {
case triple: Metadata.Triple => triple
} (metadataTriple)
.subcaseP(0x0600) {
case text: Metadata.Text => text
} (metadataText)
.subcaseP(0x0700) {
case terminal: Metadata.Terminal => terminal
} (metadataTerminal)
lazy val metadataBool: Codec[Metadata.Bool] =
(position :: bool(8).hlist).as[Metadata.Bool]
lazy val metadataPlaySoundSample: Codec[Metadata.PlaySoundSample] =
(position :: sample.hlist).as[Metadata.PlaySoundSample]
lazy val metadataNumber: Codec[Metadata.Number] =
(position :: floatL.hlist).as[Metadata.Number]
lazy val metadataTriple: Codec[Metadata.Triple] =
(position :: floatL :: floatL :: floatL.hlist).as[Metadata.Triple]
lazy val metadataText: Codec[Metadata.Text] =
(position :: fancadeString.hlist).as[Metadata.Text]
lazy val metadataTerminal: Codec[Metadata.Terminal] =
(position :: fancadeString.hlist).as[Metadata.Terminal]
lazy val sample: Codec[Metadata.Sample] =
discriminated[Metadata.Sample].by(uint16L)
.subcaseP(0) {
case chirp @ Metadata.Sample.Chirp => chirp
} (provide(Metadata.Sample.Chirp))
.subcaseP(1) {
case scrape @ Metadata.Sample.Scrape => scrape
} (provide(Metadata.Sample.Scrape))
.subcaseP(2) {
case squeek @ Metadata.Sample.Squeek => squeek
} (provide(Metadata.Sample.Squeek))
.subcaseP(3) {
case engine @ Metadata.Sample.Engine => engine
} (provide(Metadata.Sample.Engine))
.subcaseP(4) {
case button @ Metadata.Sample.Button => button
} (provide(Metadata.Sample.Button))
.subcaseP(5) {
case ball @ Metadata.Sample.Ball => ball
} (provide(Metadata.Sample.Ball))
.subcaseP(6) {
case piano @ Metadata.Sample.Piano => piano
} (provide(Metadata.Sample.Piano))
.subcaseP(7) {
case marimba @ Metadata.Sample.Marimba => marimba
} (provide(Metadata.Sample.Marimba))
.subcaseP(8) {
case pad @ Metadata.Sample.Pad => pad
} (provide(Metadata.Sample.Pad))
.subcaseP(9) {
case beep @ Metadata.Sample.Beep => beep
} (provide(Metadata.Sample.Beep))
.subcaseP(10) {
case plop @ Metadata.Sample.Plop => plop
} (provide(Metadata.Sample.Plop))
.subcaseP(11) {
case flop @ Metadata.Sample.Flop => flop
} (provide(Metadata.Sample.Flop))
.subcaseP(12) {
case splash @ Metadata.Sample.Splash => splash
} (provide(Metadata.Sample.Splash))
.subcaseP(13) {
case boom @ Metadata.Sample.Boom => boom
} (provide(Metadata.Sample.Boom))
.subcaseP(14) {
case hit @ Metadata.Sample.Hit => hit
} (provide(Metadata.Sample.Hit))
.subcaseP(15) {
case clang @ Metadata.Sample.Clang => clang
} (provide(Metadata.Sample.Clang))
.subcaseP(16) {
case jump @ Metadata.Sample.Jump => jump
} (provide(Metadata.Sample.Jump))
lazy val entry: Codec[Entry] =
( low ~ low ~ low ~ low ~
bool ~ bool ~ bool ~ bool ~
low ~ low ~ low ~ bool ~
high ~ low ~ low ~ low).consume {
case (_ ~ _ ~ _ ~ _ ~ isFaces ~ isWorld ~ isMetadata ~ isWires ~ _ ~ _ ~ _ ~ isVisible ~ _ ~ _ ~ _ ~ _) =>
(
optionC(isVisible, uint8L) ::
fancadeString ::
optionC(isFaces, faces) ::
optionC(isWorld, world) ::
optionC(isMetadata, metadatas) ::
optionC(isWires, wires).hlist
).as[Entry]
} {
case Entry(vFlags, _, f, wd, mt, wr) =>
(() ~ () ~ () ~ () ~ f.isDefined ~ wd.isDefined ~ mt.isDefined ~ wr.isDefined ~ () ~ () ~ () ~ vFlags.isDefined ~ () ~ () ~ () ~ ())
}
lazy val encCartridge: Codec[Cartridge] = zlib(cartridge)
}