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

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

Небольшое прикольное комьюнити: @decltype_chat_ptr_t
Автор: @insert_reference_here
Download Telegram
#prog #rust #rustlib

pretty-hex

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

use pretty_hex::*;

let cfg = HexConfig {
title: false,
width: 8,
group: 0,
..HexConfig::default()
};

let v = &include_bytes!("data");
assert_eq!(
config_hex(&v, cfg),
format!("{:?}", v.hex_conf(cfg)),
);

println!("{:?}", v.hex_conf(cfg));

Output:

0000:   6b 4e 1a c3 af 03 d2 1e   kN......
0008: 7e 73 ba c8 bd 84 0f 83 ~s......
0010: 89 d5 cf 90 23 67 4b 48 ....#gKH
0018: db b1 bc 35 bf ee ...5..

(thanks @goldsteinq)
👍9🔥4💔1
Forwarded from Топ Twitter
😁113💔1
💔1
Forwarded from dev optozorax
Завтра будет частичное солнечное затмение.

Зайдите сюда: https://www.timeanddate.com/eclipse/map/2022-october-25, впишите свой город в поиск на карте, и смотрите когда оно будет в полной фазе по вашему локальному времени, пример [Москва].

Лучший способ увидеть затмение - через тени маленьких объектов, по типу листьев, все их тени будут в форме полумесяца. Увидеть затмение на солнце будет сложно или легко в зависимости от вашей локации. Лучше заранее найти что-то по типу маски для сварки.

А узнать через сколько лет будет следующее затмение можно в моём репозитории: https://github.com/optozorax/sun-eclipses#частное-солнечное-затмение-25-октября-2022-г
1💔1
👍1🤣1💔1
The glass is half full-stack
💔1
👎2💔1
😁9🤯5👍3🤣1💔1
Там, это, возле Москвы началось затмение
💔1
Блог* pinned «Там, это, возле Москвы началось затмение»
Obligatory
🤩3🤔1💔1
#prog #rust #rustasync #article

An Unfortunate Experience with Rust

I consider myself to be pretty experienced in Rust. I’ve been using Rust in personal projects since late 2016 and professionally since early 2021. I’ve prepared internal presentations to teach coworkers about borrow checking and about async programming. However, even I still occasionally run into issues fighting the Rust compiler, and the following is a series of particularly unfortunate issues I ran into at work this week.
💔1
#prog #rust #meme #моё

Когда нажимаешь Ctrl+. > Implement missing trait members
👍6🤨4🤔2💔1
#prog #rust #моё

Допустим, есть трейт, в интерфейсе которого желательно иметь опциональный метод для оптимизации. Чтобы разговор был более предметным, покажу конкретный пример для иллюстрации излагаемого далее:

trait Push<T> {
fn push_single(&mut self, x: T);
}

impl<T> Push<T> for Vec<T> {
fn push_single(&mut self, x: T) {
self.push(x);
}
}

use std::sync::mpsc::Sender;

impl<T> Push<T> for Sender<T> {
fn push_single(&mut self, x: T) {
self.send(x).unwrap();
}
}

Некоторые из типов, которые реализуют Push, могут зарезервировать память под n следующих элементов (Vec<T>), но не все (Sender<T>). Хотелось бы иметь метод reserve_for_push для этого, но как его интегрировать?

===

Первый способ: добавить метод с реализацией по умолчанию, которая ничего не делает:

trait Push<T> {
fn push_single(&mut self, x: T);
fn reserve_for_push(&mut self, n: usize) {}
}

impl<T> Push<T> for Vec<T> {
// ...
fn reserve_for_push(&mut self, n: usize) {
self.reserve(n);
}
}

// реализация для `Sender<T>` без изменений

Это простой и рабочий метод. Его использование выглядит так:

fn push_vec<T, P: Push<T>>(p: &mut P, xs: Vec<T>) {
p.reserve_for_push(xs.len());
for x in xs {
p.push_single(x);
}
}

