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 package net.psforever.packet.control
import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket} 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.bits._
import scodec.codecs._ import scodec.codecs._
import shapeless.HNil
final case class MultiPacketEx(packets : Vector[ByteVector]) final case class MultiPacketEx(packets : Vector[ByteVector])
extends PlanetSideControlPacket { extends PlanetSideControlPacket {
@ -14,53 +15,57 @@ final case class MultiPacketEx(packets : Vector[ByteVector])
} }
object MultiPacketEx extends Marshallable[MultiPacketEx] { object MultiPacketEx extends Marshallable[MultiPacketEx] {
val ffFound: Codec[Boolean] = new Codec[Boolean] { val sizeCodec : Codec[Long] = new Codec[Long] {
def sizeBound = SizeBound.exact(0) private def description = s"variable-bit unsigned integer"
def encode(b: Boolean) = override def sizeBound = SizeBound.bounded(8, 32)
if(b)
Attempt.successful(hex"ff".bits) val MaxValue = (1L << 31) - 1
else val MinValue = 0
Attempt.successful(bin"")
def decode(b: BitVector) = { override def encode(i: Long) = {
if (b.length >= 8 && b.take(8) == hex"ff".bits) if (i > MaxValue) {
Attempt.successful(DecodeResult(true, b.drop(8))) Attempt.failure(Err(s"$i is greater than maximum value $MaxValue for $description"))
else } else if (i < MinValue) {
Attempt.successful(DecodeResult(false, b)) 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] { var buf = buffer
def sizeBound = SizeBound.exact(0)
def encode(b: Boolean) = for(i <- sizeTypes.indices) {
if(b) val s = sizeTypes{i}
Attempt.successful(hex"ffff".bits)
else if(!buf.sizeGreaterThanOrEqual(s))
Attempt.successful(bin"") return Attempt.failure(Err.insufficientBits(s, buf.size))
def decode(b: BitVector) = {
if (b.length >= 16 && b.take(16) == hex"ffff".bits) val value = buf.take(s)
Attempt.successful(DecodeResult(true, b.drop(16))) buf = buf.drop(s)
else
Attempt.successful(DecodeResult(false, b)) 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, implicit val codec : Codec[MultiPacketEx] = ("packets" | vector(variableSizeBytesLong(sizeCodec, bytes))).as[MultiPacketEx]
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]
} }