Size: a a a

2020 January 25
Блог*
придумал хаскель-версию
источник
Блог*
источник
Блог*
#meme
источник
Блог*
#prog #rust #amazingopensource

Ссылка на итоговый код: https://github.com/Nachasic/machine/blob/raylib/src/theme/mod.rs

https://t.me/rustlang_ru/271888
источник
Блог*
dereference_pointer_there
#prog #rust #моё
В конце этой заметки я сказал, что планирую расширить код до поддержки impl BorrowMut<VecDeque<T>>. Теперь я понимаю, что это несколько неосмотрительно: код в unsafe полагается на то, что адрес, по которому лежат данные, не меняется. В случае impl BorrowMut такой гарантии уже нет. Для доказательства того, что подобный вариант является unsound, предположим, что MutPair уже реализовал подобный функционал (это изменение я, с вашего позволения, опущу, потому что это чисто механическое изменение кода) и рассмотрим следующий тип:

#[derive(Default)]
struct DeqWrapper<T> {
   inner: VecDeque<T>,
}

Для него можно написать следующие реализации Borrow и BorrowMut:

impl<T> Borrow<VecDeque<T>> for DeqWrapper<T> {
   fn borrow(&self) -> &VecDeque<T> {
       &self.inner
   }
}

impl<T> BorrowMut<VecDeque<T>> for DeqWrapper<T> {
   fn borrow_mut(&mut self) -> &mut VecDeque<T> {
       self.inner.clear();
       &mut self.inner
   }
}

Да, это отвратительно, да, так никто (я надеюсь) не пишет. Но принципиально нас ничего от этого не ограждает. Хочу отметить, что код выше не содержит unsafe.

Теперь попытаемся использовать данный тип:

let wrapper = DeqWrapper::<i32>::default();
wrapper.inner.push_back(0);
wrapper.inner.push_back(1);
let mut mut_pair = MutPair::new(wrapper).unwrap(); // (1)
let _ = mut_pair.get(); // (2)

Что тут происходит? В (1) мы делаем внутри MutPair::new проверку длины дека. Так как при этом мы используем .borrow(), DeqWrapper даёт ссылку на поле inner, длина которого как раз достаточна, поэтому MutPair возвращает Ok и .unwrap() не паникует. В (2) мы вызываем .borrow_mut(), из дека удаляется данные, MutPair::get использует get_mut, предполагая, что данные есть, и — вуаля! — мы получаем ссылку на неинициализированные данные! Что является UB в Rust.

Хочу особо отметить, что мы получили UB, не написав (как пользователь) unsafe-код и не вызвав unsafe-код напрямую, поэтому наш код unsound.
#prog #rust #моё
Сообщаю, что данную проблему я решил, воспользовавшись несколько модифицированной версией идеи №3. Ссылка на гист та же самая, но для удобства я её продублирую: https://gist.github.com/AnthonyMikh/bb41179b20938ba329c3d411ddc1c679 (чтобы посмотреть на то, как файл выглядел в изначальном посте, откройте вторую версию). В данный момент MutPair имеет следующий вид:
   pub struct Original;
   pub struct View;

   pub struct MutPair<T, Deq = VecDeque<T>, Idx = usize, Kind = Original> {
       inner: Deq,
       first: Idx,
       _type: PhantomData<(T, Kind)>,
   }
Такое замысловатое определение позволяет расширить возможности, предоставляемые API.

1) Каким образом решена проблема злонамеренного BorrowMut? Очень просто: публичные методы дают возможность создать только MutPair с Deq, являющимся VecDeque<T> и &mut VecDeque<T>, поэтому все сложности, связанные с нестабильностью адресов слайсов, отпадают.
2) Почему для индексов не используется usize? Дело в том, что у владеющего MutPair теперь есть два метода, которые создают MutPair, держащие ссылку на дек. Один из них (создаваемый методом view) работает, как ожидается, а второй, создаваемый методом linked_view, при вызове методов step_right/step_left также меняет позицию изначального MutPair. Для того, чтобы поддержать этот случай использования, имеется возможность использовать как usize, так и &mut usize.
3) Зачем вообще нужен параметр Kind? Дело в том, что, как я уже подчёркивал, memory safety данного кода существенным образом опирается на невозможность поменять длину дека. Как для владеющего, так и для заимствующего MutPair имеет смысл операция into_inner, которая отдаёт дек, но безусловное разрешение подобного метода даёт возможность написать некорректный код с использованием безопасного API (я, к своему стыду, изначально допустил эту ошибку):
let deque = ...;
let mut owning_pair = MutPair::try_from(deque).unwrap();
let mut pair = owning_pair.view();
let mut deque = view.into_inner();
deque.clear();
let _ = owning_pair.get(); // Hello UB!
Таким образом, into_inner для заимствующего MutPair безопасен только при условии, что объект построен из ссылки на дек непосредственно, а не получен из владеющего MutPair. Именно это ограничение и обеспечивается четвёртым ти́повым параметром: методы view/linked_view возвращают MutPair с Kind = View, в то время как метод into_inner определён лишь для MutPair с Kind = Original.
источник
2020 January 26
Блог*
dereference_pointer_there
#prog #rust #моё
Сообщаю, что данную проблему я решил, воспользовавшись несколько модифицированной версией идеи №3. Ссылка на гист та же самая, но для удобства я её продублирую: https://gist.github.com/AnthonyMikh/bb41179b20938ba329c3d411ddc1c679 (чтобы посмотреть на то, как файл выглядел в изначальном посте, откройте вторую версию). В данный момент MutPair имеет следующий вид:
   pub struct Original;
   pub struct View;

   pub struct MutPair<T, Deq = VecDeque<T>, Idx = usize, Kind = Original> {
       inner: Deq,
       first: Idx,
       _type: PhantomData<(T, Kind)>,
   }
