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

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

Небольшое прикольное комьюнити: @decltype_chat_ptr_t
Автор: @insert_reference_here
Download Telegram
Но как именно это сделать? Первый способ, лежащий на поверхности (aka способ ленивого программиста) — собрать в массив вектор элементы гетерогенного списка, ослабленные до dyn Debug, и попросту отформатировать этот вектор.

Так как HNil и HCons — разные типы, нам нужно абстрагировать в трейт общую для них операцию, а именно — добавление элементов в переданный вектор. Как должна выглядеть сигнатура метода? Кажется, что как-то так:

fn append_fmt_items(&self, items: &mut Vec<&dyn Debug>)

...но это так не работает. Дело в том, что сигнатура говорит о том, что времена жизни ссылки на self и ссылок на трейт-объекты не связаны друг с другом. Но это явно не так, ведь мы собираемся класть в items данные из self! Что ж, выразим этот факт в коде:

trait AppendFmt {
fn append_fmt_items<'a>(&'a self, items: &mut Vec<&'a dyn Debug>);
}

Теперь напишем реализации для компонент списка:

impl AppendFmt for HNil {
fn append_fmt_items<'a>(&'a self, _: &mut Vec<&'a dyn Debug>) {
/* nothing to do here */
}
}

impl<H, T> AppendFmt for HCons<H, T>
where
H: Debug,
T: AppendFmt,
{
fn append_fmt_items<'a>(&'a self, items: &mut Vec<&'a dyn Debug>) {
items.push(&self.head);
self.tail.append_fmt_items(items);
}
}

Теперь мне бы очень хотелось написать impl<T: AppendFmt> Debug for T... но, к сожалению, мне не даст компилятор, потому что это будет перекрываться с impl<T: Debug> Debug for &'_ T. Так что, стиснув зубы, пишем руками:

impl Debug for HNil {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let list: &[&dyn Debug] = &[];
list.fmt(f)
// или просто f.write_str("[]")
}
}

impl<H, T> Debug for HCons<H, T>
where
Self: AppendFmt,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut items = Vec::new();
self.append_fmt_items(&mut items);
items.fmt(f)
}
}

Проверив, снова распечатав hlist![42, 'b', "sup", ((), (3.4, Vec::<i32>::new()))]:

[42, 'b', "sup", ((), (3.4, []))]

А если попросить "красивую" печать?

[
42,
'b',
"sup",
(
(),
(
3.4,
[],
),
),
]

Гораздо лучше.
Но действительно ли нам нужно собирать всё в один вектор и лишний раз выделять память? Мы же можем поступить так же, как и реализация Debug для слайса: воспользоваться хелпером std::fmt::DebugList и скормить ему элементы списка. Единственной сложностью тут выступает то, что мы, очевидно, не можем (ну то есть можем, но не хотим, потому что это потребует написания дофига кода и будет неэффективно в рантайме) воспользоваться DebugList::entries, так что придётся скармливать элементы по одному при помощи DebugList::entry.

Снова выделим общий функционал в отдельный трейт:

trait HlistFmt {
fn finish_fmt(&self, list: &mut DebugList<'_, '_>) -> fmt::Result;
}

Реализуем для HNil и HCons:

impl HlistFmt for HNil {
fn finish_fmt(&self, list: &mut DebugList<'_, '_>) -> fmt::Result {
list.finish()
}
}

impl<H, T> HlistFmt for HCons<H, T>
where
H: Debug,
T: HlistFmt,
{
fn finish_fmt(&self, list: &mut DebugList<'_, '_>) -> fmt::Result {
list.entry(&self.head);
self.tail.finish_fmt(list)
}
}

Теперь через это реализуем Debug:

impl Debug for HNil {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.finish_fmt(&mut f.debug_list())
// или опять f.write_str("[]")
}
}

impl<H, T> Debug for HCons<H, T>
where
Self: HlistFmt,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.finish_fmt(&mut f.debug_list())
}
}

Если мы теперь распечатаем тот же самый пробный список, то мы получим те же самые результаты, так что показывать это я не буду.

