Packet: Improve sizeCodec for MultiPacketEx

Was completely unreadable before. Now it's not.
This commit is contained in:
Chord 2016-06-03 21:06:49 -04:00
parent 7b82491d0e
commit 372a88bb6e

View file

@ -2,9 +2,10 @@
package net.psforever.packet.control
import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket}
import scodec.{Attempt, Codec, DecodeResult, SizeBound}
import scodec.{Attempt, Codec, DecodeResult, Err, SizeBound}
import scodec.bits._
import scodec.codecs._
import shapeless.HNil
final case class MultiPacketEx(packets : Vector[ByteVector])
extends PlanetSideControlPacket {
@ -14,53 +15,57 @@ final case class MultiPacketEx(packets : Vector[ByteVector])
}
object MultiPacketEx extends Marshallable[MultiPacketEx] {
val ffFound: Codec[Boolean] = new Codec[Boolean] {
def sizeBound = SizeBound.exact(0)
def encode(b: Boolean) =
if(b)
Attempt.successful(hex"ff".bits)
else
Attempt.successful(bin"")
def decode(b: BitVector) = {
if (b.length >= 8 && b.take(8) == hex"ff".bits)
Attempt.successful(DecodeResult(true, b.drop(8)))
else
Attempt.successful(DecodeResult(false, b))
val sizeCodec : Codec[Long] = new Codec[Long] {
private def description = s"variable-bit unsigned integer"
override def sizeBound = SizeBound.bounded(8, 32)
val MaxValue = (1L << 31) - 1
val MinValue = 0
override def encode(i: Long) = {
if (i > MaxValue) {
Attempt.failure(Err(s"$i is greater than maximum value $MaxValue for $description"))
} else if (i < MinValue) {
Attempt.failure(Err(s"$i is less than minimum value $MinValue for $description"))
} else {
if(i < 0xff) {
uint8L.encode(i.toInt)
} else if(i < 0xffff) {
(constant(hex"ff") :: uint16L).dropUnits.encode(i.toInt :: HNil)
} else {
(constant(hex"ffffff") :: uint32L).dropUnits.encode(i :: HNil)
}
}
}
override def toString = "bitsRemaining"
}
override def decode(buffer: BitVector) : Attempt[DecodeResult[Long]] = {
val sizeTypes = List(8, 16, 32)
val guards = List(hex"ff".bits, hex"ffff".bits)
val twoffFound: Codec[Boolean] = new Codec[Boolean] {
def sizeBound = SizeBound.exact(0)
def encode(b: Boolean) =
if(b)
Attempt.successful(hex"ffff".bits)
else
Attempt.successful(bin"")
def decode(b: BitVector) = {
if (b.length >= 16 && b.take(16) == hex"ffff".bits)
Attempt.successful(DecodeResult(true, b.drop(16)))
else
Attempt.successful(DecodeResult(false, b))
var buf = buffer
for(i <- sizeTypes.indices) {
val s = sizeTypes{i}
if(!buf.sizeGreaterThanOrEqual(s))
return Attempt.failure(Err.insufficientBits(s, buf.size))
val value = buf.take(s)
buf = buf.drop(s)
if(i == guards.length || value != guards{i})
return Attempt.successful(
DecodeResult(value.toLong(signed = false, ByteOrdering.LittleEndian),
buf)
)
}
// will never reach here
Attempt.failure(Err("unknown error"))
}
override def toString = "bitsRemaining"
override def toString = description
}
val sizeCodec = either(ffFound, uint8L,
either(twoffFound, uint16L, uint32L).xmap[Long](
(a : Either[Int, Long]) => a.fold[Long](a => a, a => a),
(a : Long) =>
if(a < 0xffff) Left(a.toInt) else Right(a)
)
).xmap[Long](
(a : Either[Int, Long]) => a.fold[Long](a => a, a => a),
(a : Long) =>
if(a < 0xff) Left(a.toInt) else Right(a)
)
implicit val codec : Codec[MultiPacketEx] = (
("packets" | vector(variableSizeBytesLong(sizeCodec, bytes)))
).as[MultiPacketEx]
implicit val codec : Codec[MultiPacketEx] = ("packets" | vector(variableSizeBytesLong(sizeCodec, bytes))).as[MultiPacketEx]
}