1.84K subscribers
3.27K photos
130 videos
15 files
3.55K links
Блог со звёздочкой.

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

Небольшое прикольное комьюнити: @decltype_chat_ptr_t
Автор: @insert_reference_here
Download Telegram
Блог*
💅
💅
5🎉3🤔2👎1
Forwarded from kkkkkkkkkkkkkkkkkkkkkk
🔥181
Forwarded from pɹɐɥʎɐʇoq
😁29
Forwarded from TrapsWorld
4😁3🤔1
#prog #rust

В стандартной библиотеке есть тип core::alloc::Layout. Главное его назначение — описывать форму запроса памяти у аллокатора (см., например, alloc::alloc::alloc). Одного лишь размера для подобных функций недостаточно, поскольку для корректного обращения по указателю нужно также, чтобы указатель был выравнен. Можно считать, что Layout состоит из двух usize — и конструктор from_size_align, который эти два usize и принимает, только укрепляет эти подозрения. Посмотрим, как это выглядит на практике, проверив размеры:

println!("{}", size_of::<usize>());
println!("---");
println!("{}", size_of::<Layout>());
println!("{}", size_of::<Option<Layout>>());
println!("{}", size_of::<Option<Option<Layout>>>());

Вывод:

8
---
16
16
24

Ага, Layout занимает столько же места, сколько и два usize... Стоп, а почему Option<Layout> занимает столько же места, сколько и Layout? Выходит, там внутри что-то другое, раз нашлось место для тега. И действительно, если мы откроем исходники из документации, то увидим, что Layout выглядит так (за вычетом комментариев и аннотаций):

pub struct Layout {
size_: usize,
align_: NonZeroUsize,
}

Логично. Выравнивание никогда не может быть равно нулю — разумно это значение хранить в NonZeroUsize. Также логично, что дважды вложенный Option занимает уже больше места — места для дискриминанта в нишах Layout хватает лишь на одно дополнительное значение.

В принципе, на этом можно было бы и закончить, но давайте запустим этот же код, выводящий размеры, на nightly (на момент написания — версия 2022-06-09 420c970cb1edccbf60ff):

8
---
16
16
16

Внезапно вложенный Option занимает столько же байтов, сколько и Layout. Более того, если мы сделаем такой тип:

enum ManyVariants {
_Layout(Layout),
_Variant1,
// опущено 98 вариантов
_Variant100,
}

и выведем его размер, то снова получим 16! В чём же дело?

Откроем исходники. Поле align имеет тип ValidAlign, который лежит в core::mem. Тип ValidAlign является одноместной кортежной структурой с #[repr(transparent)] с полем типа ValidAlignEnum. ValidAlignEnum имеет определение, зависящее от битности целевой архитектуры:

#[cfg(target_pointer_width = "16")]
type ValidAlignEnum = ValidAlignEnum16;

#[cfg(target_pointer_width = "32")]
type ValidAlignEnum = ValidAlignEnum32;

#[cfg(target_pointer_width = "64")]
type ValidAlignEnum = ValidAlignEnum64;

Приведём определение, скажем, ValidAlignEnum16 (самого маленького из типов):

#[derive(Copy, Clone)]
#[repr(u16)]
enum ValidAlignEnum16 {
_Align1Shl0 = 1 << 0,
_Align1Shl1 = 1 << 1,
_Align1Shl2 = 1 << 2,
_Align1Shl3 = 1 << 3,
_Align1Shl4 = 1 << 4,
_Align1Shl5 = 1 << 5,
_Align1Shl6 = 1 << 6,
_Align1Shl7 = 1 << 7,
_Align1Shl8 = 1 << 8,
_Align1Shl9 = 1 << 9,
_Align1Shl10 = 1 << 10,
_Align1Shl11 = 1 << 11,
_Align1Shl12 = 1 << 12,
_Align1Shl13 = 1 << 13,
_Align1Shl14 = 1 << 14,
_Align1Shl15 = 1 << 15,
}

ValidAlignEnum32
и ValidAlignEnum64 имеют аналогичные определения, только вариантов побольше. Конструкторы ValidAlign принимают на вход usize и вызывают на нём transmute в ValidAlignEnum.

Итого мы получаем, что ValidAlign — это тип, который имеет тот же размер, что и usize, но в качестве валидных битовых паттернов имеет только степени двойки. Помимо кучи ниш, которые можно использовать для дискриминанта, это позволяет miri проверять, что в небезопасных конструкторах Layout — не проверяющих выравнивание — аргумент align действительно является степенью двойки, причём просто за счёт проверки корректности представления типов.