Такое замысловатое определение позволяет расширить возможности, предоставляемые API.

1) Каким образом решена проблема злонамеренного BorrowMut? Очень просто: публичные методы дают возможность создать только MutPair с Deq, являющимся VecDeque<T> и &mut VecDeque<T>, поэтому все сложности, связанные с нестабильностью адресов слайсов, отпадают.
2) Почему для индексов не используется usize? Дело в том, что у владеющего MutPair теперь есть два метода, которые создают MutPair, держащие ссылку на дек. Один из них (создаваемый методом view) работает, как ожидается, а второй, создаваемый методом linked_view, при вызове методов step_right/step_left также меняет позицию изначального MutPair. Для того, чтобы поддержать этот случай использования, имеется возможность использовать как usize, так и &mut usize.
3) Зачем вообще нужен параметр Kind? Дело в том, что, как я уже подчёркивал, memory safety данного кода существенным образом опирается на невозможность поменять длину дека. Как для владеющего, так и для заимствующего MutPair имеет смысл операция into_inner, которая отдаёт дек, но безусловное разрешение подобного метода даёт возможность написать некорректный код с использованием безопасного API (я, к своему стыду, изначально допустил эту ошибку):
let deque = ...;
let mut owning_pair = MutPair::try_from(deque).unwrap();
let mut pair = owning_pair.view();
let mut deque = view.into_inner();
deque.clear();
let _ = owning_pair.get(); // Hello UB!
Таким образом, into_inner для заимствующего MutPair безопасен только при условии, что объект построен из ссылки на дек непосредственно, а не получен из владеющего MutPair. Именно это ограничение и обеспечивается четвёртым ти́повым параметром: методы view/linked_view возвращают MutPair с Kind = View, в то время как метод into_inner определён лишь для MutPair с Kind = Original.
И да, я опять немного побрюзжу: этот код было бы проще написать, будь у VecDeque адаптер, гарантирующий стабильные адреса. Я думал о том, чтобы написать такой адаптер самому, но потом понял, что с нормальными гарантиями такой адаптер может написать только автор кода VecDeque, который знает внутреннее устройство и может точно сказать, какие методы не перемещают данные — собственно, в этом смысле сейчас безопасность кода базируется на допущениях, который верны сейчас, но в силу отсутствия явных контрактов могут стать неверными в будущих релизах std
источник
Блог*
#meme со звёздочкой
источник
Блог*
Переслано от Kai Ren
источник
Блог*
#quotes
источник
Блог*
Москва лычкам не верит
источник
2020 January 27
Блог*
источник
Блог*
#prog #rust
Посмотрел, что в Rust есть для линейной алгебры. Видимо, ничего лучше nalgebra таки нет
источник
Блог*
#meme
Годнота-то какая
источник
Блог*
источник
2020 January 28
Блог*
#prog

Выглядит так, как будто катсцена подлагивает, лол
источник
Блог*
Люди часто недопонимают, зачем вся эта возня с ИИ-фильтрами для фото и видео. Вот вам конкретный пример: советские кукольные и пластилиновые мультфильмы старались делать очень натуралистично, но т.к. процесс передвигания и анимации кукол очень медленный, все равно получалось 3-7 кадров-положений в секунду. Ниже по ссылке результат работы «фильтра», достроившего промежуточные положения кукол, так чтобы получились честные 50 кадров в секунду. И местами это прямо чудовищно натурально выглядит. Да, на примере всеми любимого Чебурашки. Кто Чебу знал - тот его не позабудет!

Up! Если недостаточно плавно - смотрите чтобы было 720p, ютуб срезает FPS на более низких разрешениях https://youtu.be/-VELzks3a8U
источник
Блог*
#meme
источник
Блог*
источник
2020 January 29
Блог*
#science
источник
Блог*
Немножко географии вам в ленту:

Так, наверное, представляют себе Землю киты.
источник