36 private int $offset = 0;
38 public function __construct(
43 public function readInt(
int $bits) :
int{
44 $bitsLeft = $this->maxBits - $this->offset;
45 if($bits > $bitsLeft){
46 throw new \InvalidArgumentException(
"No bits left in buffer (need $bits, have $bitsLeft");
49 $value = ($this->value >> $this->offset) & ~(~0 << $bits);
50 $this->offset += $bits;
54 public function int(
int $bits,
int &$value) :
void{
55 $value = $this->readInt($bits);
58 private function readBoundedIntAuto(
int $min,
int $max) :
int{
59 $bits = ((int) log($max - $min, 2)) + 1;
60 $result = $this->readInt($bits) + $min;
61 if($result < $min || $result > $max){
68 $value = $this->readBoundedIntAuto($min, $max);
71 protected function readBool() : bool{
72 return $this->readInt(1) === 1;
75 public function bool(
bool &$value) : void{
76 $value = $this->readBool();
79 public function facingExcept(Facing &$facing, Facing $except) : void{
80 $result = Facing::DOWN;
82 if($result === $except){
83 throw new InvalidSerializedRuntimeDataException(
"Illegal facing value");
89 public function horizontalAxis(Axis &$axis) : void{
90 $axis = match($this->readInt(1)){
93 default =>
throw new AssumptionFailedError(
"Unreachable")
104 $packed = $this->readBoundedIntAuto(0, (3 ** 4) - 1);
105 foreach(Facing::HORIZONTAL as $facing){
106 $type = intdiv($packed, (3 ** $offset)) % 3;
108 $result[$facing->value] = match($type){
109 1 => WallConnectionType::SHORT,
110 2 => WallConnectionType::TALL,
117 $connections = $result;
120 public function enum(\UnitEnum &$case) : void{
122 $raw = $this->readInt($metadata->bits);
123 $result = $metadata->intToEnum($raw);
124 if($result ===
null){
131 public function enumSet(array &$set, array $allCases) : void{
133 foreach($allCases as $case){
134 if($this->readBool()){
135 $result[spl_object_id($case)] = $case;
141 public function getOffset() : int{ return $this->offset; }