Size: a a a

2021 September 03
Блог*
Окей, но как же нам десериализовать HNil с нужной нам логикой? Так как JSON — самоописываемый формат в том смысле, что мы можем посмотреть на начало входа и решить, как парсить остаток — мы можем вызвать у десериализатора метод dezerialize_any, что фактически означает "посмотри данные и реши сам, как их разбирать". Нам также потребуется посетитель, который для разбора подчастей JSON-документа будет вызывать вне зависимости от запрашиваемого типа deserialize_any у десериализатора и не будет при это сохранять никаких данных. К счастью, в составе serde уже есть такой тип — IgnoredAny — так что мы можем просто использовать его:

impl<'de> Deserialize<'de> for HNil {
   fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   where
       D: serde::Deserializer<'de>
   {
       deserializer.deserialize_any(serde::de::IgnoredAny)?;
       Ok(Self)
   }
}

Как видите, код проверяет, что формат корректен, но не вынимает реально из него никаких данных — ровно то, что нам и было нужно.

Теперь мы сделаем несколько структур для десериализации — и макрос для более удобной деконструкции HList:

macro_rules! hlist_pat {
   () => { HNil };
   ($head:pat $(, $rest:pat)* $(,)?) => { HCons { head: $head, tail: hlist_pat!($($rest),*) } };
}

#[derive(Deserialize)]
struct Items {
   items: Vec<String>
}

#[derive(Deserialize)]
struct Version {
   version: u32,
}

#[derive(Deserialize)]
struct User {
   user_id: String,
}

Сконструируем вход, содержащий все поля:

let json = r#"{
   "user_id": "john_doe",
   "items": ["salad", "juice", "beer", "fork"],
   "version": 0,
   "bogus": [null, 0.3, 4, "nope", {}]
}"#;

И попробуем вытащить всё, что нас интересует:

use serde_json::from_str as from_json;
let hlist_pat!(user, items, version) =
   from_json::<HList![User, Items, Version]>(json).unwrap();
assert_eq!(user.user_id, "john_doe");
assert_eq!(items.items, ["salad", "juice", "beer", "fork"]);
assert_eq!(version.version, 0);

Теперь уберём, скажем, версию:

let json = r#"{
   "user_id": "john_doe",
   "items": ["salad", "juice", "beer", "fork"],
   "bogus": [null, 0.3, 4, "nope", {}]
}"#;

assert!(from_json::<HList![User, Items, Version]>(json).is_err());
assert!(from_json::<HList![User, Items         ]>(json).is_ok());

Отсутствие user_id и items вызовет ошибку, но не в том случае, если требуемые наборы полей опциональны:

let json = r#"{
   "version": 0,
   "bogus": [null, 0.3, 4, "nope", {}]
}"#;

assert!(from_json::<HList![        User,         Items, Version]>(json).is_err());
assert!(from_json::<HList![Option<User>, Option<Items>, Version]>(json).is_ok());

Ну и, разумеется, мы можем вытащить все остальные поля, что есть:

type Rest = serde_json::Map<String, serde_json::Value>;
let json = r#"{
   "user_id": "john_doe",
   "items": ["salad", "juice", "beer", "fork"],
   "version": 0,
   "bogus": [null, 0.3, 4, "nope", {}]
}"#;

let hlist_pat!(_, _, _, rest) = from_json::<HList![User, Items, Version, Rest]>(json).unwrap();
assert_eq!(
   serde_json::Value::Object(rest),
   serde_json::json!({
       "bogus": [null, 0.3, 4, "nope", {}],
   })
);

По моему, вышло красиво и изящно. Как всегда, весь код в гисте.
источник
Блог*
🔄
источник
2021 September 04
Блог*
#prog #meme
источник
Блог*
источник
2021 September 06
Блог*
#prog #rust

Казалось бы, заезжанная тема, но Кладов таки рассказал новые вещи
источник
Блог*
https://matklad.github.io/2021/09/04/fast-rust-builds.html

matklad как обычно дело говорит, на этот раз про скорость компиляции
источник
2021 September 07
Блог*
Да блин!
источник
Блог*
Итого за день:

