#prog #rust #c #article
Eurydice: a Rust to C compiler (yes)
Сделано для интеграции кода на Rust в существующие проекты на C без того, чтобы требовать наличие двух параллельных реализаций.
Присутствует чуть-чуть джеркования:
Eurydice: a Rust to C compiler (yes)
Eurydice is a compiler from Rust to C that aims to produce readable C code.
Сделано для интеграции кода на Rust в существующие проекты на C без того, чтобы требовать наличие двух параллельных реализаций.
Присутствует чуть-чуть джеркования:
Having a backwards-compat scenario where Rust can be compiled to C serves several purposes.
<...>
3. It allows for a census of problematic scenarios. By making the Rust version the default (and putting the fallback C behind a--write-us-an-emailflag), there is finally a way to enumerate those mythical users who cannot switch to Rust just yet.
❤4❤🔥3
#prog #rust #rustlib
brie-tree - SIMD-optimized B+ Tree implementation that uses integer keys
brie-tree - SIMD-optimized B+ Tree implementation that uses integer keys
A fast B+ Tree implementation that uses integer keys.
The API is similar to the standard library's BTreeMap with some significant differences:
* Lookups and insertions are 2-4x faster than BTreeMap.
* BTree can optionally be used as a multi-map and hold duplicate keys.
* Keys must be integer types or convertible to integers via the BTreeKey trait.
* The maximum integer value is reserved for internal use and cannot be used by keys.
* Elements in the tree are ordered by the integer value of the key instead of the Ord implementation of the keys.
* Cursors can be used to seek back-and-forth in the tree while inserting or removing elements.
* Iterators only support forward iteration.
👍10
#prog #rust #article
What's "new" in Miri (and also, there's a Miri paper!)
What's "new" in Miri (and also, there's a Miri paper!)
It is time for another “what is happening in Miri” post. In fact this is way overdue, with the previous update being from more than 3 years ago <...>
❤5
#prog #rust #serde
serde's borrowing can be treacherous
Из-за экранирования данных, главным образом. Для обхода этой проблемы можно использовать
serde's borrowing can be treacherous
(This is not super surprising when you think about it, but it bit me recently so I figured I'd write it up.)
TL;DR: Be careful when using&'a stror&'a [u8]with serde deserializers; serde has no way to produce an appropriate compile-time error when zero-copy deserialization isn't possible or just isn't supported. Instead, you'll get a runtime error indefinitely later.
Из-за экранирования данных, главным образом. Для обхода этой проблемы можно использовать
Cow<'a, str> с #[serde(borrow)]#prog #rust #article
OnceMap: Rust Pattern for Running Concurrent Work Exactly Once
OnceMap: Rust Pattern for Running Concurrent Work Exactly Once
When multiple tasks need the same resource, how do you ensure the work happens exactly once? uv’s solution is OnceMap - a lightweight concurrent memoization primitive that powers deduplication across the resolver and installer.Не смотря на то, что код приведён для Rust, подход, судя по всему, можно адаптировать и под другие языки.
🤔3❤2
#prog #rust #моё
У Алексея Кладова есть пост про реализацию интернирования строк (советую прочитать перед моим постом). Как он замечает, простейший способ интернировать строки — через такой тип:
Новые строки добавляются через вставку в
Недостаток такого решения очевиден: каждая строка выделяется в куче дважды. Особенно это печально в связи с тем, что строки часто интернируют именно для того, чтобы сэкономить память, выделяя её только единожды на каждое значение. Алексей решает это тем, что выделяет память по возможности одним куском в одной
К сожалению, у этого дизайна есть несколько недостатков.
* Выдаваемые
* Из-за индексации каждый лукап — потенциальная паника.
* Идентификаторы никак не привязаны к пулу временами жизни: если мы создадим пул, выделим строку, дропнем пул, создадим заново и снова выделим строку, то возвращённые значения будут считаться равными — что технически верно, но не вполне корректно.
* Можно сравнивать идентификаторы, полученные от двух разных пулов, и получить как и ложно-положительные, так и ложно-отрицательные результаты, и компилятор вообще никак от этого не защищает.
* Очень нишевый недостаток:
* Количество потребляемой таки пулом памяти может только расти, явное переиспользование памяти невозможно. Это может быть важно, если нам требуется многократно использовать пул в ограниченной области действия.
От всех этих недостатков можно избавиться, используя два решения.
Первый из них заключается в трюке, используемом в thin_vec: вместо того, чтобы хранить длину аллокации отдельно, выделять дополнительную память в куче и хранить в начале длину строки. Сами интернированные строки будут хранить указатель на начало аллокации и создавать толстый указатель на строку по требованию. Это даёт несколько преимуществ:
* Выдаваемые идентификаторы могут быть переведены в строки без обращения к пулу — его не надо держать под рукой и получение строки не может паниковать.
* К создаваемой строке можно (на самом деле нужно, для корректности) привязать время жизни. Это позволяет избежать ошибок со случайным переиспользованием строк и до какой-то степени защищает от сравнения строк из разных пулов.
* Указатель имеет естественную нишу в виде null и потому получает оптимизацию раскладки
Второе решение заключается в том, чтобы использовать bump-аллокатор — в данном случае bumpalo. Он даёт гарантии стабильности адресов, а внутри использует тот же трюк с удваиваемыми буферами, который нам не надо повторять самостоятельно. Дополнительно он позволяет скопом освобождать память, сохраняя при этом аллокацию последнего буфера, что позволяет уменьшить потребление памяти и обращение к аллокатору и закрыть таким образом последний недостаток решения Кладова.
Что ж, приступим к реализации!
У Алексея Кладова есть пост про реализацию интернирования строк (советую прочитать перед моим постом). Как он замечает, простейший способ интернировать строки — через такой тип:
struct Interner {
map: HashMap<String, u32>,
vec: Vec<String>,
}Новые строки добавляются через вставку в
map, а идентификатор строк создаётся от длины vec на момент добавления. map позволяет быстро проверить, была ли строка записана, а vec позволяет быстро получить строку по её идентификатору.Недостаток такого решения очевиден: каждая строка выделяется в куче дважды. Особенно это печально в связи с тем, что строки часто интернируют именно для того, чтобы сэкономить память, выделяя её только единожды на каждое значение. Алексей решает это тем, что выделяет память по возможности одним куском в одной
String и хранит в мапе &str на эту память с принудительно приведённым к 'static временем жизни. Инвалидацию ссылок он обходит остроумным приёмом: при нехватке ёмкости он выделяет новый буфер, вдвое больше предыдущего, и записывает новые строки туда, а старый буфер переносит в отдельный вектор. Он эксплуатирует тот факт, что адреса выделенной в куче памяти стабильны и не меняются при перемещении String. С таким дизайном определение структуры данных выглядит так:struct Interner {
map: HashMap<&'static str, u32>,
vec: Vec<&'static str>,
// новые строки записывают сюда
buf: String,
// буферы с недостаточной памятью переносят сюда
full: Vec<String>,
}К сожалению, у этого дизайна есть несколько недостатков.
* Выдаваемые
Interner идентификаторы не самодостаточны: всё ещё нужно обращаться к пулу, если нам потребуется содержимое строки. Пул при этом можно перепутать* Из-за индексации каждый лукап — потенциальная паника.
* Идентификаторы никак не привязаны к пулу временами жизни: если мы создадим пул, выделим строку, дропнем пул, создадим заново и снова выделим строку, то возвращённые значения будут считаться равными — что технически верно, но не вполне корректно.
* Можно сравнивать идентификаторы, полученные от двух разных пулов, и получить как и ложно-положительные, так и ложно-отрицательные результаты, и компилятор вообще никак от этого не защищает.
* Очень нишевый недостаток:
u32 не имеет ниши и потому не получает null pointer optimization при оборачивании в Option. Это, в принципе, решаемо оборачиванием в NonNull<u32>, но не очень удобно из-за инкремента при генерации и декремента при индексации.* Количество потребляемой таки пулом памяти может только расти, явное переиспользование памяти невозможно. Это может быть важно, если нам требуется многократно использовать пул в ограниченной области действия.
От всех этих недостатков можно избавиться, используя два решения.
Первый из них заключается в трюке, используемом в thin_vec: вместо того, чтобы хранить длину аллокации отдельно, выделять дополнительную память в куче и хранить в начале длину строки. Сами интернированные строки будут хранить указатель на начало аллокации и создавать толстый указатель на строку по требованию. Это даёт несколько преимуществ:
* Выдаваемые идентификаторы могут быть переведены в строки без обращения к пулу — его не надо держать под рукой и получение строки не может паниковать.
* К создаваемой строке можно (на самом деле нужно, для корректности) привязать время жизни. Это позволяет избежать ошибок со случайным переиспользованием строк и до какой-то степени защищает от сравнения строк из разных пулов.
* Указатель имеет естественную нишу в виде null и потому получает оптимизацию раскладки
Option.Второе решение заключается в том, чтобы использовать bump-аллокатор — в данном случае bumpalo. Он даёт гарантии стабильности адресов, а внутри использует тот же трюк с удваиваемыми буферами, который нам не надо повторять самостоятельно. Дополнительно он позволяет скопом освобождать память, сохраняя при этом аллокацию последнего буфера, что позволяет уменьшить потребление памяти и обращение к аллокатору и закрыть таким образом последний недостаток решения Кладова.
Что ж, приступим к реализации!
👍3👎1
#prog #rust #article
What does it take to ship Rust in safety-critical?
Статья про очень конкретные препятствия к использованию Rust в safety-critical системах.
Это именно препятствия, а не блоки — в этих областях Rust уже используется в проде.
What does it take to ship Rust in safety-critical?
Статья про очень конкретные препятствия к использованию Rust в safety-critical системах.
Это именно препятствия, а не блоки — в этих областях Rust уже используется в проде.
blog.rust-lang.org
What does it take to ship Rust in safety-critical? | Rust Blog
Empowering everyone to build reliable and efficient software.
🤔2
#prog #rust #article
Офигенно!
Rust's standard library on the GPU
Офигенно!
Rust's standard library on the GPU
GPU code can now use Rust's standard library. We share the implementation approach and what this unlocks for GPU programming.
This works because of our customhostcallframework. A hostcall is analogous to a syscall. A hostcall is a structured request from GPU code to the host CPU to perform something it cannot execute itself. You can think of it like a remote procedure call from the GPU to the host to achieve syscall-like functionality.
To end users, Rust's std APIs appear unchanged and act as one would expect.
❤12👍8