С одной стороны, это изменение обратно-совместимо. С другой стороны, так как оно обратно-совместимо, существующие реализации, скорее всего, не будут обновлены для того, чтобы переопределить реализацию по умолчанию (я смотрю на тебя, Clone::clone_from). Также вызывающая сторона не может выяснить, поддерживает ли тип этот метод или нет.

===

Второй способ: дополнительный трейт и специализация:

trait Push<T> { ... }

trait ReserveForPush<T>: Push<T> {
fn reserve_for_push(&mut self, n: usize);
}

impl<T> ReserveForPush<T> for Vec<T> {
fn reserve_for_push(&mut self, n: usize) {
self.reserve(n);
}
}

// остальной код тот же

Вызывающая сторона, которая желает воспользоваться возможной оптимизацией, может сделать это явно через введение трейта, который является точкой специализации:

#![feature(specialization)] // <-- с min_specialization не работает

...

trait ReserveForPushSpec<T>: Push<T> {
fn maybe_reserve(&mut self, n: usize);
}

impl<T, P> ReserveForPushSpec<T> for P
where
P: Push<T>,
{
// неспециализированная реализация
default fn maybe_reserve(&mut self, n: usize) {}
}

impl<T, P> ReserveForPushSpec<T> for P
where
P: ReserveForPush<T>,
{
fn maybe_reserve(&mut self, n: usize) {
self.reserve_for_push(n);
}
}

Теперь вызывающая сторона может либо требовать ReserveForPush и вызывать reserve_for_push для гарантированного наличия метода, либо ReserveForPushSpec и вызывать maybe_reserve для негарантированного наличия оптимизированного метода, но при этом автоматического его использования при его наличии:

fn push_vec<T, P>(p: &mut P, xs: Vec<T>)
where
P: ReserveForPushSpec<T>,
{
p.maybe_reserve(xs.len());
for x in xs {
p.push_single(x);
}
}

fn push_vec_super_duper_fast<T, P>(p: &mut P, xs: Vec<T>)
where
P: ReserveForPush<T>,
{
p.reserve_for_push(xs.len());
for x in xs {
p.push_single(x);
}
}

Разумеется, из-за специализации это сейчас работает лишь на nightly. С другой стороны, это изменение обратно-совместимо.
4👍1👎1💔1
Третий способ: вынос метода как значения.

Мы не можем сделать опциональный метод как таковой, но мы можем сделать ассоциированную константу типа Option — в частности, оборачивающий тип метода на Self:

type ReserveForPush<P> = fn(&mut P, usize);

trait Push<T> {
fn push_single(&mut self, x: T);
const RESERVE_FOR_PUSH: Option<ReserveForPush<Self>>;
}

impl<T> Push<T> for Vec<T> {
fn push_single(&mut self, x: T) {
self.push(x);
}
const RESERVE_FOR_PUSH: Option<ReserveForPush<Self>> =
Some(Self::reserve);
}

impl<T> Push<T> for Sender<T> {
fn push_single(&mut self, x: T) {
self.send(x).unwrap();
}
const RESERVE_FOR_PUSH: Option<ReserveForPush<Self>> = None;
}

Вызывающий код теперь может проверять в рантайме наличие метода и вызывать его:

fn push_vec<T, P>(p: &mut P, xs: Vec<T>)
where
P: Push<T>,
{
if let Some(f) = P::RESERVE_FOR_PUSH {
f(p, xs.len());
}
for x in xs {
p.push_single(x);
}
}

Из недостатков: не обратно-совместимо, нельзя статически требовать наличия метода, трейт теперь не object-safe.

===

Rust всё ещё очень слаб с обращением с константами на уровне сигнатур. Но он работает с проверками на уровне типов! Так что возможен также и

Четвёртый способ

, а именно — вынос Option на уровень типов.

Для начала определим сам type-level Option:

