Блог*
#prog #rust #article На этот раз — статья про концепцию разномерности типа в Rust. github.com/pretzelhammer/rust-blog/blob/master/posts/sizedness-in-rust.md
#prog #rust #compiler #article
Восхитительная длинная статья от Крендель-молота про написание компилятора brainfuck под x86_64, ARM64, WASM и LLVM IR.
github.com/pretzelhammer/rust-blog/blob/master/posts/too-many-brainfuck-compilers.md
Восхитительная длинная статья от Крендель-молота про написание компилятора brainfuck под x86_64, ARM64, WASM и LLVM IR.
github.com/pretzelhammer/rust-blog/blob/master/posts/too-many-brainfuck-compilers.md
GitHub
rust-blog/posts/too-many-brainfuck-compilers.md at master · pretzelhammer/rust-blog
Educational blog posts for Rust beginners. Contribute to pretzelhammer/rust-blog development by creating an account on GitHub.
Блог*
#prog #rust tip: спецификатор фрагмента vis в макросах сопоставляется с описанием видимости определения, в том числе и пустым. К примеру, следующий код компилируется: macro_rules! accept_with_vis { ($vis:vis struct $name:ident;) => {} } accept_with_vis!{struct…
...Но не когда нужно сопоставиться только с спецификатором видимости (thanks @sajitar, который и заполнил issue). Вот этот код не компилируется:
macro_rules! accept_just_vis {
($vis:vis) => {}
}
accept_just_vis!{}GitHub
macro_rules! and empty :vis metavariables · Issue #71422 · rust-lang/rust
Hi. I founds some bugs, did a research, and created a repository with reproducible examples, README, and instructions. Here is the content of README, and the whole repo is attached as zip archive. ...
#prog #rust #моё
Как многие из вас знают (а если не знаете — узнаете сейчас), в Rust нельзя перемещать (move) поля из значения типа, имеющего нетривиальную реализацию Drop. В частности, значение типа, реализующего
Пусть это выглядит примерно так:
Как многие из вас знают (а если не знаете — узнаете сейчас), в Rust нельзя перемещать (move) поля из значения типа, имеющего нетривиальную реализацию Drop. В частности, значение типа, реализующего
Drop, нельзя деструктурировать. Однако надо отметить, что если тип поля реализует Copy, то к этому полю можно обратиться, в том числе и пре деструктуризации, при этом значение этого поля скопируется. Проиллюстрирую только что сказанное:struct NonCopy;
struct Dropping<T>(T, NonCopy);
impl<T> Drop for Dropping<T> {
fn drop(&mut self) {
println!("dropped");
}
}
fn main() {
// ⬇️ если раскомментировать эту строку, то программа не скомпилируется с E0509
// let Dropping(_non_copy, _) = Dropping(NonCopy, NonCopy);
// А вот это — компилируется и печатает "dropped".
// Обратите внимание, паттерн `_` *не* перемещает значение.
let Dropping(_x, _) = Dropping(0_u32, NonCopy);
}
Где это может выстрелить? При написании биндингов к сишным либам. Одна их техник обеспечения инкапсуляции в C — это определение структуры в заголовочном файле без определения её полей. Это позволяет получить доступ к полям структуры только там, где дано её определение, а внешний код может обращаться к ней лишь по указателю. И указатель — это Copy-тип, да.Пусть это выглядит примерно так:
extern "C" {
// extern types ещё не стабилизированы, так что
// в реальной библиотеке, скорее всего, будут использовать *mut std::ffi::c_void
type Some_C_Struct;Что произойдёт, если мы попытаемся деструктурировать
fn c_lib_release_resources(arg: *mut Some_C_Struct);
}
struct Handle(*mut Some_C_Struct);
impl Drop for Handle {
fn drop(&mut self) {
unsafe { c_lib_release_resources(self.0) }
}
}
Handle? Скажем, нам зачем-то потребовалась реализация метода leak:impl Handle {
fn leak(self) -> *mut Some_C_Struct {
// Здесь мы разбираем значение, но так как указатель — Copy-тип,
// имя ptr привязывается к копии значения, перемещения не происходит.
let Handle(ptr) = self; // <-- после этой точки с запятой кончается время жизни self, и вызывается деструктор
// Ура, у нас на руках невалидный указатель!
ptr
}
}
Что можно с этим сделать? Использовать ManuallyDrop. Этот тип предотвращает вызов деструктора (а также деструктуризацию, поскольку у него приватные поля), но при этом не предотвращает доступ к полям значения внутри (через Deref). Возникает вопрос, почему не использовать std::mem::forget? В принципе, в документации подробно расписано, но если коротко, то std::mem::forget значительно сложнее корректно использовать.doc.rust-lang.org
ManuallyDrop in std::mem - Rust
A wrapper to inhibit compiler from automatically calling `T`’s destructor. This wrapper is 0-cost.
Прошу прощения, в предыдущем опросе один диапазон возрастов просто не был представлен
Сколько вам лет?
(диапазон с включающей нижней и исключающей верхней границами)
(диапазон с включающей нижней и исключающей верхней границами)
Final Results
1%
0..10
7%
10..18
41%
18..25
25%
25..30
13%
30..35
7%
35..40
2%
40..45
1%
45..50
1%
50..60
1%
60..∞
#prog #rust
PR, добавляющий поддержку кастомных аллокаторов для
Интересным является тот факт, что тип остался тот же, но на stable указать аллокатор пока нельзя. Это стало возможным благодаря этому PR, который позволил вешать аннотации стабильности на ти́повые параметры.
PR, добавляющий поддержку кастомных аллокаторов для
Vec 🎉. Первый шаг на пути к стандартным коллекциям с полностью настраиваемым аллокатором.Интересным является тот факт, что тип остался тот же, но на stable указать аллокатор пока нельзя. Это стало возможным благодаря этому PR, который позволил вешать аннотации стабильности на ти́повые параметры.
GitHub
Add support for custom allocators in `Vec` by TimDiekmann · Pull Request #78461 · rust-lang/rust
This follows the roadmap of the allocator WG to add custom allocators to collections.
r? @Amanieu
This pull request requires a crater run.
Prior work:
#71873: Crater-test to solve rust-lang/wg-all...
r? @Amanieu
This pull request requires a crater run.
Prior work:
#71873: Crater-test to solve rust-lang/wg-all...
Forwarded from Generative Anton
А у кого день рождения? У @ihatereality день рождения!
С днём рождения, наше любимое умное асексуальное кондитерское изделие!
С днём рождения, наше любимое умное асексуальное кондитерское изделие!
Forwarded from Информация опасносте
Go SMS Pro, популярный мессенджер на Андроид, при пересылке картинок или файлов между пользователями закачивает их на свой сервер, чтобы ссылка была доступна для просмотра даже без приложения. Но нумерация этих файлов идёт по порядку, и при желании можно перебором просматривать чужие файлы, которые могут содержать конфиденциальную информацию. Попытки связаться с разработчиками не увенчались успехом, проблема остаётся неисправленной
https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/go-sms-pro-vulnerable-to-media-file-theft/
https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/go-sms-pro-vulnerable-to-media-file-theft/
"Тут как бы сишные нестандартизированные API, я бы назвал это pain driven developement"
#quotes #трудовыебудни
#quotes #трудовыебудни
#prog #abnormalprogramming
"Змейка" на клавиатуре с подсветкой.
Видеодемонстрация
Статья с разбором реализации
Перевод на Хабре
"Змейка" на клавиатуре с подсветкой.
Видеодемонстрация
Статья с разбором реализации
Перевод на Хабре
YouTube
Playing Snake with hacked Coolermaster Rapid-I firmware
I hacked the firmware for my Coolermaster Rapid-I to replace one of the lighting modes with a Snake game. It already does the other modes out of the box. Article on how I did it: https://spritesmods.com/?art=rapidisnake&f=yt
#prog #rust #моё
В Rust есть такая удобная вещь, как сопоставление с образцом (pattern matching), и она работает в том числе и для строк. К сожалению, оно позволяет сопоставлять только строки целиком, но не по частям. В частности (no pun intended), match не позволяет разделить строку на некоторый фиксированный префикс и всё остальное.
Или всё же позволяет? В конце-концов, можно написать так:
Если же ослабить требование максимальной эффективности генерируемого кода (серьёзно, Rust и так достаточно быстрый), то можно обойтись более слабыми macro_rules!. Как можно переписать сопоставление с префиксом на обычные функции? Один из способов — это написать match, в котором значение ни с чем не сопоставляется, а условие "начинается с заданного префикса" задаётся в охранном выражении (guard clause). Сказано — сделано:
Попробуем оставить в
Что же скажет компилятор?
В Rust есть такая удобная вещь, как сопоставление с образцом (pattern matching), и она работает в том числе и для строк. К сожалению, оно позволяет сопоставлять только строки целиком, но не по частям. В частности (no pun intended), match не позволяет разделить строку на некоторый фиксированный префикс и всё остальное.
Или всё же позволяет? В конце-концов, можно написать так:
match str_value.as_bytes() {
[b'p', b'r', b'e', b'f, b'i', b'x', rest @ ..] => {}
_ => {}
}
, и тут даже будет помогать компилятор — он подскажет нам, если мы будем дважды проверять один и тот же префикс. Но тут есть и недостатки: остаток строки (rets во второй строчке) — не &str, а &[u8], ну и, конечно, это довольно неудобно писать. Первый недостаток отчасти перекрывается str::get_unchecked/std::str::from_utf8_unchecked — отчасти, поскольку в паттерн байта можно написать и часть многобайтового символа, а вот второй недостаток обойти сложнее. В идеале мы бы хотели написать матч в виде сопоставления части строки, чтобы потом он скомпилировался в примерно такой же код, как наверху — чтобы к нему могли быть применены те же оптимизации, что и к обычному матчу, и чтобы получить выгоду от проверки полноты покрытия — но это довольно существенное вмешательство в синтаксис, требующее написания процедурного макроса, написание которого отводится читателю в качестве самостоятельного упражнения.Если же ослабить требование максимальной эффективности генерируемого кода (серьёзно, Rust и так достаточно быстрый), то можно обойтись более слабыми macro_rules!. Как можно переписать сопоставление с префиксом на обычные функции? Один из способов — это написать match, в котором значение ни с чем не сопоставляется, а условие "начинается с заданного префикса" задаётся в охранном выражении (guard clause). Сказано — сделано:
macro_rules! prefixes {
(match $value:ident {
$($prefix:literal.. => $arm:expr,)*
_ => $catch_all:expr $(,)?
}) => {
match $value {
$(x if x.starts_with($prefix) => $arm,)*
_ => $catch_all,
}
}
}
Ну и давайте сделаем какую-нибудь функцию, которая использует этот макрос:fn use_prefixes(s: &str) -> String {
prefixes!(match s {
"foo".. => s.to_string(),
"bar".. => [s, s].concat(),
_ => String::new(),
})
}
fn main() {
let inputs = [
"foobar",
"barfoo",
"overall",
];
for input in &inputs[..] {
println!("{:?}", use_prefixes(input));
}
}
Но, погодите-ка, так потеряли одно из преимуществ компилятора: проверку полноты покрытия! Как мы можем её восстановить? Пойдём ленивым путём: сделаем свою функцию, в которой будем матчить по переданным строкам и позволим компилятору сделать работу за нас. Однако возникает вопрос, где эту функцию хранить? Простейший способ добиться этого — обернуть весь итоговый match в один блок и сделать внутри этого блока функцию. Так как функция не будет использована, она будет помечена #[allow(dead_code)], а на внутренний match повесим #[warn(unreachable_patterns)], чтобы предупреждения компилятора были даже в том случае, если они по каким-то причинам выключены на верхнем уровне:macro_rules! prefixes {
(match $value:ident {
$($prefix:literal.. => $arm:expr,)*
_ => $catch_all:expr $(,)?
}) => {{
#[allow(dead_code)]
fn non_repeating() {
#[warn(unreachable_patterns)]
match "" {
$($prefix => (),)*
_ => (),
}
}
match $value {
$(x if x.starts_with($prefix) => $arm,)*
_ => $catch_all,
}
}}
}Попробуем оставить в
use_prefixes одинаковые префиксы:fn use_prefixes(s: &str) -> String {
prefixes!(match s {
"foo".. => s.to_string(),
"foo".. => [s, s].concat(), // <--
_ => String::new(),
})
}Что же скажет компилятор?