Skip to content

Commit

Permalink
documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
hrissan authored and Brat-vseznamus committed Nov 20, 2024
1 parent c0ed278 commit f612670
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 0 deletions.
109 changes: 109 additions & 0 deletions docs/go.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Go генератор

tlgen детерминистский и генерирует при повторном запуске один и тот же код, так что
сгенерированный код можно добавлять в систему контроля версий.

По-умолчанию все комбинаторы генерируются в один internal пакет, плюс для каждого
namespace TL генерируется пакет с алиасами. Это сделано потому, что Go не поддерживает рекурсивные зависимости между пакетами, а TL поддерживает.

Для очень больших TL-файлов, содержащих тысячи комбинаторов, можно передать флаг --split-internal, тогда каждый тип помещается в собственный internal пакет.
Затем пакеты для типов, рекурсивно использующих друг друга, обьединяются.
Это сделано для того, чтобы при изменении одного комбинатора TL не приходилось перекомпилировать код большинства комбинаторов.

Также tlgen поддерживает опцию --typesWhiteList, если вам нужна только часть namespace или комбинаторов, то можно явно указать их имена.

# шаблоны

TL-шаблоны полностью инстанцируются (для каждой использованной комбинации аргументов).

Так что pair<int, int> pair<long, long> превращаются в PairIntInt и PairLongLong.


# простые типы

Отображаются в соответствующие типы Go

Nat (#) в uint32, int в int32, long в int64, Bool в bool.

String в string или []byte (В так называемые Bytes-версиях типов)

# векторы и туплы

Отображаются в массивы (если размер фиксирован), либо в слайсы.

Отображение в массивы важно, так как позволяет 3*3*[int] отобразить в тип [3][3]int, который можно разместить на стеке и передать как знаение без аллокаций.

Из-за этой оптимизации для следующих комбинаторов 3*[int] 4*[int] и n*[int] где n нефиксирован будет сгенрировано 3 разных Go типа.

# структуры

Отображаются в структуры Go.

# маски полей

Локальные маски полей хранятся в натуральном для TL виде uint32, если какое-то поле зависит от маски полей, то кроме поля будет сгенерированы методы
SetFieldX и IsSetFieldX который ставят и проверяют соответствующий бит маски.

Маски полей-аргументы шаблона не хранятся в объектах, а передаются снаружи в методы Read, Write.

Таким образом сгенерированные типы не содержат избыточных масок полей.

# обьединения

Генерируются в структуру Go, содержащую все варианты обьединения.
На первый взгляд это неоптимально с точки зрения памяти, но на самом деле позволяет идеально переиспользовать []byte и слайсы в
каждом варианте при повторном парсинге. Это часто перекрывает эффект от того, что сами структуры занимают немного больше.

В качестве селектора варианта используется приватное поле номер конструктора.

# перечисления

Похожи на обьединения, но содержат функции MakeXXX

# Bytes-версии и работы с минимумом аллокаций

tlgen генерирует эффективный код на go, который поддерживает стиль
программирования с reuse, позволяющий значительно уменьшить число аллокаций и стоимость GC.

Если комбинатор содержит TL string, то генерируется go string, так что при каждом чтении TL будет происходить аллокация каждой строки.
С помощь опции --generateByteVersions можно попросить tlgen сгенерировать в дополнение к основным также версии типов, где вместо строк используется []byte.

При чтении соответствуюший []byte будет переиспользоваться, и если длина достаточно, то новой аллокации не будет.

Таким образом, например, если сервер читает некий TL запрос, он может иметь sync.Pool структур, брать из пула структуру, десерилизоввать, отвечать на запрос, и затем класть структуру обратно в пул.
При работе сервера все строки и другие слайсы довольно быстро перестанут аллоцироваться, и таким образо деаллоцироваться.

Нужно только понимать, что всеми слайсами в TL объекте владеет сам TL-объект, и при необходимости долговременного хранения нужно либо скопировать себе данные, либо сослаться на них, но тогда не класть структуру обратно в пул для reuse.

# метаданные и фабрика

Генерируется также пакет meta и factory.

meta содержит метаданные для всех комбинаторов, доступные по magic или имени комбинатора.

Если импортировать пакет factory, то для каждого комбинатора можно будет в runtime получить интерфейс, который позволит читать записывать и перекодировать TL-обьекты в другой формат на лету.

# JSON-представление

Все сгенерированные типы кроме методов ReadTL и WriteTL содержат также методы ReadJSON и WriteJSON.

Также WriteJSON используется в реализации интерфейса String(), так что печать TL-обьекта на экран или в лог
выводит его в каноническом формате, который можно распарсить.

Больше информации про каноническое представление JSON есть в документе TLPrimer.pdf

Если передать флаг --generateSchemaDocumentation, то сгенерируется HTML с документацией и примерами JSON для каждого комбинатора.

# RPC

Если передать флаг --generateRPCCode, то для всех TL-функций будет сгенерирова код
для реализации сервера (Handler) и клиентов (Client) в каждом пакете соответствующем TL namespace.

Этот код требует пакет RPC, который находится в opensource как часть проекта statashouse.
В дальнейшем есть планы пепеместить код RPC в проект tlgen.

# random

Если передать флаг --generateRandomCode, то у каждого сгенерированного типа появится возможность
создавать детерминистски случайный экземпляр, это важно для тестов.

5 changes: 5 additions & 0 deletions docs/tldoc.ru.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# TL (Type Language)

Формат md не поддерживает цвета, так что лучше всего читать
исходный документ в формате pdf.

Этот же файл получен автоконвертером и без цветов на схемах гораздо менее понятен, чем оригинал.

## Общие сведения

TL это язык описания данных и формат хранения данных.
Expand Down

0 comments on commit f612670

Please sign in to comment.