-
Notifications
You must be signed in to change notification settings - Fork 0
Union
A discriminated union is arguable the most useful XDR data structure, and perhaps also the hardest to understand. An XDR union consists of a 'discriminator' and a value.
The discriminator is used to determine the value type. With only four bytes it can only be an integer, unsigned integer, boolean or an enum.
The union value can be any XDR type. It is the responsibility of the user to define the types for each valid value of the discriminator. The spec refers to these type options as 'arms'.
To define a union, create a class that implements the StageRightLabs\PhpXdr\Interfaces\XdrUnion interface. This interface has seven methods:
-
static function getXdrDiscriminatorType(): string: Return a string that represents the type of discriminant:XDR::INT,XDR::UINT,XDR::BOOL, or the name of a class that implements theXdrEnuminterface. -
getXdrDiscriminator(): int|bool|XdrEnum: Return the discriminator. -
static getXdrType(int|bool|XdrEnum $discriminator): string: Return the value type for a discriminator as defined in the arms array. This can either be one of the primitive constants or the name of a custom class that implements an XDR interface. -
static getXdrLength(int|bool|XdrEnum $discriminator): ?int: If a discriminated value type requires a specified length return that here. Otherwise return null. -
getXdrValue(): mixed: Return the value of the union. -
static newFromXdr(int|bool|XdrEnum $discriminator): static: Create a new instance of the class. The decoded discriminator value is the only provided parameter.
The spec requires that the value type must be a known arm, otherwise the data structure is invalid and won't translate. It is possible to have a default value type for a union but this is the responsibility of the implementing class.
For example:
use StageRightLabs\PhpXdr\XDR;
use StageRightLabs\PhpXdr\Interfaces\XdrUnion;
class NameOrNumber implements XdrUnion
{
protected static $arms = [
10 => XDR::STRING,
20 => XDR::INT,
;
public function getXdrDiscriminator(): int|bool|XdrEnum
{
return $this->type;
}
public static function getXdrDiscriminatorType(): string
{
return XDR::INT;
}
public static function getXdrType(int $discriminator): string
{
return self::$arms[$discriminator];
}
public static function getXdrLength(int $discriminator): ?int
{
return null;
}
public function getXdrValue(): mixed
{
return $this->getValue();
}
public static function newFromXdr(int $discriminator, mixed $value): static
{
return new static($discriminator, $value);
}
// The methods below are not required by the interface
const DEFAULT = 20;
public function __construct(public ?int $type = null, protected ?mixed $value = null)
{
$this->type = $type ?? self::DEFAULT;
$this->value = $value;
}
public function setValue(int $type, mixed $value): void
{
$this->type = $type;
$this->value = $value;
}
public function getValue(): mixed
{
return $this->value;
}
}To encode a union:
use StageRightLabs\PhpXdr\XDR;
$union = new NameOrNumber;
$union->setValue(20, 42)
$xdr = XDR::fresh()->write($union, XDR::UNION);To decode a union:
use StageRightLabs\PhpXdr\XDR;
$union = $xdr->read(XDR::UNION, NameOrNumber::class);
$union->getValue(); // 42