From f83bae76b4ec5e58a77eb69b63addc18d1afc119 Mon Sep 17 00:00:00 2001 From: Eugene Leonovich Date: Mon, 25 Oct 2021 00:19:47 +0200 Subject: [PATCH] Move interface classes, update README.md --- README.md | 180 +++++++----------- examples/MessagePack/DateTimeExtension.php | 2 +- examples/MessagePack/StructListExtension.php | 2 +- examples/MessagePack/TextExtension.php | 2 +- examples/MessagePack/TraversableExtension.php | 2 +- examples/MessagePack/Uint64.php | 2 +- src/BufferUnpacker.php | 1 - src/{TypeTransformer => }/CanBePacked.php | 4 +- src/{TypeTransformer => }/CanPack.php | 4 +- src/{TypeTransformer => }/Extension.php | 4 +- src/Packer.php | 2 - src/Type/Bin.php | 2 +- src/Type/Ext.php | 2 +- src/Type/Map.php | 2 +- src/TypeTransformer/StreamTransformer.php | 1 + .../TraversableTransformer.php | 11 +- tests/Unit/BufferUnpackerTest.php | 2 +- tests/Unit/PackerTest.php | 2 +- 18 files changed, 92 insertions(+), 135 deletions(-) rename src/{TypeTransformer => }/CanBePacked.php (83%) rename src/{TypeTransformer => }/CanPack.php (85%) rename src/{TypeTransformer => }/Extension.php (85%) diff --git a/README.md b/README.md index 42d0f3c..0fc70d4 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,10 @@ A pure PHP implementation of the [MessagePack](https://msgpack.org/) serializati * [Packing options](#packing-options) * [Unpacking](#unpacking) * [Unpacking options](#unpacking-options) - * [Extensions](#extensions) - * [Type transformers](#type-transformers) + * [Custom types](#custom-types) + * [Type objects](#type-objects) + * [Type transformers](#type-transformers) + * [Extensions](#extensions) * [Exceptions](#exceptions) * [Tests](#tests) * [Fuzzing](#fuzzing) @@ -108,7 +110,7 @@ $packer->packMap(['a' => 1]); // MP map $packer->packExt(1, "\xaa"); // MP ext ``` -> *Check the ["Type transformers"](#type-transformers) section below on how to pack custom types.* +> *Check the ["Custom types"](#custom-types) section below on how to pack custom types.* #### Packing options @@ -135,8 +137,9 @@ the packing process (defaults are in bold): > UTF-8 strings or/and associative arrays), you can eliminate this overhead by > forcing the packer to use the appropriate type, which will save it from running > the auto-detection routine. Another option is to explicitly specify the value -> type. The library provides 2 auxiliary classes for this, `Map` and `Bin`. -> Check the ["Type transformers"](#type-transformers) section below for details.* +> type. The library provides 2 auxiliary classes for this, [Map](src/Type/Map.php) +> and [Bin](src/Type/Bin.php). Check the ["Custom types"](#custom-types) section +> below for details.* Examples: @@ -180,7 +183,8 @@ $value = MessagePack::unpack($packed); If the packed data is received in chunks (e.g. when reading from a stream), use the `tryUnpack` method, which attempts to unpack data and returns an array -of unpacked messages (if any) instead of throwing an `InsufficientDataException`: +of unpacked messages (if any) instead of throwing +an [InsufficientDataException](src/Exception/InsufficientDataException.php): ```php while ($chunk = ...) { @@ -284,120 +288,65 @@ var_dump($unpacker->unpack()); // object(Decimal\Decimal) {...} ``` -### Extensions +### Custom types -The `Ext` class is used to represent [extension types](https://github.com/msgpack/msgpack/blob/master/spec.md#extension-types): - -```php -use MessagePack\Ext; -use MessagePack\MessagePack; - -$packed = MessagePack::pack(new Ext(42, "\xaa")); -$ext = MessagePack::unpack($packed); - -assert($ext->type === 42); -assert($ext->data === "\xaa"); -``` - -Although it can be useful for dealing with types that are not supported by your -setup, in most cases you will not use `Ext`, but rather type transformers that -make extension types first-class citizens in your code. +In addition to the [basic types](https://github.com/msgpack/msgpack/blob/master/spec.md#type-system), +the library provides functionality to serialize and deserialize arbitrary types. +This can be done in several ways, depending on your use case. Let's take a look at them. +#### Type objects -### Type transformers - -In addition to [the basic types](https://github.com/msgpack/msgpack/blob/master/spec.md#type-system), -the library provides functionality to serialize and deserialize arbitrary types. -In order to support a custom type you need to create and register a transformer. -The transformer should implement either the `CanPack` interface or the `Extension` -interface. - -The purpose of `CanPack` transformers is to serialize a specific value to -one of the basic MessagePack types. A good example of such a transformer is -a `MapTransformer` that comes with the library. It serializes `Map` objects -(which are simple wrappers around PHP arrays) to MessagePack maps. This is -useful when you want to explicitly mark that a given PHP array must be packed -as a MessagePack map, without triggering the type's auto-detection routine. - -> *More types and type transformers can be found in [src/Type](src/Type) -> and [src/TypeTransformer](src/TypeTransformer) directories.* - -The implementation is trivial: +If you need to *serialize* a specific value into one of the basic MessagePack types, it is recommended +to use an instance of a class that implements the [CanBePacked](src/CanBePacked.php) interface. A good +example of such a class is the [Map](src/Type/Map.php) type class that comes with the library. This type +is useful when you want to explicitly specify that a given PHP array should be packed as a MessagePack +map without triggering an automatic type detection routine: ```php -namespace MessagePack\TypeTransformer; - use MessagePack\Packer; use MessagePack\Type\Map; -class MapTransformer implements CanPack -{ - public function pack(Packer $packer, $value) : ?string - { - return $value instanceof Map - ? $packer->packMap($value->map) - : null; - } -} +$packer = new Packer(); + +$packedMap = $packer->pack(new Map([1, 2, 3])); +$packedArray = $packer->pack([1, 2, 3]); ``` -Once `MapTransformer` is registered, you can pack `Map` objects: +> *More type examples can be found in the [src/Type](src/Type) directory.* -```php -use MessagePack\Packer; -use MessagePack\Type\Map; -use MessagePack\TypeTransformer\MapTransformer; +#### Type transformers -$packer = new Packer(null, [new MapTransformer()]); +As with type objects, type transformers are only responsible for *serializing* values. They should be +used when you need to serialize a value that does not implement the [CanBePacked](src/CanBePacked.php) +interface. Examples of such values could be instances of built-in or third-party classes that you don't +own, or non-objects such as resources. -$packed = $packer->pack([ - [1, 2, 3], // MP array - new Map([1, 2, 3]), // MP map -]); -``` - -Transformers implementing the `Extension` interface are intended to handle -[extension types](https://github.com/msgpack/msgpack/blob/master/spec.md#extension-types). -For example, the code below shows how to create an extension that allows you -to work transparently with `DateTime` objects: +A transformer class must implement the [CanPack](src/CanPack.php) interface. To use a transformer, +it must first be registered in the packer. Here is an example of how to serialize PHP streams into +the MessagePack `bin` format type using one of the supplied transformers, `StreamTransformer`: ```php -use MessagePack\BufferUnpacker; use MessagePack\Packer; -use MessagePack\TypeTransformer\Extension; +use MessagePack\TypeTransformer\StreamTransformer; -class DateTimeExtension implements Extension -{ - private $type; +$packer = new Packer(null, [new StreamTransformer()]); - public function __construct(int $type) - { - $this->type = $type; - } - - public function getType() : int - { - return $this->type; - } +$packedBin = $packer->pack(fopen('/path/to/file', 'r+')); +``` - public function pack(Packer $packer, $value) : ?string - { - if (!$value instanceof \DateTimeInterface) { - return null; - } +> *More type transformer examples can be found in the [src/TypeTransformer](src/TypeTransformer) directory.* - return $packer->packExt($this->type, $value->format('YmdHisue')); - } +#### Extensions - public function unpackExt(BufferUnpacker $unpacker, int $extLength) - { - return \DateTimeImmutable::createFromFormat('YmdHisue', $unpacker->read($extLength)); - } -} -``` +In contrast to the cases described above, extensions are intended to handle +[extension types](https://github.com/msgpack/msgpack/blob/master/spec.md#extension-types) +and are responsible for *serializing* and *deserializing* values. An extension class must implement +the [Extension](src/Extension.php) interface. -Register `DateTimeExtension` for both the packer and the unpacker with a unique -extension type (an integer from 0 to 127) and you're ready to go: +For example, to make the built-in PHP `DateTime` objects first-class citizens in your code, you can +create a corresponding extension, as shown in the [example](examples/MessagePack/DateTimeExtension.php). +Register the extension for both the packer and the unpacker with a unique extension type (an integer +from 0 to 127) and you're ready to go: ```php use App\MessagePack\DateTimeExtension; @@ -412,21 +361,37 @@ $packer = $packer->extendWith($dateTimeExtension); $unpacker = new BufferUnpacker(); $unpacker = $unpacker->extendWith($dateTimeExtension); -$packed = $packer->pack(new DateTimeImmutable()); -$date = $unpacker->reset($packed)->unpack(); +$packedDate = $packer->pack(new DateTimeImmutable()); +$originalDate = $unpacker->reset($packed)->unpack(); +``` + +If you unpack a value from an extension that is not known to the unpacker, an [Ext](src/Type/Ext.php) +object will be returned. It can also be used to pack an extension: + +```php +use MessagePack\Ext; +use MessagePack\MessagePack; + +$packed = MessagePack::pack(new Ext(42, "\xaa")); +$ext = MessagePack::unpack($packed); + +assert($ext->type === 42); +assert($ext->data === "\xaa"); ``` -> *More type transformer examples can be found in the [examples](examples) directory.* +> *More extension examples can be found in the [examples/MessagePack](examples/MessagePack) directory.* ## Exceptions -If an error occurs during packing/unpacking, a `PackingFailedException` or -an `UnpackingFailedException` will be thrown, respectively. In addition, -an `InsufficientDataException` can be thrown during unpacking. +If an error occurs during packing/unpacking, +a [PackingFailedException](src/Exception/PackingFailedException.php) or +an [UnpackingFailedException](src/Exception/UnpackingFailedException.php) will be thrown, respectively. +In addition, an [InsufficientDataException](src/Exception/InsufficientDataException.php) can be thrown +during unpacking. -An `InvalidOptionException` will be thrown in case an invalid option -(or a combination of mutually exclusive options) is used. +An [InvalidOptionException](src/Exception/InvalidOptionException.php) will be thrown in case an invalid +option (or a combination of mutually exclusive options) is used. ## Tests @@ -924,5 +889,4 @@ Ignored 16 16 0 7 ## License -The library is released under the MIT License. See the bundled [LICENSE](LICENSE) -file for details. +The library is released under the MIT License. See the bundled [LICENSE](LICENSE) file for details. diff --git a/examples/MessagePack/DateTimeExtension.php b/examples/MessagePack/DateTimeExtension.php index d6a2966..d185ee8 100644 --- a/examples/MessagePack/DateTimeExtension.php +++ b/examples/MessagePack/DateTimeExtension.php @@ -12,8 +12,8 @@ namespace App\MessagePack; use MessagePack\BufferUnpacker; +use MessagePack\Extension; use MessagePack\Packer; -use MessagePack\TypeTransformer\Extension; class DateTimeExtension implements Extension { diff --git a/examples/MessagePack/StructListExtension.php b/examples/MessagePack/StructListExtension.php index 957a7d6..5dbfee9 100644 --- a/examples/MessagePack/StructListExtension.php +++ b/examples/MessagePack/StructListExtension.php @@ -12,8 +12,8 @@ namespace App\MessagePack; use MessagePack\BufferUnpacker; +use MessagePack\Extension; use MessagePack\Packer; -use MessagePack\TypeTransformer\Extension; class StructListExtension implements Extension { diff --git a/examples/MessagePack/TextExtension.php b/examples/MessagePack/TextExtension.php index ea52396..ea3f4db 100644 --- a/examples/MessagePack/TextExtension.php +++ b/examples/MessagePack/TextExtension.php @@ -12,8 +12,8 @@ namespace App\MessagePack; use MessagePack\BufferUnpacker; +use MessagePack\Extension; use MessagePack\Packer; -use MessagePack\TypeTransformer\Extension; class TextExtension implements Extension { diff --git a/examples/MessagePack/TraversableExtension.php b/examples/MessagePack/TraversableExtension.php index d6db101..2b0fdb0 100644 --- a/examples/MessagePack/TraversableExtension.php +++ b/examples/MessagePack/TraversableExtension.php @@ -12,8 +12,8 @@ namespace App\MessagePack; use MessagePack\BufferUnpacker; +use MessagePack\Extension; use MessagePack\Packer; -use MessagePack\TypeTransformer\Extension; class TraversableExtension implements Extension { diff --git a/examples/MessagePack/Uint64.php b/examples/MessagePack/Uint64.php index f195f6e..1e31d06 100644 --- a/examples/MessagePack/Uint64.php +++ b/examples/MessagePack/Uint64.php @@ -11,8 +11,8 @@ namespace App\MessagePack; +use MessagePack\CanBePacked; use MessagePack\Packer; -use MessagePack\TypeTransformer\CanBePacked; final class Uint64 implements CanBePacked { diff --git a/src/BufferUnpacker.php b/src/BufferUnpacker.php index fa6bd23..8f71ce4 100644 --- a/src/BufferUnpacker.php +++ b/src/BufferUnpacker.php @@ -16,7 +16,6 @@ use MessagePack\Exception\InvalidOptionException; use MessagePack\Exception\UnpackingFailedException; use MessagePack\Type\Ext; -use MessagePack\TypeTransformer\Extension; class BufferUnpacker { diff --git a/src/TypeTransformer/CanBePacked.php b/src/CanBePacked.php similarity index 83% rename from src/TypeTransformer/CanBePacked.php rename to src/CanBePacked.php index 26c53f7..6cca02e 100644 --- a/src/TypeTransformer/CanBePacked.php +++ b/src/CanBePacked.php @@ -9,9 +9,7 @@ * file that was distributed with this source code. */ -namespace MessagePack\TypeTransformer; - -use MessagePack\Packer; +namespace MessagePack; interface CanBePacked { diff --git a/src/TypeTransformer/CanPack.php b/src/CanPack.php similarity index 85% rename from src/TypeTransformer/CanPack.php rename to src/CanPack.php index c240e80..e54637a 100644 --- a/src/TypeTransformer/CanPack.php +++ b/src/CanPack.php @@ -9,9 +9,7 @@ * file that was distributed with this source code. */ -namespace MessagePack\TypeTransformer; - -use MessagePack\Packer; +namespace MessagePack; interface CanPack { diff --git a/src/TypeTransformer/Extension.php b/src/Extension.php similarity index 85% rename from src/TypeTransformer/Extension.php rename to src/Extension.php index bf9fc28..88436ed 100644 --- a/src/TypeTransformer/Extension.php +++ b/src/Extension.php @@ -9,9 +9,7 @@ * file that was distributed with this source code. */ -namespace MessagePack\TypeTransformer; - -use MessagePack\BufferUnpacker; +namespace MessagePack; interface Extension extends CanPack { diff --git a/src/Packer.php b/src/Packer.php index 496691a..024847f 100644 --- a/src/Packer.php +++ b/src/Packer.php @@ -13,8 +13,6 @@ use MessagePack\Exception\InvalidOptionException; use MessagePack\Exception\PackingFailedException; -use MessagePack\TypeTransformer\CanBePacked; -use MessagePack\TypeTransformer\CanPack; class Packer { diff --git a/src/Type/Bin.php b/src/Type/Bin.php index 607d465..1d76b14 100644 --- a/src/Type/Bin.php +++ b/src/Type/Bin.php @@ -11,8 +11,8 @@ namespace MessagePack\Type; +use MessagePack\CanBePacked; use MessagePack\Packer; -use MessagePack\TypeTransformer\CanBePacked; final class Bin implements CanBePacked { diff --git a/src/Type/Ext.php b/src/Type/Ext.php index 407631e..f59761a 100644 --- a/src/Type/Ext.php +++ b/src/Type/Ext.php @@ -11,8 +11,8 @@ namespace MessagePack\Type; +use MessagePack\CanBePacked; use MessagePack\Packer; -use MessagePack\TypeTransformer\CanBePacked; final class Ext implements CanBePacked { diff --git a/src/Type/Map.php b/src/Type/Map.php index 814762e..68891b5 100644 --- a/src/Type/Map.php +++ b/src/Type/Map.php @@ -11,8 +11,8 @@ namespace MessagePack\Type; +use MessagePack\CanBePacked; use MessagePack\Packer; -use MessagePack\TypeTransformer\CanBePacked; final class Map implements CanBePacked { diff --git a/src/TypeTransformer/StreamTransformer.php b/src/TypeTransformer/StreamTransformer.php index eeb8a38..fc32d82 100644 --- a/src/TypeTransformer/StreamTransformer.php +++ b/src/TypeTransformer/StreamTransformer.php @@ -11,6 +11,7 @@ namespace MessagePack\TypeTransformer; +use MessagePack\CanPack; use MessagePack\Packer; class StreamTransformer implements CanPack diff --git a/src/TypeTransformer/TraversableTransformer.php b/src/TypeTransformer/TraversableTransformer.php index 0b7544e..799642e 100644 --- a/src/TypeTransformer/TraversableTransformer.php +++ b/src/TypeTransformer/TraversableTransformer.php @@ -11,19 +11,20 @@ namespace MessagePack\TypeTransformer; +use MessagePack\CanPack; use MessagePack\Packer; class TraversableTransformer implements CanPack { /** @var bool */ - private $toMap; + private $packToMap; /** - * @param bool $toMap + * @param bool $packToMap */ - private function __construct($toMap) + private function __construct($packToMap) { - $this->toMap = $toMap; + $this->packToMap = $packToMap; } public static function toMap() : self @@ -42,7 +43,7 @@ public function pack(Packer $packer, $value) : ?string return null; } - return $this->toMap + return $this->packToMap ? self::packMap($packer, $value) : self::packArray($packer, $value); } diff --git a/tests/Unit/BufferUnpackerTest.php b/tests/Unit/BufferUnpackerTest.php index 4c9dde9..0da10a6 100644 --- a/tests/Unit/BufferUnpackerTest.php +++ b/tests/Unit/BufferUnpackerTest.php @@ -16,9 +16,9 @@ use MessagePack\Exception\InsufficientDataException; use MessagePack\Exception\InvalidOptionException; use MessagePack\Exception\UnpackingFailedException; +use MessagePack\Extension; use MessagePack\Tests\DataProvider; use MessagePack\Type\Ext; -use MessagePack\TypeTransformer\Extension; use MessagePack\UnpackOptions; use PHPUnit\Framework\TestCase; diff --git a/tests/Unit/PackerTest.php b/tests/Unit/PackerTest.php index 7f20143..6a536ae 100644 --- a/tests/Unit/PackerTest.php +++ b/tests/Unit/PackerTest.php @@ -11,12 +11,12 @@ namespace MessagePack\Tests\Unit; +use MessagePack\CanPack; use MessagePack\Exception\InvalidOptionException; use MessagePack\Exception\PackingFailedException; use MessagePack\Packer; use MessagePack\PackOptions; use MessagePack\Type\Ext; -use MessagePack\TypeTransformer\CanPack; use PHPUnit\Framework\TestCase; final class PackerTest extends TestCase