И напоследок. Судя по PR, который это внёс, это изменение будет уже буквально в следующей стабильной версии, 1.62. Ну и, так как тип ValidAlign полезен, возможно, в будущем этот тип попадёт в публичное API std.
👍5
Forwarded from Санечка Ъысь (ǺʎĔĶ₡Ǻ)
4🔥3😁2
#prog #rust #rustlib #article

Announcing error-stack, a context-aware error library for Rust that supports arbitrary attached user data

Вы не поверите, но ещё одна Rust-библиотека для ошибок. Вместе со статьёй, в которой описывается мотивация для её создания и дизайна
👍2🎉1
#prog #rust #serde

В serde_json есть тип Value, который может представить любое валидное JSON-значение. Есть парочка вещей, которые не столь известны и стоят упоминания.

1. Value, а также обе разновидности ссылок на него могут быть сравнены на равенство со всеми примитивными числами, bool, str и String.

2. В Value можно сконвертировать из множества различных типов, которые могут входить в его состав, а также составлять из итератора по элементам и итератора по элементам вместе с ключами.

3. Value можно индексировать как строками, так и числовыми индексами, при этом в случае, если индексировать значение таким образом нельзя, иммутабельное индексирование вместо паники возвращает ссылку на Value::Null.

4. Если вам нужно достать глубоко вложенное значение, можно вместо череды индексаций или вызовов get использовать метод pointer/pointer_mut, которые достают значение по указанному строковому пути:

let data = json!({
"x": {
"y": ["z", "zz"]
}
});

assert_eq!(data.pointer("/x/y/1").unwrap(), &json!("zz"));
assert_eq!(data.pointer("/a/b/c"), None);

5. Value и &Value реализуют Deserialize. Это значит, что если у вас есть разобранный JSON в неструктурированном виде, вы можете сконвертировать его в свои типы, реализующие Deserialize — причём в случае со ссылкой у вас при этом останется изначальный JSON. Так можно пробовать десериализовывать поочерёдно в несколько типов, и это может оказаться дешевле, чем парсить всё с нуля.

6. У Value есть собрат RawValue. Этот тип фактически представляет собой синтаксически валидный JSON, который хранится в виде слайса на входную строку. Его можно использовать для того, чтобы проводить манипуляции над JSON и при этом не хранить разобранный JSON в памяти целиком:

use serde::{Deserialize, Serialize};
use serde_json::{Result, value::RawValue};

#[derive(Deserialize)]
struct Input<'a> {
code: u32,
#[serde(borrow)]
payload: &'a RawValue,
}

#[derive(Serialize)]
struct Output<'a> {
info: (u32, &'a RawValue),
}

// Efficiently rearrange JSON input containing separate "code" and "payload"
// keys into a single "info" key holding an array of code and payload.
//
// This could be done equivalently using serde_json::Value as the type for
// payload, but &RawValue will perform better because it does not require
// memory allocation. The correct range of bytes is borrowed from the input
// data and pasted verbatim into the output.
fn rearrange(input: &str) -> Result<String> {
let input: Input = serde_json::from_str(input)?;

let output = Output {
info: (input.code, input.payload),
};

serde_json::to_string(&output)
}

fn main() -> Result<()> {
let out = rearrange(r#" {"code": 200, "payload": {}} "#)?;

assert_eq!(out, r#"{"info":[200,{}]}"#);

Ok(())
}
👍10
Forwarded from Nano
😁252👎1
В так называемых "Чистых прудах" всего один пруд, и не особо чистый 😒
😢93😁1
#quotes

(по поводу открытия "Вкусно и точка")

— Это ж насколько нужно ждать открытия нового ресторана, чтобы в его честь зафигачить государственный праздник?
😁71
😁9
Forwarded from Anton
Как я представляю @insert_reference_here когда он агрится в чате
😁83
Блог*
#science #article Прекрасная интерактивная статья, рассказывающая о том, как работает GPS, с поэтапным учётом всё новых и новых обстоятельств. (thanks @jemalloc)
#mechanics #article

Статья от того же автора. Покрывает не только часть, отвечающую за равномерный ход часов, но и также устройство механизма для показывания дня месяца, устройство головки часов, позволяющей заводить, корректировать время и день одной деталью, и механизм для автоподзавода часов. Крайне рекомендую к прочтению, часы — это восхитительный механизм.

(thanks @theLastOfCats)
5🤯3🔥1