Должна быть поддержана сериализация типа в yson и json форматы.

### Введение

#### Каждый тип это словарь
Каждый тип представляется словарём, с одним обязательным ключом `type_name`, значением этого ключа является строка с именем типа. В зависимости от значения `type_name` допускается или требуется наличие других ключей.
Имена типов, полей, тегов должны быть валидными utf8 последовательностями.

Пример:
```
{
   type_name="decimal";
   precision=20;
   scale=10;   
}
```

#### Другие ключи в представлении типа
В представлении типа могут встречаться другие ключи. Тут у нас сильная типизация, если ключ встречается, в нём всегда ожидается что-то конкретное:
  - `item`, `key`, `value` -- всегда ожидается описание другого типа;
  - `members` -- всегда ожидается список словарей с ключами:
    - `type` -- описание другого типа,
    - `name` -- какая-то строка;
  - `elements` -- всегда ожидается список словарей с ключами:
    - `type` -- описание другого типа (пока ключ один, в дальнейшем рассматриваем возможность расширения);
  - `tag` -- ожидается строка;
  - `precision`, `scale` -- в качестве значений ожидаются целые числа;
  - `type_name` -- строка с именем типа.


### Оптимизация для типов без зависимостей
В качестве оптимизации типы, которые представляются словарём с единственной ключом ``type_name``, допускается представлять просто строкой с именем типа. Имплементации должны уметь парсить оба варианта, при сериализации отдавая предпочтение короткому.

Пример:
```
// Это эквивалентные типы:
{
  type_name=optional;
  item={
     type_name=uint32;
  };
}

{
  type_name=optional;
  item=uint32; // <<< словарь стал строкой
}
```

### Представление разных типов
#### Типы без дополнительных аргументов
Список типов:

- `int8`
- `int16`
- `int32`
- `int64`
- `uint8`
- `uint16`
- `uint32`
- `uint64`
- `null`
- `void`
- `float`
- `double`
- `bool`
- `string`
- `utf8`
- `date`
- `datetime`
- `timestamp`
- `tz_date`
- `tz_datetime`
- `tz_timestamp`
- `interval`
- `json`
- `yson`
- `uuid`

Все эти типы не требуют специальных дополнительных аргументов и могут представляться просто map'ой с одним ключом `type_name` или просто строкой с именем типа.

Пример:
```
{
   type_name=int16;
}
utf8
```

#### Decimal
Должны присутсвовать обязательные ключи `precision` и `scale`, в качестве значений ожидаются целые числа (тип `int` в yson).

Пример:
```
{
   type_name=decimal;
   precision=10;
   scale=5;
}
```

#### Optional,List
Должен присутсвовать обязательный ключ `item`, в качестве значения ожидается описание другого типа.

Примеры:
```
{
   type_name=optional;
   item=string;
}

{
   type_name=list;
   item=string;
}
```

#### Struct
Должен присутсвовать ключ `members`, в качестве значений список других словарей, в каждом из которых ключи:
  * `type` -- описание другого типа;
  * `name` -- имя поля.

Пример:
```
{
  type_name=struct;
  members=[
    {
      name=foo;
      type=int32;
    };
    {
      name=bar;
      type={
        type_name=optional;
        item=string;
      }
    };   
  ]
}

```

#### Tuple
Должен присутсвовать ключ `elements`, в качестве значений список других словарей, в каждом из которых ключи:
  * `type` -- описание другого типа.
   
(В дальнейшем мы планируем добавлять другие ключи внутрь этого словаря, например аннотации / документацию по отдельным полям.)

Пример:
```
{
  type_name=tuple;
  elements=[
     {
       type=double;
     };
     {
       type=double;
     };
  ]
}
```

#### Variant
Для варианта над структурой должен присутсвовать ключ `members`, в качестве значений список других словарей, в каждом из которых ключи:
  * `type` -- описание другого типа
  * `name` -- имя поля

Для варианта над таплом должен присутсвовать ключ `elements`, в качестве значений список других словарей, в каждом из которых ключи:
  * `type` -- описание другого типа

Таким образом ключи `members` / `elements` соответствуют ключам в нижележащем контейнере struct/tuple.
Если присутсвуют оба ключа и `members`, и `elements`, то такой yson является невалидным.

Пример:
```
{
  type_name=variant;
  members=[
     {
       name=int_field;
       type=int64;
     };
     {
       name=string_field;
       type=string;
     };
  ]
}

{
  type_name=variant;
  elements=[
     {
       type=void;
     };
     {
       type=string;
     };
  ]
}
```

#### Dict
Должны присутствовать ключи `key`, `value`, в качестве значений ожидаем другие типы.

Пример:
```
{
  type_name=dict;
  key=string;
  value={
    type_name=optional;
    item=int32;
  }
}
```


#### Tagged
Должны присутствовать ключи
  - `tag` -- строка с тегом;
  - `item` -- другой тип.

Пример:
```
{
  type_name=tagged;
  tag="image/svg";
  item="string";
}
```
