Как стать автором
Обновить

Комментарии 14

А зачем Box, а не RefCell? Мне кажется, у Box какая-то другая семантика, там же предполагается выделение на куче, нет?

Это разные совершенно задачи, ты не сможешь взять и создать RefCell<dyn Trait>, рефцел это скорее эдакий однопоточный мьютекс, который переносит все гарантии BC в рантайм.

struct Box забыли процитировать — хотя и очевидно, что в нем.

M: AsRef<[u8]> + AsMut<[u8]>,

Учитывая, что .len() можно вызвать и на &mut [u8], ограничение AsRef<[u8]> излишне.


        assert!(layout.size() > 0);
        assert!(layout.size() <= mem.as_ref().len());

        unsafe {
            let ptr = NonNull::new(mem.as_mut().as_mut_ptr()).unwrap();
            // ...

А вот так, пожалуйста, делать не надо, у нас нет никакой гарантии, что .as_ref() и .as_mut() возвращают одно и то же:


struct VecPair<T>(Vec<T>, Vec<T>);

impl<T> AsRef<[T]> for VecPair<T> {
    fn as_ref(&self) -> &[T] {
        &self.0
    }
}

impl<T> AsMut<[T]> for VecPair<T> {
    fn as_mut(&mut self) -> &mut [T] {
        &mut self.1
    }
}

Так что в данной ситуации правильным будет вызвать .as_mut() ровно один раз и в дальнейшем только этот указатель и использовать.


// SAFETY: This code relies on the fact that this method will be inlined.

А вот это совсем плохо, код совершенно точно теперь unsound в дебаге и наверняка unsound и в релизе, поскольку гарантии RVO в Rust нету до сих пор. Собственно, именно для этих целей и сделали Pin и MaybeUninit.


Ещё надо посмотреть код, возможно, найду ещё огрехи.

Насчет mut да, такой кейс в уме не держал, хотя он и довольно странный, но не до такой степени, чтобы он все мог сломать.


А поводу unsound да, я думал, но мне кажется, что в данном случае Pin не поможет, но в 99% случаев это все касается условного случая Box<Option<dyn SerialWrite>, [u8; 32]>, так что можно попробовать написать специализацию для такого случая, которая бы позволяла копировать объект только в уже сконструированный Box.

Насчет mut да, такой кейс в уме не держал, хотя он и довольно странный, но не до такой степени, чтобы он все мог сломать.

А исправить надо бы, поскольку ломает библиотеку при помощи safe кода.


А поводу unsound да, я думал, но мне кажется, что в данном случае Pin не поможет, но в 99% случаев это все касается условного случая...

Это не решает ту проблему, что Box можно переместить, потенциально переместив так же и память, в которой размещаются данные, и таким образом инвалидировать ссылки. Честно, я не совсем понимаю, что мешает вместо обобщённого типа M хранить просто &mut [u8].

Скорее всего это просто артефакты overengineering. Потом внимательно это все переосмыслю.

Вопрос — а не лучше ли было бы тогда взять какой-нибудь https://docs.rs/enum_dispatch/0.3.7/enum_dispatch/ и заменить все dyn Trait на энумы? Они на стеке аллоцируются без всякой магии, да ещё и шустрее работают.

Он не расширяем, а если мы хотим сделать фасад потипу крейта log, то вариант с енамом точно не вариант.

Нерясшираем когда? Есть случаи когда в компайл тайм мы не знаем все возможные реализации?

Например когда они в разных крейтах? Или хочется новую реализацию для своей кастомной борды?

Ну мы же про эмбед. Там обычно какой-то оконечный апп, который все знает. Про все используемые реализаии и т.п. Нет никаких проблем их в один энум запихнуть вроде.


Я могу ошибаться, но в том информации что есть кажется что энум снимает все вопросы. А энум диспатч крейт чутка упрощает вопрос написания оберток руками.

Было бы хорошо увидеть на реальном примере использование данной библиотеки.
Чем мне нравится Rust: он явно показывает, сколько всего скрывается за простыми C-конструкциями.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории