Как стать автором
Обновить

AS3 Vector в AMF3: приподымаем занавес

Время на прочтение3 мин
Количество просмотров3K
Начиная с версии flash player 10.0, появилась поддержка нового вида списков — vector. Vector — это типизированный, упорядоченный список. Более подробно можно почитать на сайте Adobe. Тесты показывают неплохой прирост по скорости чтения/записи по сравнению с простыми массивами. (Не так давно soulburner опубликовал свои тесты). К несчастью, ни одна библиотека на PHP (да в прочем и на других языках, не считая AS3) не поддерживает этот тип данных.

Немного погуглив, была найдена статейка, в которой описывается десериализация векторов на java. Оказывается всё не так уж и плохо: существует четыре дополнительных маркера для Vector.<int>, Vector.<uint>, Vector.<Number> и Vector.<Object>. Но у меня так и не получилось полностью портировать код — сервер никак не мог десериализовать вектор объектов (с числовым типами всё было в порядке). В итоге пришлось поставить xdebug и начать самому искать «где собака зарыта». Как я и подозревал, автор той статьи неправильно реализовал парсинг вектора объектов и немного некорректно парсинг числовых векторов.

Спецификация векторов

Adobe выпустила спецификацию протокола AMF3, но забыла (или не захотела) обновить её после появления векторов. Ниже можно увидеть дополнение спецификации, касающееся векторов.

S32 = An signed 32-bit integer in big endian (network) byte order

vector-type = vector-int-type | vector-uint-type | vector-number-type |
              vector-object-type | vector-other-type

value-type =| vector-type

vector-int-marker    = 0x0D
vector-uint-marker   = 0x0E
vector-number-marker = 0x0F
vector-object-marker = 0x10

U29V-len = U29 ; The first (low) bit is a flag with value 1.
               ; The remaining 1 to 28 significant bits are used to encode
               ; the length of the vector
vector-fixed-flag = U8

vector-int-type     = vector-int-marker (U29O-ref | U29V-length vector-fixed-flag *(S32))
vector-uint-type    = vector-uint-marker (U29O-ref | U29V-length vector-fixed-flag *(U32))
vector-number-type  = vector-number-marker (U29O-ref | U29V-length vector-fixed-flag *(DOUBLE))
vector-object-type  = vec tor-object-marker (U29O-ref | U29V-length vector-fixed-flag class-name
                      *(null-type | object-type))
vector-other-type  = vector-object-marker (U29O-ref | U29V-length vector-fixed-flag UTF-8-empty
                      *(null-type | false-type | true-type | array-type | string-type |
                      vector-type | date-type | byte-array-type))


Как видно, было добавлено 4 дополнительных маркера: 3 специальных для числовых значений и один для всего остального.

Замечание. На самом деле спецификация не совсем верная, а именно vector-other-type правило. По спецификации получается, что такой вектор может содержать одновременно все перечисленные типы, но на самом деле только один из перечисленных типов. И только null-type может использоваться одновременно с остальными типами. К сожалению я не знаю как указать такое правило с помощью ABNF.

Числовые векторы

С ними всё просто. Читаем длину вектора, fixed флаг, и N значений (int, uint или double). Если честно, меня удивило то, что эти три вектора были вынесены, особенно на фоне того что вектора строк и буленов кодируются как вектора объектов (об этом чуть ниже).

Вектор объектов

Точно такой же как и числовые векторы. Единственное отличие — дополнительный параметр class-name, имя класса, объекты которого содержит вектор. class-name может быть пустым, подразумевая под собой Object.

Вектора строк, буленов, массивов, векторов

Я был неприятно удивлен тому, как кодируются векторы для остальных «спец-типов». Для них используется маркер вектора объектов с пустой строкой вместо class-name. А значит без данных невозможно узнать, что именно содержит вектор, т.е. невозможно узнать, что за вектор приехал, если он пустой.

Реализация

Из-за таких векторов для «особых типов данных» я и столкнулся с трудностями в реализации поддержки векторов для PHP. Проблема заключается именно в строгой типизации векторов — вектор может хранить только один тип данных. Тут меня разрывало между 2-мя способами реализации:
— простой, но тупой контейнер для массивов
— typesafe вектора
С первым всё просто, но хочется второго. В итоге патч для Zend_Amf так и не был написан, потому что я покинул компанию, на которую работал. А сейчас нет времени закончить его. Поэтому решил просто выложить спецификацию. Я уверен найдётся много желающих, готовых реализовать поддержку векторов в Zend_Amf, AMFPHP, WebORB, PyAMF и остальных.

P.S.

Спецификация не проходила тщательного тестирования, поэтому она вполне может быть не полной. Буду рад любым поправкам.
Теги:
Хабы:
Всего голосов 14: ↑11 и ↓3+8
Комментарии5

Публикации