Random Rust Dev
438 subscribers
144 photos
49 videos
1 file
37 links
Разработка на языке Rust.
Пишу простыни со своими мыслями о Rust и проектах на нем.
Download Telegram
Random Rust Dev
Photo
В инвестициях прибыль совершенно не важна. Важно разогнать hype train. Цена компаний зависит от ожиданий, которые зависят от обещаний и демок.
💯5
Только не бегите покупать их акции. Это надо было делать 3 года назад.

Хотя всё равно нельзя :(
👍3
Неожиданно хороший юмор на реддите.

Моя жена долго искала гигантов на картинке.
😁97👍3
Багофичи будущего, которые мы заслуживаем.
😁14🥰3
Я когда-то давно соптимизировал вот такое выражение (a * 3 + b * 5 + c * 7 + d * 11) & 63
До трех инструкций
mul
shr
and

На днях пришел чел и убрал and.
А github copilot взял, да и нашел мелкую ошибку в коде чела.
Додумать до таких оптимизаций ни один ИИ сам не умеет.
Но искать глупые ошибки даже в низкоуровневом коде - очевидно да.

Читателям предлагается самим придумать эти оптимизации.

Ленивым читателям:
Смотреть сюда https://github.com/zakarumych/rapid-qoi/pull/12
🔥5👍1
Не понял, пока не произнес правильно.
🌭7🔥4😁1
Масса в уравнении импульса: Ну да, ну да, пошла я на....й
😁7
Понял сегодня, что один поляк предсказал генеративные LLM целых 62 года назад.

Да, это Станислав Лем
🔥8💯1
Кто-нибудь уже опробовал
"No Rest for the Wicked"?
Побегал пока бесплатная была, выглядит интересно, дизайн стильный.
Ко-оп добавили. Есть желающие пройти в коопе?
Сам концепт "выглядеть как-то", это что-то из макро области.
Когда речь идет о единицах квантовых объектов, то фотоны поглащаются/излучаются случайным образом и строить какую-то картинку из этого не представляется возможным.

Лишь на больших масштабах выявляется сигнал из шума случайностей и появляется "выглядеть".
4
Я два дня сражался с тем фактом, что в Rust нельзя просто взять и написать

trait Foo {
const fn bar(arg: Arg) -> Ret;
}

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

Если бы без Arg - я бы просто сделал const BAR: Ret.
Если что const BAR<const ARG: Arg>; Тоже нельзя, но хотя бы в найтли можно.

Пробовал сделать функцию не const, но писать её, как если бы она была const. Надеялся, что соптимизируется.
До некоторой глубины действительно оптимизировалось.

В итоге пришел вот к такой форме "конст-функции-на-стейбле"

trait Foo {
type Bar<const ARG: Arg>: RetType;
}

trait RetType {
const VALUE: Ret;
}


impl Foo for FooImpl {
type Bar<const ARG: Arg> = FooBar<ARG>;
}

struct FooBar<const ARG: Arg>;
impl RetType for FooBar<const ARG: Arg> {
const VALUE: Ret = {
// faked const fn body.
};
}


Это ужасно выглядит? Да.
Это гарантирует, что в результате компиляции на месте FooImpl::Bar::<ARG>::VALUE будет константа, а не вызов функции? Тоже да.
6👍4🔥1
Я снова решил поупражняться в сериализаторском деле.

Я как-то давно писал библиотеку alkahest для сериализации со схемой.
Идея её проста - разделение ответственности. Тогда как в serde (самой популярной библиотеке для сериализации) сериализуемый и десериализуемый тип диктует схему, то начинаются проблемки, когда это два разных типа - нет никакой гарантии, что схема их совпадёт.

Так же, если у вас есть данные для сериализации, но не в виде сериализуемого типа, вам обязательно нужно будет собрать их в сериализуемый тип.
Если там HashMap, а у вас данные в итераторе - придется делать Iterator::collect только лишь за тем что бы функция сериализатора вызвала HashMap::iter.
Абсурд? Абсурд. Но ёжики продолжают жрать кактус.

Что даёт явная схема?
1. Много разных типов могут сериализовываться в одну явно указываемую схему. Результат "гарантировано" будет соответствовать схеме, а значит любой десерилизуемый тип, который поддерживает эту схему, можно получить из этих данных.
Так можно сериализовывать и десериализовывать Vec, VecDeque и итераторы, ведь все они сооветствуют схеме List Слайсы только сериализовывать.

2. Сериализовывать типы, собственная структура которых является подмножеством схемы.

Например массив может писать свой размер при сериализации, если схема - List, а в схему Array<N> не нужно.

Структура может сериализовываться в определенный вариант enum-а, но все равно писать дискриминант.

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

3. Десериализовывать типы, собственная структура которых является надмножеством схемы. Где /dev/null считается надмножество всего.

Повторяя пример с массивом, можно десериализовать схемы Array<N> в Vec, а <Vec as Deserialize<Array<N>>>::deserialize не будет пытаться искать размер в данных.

Можно пропустить поля в структуре и не десериализовывать их вовсе. Если у схемы поля фиксированный размер, то даже его читать не придется.
Или можно отложить десериализацию куска данных на потом, если всё же понадобится.

Кроме всего и ядро и сгенерированный код на Rust полностью unsafe-free, а по скорости соперничает unsafe-heavy библиотеками, такими как rkyv. Новая цель - догнать bitcode

Всё это и многое другое уже есть в последней версии alkahest. Зачем же я опять за него взялся?

Во-первых чтобы поддержать другие языки. У вас бэк с Rust и Python, а на фронте JS? Игра на Unreal (C++), а сервер на Rust? Alkahest поможет им общаться.
Кто пользовался protobuf, Flexbuffers и Flatbuffers? Alkahest по процессу сериализации ближе всех к Flatbuffers, но круче конечно, ведь есть дженерики :)

