JSON/CBOR
Модуль stappler_data
предназначен для работы с нетипизированными форматами JSON, CBOR, форматами urlencoded и собственным форматом Serenity Query
.
Модуль предоставляет контейнер нетипизированных значений Value
в вариантах для обоих интерфейсов памяти.
Для чтения данных предназначены функции:
data::read
data::readFile
Функции определяют исходный формат автоматически.
Для записи данных:
data::write
data::save
- сохраняет в файлdata::toString
- записывает в строку (если возможно для формата
Формат записи определяется типом data::EncodeFormat
.
Формат характеризуется типом и сжатием;
Тип:
Json
- JSONPretty
- человекочитаемый JSONCbor
- CBOR (http://cbor.io/, http://tools.ietf.org/html/rfc7049)DefaultFormat
- на выбор SDK (обычно CBOR)Serenity
- Serenity QuerySerenityPretty
- человекочитаемый Serenity QueryPrettyTime
- человекочитаемый JSON с декодированными метками времени SDK
Сжатие:
NoCompression
LZ4Compression
LZ4HCCompression
Brotli
- доступно, если подключенstappler_brotli_lib
Пример работы с Value
:
// создание массива объектов
Value arr({
Value({
pair("one", Value(1)),
pair("two", Value(2)),
}),
Value({
pair("one", Value(3)),
pair("two", Value(4)),
})
});
// перебор массива
for (auto &it : arr.asArray()) {
for (auto &obj : it.asDict()) {
std::cout << "Key: " << obj.first << " Value: " << data::toString<Interface>(obj.second) << "\n"
}
}
Сжатие
Интерфейс сжатия можно использовать без Value функциями
data::compress
- сжимает в блок данных из интерфейса памяти, блок автоматически будет распознан при декомпрессииdata::getCompressBounds
- возвращает максимальный размер буфера для сжатияdata::compressData
- выполняет сжатие буфера в целевой буферdata::writeCompressionMark
- записыает 4-байтную метку сжатия, по которой система распознаёт форматdata::decompress
- в полном варианте расшифровывает сжатый блок в буфер с известным размером, в малом - в блок интерфейса памятиdata::getDecompressedSize
- получает размер данных до сжатия
Serenity Query
Формат строки запроса Serenity нужен для компактного определения json-подобных структур в строке запроса без дополнительного кодирования. Схож по задачам с GraphQL.
Допустимые специальные символы в строке запроса: `/ ? : @ - . _ ~ ! $ & ' ( ) * + , ; =``
Допустимые символы в токенах:
0-9 A-Z a-z / ? @ - . _ ! $ ' * +
Запрещены в токенах:
: & ( ) , ; = ~
В реальной работе пробельные символы недопустимы, они используются для демонстрации логики формата человеку.
Для кодирования токенов можно использовать процентное кодирование, как в обычных URL. Процентно-кодированные символы не считаются спецсимволами.
Зарезервированные токены:
n, t, f, null true false inf +inf -inf nan
Зарезервированные токены можно использовать в качестве обычных, если использовать процентное кодирование
Пример кодирования:
http://localhost/index?(field:value;arrayField:array1,array2,array3;dictField:(field1:value1;field2:value2))
Запрос
(
field: value;
arrayField: array1, array2, array3;
flagField;
dictField (
field1: value1;
field2: value2
)
)
интерпретируется как:
{
“field”: “value”,
“arrayField”: [“array1”, ”array2”, ”array3”],
“flagField”: true,
“dictField”: {
“field1”: “value1”,
“field2”: “value2”
}
}
Первичный объект всегда должен присутствовать и интерпретироваться как объект/словарь.
Токены на позициях, соответствующих именам полей объекта всегда интерпретируются как строки. В других позициях тип определяется автоматически. Поддерживаются стандартные JSON-типы (float, integer, bool, null, string) и тип bytes (кодируется префиксом ~ перед токеном и процентным кодированием байт).
Явное объявление массива:
~(array1, ~(subarray1, subarray2, ~(subsubarrayItem)), array3)
Типы
Базовые:
- true, t - bool true
- false, f - bool false
- null, n - null
Числовые - Аналогично JSON
Строки
Строки не выделяются кавычками, могут содержать символы 0-9 A-Z a-z / ? @ - . _ ! $ ' * +
. Другие символы кодируются с помощью процентного кодирования. Для определения строки, совпадающей с зарезервированным токеном или выглядящей как число нужно использовать процентное кодирование, как минимум, первого символа.
Токены, начинающиеся с числа или + -
могут быть распознаны как строки, если не распознаны, как числа.
Бинарные данные
Кодируются аналогично строкам, с префиксом ~
. Реализация должна учитывать, что бинарный блок может содержать процентно-кодированные нечитаемые и специальные символы, включая ~%00
.
Объекты/Словари
Объекты кодируются с помощью круглых скобок и ; в качестве разделителя
Типовое кодирование объекта выглядит так:
(field:value;arrayField:array1,array2,array3;dictField:(field1:value1;field2:value2);flagField:true)
Некоторые части могут быть опущены:
;
после закрывающей скобки объекта:
перед открывающей скобкой объекта:true
,:t
для полей-флагов
В итоге, строка будет выглядеть так:
(field:value;arrayField:array1,array2,array3;dictField(field1:value1;field2:value2)flagField)
(
field : value;
arrayField : array1, array2, array3;
dictField (
field1 : value1;
field2 : value2
)
flagField
)
Массивы
Массивы могут кодироваться двумя способами.
Вложенное кодирование массивов может использоваться для описания массива как поля объекта. В таком случае элементы массива перечисляются через запятую без других специальных символов. Для интерпретации вложенного массива нужны, как минимум, два значения.
(
arrayField : array1, {field:value), ~(val1, val2), false;
)
Универсальное кодирование массивов используется в любом месте, в том числе, для определения массивов внутри других массивов. Массивы кодируются внутри конструкции ~( ), через запятую.
(
arrayField : ~(array1, {field:value), ~(val1, val2), false);
)