1.92K subscribers
3.67K photos
138 videos
15 files
3.87K links
Блог со звёздочкой.

Много репостов, немножко программирования.

Небольшое прикольное комьюнити: @decltype_chat_ptr_t
Автор: @insert_reference_here
Download Telegram
👍8❤‍🔥1😁1
#prog #rust #gamedev #amazingopensource (но пока сырое)

Revy is a proof-of-concept time-travel debugger for the Bevy game engine, built using Rerun.

Revy works by snapshotting diffs of the Bevy database every frame that are then logged into the Rerun database.
This allows you to inspect and visualize the state of the engine at any point in time, either in real-time or after the fact.
These recordings can then be shared to be replayed or e.g. attached to bug reports.
👍7🤔31
#prog #rust #rustreleasenotes

Вышла версия Rust 1.93.0! Как обычно, тут только избранное, остальное только в детальных заметках о релизе.

(да, я выкладываю анонс с опозданием больше недели, и что ты мне сделаешь?)

В этот раз большинство изменений связаны со стандартной библиотекой.

▪️Немного печальное изменение: даже с установлением #[global_allocator] std всё ещё может вызывать System аллокатор. По крайней мере, на core это не распространяется.

▪️Компилятор теперь выдаёт предупреждение на #[repr(C)]-перечисления, у которых значения дискриминантов не умещаются в сишный int. Смешно, но до C23 у сишных enum нельзя было указать численный тип и нельзя было использовать значения больше int для дискриминантов.

▪️Компилятор теперь выдаёт предупреждение на попытку вызвать метод на const-значении, который эксплуатирует внутреннюю изменяемость. Так как константы инлайнятся по месту использования, эти изменения не будут видны. Обычно это является следствием ошибки — использования const вместо static (и я, кстати, такую ошибку уже делал).

▪️Метод append на BTreeSet и BTreeMap теперь сохраняет ключ из исходной коллекции, если ключи считаются равными через ==. До этого перезаписывались и ключ, и значение.

▪️Стабилизированы API:

🔸assume_init_drop, assume_init_ref и assume_init_mut на MaybeUninit<T>
🔸write_{copy, clone}_of_slice на [MaybeUninit<T>]
🔸into_raw_parts на String и на Vec. Странно, что только сейчас, потому что обратные from_raw_parts методы были стабилизированы ещё в версии 1.0.
🔸методы для непроверяемых (и потому потенциально дающих UB) битовых сдвигов в обе стороны на примитивных числах, а на знаковых — ещё и unchecked_neg
🔸методы для перевода ссылок на слайсы в (опциональные, разумеется) ссылки на массивы и сырых указателей на слайсы в сырые указатели на массивы, включая мутабельные варианты
🔸pop_front_if и pop_back_if на VecDeque
🔸std::fmt::from_fn для ad-hoc форматирования через переданную функцию. Позволяет избежать создания одноразовых типов, нужных только для форматирования

▪️Cargo теперь прокидывает значение конфигурации debug_assertions в билд-скрипты.

▪️Команда cargo tree теперь позволяет использовать для форматирования записей в дереве длинные имена для элементов шаблонов. Например, следующие два вызова эквивалентны:

cargo tree --format='{p} {f}'

cargo tree --format='{package} {features}'

▪️cargo clean теперь может удалять артефакты компиляции из всего workspace-а целиком.
👍8😁1
Random Rust Dev
Как заставить растовика задуматься над элементарной вещью?

Задайте ему вопрос: Какой тип у `0x12345_f32`?
#prog #rust

Но вообще ответ не вполне корректен. Тип числового литерала уточняется выводом типов, а конкретно i32 выбирается только в том случае, если ограничений на тип недостаточно, чтобы выбрать конкретный числовой тип (и лично я это считаю недостатком Rust)
🤔7👍3
#prog #rust #article

В стандартной библиотеке Rust есть несколько ассоциативных контейнеров: HashMap, HashSet, BTreeMap и BTreeSet. Часто на практике в качестве ключей в них хранятся строки — String. Требовать от пользователя для поиска значение типа String неудобно и чревато проблемами в производительности. Потому у этих структур данных есть API, позволяющие использовать для поиска ключи других, "похожие" на те, что хранятся в контейнере.

Возьмём в качестве примера HashMap::get:

fn get<Q>(&self, k: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,


Как видно из кода, тип для поиска (Q) не обязан совпадать с типом хранимых ключей (K), но на K есть ограничение K: Borrow<Q>. Трейт Borrow выглядит таким образом:

trait Borrow<Borrowed>
where
Borrowed: ?Sized,
{
fn borrow(&self) -> &Borrowed;
}


В процессе поиска значения на хранимых ключах вызывается метод <K as Borrow<Q>>::borrow, и результат возвращаемого значения сравнивается со значением, переданным в get. Именно благодаря этому API (и реализациям в std, разумеется) коллекцию HashMap<String, Thing> можно индексировать значениями типа &str.

Но у этого API есть недостаток. Именно, оно требует, чтобы предоставляемое значение было ссылкой и чтобы из ссылки на ключ можно было получить ссылку на Q. Это ограничивает применимость API. Если, например, в мапе в качестве ключей хранятся (String, String), то логичный невладеющий эквивалент для индексации (&str, &str) не будет работать, потому что это кортеж ссылок, а не ссылка.

В короткой статье Borrowed tuple indexing for HashMap рассказывается, как с некоторым количеством бойлерплейта можно обойти это ограничение.

Для сравнения, hashbrown (поверх которого сделаны мапы в std) от подобных ограничений не страдает, поскольку там в API используется более гибкий трейт Equivalent:

trait Equivalent<K>
where
K: ?Sized,
{
fn equivalent(&self, key: &K) -> bool;
}
👍10🤯3🤡1
#prog #rust #article

Making cargo-semver-checks faster - Google Summer of Code 2025

Overall, I reduced the typical runtime on very large crates down to ~2s from ~8s - nearly an 80% speedup - without compromising performance on smaller crates. Along the way I reduced test time from ~7min to ~1min.
6
#rust

Rust debugging survey 2026

You can fill out the survey here.

Filling the survey should take you approximately 5 minutes, and the survey is fully anonymous. We will accept submissions until Friday, March 13th, 2026.
🤔2
😁285
#prog #rust #rustreleasenotes

Вышла версия Rust 1.94.0! Как всегда, тут только то, что интересно мне, остальное в детальных заметках о релизе.

▪️Атрибуты для линта dead_code (allow/warn/deny/expect) на трейтах и их частях теперь наследуются impl-ами:

#[allow(dead_code)]
trait Foo {
const FOO: u32;
}

impl Foo for u32 {
const FOO: u32 = roundtrip(0);
}

// нет предупреждения о мёртвом коде
const fn roundtrip(x: u32) -> u32 {
x
}


▪️Касты между сырыми указателями на unsized типы с указанием лайфтаймов теперь требуют, чтобы предыдущий тип жил не меньше нового. Или, иными словами, каст из *mut dyn Trait + 'a в *mut dyn Trait + 'b теперь требует 'a: 'b

▪️Стабилизировали array_windows! Украду пример прямо из блогпоста:

For example, part of one 2016 Advent of Code puzzle is looking for ABBA patterns: "two different characters followed by the reverse of that pair, such as xyyx or abba." If we assume only ASCII characters, that could be written by sweeping windows of the byte slice like this:


fn has_abba(s: &str) -> bool {
s.as_bytes()
.array_windows()
.any(|[a1, b1, b2, a2]|
(a1 != b1)
&& (a1 == a2)
&& (b1 == b2)
)
}


Благодаря выводу типов ещё и размер, как правило, не нужно указывать на методе явно.

▪️LazyCell и LazyLock обзавелись методами get, get_mut и force_mut.

▪️Для iter::Peekable добавили методы next_if_map и next_if_map_mut. Пример из документации:

let mut iter = "125 GOTO 10".chars().peekable();
let mut line_num = 0_u32;
while let Some(digit) = iter.next_if_map(|c| c.to_digit(10).ok_or(c)) {
line_num = line_num * 10 + digit;
}
assert_eq!(line_num, 125);
assert_eq!(iter.collect::<String>(), " GOTO 10");


▪️cargo теперь использует для парсинга манифестов наконец-то вышедшую версию TOML 1.1. С практической точки зрения это главным образом означает, что inline-таблицы можно писать на нескольких строках и с запятой после — или, иными словами, зависимость в Cargo.toml с большим количеством фичей теперь можно писать среди остальных и не пихать её в одну длинную строку.

▪️Ещё стабилизация: cargo теперь позволяет разбить конфиг на несколько файлов и объединить их при помощи top-level ключа include (документация).
👍5