Понедельничный Rust Tip.
Простой совет для невыспавшихся за выходные.
Старайтесь не добавлять трейт баунды в объявление типа.
Любой
В результате некоторые методы, которые никак не зависят это реализации этого трейта, будут на него завязаны.
Конечно иногда придется. Например если вы используете ассоциированный тип в объявлении полей.
Простой совет для невыспавшихся за выходные.
Старайтесь не добавлять трейт баунды в объявление типа.
Любой
T: Trait
потребуют добавить этот баунд во все имплы и функции, кроме случаев, где вместо T
будет конкретный тип.В результате некоторые методы, которые никак не зависят это реализации этого трейта, будут на него завязаны.
Конечно иногда придется. Например если вы используете ассоциированный тип в объявлении полей.
Запоздалый Rust Tip.
Используйте impl AsRef<T>, impl AsMut<T> и impl Into<T> в аргументах, когда ожидается, что вызываться функция будет удобнее с автоматической конверсией без потери выразительности API.
Но только если
Классический пример это AsRef<Path> аргументы в std всюду, где нужен &Path, потому что удобно вызывать со строковым литералом. При этом на вызывающей стороны не возникает вопросов, куда там оно сконвертируется.
Еще хороший пример - impl Into<EnumType>, где для вариантов есть отдельный тип, который конвертируется в этот вариант. Концептуально они должны быть одним и тем же.
Использовать ли impl Trait или объявить generic, дело вкуса по большей части. Единственная разница в невозможности явно указать тип. Если вы ожидаете, что пользователю функции когда-то понадобится явно указать тип - объявляйте, иначе можно и с анонимным.
Используйте impl AsRef<T>, impl AsMut<T> и impl Into<T> в аргументах, когда ожидается, что вызываться функция будет удобнее с автоматической конверсией без потери выразительности API.
Но только если
T
это не дженерик. Иначе придется его явно указывать.Классический пример это AsRef<Path> аргументы в std всюду, где нужен &Path, потому что удобно вызывать со строковым литералом. При этом на вызывающей стороны не возникает вопросов, куда там оно сконвертируется.
Еще хороший пример - impl Into<EnumType>, где для вариантов есть отдельный тип, который конвертируется в этот вариант. Концептуально они должны быть одним и тем же.
Использовать ли impl Trait или объявить generic, дело вкуса по большей части. Единственная разница в невозможности явно указать тип. Если вы ожидаете, что пользователю функции когда-то понадобится явно указать тип - объявляйте, иначе можно и с анонимным.
Вот еще один Rust Tip
Делайте derive макросы для своих трейтов.
Если из структуры типа примерно понятно, как реализовать трейт - этот трейт отличный кандидат для
Это значительно уменьшит количество бойлерплейта и уменьшит вероятность глупых ошибок, что мы можем допустить при ручной реализации трейта.
Процедурные макросы могут показаться довольно сложными сначала. Надо парсить и генерировать код.
На самом деле все просто, так как у нас есть крейты
С помощью
А
Не забудьте при генерации Rust кода устанавливать корректные
Так же существует множество надстроек, что делают процедурные макросы вовсе тривиальными. Хотя каждая обладает своими ограничениями.
Делайте derive макросы для своих трейтов.
Если из структуры типа примерно понятно, как реализовать трейт - этот трейт отличный кандидат для
derive
.Это значительно уменьшит количество бойлерплейта и уменьшит вероятность глупых ошибок, что мы можем допустить при ручной реализации трейта.
Процедурные макросы могут показаться довольно сложными сначала. Надо парсить и генерировать код.
На самом деле все просто, так как у нас есть крейты
syn
и quote
.С помощью
syn
можно без труда распарсить код на Rust, который передается в процедурный макрос. А с помощью иных крейтов можно и содержимое аттрибутов распарсить как по волшебству.А
quote
поможет сгенерировать код реализации трейта из шаблона с подстановками.Не забудьте при генерации Rust кода устанавливать корректные
Span
-ы. Это поможет пользователю макроса найти причину ошибки.Так же существует множество надстроек, что делают процедурные макросы вовсе тривиальными. Хотя каждая обладает своими ограничениями.
Пятнично.
Я заметил, что у меня есть почти все ачивки в ER.
И не хватало только пары легендарок и 2х концовок.
И у меня был перс, прошедший базу в Jorney 2, кроме ластов.
Что, ж. Собрал леги (пришлось пройти весь квест Ранни, но на это ушел всего час), завалил ластов.
Бегом в Jorney 3. Взял 2 великие руны (Годрик и Райкард), проскочил Линдел, Напрямик к Огненному Гиганту, заваливая только боссов, что встречались по дороге.
Фарум Азула как нож сквозь масло (Jorney 3 кажется проще чем Jorney 2).
Маликет взят с первого пула, несмотря на небольшой факап с бафанием.
На Всезнайке попотел.
Годфри дал жару еще хлеще, оставил его на утро. Утром с первого пула.
Радагон и Зверь с нескольких пулов.
Я точно мучался на Jorney 2 намного больше.
А ведь за весь Jorney 3 я вкачал че-то типа 240-245. Потому что руны с нескольких боссов профукал на вайпах на следующих.
В целом что хочу сказать.
Elden Ring это одна из лучших игр, в какие я играл. Максимально советую всем любителям помахать мечем.
И не бойтесь сложности, она проще чем Dark Souls.
Я заметил, что у меня есть почти все ачивки в ER.
И не хватало только пары легендарок и 2х концовок.
И у меня был перс, прошедший базу в Jorney 2, кроме ластов.
Что, ж. Собрал леги (пришлось пройти весь квест Ранни, но на это ушел всего час), завалил ластов.
Бегом в Jorney 3. Взял 2 великие руны (Годрик и Райкард), проскочил Линдел, Напрямик к Огненному Гиганту, заваливая только боссов, что встречались по дороге.
Фарум Азула как нож сквозь масло (Jorney 3 кажется проще чем Jorney 2).
Маликет взят с первого пула, несмотря на небольшой факап с бафанием.
На Всезнайке попотел.
Годфри дал жару еще хлеще, оставил его на утро. Утром с первого пула.
Радагон и Зверь с нескольких пулов.
Я точно мучался на Jorney 2 намного больше.
А ведь за весь Jorney 3 я вкачал че-то типа 240-245. Потому что руны с нескольких боссов профукал на вайпах на следующих.
В целом что хочу сказать.
Elden Ring это одна из лучших игр, в какие я играл. Максимально советую всем любителям помахать мечем.
И не бойтесь сложности, она проще чем Dark Souls.
Rust Tip по оптимизации дебажного билда.
В Cargo.toml можно указать, что в
Такая запись заставит сборщик оптимизировать зависимость
А вот так можно оптимизировать все зависимости разом.
А так будут оптимизировать билдскрипты и процедурные макросы.
Оптимизируя зависимости вы ускорите процесс дебега, если только вам не надо заходить внутрь функций зависимости. При необходимости уберите оптимизацию для нее.
Приятного вам дебага.
В Cargo.toml можно указать, что в
dev
профиле нужно оптимизировать определенные зависимости.Такая запись заставит сборщик оптимизировать зависимость
foo
.
[profile.dev.package.foo]
opt-level = 3
А вот так можно оптимизировать все зависимости разом.
[profile.dev.package."*"]
opt-level = 2
А так будут оптимизировать билдскрипты и процедурные макросы.
[profile.dev.build-override]
opt-level = 3
Оптимизируя зависимости вы ускорите процесс дебега, если только вам не надо заходить внутрь функций зависимости. При необходимости уберите оптимизацию для нее.
Приятного вам дебага.
Занимался сегодня рефакторингом небольшого крейта
Сделал чистку всех предупреждений с
В крейте функционал для работы со временем в играх.
И минимум сложностей.
Во первых
Предполагается использовать
Удобно для контроля времени в симуляции. Паузы, буллет таймы, перемотки. Просто вся симуляция должна использовать
Ознакомиться с кодом можно здесь.
https://github.com/zakarumych/gametime
gametime
.Сделал чистку всех предупреждений с
clippy::pedantic
и задокументировал всё, хоть и минимально.В крейте функционал для работы со временем в играх.
И минимум сложностей.
Во первых
TimeStamp
- точка во времени с наносекундной точностью. Относительно чего-то. Обычно относительно того, откуда они берутся.TimeSpan
- промежуток между меньшим и большим TimeStamp
ами. Почти как Duration
, но лишь u64 наносекунд.Clock
- часы. Связывают монотонный таймер core::time::Instant
и TimeStamp
ы. Генерирует ClockStep
, на каждый вызов Clock::step
, где есть текущий TimeStamp
и TimeSpan
между текущим и предыдущим.Предполагается использовать
Clock
в главном цикле, делать Clock::step
в начале каждой итерации и раздавать ClockStep
везде, где нужно знать время.GlobalClock
- как Clock
, но используют единую для процесса точку отсчета. Требуется std
и global_reference
фичаClockRate
- часы со скоростью. Использует внешний источник TimeSpan
, генерирует ClockStep
с указанной относительной скоростью. Без накапливаемой потери точности.Удобно для контроля времени в симуляции. Паузы, буллет таймы, перемотки. Просто вся симуляция должна использовать
ClockStep
из ClockRate
, а не общего Clock
.FrequencyTicker
- генератор тиков с заданной частотой. Использует внешний TimeSpan
и возвращает итератор по ClockStep
тиков, произошедших в течение этого времени. Без накапливаемой потери точности.Ознакомиться с кодом можно здесь.
https://github.com/zakarumych/gametime
GitHub
GitHub - zakarumych/gametime: Time calculations oriented for games
Time calculations oriented for games. Contribute to zakarumych/gametime development by creating an account on GitHub.
Если кто-то из подписчиков пользуется egui-snarl, то я сделал PR (вместо того что бы лить в main)
https://github.com/zakarumych/egui-snarl/pull/73
https://github.com/zakarumych/egui-snarl/pull/73
GitHub
Add pin heights setting into NodeLayout by zakarumych · Pull Request #73 · zakarumych/egui-snarl
This change fixes problem with misaligned pins and gives better control to the user.
Allows to make pin rows equally sized
And to specify minimal size of a row
Allows to make pin rows equally sized
And to specify minimal size of a row
Кстати говоря,
бесцветные зеленые идеи спят яростно.
А я тем временем пробую chumsky для написания парсера моего игрушечного языка.
бесцветные зеленые идеи спят яростно.
А я тем временем пробую chumsky для написания парсера моего игрушечного языка.
Попробовал Codex от OpenAI.
Плюсы:
Он нашел в одном месте баг, где я вместо min написал max. И добавил юнит тест на этот код.
Минусы:
Попросил его написать за меня парсер.
Он написал игрушечный нерабочий парсер, где Expr это просто SmolStr, а Operators ограничивается вариантом Add, и вообще все не то, как я описал синтаксис.
Попросил переделать - ответил, что ему слишком сложно.
Вывод:
Можно время от времени просить найти баги в репе. Найдет - хорошо. Не найдет - ну и ладно.
В обучающем датасете слишком много кода из туториалов.
Плюсы:
Он нашел в одном месте баг, где я вместо min написал max. И добавил юнит тест на этот код.
Минусы:
Попросил его написать за меня парсер.
Он написал игрушечный нерабочий парсер, где Expr это просто SmolStr, а Operators ограничивается вариантом Add, и вообще все не то, как я описал синтаксис.
Попросил переделать - ответил, что ему слишком сложно.
Вывод:
Можно время от времени просить найти баги в репе. Найдет - хорошо. Не найдет - ну и ладно.
В обучающем датасете слишком много кода из туториалов.
Как почувствовать себя хакером. Пошаговая инструкция:
1. Зайдите в кафе или заправку, где посетитель сам использует кофе-машину.
2. Получите сообщение об ошибке.
3. Нажмите на незаметную кнопочку на сенсорном экране, что бы открыть админское меню.
4. Угадайте пин с первого раза. Например 1111.
5. Перезагрузите кофе-машину.
6. Сделайте себе кофе.
7. Наслаждайся своим кофе, хакерман. (Или хакервуман. Но есть ли такие у меня в подписчиках, даже не знаю.)
1. Зайдите в кафе или заправку, где посетитель сам использует кофе-машину.
2. Получите сообщение об ошибке.
3. Нажмите на незаметную кнопочку на сенсорном экране, что бы открыть админское меню.
4. Угадайте пин с первого раза. Например 1111.
5. Перезагрузите кофе-машину.
6. Сделайте себе кофе.
7. Наслаждайся своим кофе, хакерман. (Или хакервуман. Но есть ли такие у меня в подписчиках, даже не знаю.)
Не могу понять прикола.
Работаю потихоньку над арканой, но как только надо делать импорт ассетов начинаю забивать.
Потом снова берусь делать что-то другое. И опять, сел делать ассеты, потупил 10 минут и переключился на поиграть.
Работаю потихоньку над арканой, но как только надо делать импорт ассетов начинаю забивать.
Потом снова берусь делать что-то другое. И опять, сел делать ассеты, потупил 10 минут и переключился на поиграть.