Комментарии 78
До "собирается на современных платформах" всё же ещё далеко, пока что этот форк работает только под линукс
ioquake3 должен работать на всех платформах, согласно README вот тут: https://github.com/ioquake/ioq3. Совершенно точно он работает под macOS.
Исходный ioquake — вполне собирается и под windows. Но сравнивая репозитории очевидно, что winows-specific вещи исключены
Время сборки исходников компилятором сильно отличается?
Ну и возможно кому-то на практике пригодится тулза которая конвертит исходники на C, например, какой-нибудь видео encoder, скажем, AV1 ;)
Что Сишный, что ржавый вариант на 60% состоят из ассемблерных вставок под платформенные SSE. Это скорее что-то из разряда "как не переписать все на Rust". Есть какая-то легаси либа в проде, которая вроде и работает, но код ужасно пахнет, тестов толком не было и допилить что-то к ней надо. Скармливаем в C2Rust, допиливаем напильником и запиливаем недостающие фичи и используем как drop-in решение.
Я имел ввиду ситуацию, когда к этому нужно новый функционал. Или есть какие-то странные плавующие SEGFAULT. Или есть завязки на другие либы, которые уже работают, но не имеют порта (типа SDL какой-нибудь для геймдева).
А вообще было бы неплохо если б кто-нибудь взялся перевести пару постов по теме (раз, два). В первой статье конвертация помогла избавиться от древненего незадокументированного косяка, как пример. Где-то тут же на хабре была статья про сферический анализатор текстов в типографии, который надо допиливать и в Си-лэнде оно оставляет много проблем как с IO так и с доступом к памяти, но это уже про полноценный RIIR, не про конвертацию.
А что, конвертация в Rust настолько умная, что поможет с плавающими SEGFAULT в С?
Сорян, ошибся, это со второй статьи. Там тоже RIIR. Рекурсивный вызов в Сишном коде паниковал после некоторого предела, растовая часть заимплементив кусок избавилась от этого косяка.
As an aside, this test was originally written to nest things three layers deep (e.g. top_level.vm includes nested.vm which includes really_nested.vm) to make sure it handles more than one level of %include, but no matter how it was written the test kept segfaulting.
Then I tried running the original C tvmi binary…
$ cd vendor/tinyvm/ $ cat top_level.vm %include nested $ cat nested.vm %include really_nested $ cat really_nested.vm Hello World $ ./bin/tvmi top_level.vm [1] 10607 segmentation fault (core dumped) ./bin/tvmi top_level.vm
Turns out the original tinyvm will crash for some reason when you have multiple layers of includes
https://github.com/xiph/rav1e
Assembly 57.2%
Rust 42.5%
Other 0.3%
sloc на репу не травил, поэтому сколько сотен строк asm там не знаю. в сишной имплиментация похожая история.
Там еще часть раст кода https://github.com/xiph/rav1e/tree/master/src/asm/x86 — unsafe функции из интринзиков.
Или, может, там под assebmly другое подразумевается?
Вообще-то Кармак не любил ассемблер начиная с первого Doom, даже там его самую чуточку.
Ну, так кармак игры писал, а не выжимал из железа каждый бит. Производительность кода — скорее побочный эффект, необходимый для комфортной игры, нежели цель. У кодеков же бенчмаркинг едва ли не такты считает ради оптимальнейшей утилизации ресурсов железа, чтоб обработка чуть ли не в скорость шины данных упиралась, энергоэффективность тут же рядом.
Да, исходники смотрел, но по большей части уделял ржавой части и arm neon. Не слишком детально, конечно.
У сишного dav1d cхожие автометрики. Нюанс в том, что ассемблерный код не слишком компактный и десяток строк высокоуровневого языка вполне может вылиться в пару сотен строк на asm, а метрики gitlab и github почти наверняка ориентируются именно на sloc ничего удивительного, что "10 строк" asm не очень десять, а половина значимых возвратов каретки в репе
$ find ~/prog/ioq3 -name "*.rs" | xargs cat | grep unsafe | wc -l
9241
$ find ~/prog/ioq3 -name "*.rs" | xargs cat | grep fn | wc -l
9740
+1 стандарт? Не, спасибо, нам такого не надо — раста достаточно.
Это связано не с трендом, а с выводом типов в различных контекстах (объявление локальной переменной — это лишь один из них).
Когда создавали C, о выводе типов не задумывались, а когда задумались, то позже, в C++, вынуждены были лепить костыли.
template <typename T1, typename T2>
auto add(T1 lhs, T2 rhs) { return lhs + rhs; }
template <typename T1, typename T2>
decltype(lhs + rhs) add(T1 lhs, T2 rhs);
не прокатит, lhs/rhs was not declared in this scope. А вот такое:
template <typename T1, typename T2>
auto add(T1 lhs, T2 rhs) -> decltype(lhs + rhs);
прокатит без проблем.
template <typename T1, typename T2>
decltype(lhs + rhs) add(T1 lhs, T2 rhs);
если про lhs + rhs ничего не известно на момент парсинга decltype(lhs + rhs) — то это совершенно не проблема. Проблема возникает, если такие переменные объявлены выше по коду.
double lhs;
double rhs;
decltype(lhs + rhs) add(int lhs, int rhs);
Какой тип результата по твоему должен быть у функции ??
Ну да, такое тоже может быть.
сунь код в компилятор
потому что неправильно написано. должно быть
auto add(int lhs, int rhs) -> decltype(lhs + rhs) ;
Пожалуйста, читайте всю ветку целиком, а не только последний комментарий. Вот тут этот вариант уже приводили: https://habr.com/ru/post/483142/#comment_21111542
Потому что изначально template<> и существует для того, что-бы определить все параметры шаблона до сигнатуры. decltype() появился позже. Правда непонятно зачем тут decltype, ведь в С++ есть вывод типа возврата.
Смысл переписать есть, денег нет, зачастую.
Программист на Фортран может писать на Фортране на любом языке программирования.
Нужно по возможности защитить весь Open-Source софт от этой заразы путем форка.
Ну, так у них и боль это баги безопасности из-за нарушения целостности памяти, а не offline хранилища. Поддержку, кастомных источников крейтов, кстати, уже завезли.
А где же фраза "го вместе защищать, я создал"?
А зачем может быть нужен указатель за пределами массива?
указатель в принципе может указывать на ЛЮБОЙ адрес в памяти. NULL — так-то это тоже адрес ЗА пределами массива. Так что если так рассуждать, то от указателей надо переходить к индексам и итераторам, но, внезапно, мы сразу теряем в эффективности работы
Только в сорсах ioq3 индекс с выходом за пределы массива используется для проверки указателя на выход за пределы массива. Rust проверяет это в рантайме. Проще при рефакторинге перейти как минимум на индексы, а не указатели, это раз, а второе — работа с такими абстракциями, как итераторы, в Rust — это zero-cost.
nullptr — это таки другое.
Ну и NULL :
- не обязан быть 0
- 0 не обязательно невалидный указатель
if (p >= &array[1024]) { // error... }
это они так выход за границы массива проверяют.
Потому что иногда (на самом деле часто) имеет смысл рассматривать указатели как указывающие не на элемент массива, а на границу между элементами. А таких границ всегда можно провести на одну больше, чем в массиве элементов...
Перенос Quake 3 на Rust