$memberNames * * @return string[] * @phpstan-return list */ function buildWriterFunc(string $virtualTypeName, string $nativeTypeName, array $memberNames, string &$functionName) : array{ $bits = getBitsRequired($memberNames); $lines = []; $functionName = lcfirst($virtualTypeName); $lines[] = "public function $functionName(\\$nativeTypeName \$value) : void{"; $lines[] = "\t\$this->int($bits, match(\$value){"; foreach($memberNames as $key => $memberName){ $lines[] = "\t\t$memberName => $key,"; } $lines[] = "\t\tdefault => throw new \pocketmine\utils\AssumptionFailedError(\"All $virtualTypeName cases should be covered\")"; $lines[] = "\t});"; $lines[] = "}"; return $lines; } /** * @param string[] $memberNames * @phpstan-param list $memberNames * * @return string[] * @phpstan-return list */ function buildReaderFunc(string $virtualTypeName, string $nativeTypeName, array $memberNames, string &$functionName) : array{ $bits = getBitsRequired($memberNames); $lines = []; $functionName = lcfirst($virtualTypeName); $lines[] = "public function $functionName(\\$nativeTypeName &\$value) : void{"; $lines[] = "\t\$value = match(\$this->readInt($bits)){"; foreach($memberNames as $key => $memberName){ $lines[] = "\t\t$key => $memberName,"; } $lines[] = "\t\tdefault => throw new InvalidSerializedRuntimeDataException(\"Invalid serialized value for $virtualTypeName\")"; $lines[] = "\t};"; $lines[] = "}"; return $lines; } /** * @param mixed[] $members */ function getBitsRequired(array $members) : int{ return (int) ceil(log(count($members), 2)); } /** * @param object[] $members * @phpstan-param array $members * * @return string[] * @phpstan-return list */ function stringifyEnumMembers(array $members, string $enumClass) : array{ ksort($members, SORT_STRING); return array_map(fn(string $enumCaseName) => "\\$enumClass::$enumCaseName()", array_keys($members)); } /** * @param object[] $enumMembers * @phpstan-param array $enumMembers * * @return string[] * @phpstan-return list */ function buildEnumWriterFunc(array $enumMembers, string &$functionName) : array{ $reflect = new \ReflectionClass($enumMembers[array_key_first($enumMembers)]); return buildWriterFunc( $reflect->getShortName(), $reflect->getName(), stringifyEnumMembers($enumMembers, $reflect->getName()), $functionName ); } /** * @param object[] $enumMembers * @phpstan-param array $enumMembers * * @return string[] * @phpstan-return list */ function buildEnumReaderFunc(array $enumMembers, string &$functionName) : array{ if(count($enumMembers) === 0){ throw new \InvalidArgumentException("Enum members cannot be empty"); } $reflect = new \ReflectionClass($enumMembers[array_key_first($enumMembers)]); return buildReaderFunc( $reflect->getShortName(), $reflect->getName(), stringifyEnumMembers($enumMembers, $reflect->getName()), $functionName ); } $enumsUsed = [ BellAttachmentType::getAll(), CopperOxidation::getAll(), CoralType::getAll(), DyeColor::getAll(), LeverFacing::getAll(), MushroomBlockType::getAll(), SkullType::getAll(), SlabType::getAll(), PotionType::getAll() ]; $readerFuncs = [ "" => [ "abstract protected function readInt(int \$bits) : int;" ] ]; $writerFuncs = [ "" => [ "abstract public function int(int \$bits, int \$value) : void;" ] ]; $functionName = ""; foreach($enumsUsed as $enumMembers){ $writerF = buildEnumWriterFunc($enumMembers, $functionName); /** @var string $functionName */ $writerFuncs[$functionName] = $writerF; $readerF = buildEnumReaderFunc($enumMembers, $functionName); /** @var string $functionName */ $readerFuncs[$functionName] = $readerF; } /** * @param string[][] $functions * @phpstan-param array> $functions */ function printFunctions(array $functions, string $className) : void{ ksort($functions, SORT_STRING); ob_start(); echo <<<'HEADER' "\t" . implode("\n\t", $functionLines), $functions)); echo "\n\n}\n"; file_put_contents(dirname(__DIR__) . '/src/data/runtime/' . $className . '.php', ob_get_clean()); } printFunctions($writerFuncs, "RuntimeEnumSerializerTrait"); printFunctions($readerFuncs, "RuntimeEnumDeserializerTrait"); echo "Done. Don't forget to run CS fixup after generating code.\n";