1.83K subscribers
3.3K photos
131 videos
15 files
3.57K links
Блог со звёздочкой.

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

Небольшое прикольное комьюнити: @decltype_chat_ptr_t
Автор: @insert_reference_here
Download Telegram
> а что произойдет если выстрелить в ногу?
> давай я тебе, а ты мне (два молодых C++ программиста)
Forwarded from мне не нравится реальность (вафель 🧇🍓)
Хочу подчеркнуть пару моментов из последнего TWIR:
allow using generic trait methods in const fn

Этот PR добавляет возможность использовать трейты в const fn!

Это часть реализации (ещё не принятого, ммм) RFC #2632, которое предлагает позволить такое:

impl const Add for MyInt {
fn add(self, other: Self) -> Self {
MyInt(self.0 + other.0)
}
}

и такое:

const fn triple_add<T: Add<Output=T>>(a: T, b: T, c: T) -> T {
a + b + c
}

Мне кажется что const требование на весь трейт слишком ограничивает, но впрочем другие варианты не лучше :(

В любом случае хорошо что работы в этом направлении ведутся.

allow Trait inheritance with cycles on associated types

Фиксит старое странное поведение, которое заставляло писать

trait Sub: Super<<Self as Sub>::Assoc> {
type Assoc;
}

вместо

trait Sub: Super<Self::Assoc> {
type Assoc;
}
#prog #rust #article

Статья о внутреннем устройстве BTreeMap из стандартной библиотеки Rust. Старая, вышла ещё до Rust 1.0, но она даёт хороший обзор принципиального устройства этой структуры данных вкупе с обзором различных трюков для локализации небезопасных операций. Эти трюки применяются и в современной реализации BTreeMap
#prog #rust #amazingopensource #article

Рантайм, позволяющий запускать легковесные процессы на WASM и изолировать их падения, а также ограничивать доступный процесcам API операционной системы. Обзорная статья прилагается.

А вы ещё спрашиваете, зачем WASM нужен.
#prog #rust #rustlib #parsing #amazingopensource

Жора Geoffroy Couprie aka Geal в очередной раз переписал nom. На раст. С раста.

Стоило ли оно того? Определённо.

Во-первых, парсер-комбинаторы теперь вместо impl Fn(...) -> ... возвращают impl FnMut(...) -> .... Функциональность от этого не пострадала, но теперь из них убрано лишнее ограничение. Да, это означает, что теперь можно очень легко написать stateful парсер. Смиритесь с этим.

Во-вторых, парсер теперь — это не что-то, реализующее FnMut(I) -> IResult<O, E>, а что-то реализующее nom::Parser. Помимо того, что это изменение поменяло ограничения на типы аргументов комбинаторов, оно позволяет теперь некоторые комбинаторы использовать не в качестве свободных функций, а в качестве методов этого трейта. Это сильно влияет на эргономику — теперь можно написать .map(...) прямо на парсере, а также набирать альтернативные варианты парсинга цепочкой .or(...) вместо того, чтобы передавать кортеж парсеров в alt. Разумеется, у трейта есть blanket impl для замыканий, так что все старые комбинаторы продолжат работать.

В-третьих, в nom теперь должно быть удобнее пользоваться ошибками. Ошибки из nom теперь реализуют std::error::Error, комбинатор Parser::into позволяет сделать новый парсер, который применяет From к результату и ошибке парсера, а к самим ошибкам можно прицепить контекст — к сожалению, на текущий момент это может быть только &'static str.

Я рассказал лишь о наиболее примечательных, на мой взгляд, изменениях в nom, остальное (вроде улучшенного парсинга на уровне битов и повышения качества документации) вы можете сами прочитать в changelog.
#prog

Кто такой Rockstar programmer? Очевидно, программист, пишущий на Rockstar.
Итак, сегодня 5 декабря. Чем примечателен этот день? Это — день, когда Блог* появился на свет.

Тогда мои амбиции были невелики: я считал, что этот блог будут читать только моя семья и ближайшие знакомые — полтора-два десятка человек максимум. Собственно, само название, как и логотип, я считал временным — даже думал в какой-то момент его поменять. Оглядываясь назад, легко обвинить меня в недальновидности — но с другой стороны, кто тогда мог подумать, что канал с мемасиками и заметками по расту станет... Не популярным, но всё же достаточно известным?

Тем не менее, наиболее характерные черты канала, кажется, оформились уже тогда — пачки репостов и чужого контента (но обязательно только то, что я прочитал сам), малость разбавленные собственными постами про не совсем тривиальные вещи на Rust (собственно, свой самый первый пост я и сейчас считаю довольно хардкорным — большая часть остальных постов у меня вроде попроще). С течением времени канал обрёл лицо, но не изменил заложенным в самом начало принципам. Единственное, что существенно изменилось с тех пор — это то, что с весны я начал лично приветствовать всех новых подписчиков.

Разумеется, я повлиял на канал просто в силу того, что я являюсь его единственным автором, но вот повлиял ли он на меня? На самом деле — да. По себе я знаю, что я человек, который относительно быстро увлекается чем-то новым, но так же быстро к этому охладевает, и потому я опасался, что быстро забью на блог и тот просто умрёт. Именно поэтому я дал себе обещание выкладывать на канале хоть что-то каждый день. Те, кто подписан на Блог* достаточно давно, знают, что в полной мере я сдержать это обещание не смог (некоторые дни я всё же пропускал), но всё же мой план сработал — то, что вы сейчас читаете этот пост, является живым тому подтверждением. Я целый год ежедневно занимался чем-то исключительно по собственной прихоти. Это может показаться незначительным, но для меня — человека со слабой волей — это стало достижением.

Ещё более удивительным для меня стал тот факт, что за этот год я написал в общей сложности — так, дайте-ка посчитаю — 23 оригинальных авторских поста, причём без какого-то специального намерения. Я даже сделал на Хабре перевод весьма крутой и крупной статьи, сделав себя несколько заметным и за пределами Telegram. Если бы мне в начале предыдущего года сказали бы, что я столько напишу — я бы не поверил. Блог* не только замотивировал меня заниматься им ежедневно, но и раскрыл писательскую жилку. Одним словом, он повлиял на меня куда сильнее, чем я ожидал, когда выложил тот мем с жирафом.

Но, впрочем, достаточно разговоров обо мне. Своим нынешним состоянием Блог* обязан и другим людям.
Один из них — это Олег Ковалёв (@olegkovalov), ведущий @oleg_log. Именно он, обладающий поистине гигантским терпением, терпеливо выслушивал мои замечания в духе "А вот на расте!..", проявил искренний интерес к моему блогу, сделал первый, кажется, публичный репост и, подкинув мне идею для поста, помог мне набрать первую сотню подписчиков. Олег, если ты это читаешь — спасибо тебе большое.
Другой человек — это... Тоже Олег, но другой, который ведёт небезызвестный Профунктор (я ещё застал время, когда у него была ссылка @libmustdie). Он организовал подборку, в которую попал в том числе и канал вашего (не)покорного слуги, и разом нагнал мне больше сотни подписчиков. И тебе, Олег, спасибо (а также Моноид-тян).
Также я благодарен множеству других людей — владельцам каналов, которые репостили отдельные посты и тепло отзывались о канале (Рома, я типа до сих пор помню твой комплимент). Это очень греет душу и помогает осознавать, что я стараюсь над этим каналом не ради себя одного.

Но главные, кому я хочу сказать спасибо — это моим подписчикам (слишком многочисленным, чтобы перечислить их тут поимённо). Тот факт, что вы читаете мой канал — и даёте мне ценный фидбек — помог мне перестать относиться к каналу как к какой-то блажи и начать относиться к нему как чему-то, что имеет ценность для многих людей — куда большего числа, чем с которым я бы мог познакомиться лично.
Этот день рождения Блог*а — первый, но, надо думать, отнюдь не последний. Пусть в следующий раз я смогу похвастать уже тысячами подписчиков (впрочем, я не гонюсь в первую очередь за количеством — пусть их будет поменьше, но они будут действительно читать мой блог!), пусть в следующем году оригинального контента станет больше и пусть Блог* станет уважаемым СМИ, на которое будут ссылаться международные издания. Спасибо, что довели меня до этого.

Отпразднуем снова через год! Ура!
Блог* pinned «Итак, сегодня 5 декабря. Чем примечателен этот день? Это — день, когда Блог* появился на свет. Тогда мои амбиции были невелики: я считал, что этот блог будут читать только моя семья и ближайшие знакомые — полтора-два десятка человек максимум. Собственно,…»
Ну и в годовщину имеет смысл устроить небольшое голосование. Я отобрал пачку наиболее достойных, на мой взгляд, авторских постов, а теперь предлагаю судить вам о том, какой из них лучший. Вот они (ибо ссылки в опросах не работают):

1. Реализация трейта, гарантирующего нулевой размер Self.
2. Написание zero-cost (ну, почти) форматировщиков даты.
3. Эпические "Хроники замыканий" в трёх частях: раз, два, три.
4. Рассказ о lifetime elision и анонимном лайфтайме ('_).
5. Как написать код, за который вас возненавидят коллеги (или о том, как можно абьюзить Deref).
6. Конструирование макроса, переводящего численные константы в строки на этапе компиляции.
7. Тонкий и глубокий анализ недостатков регулярных выражений (aka "Да не бомбит у меня!").

⬇️⬇️⬇️⬇️
Блог* pinned «Ну и в годовщину имеет смысл устроить небольшое голосование. Я отобрал пачку наиболее достойных, на мой взгляд, авторских постов, а теперь предлагаю судить вам о том, какой из них лучший. Вот они (ибо ссылки в опросах не работают): 1. Реализация трейта, гарантирующего…»
#prog #rust #моё

Вы что, правда думали, что за всеми празднествами я оставлю вас без поста? Не скрою, идея заманчивая, но я решил ей не поддаваться... Хотя к тому моменту, как я закончу писать этот пост, уже наверняка наступит 6 декабря... Впрочем, достаточно прелюдий — переходим к постановке задачи!

Иногда нам требуется сопоставить значение с одной из строк... Но при этом игнорируя регистр символов. В общем случае это довольно сложная задача, и даже не из-за зависимости от локали, а просто от сложности правил перевода символов из одного регистра в другой. Пока что забьём на это и будем рассматривать только ASCII-строки. Что нам требуется? Чтобы:
а) чтобы можно было сопоставить (ASCII) строку, невзирая на её регистр;
б) чтобы нас предупреждал компилятор о перекрывающихся паттернах (а вот это уже интересно — компилятор требует точного совпадения паттернов для проверки);
в) чтобы по возможности сохранить возможности, предоставляемые match.

