Forwarded from мне не нравится реальность
Ещё пара моментов, которые я упустил в предыдущем посте:
— Вопрос после вызовов макросов с
— Unicode 14.0
— Много функций пометили
—
Rust: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1570-2021-12-02
Cargo: https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-157-2021-12-02
Clippy: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md#rust-157
— Вопрос после вызовов макросов с
{} теперь валиден (можно писать m!{...}?)— Unicode 14.0
— Много функций пометили
#[must_use]
— Vec::leak теперь не реалоцирует (кто-нибудь знал что он так делал??)—
Ordering теперь #[repr(i8)]
Ну и ссылки на полные чейнджлоги (ставьте лайк если тоже забыли про их существование):Rust: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1570-2021-12-02
Cargo: https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-157-2021-12-02
Clippy: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md#rust-157
Forwarded from Life of Tau
GitHub
feat: Import cargo-add into cargo by epage · Pull Request #10472 · rust-lang/cargo
Motivation
The reasons I'm aware of are:
Large interest, see Add cargo-add (from cargo-edit) to cargo proper #5586
Make it easier to add a dependency when you don't care about the ...
The reasons I'm aware of are:
Large interest, see Add cargo-add (from cargo-edit) to cargo proper #5586
Make it easier to add a dependency when you don't care about the ...
👍2
#prog #rust #rustreleasenotes
Вышла версия Rust 1.73.0! Как обычно, тут только выдержки, а полный ченджлог — для компилятора, для cargo и для clippy.
В целом довольно минорный релиз, сильных причин обновлять нету.
▪️Текущее поведение компилятора — считать
▪️В макросах теперь можно вставлять метапеременные типа block после ключевых слов
▪️Как и обещано, линт
▪️Задокументирована текущая (v0) используемая rustc версия манглинга имён.
▪️Строку теперь можно индексировать парами
Код:
▪️Для
▪️Для примитивных беззнаковых числовых типов доступны методы div_ceil (деление с округлением вверх, наконец-то!), next_multiple_of и checked_next_multiple_of. Все из них работают в cosnt-контексте.
▪️Ещё в const-контексте теперь можно создавать слабые ссылки (и Arc-сорта тоже) и переводить NonNull в ссылку.
Вышла версия Rust 1.73.0! Как обычно, тут только выдержки, а полный ченджлог — для компилятора, для cargo и для clippy.
В целом довольно минорный релиз, сильных причин обновлять нету.
▪️Текущее поведение компилятора — считать
impl-ы трейтов неперекрывающимися, если попытка их унифицировать приводит к циклу в логике. Теперь на это поведение выдаётся предупреждение, поскольку, возможно, это могут поменять в будущем.▪️В макросах теперь можно вставлять метапеременные типа block после ключевых слов
try и async. Пример кода, который не работал раньше, но работает теперь (результат раскрытия второго макроса, конечно, всё ещё требует активации фичи):▪️Как я уже писал, компилятор теперь ловит безусловную рекурсию в дропах.
macro_rules! create_async {
($body:block) => {
async $body
};
}
macro_rules! create_try {
($body:block) => {
try $body
};
}
▪️Как и обещано, линт
cast_ref_to_mut (на касты из &T в &mut T — в том числе и не напрямую) теперь deny по умолчанию.▪️Задокументирована текущая (v0) используемая rustc версия манглинга имён.
▪️Строку теперь можно индексировать парами
core::ops::Bound
▪️Немного поменяли формат сообщений паник по умолчанию для assert! и assert_eq!/assert_ne!. Примеры:Код:
До:
fn main() {
let file = "ferris.txt";
panic!("oh no! {file:?} not found!");
}
После:
thread 'main' panicked at 'oh no! "ferris.txt" not found!', src/main.rs:3:5
Код:
thread 'main' panicked at src/main.rs:3:5:
oh no! "ferris.txt" not found!
До:
fn main() {
assert_eq!("🦀", "🐟", "ferris is not a fish");
}
После:
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `"🦀"`,
right: `"🐟"`: ferris is not a fish', src/main.rs:2:5
По моему, стало более читаемо.
thread 'main' panicked at src/main.rs:2:5:
assertion `left == right` failed: ferris is not a fish
left: "🦀"
right: "🐟"
▪️Для
LocalKey<Cell<T>> и LocalKey<RefCell<T>> (LocalKey — тип, в который заворачиваются значения в макросе thread_local!) добавили несколько методов для прямой манипуляции с значениями, без использования общего with. Мало того, что это позволяет сделать код нагляднее, так ещё и позволяет в некоторых случаях избежать инициализации thread local переменной значением, которое будет тут же перезаписано. При этом в общности API не теряет, поскольку на практике почти всегда из-за требований внутренней изменяемости значение и так было завёрнуто в Cell или RefCell.▪️Для примитивных беззнаковых числовых типов доступны методы div_ceil (деление с округлением вверх, наконец-то!), next_multiple_of и checked_next_multiple_of. Все из них работают в cosnt-контексте.
▪️Ещё в const-контексте теперь можно создавать слабые ссылки (и Arc-сорта тоже) и переводить NonNull в ссылку.
GitHub
rust/RELEASES.md at master · rust-lang/rust
Empowering everyone to build reliable and efficient software. - rust-lang/rust
👍9❤1
#prog #rust
Модель компиляции Rust отличается от сишной. Модули могут иметь циклические зависимости, но единицей компиляции являются крейты. Крейты сами по себе не имеют имён и идентифицируются только при указывании зависимостей других крейтов. Вкупе с отсутствием глобального пространства имён это даёт возможность иметь в дереве зависимостей один и тот же крейт нескольких версий.
С одной стороны, это хорошо, потому что позволяет удовлетворять требования к версиям зависимостей без того, чтобы выбирать только одну версию каждой библиотеки. С другой стороны, это плохо, потому что код библиотек обычно не очень сильно меняется от версии к версии (по крайней мере, при смене минорной версии), и потому при компиляции итогового проекта компилятор в итоге компилирует примерно один и тот же код с небольшими отличиями, увеличивая время компиляции.
При разработке большого проекта избежать дублирования зависимостей сложно. Это не является неизбежностью, поскольку cargo старается по возможности выбирать одну версию библиотеки, которая удовлетворяет всем ограничениям на версию, но всё же это порой случается — особенно, если в зависимостях где-то ограничение на версию сверху. Иногда на это могут быть обоснованные причины — например, когда используются две разные мажорные версии библиотеки, у которых из общего в основном только название — но чаще это просто увеличивает технический долг.
Убирать дубликаты зависимостей не всегда так же просто, как просто вызвать
Один из способов контролировать технический долг — это зафиксировать его состояние и убедиться, что он не растёт. Конкретно в данном случае это решение довольно простое: вынести список дубликатов зависимостей в отдельный файл, который включается в репозиторий, и вставить в CI проверку, которая будет сравнивать этот список с реальным списком дубликатов.
Именно это я недавно сделал у себя на работе. Весь нужный для этого код уместился в чуть менее, чем в 200 строчек кода на Rust — и это включая пустые строки и комментарии. Если бы я меньше заботился о диагностике и некоторых допфичах (об этом ниже), то вышло бы ещё меньше. В связи с этим я хочу поделиться некоторыми практическими советами на тот случай, если вы захотите сделать нечто подобное у себя.
Самый насущный из практических вопросов: куда положить нужный код? Возможно, наиболее идеологически правильным было бы отнести это в отдельную стадию внешнего линтинга, но это значит, что нужный код нужно или иметь в качестве уже собранного бинарника и каким-то образом подтягивать его, или собирать во время сборки. Оба подхода усложняют CI, особенно первый. Всех этих хлопот можно избежать, если включиться в шаг, который уже подразумевает компиляцию кода и его запуск. Именно, нужный код можно поместить в тесты, и он будет автоматически запускаться во время
Второй по важности момент — как именно получать список дублирующихся зависимостей. Для этого можно использовать cargo, и если вы разрабатываете проект на Rust, почти наверняка вы уже его используете, поэтому это не приносит новых зависимостей для сборки. Нам понадобится cargo tree (команда доступна с версии cargo 1.44) с ключом
Модель компиляции Rust отличается от сишной. Модули могут иметь циклические зависимости, но единицей компиляции являются крейты. Крейты сами по себе не имеют имён и идентифицируются только при указывании зависимостей других крейтов. Вкупе с отсутствием глобального пространства имён это даёт возможность иметь в дереве зависимостей один и тот же крейт нескольких версий.
С одной стороны, это хорошо, потому что позволяет удовлетворять требования к версиям зависимостей без того, чтобы выбирать только одну версию каждой библиотеки. С другой стороны, это плохо, потому что код библиотек обычно не очень сильно меняется от версии к версии (по крайней мере, при смене минорной версии), и потому при компиляции итогового проекта компилятор в итоге компилирует примерно один и тот же код с небольшими отличиями, увеличивая время компиляции.
При разработке большого проекта избежать дублирования зависимостей сложно. Это не является неизбежностью, поскольку cargo старается по возможности выбирать одну версию библиотеки, которая удовлетворяет всем ограничениям на версию, но всё же это порой случается — особенно, если в зависимостях где-то ограничение на версию сверху. Иногда на это могут быть обоснованные причины — например, когда используются две разные мажорные версии библиотеки, у которых из общего в основном только название — но чаще это просто увеличивает технический долг.
Убирать дубликаты зависимостей не всегда так же просто, как просто вызвать
cargo update (говорю по своему опыту), но и оставлять их в долгосрочной перспективе не стоит. Не всегда можно сразу одним разом убрать дубликаты, но даже если и можно, то это часто может стать блокером для внесения других изменений в кодовую базу. С другой стороны, если за этим не следить, новые изменения могут добавить новые дубликаты зависимостей, только увеличивая время компиляции и технический долг.Один из способов контролировать технический долг — это зафиксировать его состояние и убедиться, что он не растёт. Конкретно в данном случае это решение довольно простое: вынести список дубликатов зависимостей в отдельный файл, который включается в репозиторий, и вставить в CI проверку, которая будет сравнивать этот список с реальным списком дубликатов.
Именно это я недавно сделал у себя на работе. Весь нужный для этого код уместился в чуть менее, чем в 200 строчек кода на Rust — и это включая пустые строки и комментарии. Если бы я меньше заботился о диагностике и некоторых допфичах (об этом ниже), то вышло бы ещё меньше. В связи с этим я хочу поделиться некоторыми практическими советами на тот случай, если вы захотите сделать нечто подобное у себя.
Самый насущный из практических вопросов: куда положить нужный код? Возможно, наиболее идеологически правильным было бы отнести это в отдельную стадию внешнего линтинга, но это значит, что нужный код нужно или иметь в качестве уже собранного бинарника и каким-то образом подтягивать его, или собирать во время сборки. Оба подхода усложняют CI, особенно первый. Всех этих хлопот можно избежать, если включиться в шаг, который уже подразумевает компиляцию кода и его запуск. Именно, нужный код можно поместить в тесты, и он будет автоматически запускаться во время
cargo test. В этом случае код для проверки будет запускаться автоматически для каждого нового изменения (вы же запускаете тесты в CI, верно?) и завалит тесты в случае изменения списка дубликатов, достигая нужной нам цели.Второй по важности момент — как именно получать список дублирующихся зависимостей. Для этого можно использовать cargo, и если вы разрабатываете проект на Rust, почти наверняка вы уже его используете, поэтому это не приносит новых зависимостей для сборки. Нам понадобится cargo tree (команда доступна с версии cargo 1.44) с ключом
-d (--duplicates). Задача кажется простой, но тут есть пара тонкостей, о которых стоит упомянуть. ⬇️👍4🔥2❤1
По умолчанию
А препроцессировать его придётся. Ввиду того, что вывод
Кстати, насчёт зависимостей: у
Ещё один из дефолтов
Теперь немного о самом процессе проверки. Вывод
Именно это значение нам и надо сохранить. Можно также считать разными зависимости несовместимых версий, но это несколько менее удобно в обработке (код не проверял):
Надо отметить, что в этом случае в списке будут не только сами зависимости, но и их версии, что может создать неудобства при их обновлении.
Насчёт обработки списков: сигнализировать об ошибке стоит не только в том случае, если есть дубликат вне зафиксированного списка, но и в том случае, если зависимость вне фиксированного списка отсутствует в выдаче
cargo tree -d показывает не только дубликаты зависимостей, но и зависимые от них крейты. Это удобно для человека, но не особо пригодно для наших целей, когда мы хотим получить только дубликаты и ничего более. Для того, чтобы оставить только нужные нам результаты, можно воспользоваться флагом --depth=0 (доступен с версии cargo 1.54). В этом случае обработка вывода cargo tree будет сведена к минимуму.А препроцессировать его придётся. Ввиду того, что вывод
cargo tree для пользователя, а не для обработки машиной (и потому чисто технически это всё может сломаться с обновлением версии cargo), в нём есть пустые строки (которые отделяют деревья зависимостей друг от друга) и строки, предваряющие разных секции зависимостей, а именно, [build-dependencies] и [dev-dependencies]. Эти строки при обработке вывода нужно убирать.Кстати, насчёт зависимостей: у
cargo tree есть флаг -e/--edges, который указывает, какие именно зависимости показывать. По умолчанию это прямые зависимости, build-зависимости (которые нужны для сборки, но не нужны непосредственно для компиляции исполняемого кода — скажем, генератор кода поверх .proto-файлов) и dev-зависимости (не нужные для сборки, но полезные для разработки — обычно это зависимости для тестов и бенчмарков). Лично меня куда меньше волнует дублирование, вызванное dev-зависимостями, во многом из-за того, что они не компилируются при каждом cargo build/cargo check. Если вы разделяете моё мнение на этот счёт, используйте флаг -e=normal,build.Ещё один из дефолтов
cargo tree — консистентный с остальными командами — по умолчанию код генерируется только для текущей целевой платформы и с фичами проекта по умолчанию. Из-за этого можно упустить дубликаты, которые появляются при компиляции под другие платформы и с другими фичами. Конкретно в моём случае это не является проблемой, поскольку в силу специфики используемых технологий компонент, над которым я работаю, поддерживает только один target triple, а все наши features нужны исключительно для отладки, но, скорее всего, имеет смысл использовать флаги --all-targets и --all-features. Только имейте в виду, что по очевидным причинам это может сильно замедлить скорость проверки.Теперь немного о самом процессе проверки. Вывод
cargo tree выводит имя зависимости вместе с версией. Нам нужно только имя зависимости для исключения дубликатов. К счастью, так как имя пакета не может включать в себя пробел, выделение имени — это простоlet name = line.split_once(' ').unwrap().0;Именно это значение нам и надо сохранить. Можно также считать разными зависимости несовместимых версий, но это несколько менее удобно в обработке (код не проверял):
let (name, version) = line.split_once(' ').unwrap();
let version = {
let (major, rest) = version.split_once('.').unwrap();
if major == "v0" {
let minor = rest.split_once('.').unwrap().0;
format!("v0.{minor}")
} else {
major.to_owned()
}
};
// (name, version) используется в качестве ключаНадо отметить, что в этом случае в списке будут не только сами зависимости, но и их версии, что может создать неудобства при их обновлении.
Насчёт обработки списков: сигнализировать об ошибке стоит не только в том случае, если есть дубликат вне зафиксированного списка, но и в том случае, если зависимость вне фиксированного списка отсутствует в выдаче
cargo tree. Это позволяет поддерживать список в актуальном, не врущем состоянии. ⬇️🔥5❤2