35    use LegacyRuntimeEnumDescriberTrait;
 
   37    private int $value = 0;
 
   38    private int $offset = 0;
 
   40    public function __construct(
 
   44    public function writeInt(
int $bits, 
int $value) : 
void{
 
   45        if($this->offset + $bits > $this->maxBits){
 
   46            throw new \InvalidArgumentException(
"Bit buffer cannot be larger than $this->maxBits bits (already have $this->offset bits)");
 
   48        if(($value & (~0 << $bits)) !== 0){
 
   49            throw new \InvalidArgumentException(
"Value $value does not fit into $bits bits");
 
   52        $this->value |= ($value << $this->offset);
 
   53        $this->offset += $bits;
 
   56    public function int(
int $bits, 
int &$value) : 
void{
 
   57        $this->writeInt($bits, $value);
 
   63    public function boundedInt(
int $bits, 
int $min, 
int $max, 
int &$value) : void{
 
   64        $offset = $this->offset;
 
   65        $this->writeBoundedIntAuto($min, $max, $value);
 
   66        $actualBits = $this->offset - $offset;
 
   67        if($actualBits !== $bits){
 
   68            throw new \InvalidArgumentException(
"Bits should be $actualBits for the given bounds, but received $bits. Use boundedIntAuto() for automatic bits calculation.");
 
 
   72    private function writeBoundedIntAuto(
int $min, 
int $max, 
int $value) : void{
 
   73        if($value < $min || $value > $max){
 
   74            throw new \InvalidArgumentException(
"Value $value is outside the range $min - $max");
 
   76        $bits = ((int) log($max - $min, 2)) + 1;
 
   77        $this->writeInt($bits, $value - $min);
 
   81        $this->writeBoundedIntAuto($min, $max, $value);
 
 
   84    protected function writeBool(
bool $value) : void{
 
   85        $this->writeInt(1, $value ? 1 : 0);
 
   88    public function bool(
bool &$value) : void{
 
   89        $this->writeBool($value);
 
   92    public function horizontalFacing(
int &$facing) : void{
 
   93        $this->writeInt(2, match($facing){
 
   98            default => 
throw new \InvalidArgumentException(
"Invalid horizontal facing $facing")
 
  106        $uniqueFaces = array_flip($faces);
 
  107        foreach(Facing::ALL as $facing){
 
  108            $this->writeBool(isset($uniqueFaces[$facing]));
 
 
  116        $uniqueFaces = array_flip($faces);
 
  117        foreach(Facing::HORIZONTAL as $facing){
 
  118            $this->writeBool(isset($uniqueFaces[$facing]));
 
 
  122    public function facing(
int &$facing) : void{
 
  123        $this->writeInt(3, match($facing){
 
  130            default => 
throw new \InvalidArgumentException(
"Invalid facing $facing")
 
  134    public function facingExcept(
int &$facing, 
int $except) : void{
 
  135        $this->facing($facing);
 
  138    public function axis(
int &$axis) : void{
 
  139        $this->writeInt(2, match($axis){
 
  143            default => 
throw new \InvalidArgumentException(
"Invalid axis $axis")
 
  147    public function horizontalAxis(
int &$axis) : void{
 
  148        $this->writeInt(1, match($axis){
 
  151            default => 
throw new \InvalidArgumentException(
"Invalid horizontal axis $axis")
 
  162        foreach(Facing::HORIZONTAL as $facing){
 
  163            $packed += match($connections[$facing] ?? 
null){
 
  165                WallConnectionType::SHORT => 1,
 
  166                WallConnectionType::TALL => 2,
 
  170        $this->writeBoundedIntAuto(0, (3 ** 4) - 1, $packed);
 
 
  180        $this->enumSet($slots, BrewingStandSlot::cases());
 
 
  183    public function railShape(
int &$railShape) : void{
 
  184        $this->int(4, $railShape);
 
  187    public function straightOnlyRailShape(
int &$railShape) : void{
 
  188        $this->int(3, $railShape);
 
  191    public function enum(\UnitEnum &$case) : 
void{
 
  192        $metadata = RuntimeEnumMetadata::from($case);
 
  193        $this->writeInt($metadata->bits, $metadata->enumToInt($case));
 
 
  196    public function enumSet(array &$set, array $allCases) : void{
 
  197        foreach($allCases as $case){
 
  198            $this->writeBool(isset($set[spl_object_id($case)]));
 
 
  202    public function getValue() : int{ return $this->value; }
 
  204    public function getOffset() : int{ return $this->offset; }