Итак, как нам проверить, что строки неодинаковы с точностью до регистра? В принципе, можно сделать уже известным способом const assert, используя соответствующие const fn, но так как я человек ленивый, я пойду по лёгкому пути: я проверю, что все паттерны на самом деле в нижнем регистре, а проверить их уникальность оставлю компилятору.

Итак, переходим к подзадаче: убедиться, что строка состоит из символов ASCII, но в нижнем регистре, на этапе компиляции. Правда, так как мы хотим использовать в паттернах не только буквы, но и, скажем, цифры, правильнее сказать "из символов ASCII не в верхнем регистре". Для решения части "на этапе компиляции" воспользуемся уже знакомым трюком, который я тут вроде уже показывал: заведём новую константу типа [(); 1], а в качестве значения ей присвоим [(); condtion as _], где condition — условие, которое нам нужно проверить. Если condition вычисляется в true (и вычисляется на этапе компиляции в принципе), то as _ приводит булево значение к 1usize, получая выражение [(); 1], соответствующее типу. В противном случае false приводится к 0 и выражение принимает вид [(); 0], вызывая ошибку компиляции из-за несовпадения типов. Теперь всё, что нам остаётся для решения это подзадачи — написать функцию, которую можно вызвать на этапе компиляции и которая проверяет указанное выше условие. Написать такую функцию несколько неудобно из-за ограничений const fn (в частности, мы не можем использовать итераторы), но вполне возможно:

const fn is_ascii_lowercase(s: &str) -> bool {
let s = s.as_bytes();
let len = s.len();
let mut i = 0;
while i < len {
if !s[i].is_ascii() || s[i].is_ascii_uppercase() {
return false;
}
i += 1;
}
true
}

Ладно, а как нам проверить, что несколько строк записаны в ASCII lowercase? Ну как-как, принимаем список и проходимся о нему:

const fn are_all_ascii_lowercase(ss: &[&str]) -> bool {
let len = ss.len();
let mut i = 0;
while i < len {
if !is_ascii_lowercase(&ss[i]) {
return false;
}
i += 1;
}
true
}

Окей, с этой подзадачей мы разобрались. Как нам теперь убедиться, что все строки разные? А эту задачу мы уже решали: генерируем функцию, которая разбирает строку, и подсовываем в match наши строки — и компилятор всё прекрасно проверяет за нас!