DebugList — не единственный хелпер для форматирования в std, есть также DebugMap, DebugSet, DebugStruct и DebugTuple, суть функционала которых ясна из названий. Эти вещи сильно облегчают написание кастомных реализаций Debug, так что используйте их, пожалуйста.

P. S.: как всегда, весь код в гисте.
За час с момента публикации пост расшарили трижды, но ни одного комментария не последовало. Всё и так понятно или всё совсем непонятно? 🤔
#prog #rust

В каком-то смысле костыль, но штука нужная
Наткнулся в твиттере на анонс интересного инструмента:

> cargo-hakari

Он автоматизирует создание и поддержку "workspace-hack" крейтов, ускоряя компиляцию для больших воркспейсов. Что такое "workspace-hack" и зачем его используют в rustc и firefox — читайте в треде.
Вы не поверите, но это японские блины. Их подают в Crepes de Anne в Нагое.
Forwarded from Puh
Как сделать ноготочки на типах rust
#prog #rust #rustlib #serde

Трейт Deserializer имеет методы вида deserialize_type. Трейт Serializer имеет методы вида serialize_type. Что это значит? Это значит, что одно можно непосредственно сцепить с другим, и таким образом перегонять данные из одного формата данных, поддерживаемых serde, в другой, никогда не материализуя экземпляры соответствующих типов в памяти целиком. Собственно, именно это и делает serde-transcode.

Пример из документации (преттификация JSON):

extern crate serde;
extern crate serde_json;
extern crate serde_transcode;

use serde::Serialize;
use serde_json::{Serializer, Deserializer};
use std::io::{Read, Write, BufReader, BufWriter};
use std::fs::File;

fn main() {
let reader = BufReader::new(File::open("input.json").unwrap());
let writer = BufWriter::new(File::create("output.json").unwrap());

let mut deserializer = Deserializer::from_reader(reader);
let mut serializer = Serializer::pretty(writer);
serde_transcode::transcode(&mut deserializer, &mut serializer).unwrap();
serializer.into_inner().flush().unwrap();
}
Сделать, что ли, отдельный хештег для serde 🤔
Forwarded from Санечка Ъысь (Anna Weiss)
Я уволился.
#prog #article

Статья о PubGrub — алгоритме разрешения ограничений, который используется в pub — пакетном менеджере для Dart — для выбора версий зависимостей.

Во главе алгоритма лежит идея несовместимостей (incompatibilities) — набор ограничений на версии, которые не могут быть удовлетворены все одновременно. Замечательной особенностью несовместимостей является то, что они являются фактами конкретного набора ограничений: неважно, какие именно версии будут выбраны в процессе разрешения зависимостей, они не могут инвалидировать уже обнаруженные несовместимости.

Алгоритм состоит из двух частей: unit propagation и decision making (нет, я не смог придумать перевода, который бы звучал не коряво). Unit propagation анализирует несовместимости и выводит конкретные факты (то бишь ограничение на версии), которые должны быть справедливы при текущем выборе версий. Так как эти факты зависят от принятых решений, в базу знаний они добавляются не напрямую, а в виде несовместимостей. Эта фаза продолжается до тех пор, пока получение новых фактов возможно.

Вторая фаза, decision making, вступает в силу, если unit propagation закончил работу, но в отношении конкретных выбранных версий ещё осталась неопределённость. Алгоритм пробует одну из возможных альтернатив для выбора версии и пытается вывести версии, исходя из этого решения. Важным тут является то, что когда выбор альтернативы приводит к конфликту ограничений, этот факт записывается в базу знаний в виде несовместимости. Это позволяет не терять полученную информацию и и использовать её при выборе альтернатив, существенно снижая список альтернатив для проб за счёт пропуска диапазонов версий, которые заведомо не приведут к решению.

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

P. S.: не смотря на мои объяснения, советую прочитать оригинальную статью: мало того, что я мог понять что-то неправильно, так ещё и там работа алгоритма демонстрируется на наглядном конкретном примере.
#prog #meme
Я старый(