До сих пор схема писалась либо руками (на Rust), либо генерировалась процедурным макросом из объявления структуры или энама.
Сейчас я соорудил небольшой DSL, на котором можно описывать схемы.

Но я бы ни за что не просил программистов на Rust запускать генератор кода через build-script, поэтому генерация раста происходит в проценурном макросе вот так:

#[alkahest("schemas.alk")] // Путь до файла со схемами. Если не указано, то это "<modulename>.alk".
mod schemas {} // я бы предпочел mod schemas; но на стейбле нельзя. Макрос принимает обе формы.


Генерируется целый модуль, в котором будут все схемы из файла.

Старый вариант с derive-макросом для схемы остаётся для быстрого plug'n'play использования.

Для С++ будет генерация кода, которую надо будет добавить в билдскрипты.
Python будет парсить функцией, а схемы возвращаться `dict`ом.
Как правильно делать для JS я еще разберусь :)
🔥51
Во-вторых чтобы реализовать верифицируемую эволюцию схемы.
Схемы очень часто изменяются с выходом новых версий программы. Общающиеся программы обновляются не синхронно и надо как-то им уметь продолжать общение несмотря на то что у кого-то схема новее, у кого-то древнее. Так же сохраненные данные могут быть старой версии.
Для этого схемы должны обладать совместимостью. Совместимость бывает прямой и обратной, давайте рассмотрим оба случая.

Обратная совместимость означает, что данные сериализованные старой версией схемы могут быть десериализованны новой версией.
Прямая совместимость означает, что данные сериализованные с новой версией схемы могут быть десериализованны старой версией.

Как такое возможно? Десериализатор должен узнать какая версия схемы у данных, либо снаружи, либо из данных. А так же должна быть стратегия того, как конвертировать данные, например какое значение новым полям указать.
Это уже сразу несколько вариантов. Alkahest точно будет поддерживать вариант с указанием версии снаружи и указанием версии прямо в данных.
Но скорее всего не будет варианта с указанием в данных версии для субструктур, всё дерево схемы будет с одной версией.

С прямой совместимостью есть еще вариант без указания версии. Если новая версия строго шире старой, то десериализатор со старой схемой просто игнорирует хвост.
Тут помогает сериализация с указателем, потому что размер поля указателя фиксированный, так что схема может обладать прямой совместимостью и не влиять на схему, полем которой она является, если используется указатель.

То есть если было:
formula A = { ... }
formula B = { ... }

formula Foo = {
a: A,
b: B,
};

formula Bar = {
a: &A,
b: &B,
};

То старая формула Foo не будет совместимой с новой версией, если A расширилось, а Bar будет.


Что тут будет делать Alkahest? Проверять совместимость! Автор схемы указывает вид совместимости, а функция верификации убедится, что новая схема обладает указанной совместимостью со старой схемой.
Ультой будет проверка диффа кода на наличие несовместимых изменений схемы. И GitHub Action для запуска этой проверки в PR.
👍1🔥1
Интересным образом оказывается, что не так уж сложно сериализовывать Option<!> в 0 байт.

Без специализации и special-casing-а.
Просто дискриминанты с uninhabited схемами не считаются.
А значит у Option<!> только 1 дискриминант None. Значит надо 0 байт на него, и на его тело тоже 0 байт.
🤣2💯1👀1
Еще одно очевидное свойство ! типа и сериализации.

Его можно сериализовать в любую схему!
В самом деле, если мы сериализуем значение !, то как известно этот код недостижим. А значит не важно, какая там схема.
На практике ! будет у варианта `enum`а, который невозможен. Значит сериализовываться будет всегда какой-то другой вариант или вообще не будет.

А вот десериализовывать ! можно только из схемы !.
Потому что эта схема не имеет представления в данных.
На практике ! будет у варианта схемы enum`а, которому дискриминант не назначен вовсе, а значит какие бы ни были данные, а функция десериализации ! не будет вызвана.
Загадка про Rust

Что происходит с атрибутом #[cold] над const функцией, когда её вызов вычисляется еще до LLVM?

#[cold]
const fn mark_cold() {}

if condition {
mark_cold();
// Это холодный бранч или нет?
}
🤔6
Мой друг сказал, что код на расте сложно читать.

Ну что тут сложного?
😁15🌚4🔥2😈2
Пишу тесты.
В прошлый раз у меня ушла уйма времени на отладку процесса сериализации и десериализации.

В этот раз минорный неточности, но в основном все сразу работает.
Чаще ошибка в тесте, а не в библиотеке.
👍1