* уронил телефон, разбив экран
* не смог поесть свой обед, поскольку не успел вчера его заказать...
* ...но воспользовался любезностью коллеги, который отдал свой (его сегодня не было в офисе)
* почитал хабр, нашёл ссылку на issue про unsound код в nalgebra, посмотрел, увидел, что и сейчас можно эксплуатировать, сделал MRE и открыл новое issue
* ещё немного посрался в том гигантском MR с тем упёртым сишником, который, в частности, считает, что писать вручную реализацию PartialEq для структуры на три десятка полей — это нормально
* ...но при этом всё же принимает некоторые из моих изменений
* взялся исправлять issue с нашим крейтом, нашёл проблему, но коллеги меня опередили и успели сделать MR
* 💅

Пожалуй, в целом тянет на 0 по шкале Оптозоракса
источник
Блог*
#prog #rust

Боже, храни Вафеля
источник
Блог*
Inside Rust: Splitting the const generics features

Маленькая заметка о прогрессе с расширением const generics.
источник
2021 September 08
Блог*
#prog #rust

Библиотека для todo, которая валит компиляцию при специфических условиях.

lib.rs/todo-or-die
источник
2021 September 09
Блог*
Нашёл тут любопытный список https://github.com/daviddao/awful-ai

Это один из примеров, почему мне не нравится сверхобобщающий термин AI. Но на самом деле, хоть у меня и бомбит от некоторых пунктов списка, ответственность за имидж области лежит на непосредственных её участниках. Так что давайте я попробую внести свой маленький вклад в просвещение.

Меня больше всего напряг самый первый раздел "Discrimination". Потому что примерно половина примеров — это не "they build a racist AI" а просто зеркало того, что люди делают в интернете. Ну научите попугая на твитах, он тоже будет выдавать вам довольно неприятные фразы. Это не расист-попугай, он же не понимает что говорит, он учит распределение данных, которые ему дали. Поэтому да, если в исходных данных белых больше чем people of color, или Dr. чаще стоит рядом с фамилией у мужчин, то чёрт возьми, не алгоритм имеет смещение, а данные. Алгоритмы машинного обучения не вносят никакой логики в данные, не интерпретируют их, грубо говоря, они учат только "как оно чаще бывает в примерах, которые им показали".
И такие работы, которые показывают смещение данных неизбежны и важны. И я бы их как раз пихал не в раздел "фу какие неправильные", а в раздел "смотрите, с этим надо быть осторожными".

И вот тут мы приходим к другой половине раздела и за одно к разделу "Surveillance" а заодно и к "Social credit systems". То есть мы видели на примерах, которые я пытался оправдать, что судить людей алгоритмами не стоит, потому что мы не сможем собрать честные репрезентативные данные, и тем более не сможем вложить в них какую-то этичную логику решений. Потому что они просто учатся правильно угадывать, а не разбираться. И тем не менее, много кто занимается созданием алгоритмов, чтобы прямо искать кого осудить.
С другой стороны, не нужно ограничиваться одними заголовками. Всегда есть тонна деталей, которые могут в корне менять дело, и может оказаться, что AI совсем не AI у них. Просто области, которые касаются отбора людей, разных скорингов и так далее, в принципе такие, что никакой чёрный ящик не допустим, будь то AI или что угодно другое.

Кстати, про переименование NIPS потому что кому-то это напомнило nipples, у меня тоже бомбит. Это напоминает мне ту историю, как за рисунки на рубашке затравили чувака, который посадил Розетту на комету Чурюмова-Герасименко. Какие блин соски? Никто о них и не думал.
источник
Блог*
#prog #c #rust

История получила продолжение

t.me/psauxww/556
источник
2021 September 10
Блог*
#prog #rust

Новый релиз Rust — уже 1.55.0! — и мой новый разбор избранных кусков новых фич.

Теперь в качестве паттернов можно использовать диапазоны с открытой верхней границей:

match x as u32 {
     0 => println!("zero!"),
     1.. => println!("positive number!"),
}

Конечно, раньше ничто не мешало вместо 0.. написать 0..=u32::MAX, но это требовало знания конкретного типа, что не всегда возможно. Макросы стало писать чуть проще. Что любопытно, паттерны с открытой нижней границей (..42) остаются нестабильными.

rustdoc стал чуть более умным: теперь он понимает ссылки на ассоциированные определения через алиасы на типы и не показывает лишние определения методов в секции реализаций трейтов. Последнее изменение позволило снизить размер страницы с документацией к трейту Read с 128 килобайт до 68. Ну и ещё кое-что по мелочи.

Всё остальные изменения по факту связаны со стандартной библиотекой — и в очередной раз приличная доля изменений сводится к "О боже, как же я вообще раньше жил без этой абсолютно необходимой фичи".

Поменяли алгоритм для парсинга чисел с плавающей точкой. Это позволило в целом ускорить работу парсинга примерно на порядок (а для некоторых вырожденных случаев — на три порядка), позволить корректно обрабатывать граничные случаи, на которых валился старый алгоритм и вдобавок уменьшить количество генерируемого без strip-а кода.

В модуль ops добавили перечисление ControlFlow:

pub enum ControlFlow<B, C = ()> {
   Continue(C),
   Break(B),
}

Это перечисление позволяет указать, надо ли продолжать вычисление или же нужно прервать их. Это удобно для обхода графовых структур. Технически ControlFlow изоморфен Result, но применять Result для тех же целей, что и ControlFlow, было неудобно: в подобных случаях то значение, которое пробрасывается наверх (а для ControlFlow это Break), было Err, и использовать этот вариант приходилось именно по этой причине. Это сбивало с толку, поскольку возвращаемое значение, как правило, не несло семантики ошибки. Теперь эта проблема решена, поскольку ControlFlow реализует Try с удобной семантикой. Что, однако, расстраивает — так это то, что у этого перечисления есть пачка тривиальнейших методов — и все нестабильные :/ Видимо, в своих проектах придётся лепить extension trait.

Тип MaybeUninit обзавёлся методами assume_init_{ref, mut} и write. Первый позволяет объявить значение инициализированным, имея на руках лишь ссылку на него — полезно в тех случаях, когда получить владение не представляется возможным. А ещё это позволяет инициализировать данные, не перемещая их памяти, в отличие assume_init. Метод же write просто записывает переданное значение и функционально эквивалентен maybe_uninit.as_mut_ptr().write(value), но не требует unsafe-блока. Я удивлён, что его стабилизация вообще заняла время.

В продолжение начатым Вафелем изменений в полку связанных со строками итераторов, позволяющих извлекать внутреннюю строку, прибыло: теперь в их число входит std::string::Drain с методом as_str. Дополнительно он теперь реализует AsRef<str> и AsRef<[u8]>.

Операцию map теперь можно применять непосредственно на массивах при помощи соответствующего метода. Больше никаких аллокаций промежуточных векторов только из-за нехватки методов!

На этом от меня всё, ну а более подробные изменения всегда можно почитать в RELEASES.md.
источник
2021 September 11
Блог*
#prog #rust

Rudra — статический анализатор Rust-кода, нацеленный на поиск семантических ошибок в unsafe-коде. Работает с обобщённым кодом, быстр, фантастически эффективен на практике:

"New bugs. We reported 263 previously unknown memory-safety bugs in 145 packages, resulting in 98 RustSec advisories and 74 CVEs (see Table 3 and Table 4). This is an unprecedented number of memory-safety bugs, constituting 51.3% of all memory-safety bugs in the Rust ecosystem since2016 (see Figure 1). Also, the bugs RUDRA discovered are non-trivial: two higher-order invariant bugs in the Rust std library, one SV bug in the Rust compiler, rustc, one SV bug in the official futures library, and several SV bugs in lock_api, a very popular lock abstraction library. These are mistakes made by Rust experts. It is worth noting that the average latent time of the discovered bugs is over three years despite community efforts to manually audit unsafe code inRust [35]."
источник
2021 September 12
Блог*
Поздравляю Вафеля!
источник
Блог*
Что может быть приятнее, чем
источник
Блог*
Оооо, эта мерзкая херня TrustArc шагает по вебу, вот только я поленился проверять, чего она 5сек висит.

https://twitter.com/pixelscript/status/1436664488913215490
источник
2021 September 13
Блог*
Естественным языкам временами не хватает тайпчекера
источник
2021 September 15
Блог*
Это я экспериментировал с показом ошибок в rustc. В итоге мои эксперименты привели к rust/#88907, который кстати одобрили :>
источник