[3e74d4c7508130e47831eae2fcc5ee3e79113386]
#keks
choice в KEKS/Schema
KEKS я давно не трогаю. Использую KEKS/CM постоянно, но типа все форматы
текущие устаканились и не требуют доработки. Но, как часто бывает, нужно
чтобы всё это отлежалось.
Почему то вчера возникла мысль о CHOICE-ах (аналог из ASN.1). Пока
предполагалось что будет некое поле с типом, которое уже вне схемы будет
проверяться программой а дальше вызываться соответствующая валидация по
другой схеме.
А потом осенило: ведь choice это же по сути просто MAP, но с одним
единственным выбранным полем! В ASN.1 это не обязательно SEQUENCE,
конечно же, но в KEKS пускай выбор будет явно виден как поле в MAP. Даже
в ASN.1 он описывается как SEQUENCE визуально. И ведь мой текущий
KEKS/Schema не мешает никоим образом это провалидировать.
some {
{field . {map} len=1}
{field foo {...} optional}
{field bar {...} optional}
{field baz {...} optional}
}
Вот и choice из foo, bar, baz. Только один может быть выбран. Для
удобства я всё же добавил "choice" тип данных для корневого поля:
some {
{field . {choice}}
{field foo {...}}
{field bar {...}}
{field baz {...}}
}
исключительно синтаксический сахар, не влияющий на генерируемые команды
валидации.
Недавно я чуть-чуть менял схему для KEKS/RPC, где использовал MAP-ы
вместо LIST-ов, ибо нефиг экономить. Было поле "t", в котором указан тип
пакета (call, notify, reply), на основе которого предполагался вызов
нужной схемы валидации. Теперь же:
pkt {
{field . {choice}}
{field call {with call}}
{field notify {with notify}}
{field reply {with reply}}
}
call {
{field . {map}}
{field id {bin} >0}
{field fun {str} >0}
{field args {map}}
}
notify {
{field . {map}}
{field id {bin} >0 optional}
{field fun {str} >0}
{field args {map}}
}
reply {
{field . {map}}
{field id {bin} >0}
{field err {str} >0 optional}
{field body {map}}
}
и просто по наличию, гарантированно только одного, поля call, notify или
reply мы понимаем тип пакета. Код программы стал проще.
Вместо {"a": "algo", "v": bin(...)}, можно использовать MAP с одним
полем, являющимся идентификатором алгоритма. И код проще и кодирование
чуть более компактно.
prv-algos {
{field . {choice}}
{field ed25519-blake2b {bin} len=32}
{field gost3410-256A {bin} len=32}
{field gost3410-512C {bin} len=64}
{field mceliece6960119-x25519 {bin} len=13980}
{field sntrup761-x25519 {bin} len=1795}
{field slh-dsa-shake-256s {bin} len=128}
}
Вообще про это не думая и не вспоминая, но полностью ушли все "t", "a",
"v" короткие названия полей в схемах. Это с самого начала было спорным
решением. С одной стороны я наезжаю на уродский CBOR, в котором люди
совершенно бесчеловечные структуры делают, которые декодировать можно,
но не понять физический смысл, но и сам при этом делаю исключение и
применяю короткие названия type, algo, value, так как они очень часто
используются.
В общем, всё ещё красивее, попроще и удобнее становится. Эх, все
структуры правда немного меняются и надо будет уже имеющиеся
зашифрованные/подписанные файлы и ключи менять. Не охота мне обратную
совместимость сейчас поддерживать. Благо, подправить вроде бы всё можно
просто сделав kekspp -tcl <data.keks >data.tcl, руками подправить в
редакторе несколько полей, а дальше keks.tcl <data.tcl >data.keks. Или
скрипт какой-нибудь написать. В общем, возня.
Плюс решил избавиться от HEXLET типа данных. С самого начала он был
исключительно для красоты и удобства отображения пользователю. Вот
различать бинарные и printable (UTF-8) данные -- необходимость. А UUID
тоже был под вопросом. Кода занимает не много, но всё же склоняюсь к
тому, что он точно излишен.
[оставить комментарий]