mod ty_opt {
// Rust не поддерживает перечисления на уровне типов,
// поэтому сделаем две альтернативы и объединим их
// через sealed trait
mod private {
pub trait Sealed {}
impl<T> Sealed for super::Some<T> {}
impl Sealed for super::None {}
}

pub struct Some<T>(pub T);
pub struct None;

pub trait TypeOption<T>: private::Sealed {
// нам нужно как-то в итоге заматчиться
// по значению, поэтому предоставим
// метод для унификации
fn unlift(self) -> Option<T>;
}

impl<T> TypeOption<T> for Some<T> {
fn unlift(self) -> Option<T> {
::core::option::Option::Some(self.0)
}
}

impl<T> TypeOption<T> for None {
fn unlift(self) -> Option<T> {
::core::option::Option::None
}
}
}

Теперь внесём этот type-level Option в интерфейс Push:

type ReserveForPush<P> = fn(&mut P, usize);

trait Push<T> {
fn push_single(&mut self, x: T);
type ReserveForPushOpt: ty_opt::TypeOption<ReserveForPush<Self>>;
const RESERVE_FOR_PUSH_OPT: Self::ReserveForPushOpt;
}

И реализуем Push<T> для всё тех же типов:

impl<T> Push<T> for Vec<T> {
fn push_single(&mut self, x: T) {
self.push(x);
}
type ReserveForPushOpt = ty_opt::Some<ReserveForPush<Self>>;
const RESERVE_FOR_PUSH_OPT: Self::ReserveForPushOpt
= ty_opt::Some(Self::reserve);
}

impl<T> Push<T> for Sender<T> {
fn push_single(&mut self, x: T) {
self.send(x).unwrap();
}
type ReserveForPushOpt = ty_opt::None;
const RESERVE_FOR_PUSH_OPT: Self::ReserveForPushOpt
= ty_opt::None;
}

Теперь мы можем сделать общую функцию, которая по возможности использует этот опциональный метод:

use ty_opt::TypeOption;

fn push_vec<T, P>(p: &mut P, xs: Vec<T>)
where
P: Push<T>,
{
if let Some(f) = P::RESERVE_FOR_PUSH_OPT.unlift() {
f(p, xs.len());
}
for x in xs {
p.push_single(x);
}
}

И у нас всё ещё есть возможность требовать наличие метода статически:

use ty_opt::TypeOption;

fn push_vec_super_duper_fast<T, P>(p: &mut P, xs: Vec<T>)
where
P: Push<T, ReserveForPushOpt = ty_opt::Some<ReserveForPush<P>>>,
{
let ty_opt::Some(f) = P::RESERVE_FOR_PUSH_OPT;
f(p, xs.len());
for x in xs {
p.push_single(x);
}
}

При желании можно даже гарантировать отсутствие метода, но мне сложно представить ситуацию, когда это было бы нужно.

Из недостатков:
* ломает обратную совместимость
* трейт не object-safe
* для общего случая нужно импортировать трейт ради метода unlift
* боже зачем вам это

Не как всегда, в этот раз без гиста.
👍7🤯1💔1
Forwarded from Протестировал (Sergey Bronnikov)
Помните SETI@home? Проект анализировал радиосигнал из космоса для поиска внеземного разума используя для этого вычислительные ресурсы добровольцев. По аналогии с SETI@Home есть проект Fuzzing@Home, в котором можно запускать фаззинг проектов, добавленных в OSS Fuzz, в обычном веб браузере. Это возможно благодаря компиляции в WebAssembly. Попробуйте сами - https://fuzzcoin.gtisc.gatech.edu:8000/
👍5💔1
DELO (18+)
17 октября 2022 года состоялись общественные слушания по принятию законопроекта, полностью запрещающего "пропаганду" ЛГБТ+. На следующую неделю запланировано первое чтение. Депутаты Госдумы высказались, что ЛГБТ – оружие Запада, угрожающее государственной…
Госдума единогласно приняла в I чтении пакет законопроектов о запрете «пропаганды нетрадиционных сексуальных отношений».

ЕДИНОГЛАСНО, БЛЯТЬ. Какие же конченые мрази.
🤬10💔5💩3😁1