Y3 Codec: формат данных версии 202007
Обзор
Версия: Draft-01 (v202007). Данный протокол определяет формат кадров Y3 Codec.
Содержание
Цели проектирования
Y3 Codec — это кодировщик, работающий быстрее реального времени. Бинарный формат подходит для кодирования и декодирования, особенно в контексте потоковой обработки и случайного доступа. Оптимизирован для использования в QUIC Transport. В данном документе не рассматривается RPC, он не связан с подключением и описывает только структуру данных.
Условные обозначения
В этом документе используются пользовательские форматы для описания пакетов данных и фреймворков. Цель этих форматов — описать метод представления, а не определить конкретные элементы протокола. Этот документ определяет полную семантику и структуру.
Сначала определяются сложные структуры (complex fields), затем список полей внутри фигурных скобок, каждый элемент списка отделяется запятой.
Каждое поле включает информацию о длине и указание на фиксированные поля: значение, опциональность или повторяемость.
Для одиночных полей используется следующий символ: x (A) обозначает длину x как A бит; x (A..B) — длина x может быть любой от A до B; x (?) = C — фиксированная длина x равна C; x (?) = C..D — значение x находится между C и D; [x (E)] — часть в квадратных скобках является опциональной; x (E) ... — x повторяется ноль или более раз, и каждый повтор имеет длину E.
Этот документ использует порядок байтов Big-Endian, поля начинаются с высокого бита каждого байта.
По соглашению, отдельные поля могут ссылаться на сложную структуру, используя следующие имена. Например:
Example Structure {
One-bit Field (1),
7-bit Field with Fixed Value (7) = 61,
Arbitrary-Length Field (..),
Variable-Length Field (8..24),
Field With Minimum Length (16..),
Field With Maximum Length (..128),
[Optional Field (64)],
Repeated Field (8) ...,
}
Формат TLV
0 7
+--------+
| Tag |
+--------+--------+--------+--------+
| Length |
+--------+--------+--------+--------+
| ...
+--------+--------+--------+--------+
| Value Payloads |
+--------+--------+--------+--------+
| ...
+--------+--------+--------+--------+
Базовый пакет (Base Packet):
Base Packet {
Tag (8),
Length (8) ...,
Value (8) ...,
}
Tag {
TypeFlag (1),
ArrayFlag (1),
SequenceID (6),
}
Длина тега составляет фиксированные 8 бит (1 байт).
Представляют значения данных базовых типов.
Содержит по крайней мере один тип пакета узла или базовый тип. Все дочерние узлы объединяются в соответствии с форматом TLV для формирования окончательного значения типа пакета узла.
Описывает длину в байтах значения (Value) пакета. Используется переменный целочисленный тип pvarint.
Хранит значение пакета. При декодировании указывается конкретный тип данных.
Пример: если использовать Y3 для кодирования следующей структуры данных JSON:
{
"age" : 5,
"summary": {
"name": "CELLA",
"create": "Y3"
}
}
Во-первых, определяется вся структура сообщения, подобно файлу .proto в ProtoBuffer:
Базовый тип пакета, Tag определяется как 0x01, представляющий «age», его значение — переменное целое число (pvarint).
Тип пакета узла, Tag определяется как 0x82, представляющий «summary», этот узел содержит два базовых типа пакета:
Базовый тип пакета, Tag определяется как 0x03, представляющий «name», его значение является строкой (string).
Базовый тип пакета, Tag определяется как 0x04, представляющий «create», его значение также является строкой (string).
Порядок кодирования (порядковые номера обозначают порядок):
1️⃣ 0x01 -> Tag=0x01 описывает key="age", так как старший бит равен 0, это означает, что его значение относится к базовому типу пакета.
3️⃣ 0x01 -> длина этого значения составляет 1 байт, поэтому следующий байт является конкретным содержимым значения.
2️⃣ 0x05 -> является переменным целым числом (pvarint), 0x05 представляет число 5.
8️⃣ 0x82 -> Tag=0x82 описывает key="summary", так как старший бит равен 1, это указывает на то, что значение (Value) относится к типу пакета узла.
7️⃣ 0x0B -> длина этого значения равна 11 байтам, поэтому следующие 11 байт являются конкретным содержимым значения.
1️⃣ 0x03 -> Tag=0x03 описывает key="name", так как старший бит равен 0, это указывает на то, что его значение принадлежит базовому типу пакета.
3️⃣ 0x05 -> длина этого значения составляет 5 байтов, поэтому следующие 5 байтов являются конкретным содержимым значения.
2️⃣ 0x43 0x45 0x4C 0x4C 0x41 -> **Система примитивных типов**
Основана на базовых типах данных:
* строка (используется кодировка UTF-8);
* двоичные данные;
* pvarint — тип переменной длины, который описывает переменное целочисленное значение.
**pvarint**
Используется прямой порядок байтов. Старший бит C является битом продолжения, он равен 1, если следующий байт также является частью значения, и 0 в противном случае. Следующий за старшим бит S определяет тип числа: для знаковых целых чисел это бит знака, а для беззнаковых целых — информационный бит. Оставшиеся биты старшего байта используются как бит знака для знаковых чисел или игнорируются для беззнаковых.
Для знаковых целых:
pvarint = {
Continuation Bit (1),
Signed Bit (1),
Payloads (6..),
}
Для беззнаковых:
pvarint Value = {
Continuation Bit (1),
Payloads (7..),
}
Пример использования pvarint
В качестве примера возьмём десятичное число 511 в типе i32 языка Rust. В двоичном представлении оно выглядит так: 0000 0000 0000 0000 0000 0001 1111 1111. Если использовать тип pvarint, то процесс кодирования будет состоять из четырёх шагов:
1. Эффективные данные: xxxx xxx0 1111 1111 (для обозначения каждого байта используется 8 бит, x обозначает игнорируемые биты; 511 — положительное число, поэтому его бит знака равен 0).
2. Все биты x заменяются битами знака 0: 0000 0001 1111 1111.
3. Поскольку старший бит используется для обозначения продолжения, эффективные данные имеют только 7 бит. Мы добавляем старший бит y к каждому байту: y000 0011 y111 1111.
4. Если есть ещё байты, старший бит следующего байта устанавливается в 1, иначе в 0. Таким образом, получаем: 1000 0011 0111 1111.
После кодирования Y3 для представления числа 511 требуется всего два байта.
Рассмотрим пример с отрицательным числом -1 в типе i32. Его двоичное представление: 1111 1111 1111 1111 1111 1111 1111 1111. Процесс кодирования с использованием pvarint состоит из следующих шагов:
1. Эффективные данные: xxxx xx11 (каждый байт имеет 8 бит; -1 — отрицательное число, поэтому бит знака равен 1).
2. Заменяем все биты x битами знака: 1111 1111.
3. Так как старший бит используется для продолжения, эффективные данные содержат только 7 битов. Добавляем старший бит y к каждому байту: y111 1111.
4. Поскольку больше нет байтов, старший бит устанавливается в 0, что даёт нам: 0111 1111.
Используя кодировку Y3, для представления -1 нужен только один байт.
Булевы значения можно описать с помощью типа pvarint: 1 означает True, 0 — False.
Тип float пока не реализован.
Slice
Для реализации Tag предлагается исключить старший бит массива, обозначающий тип элемента, и сделать Slice встроенным базовым типом данных, структура которого представляет собой повторяющуюся пару Length-Value.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )