Справочная информация: Я пытаюсь избежать использования Mutex
/ RefCell
/ Option
dance в обработчике прерываний для встроенной системы. Я не хочу использовать кучу (и я не думаю, что это необходимо, но не стесняйтесь показывать мне неправильно). Я не могу использовать std
. Я посмотрел на cortex-m-rtfm
, и это аккуратно, но довольно агрессивно. И вообще, это немного учебное упражнение. Если это сработает, я бы предпочел использовать замыкания для обработки прерываний, так как он кажется ближе к голой Rust. Я новичок в Rust - я работаю с ним около недели. Я попробовал много различных вариантов этого, поскольку я прочитал документацию, перечитал книгу Rust, сообщения в блоге и т. Д.,. Я не могу понять, что я делаю здесь неправильно.
Вот пример кода. Вопросы для следования:
use core::cell::UnsafeCell;
pub struct Handler<'a> {
h: UnsafeCell<&'a dyn FnMut()>,
}
impl<'a> Handler<'a> {
pub fn new<T: FnMut()>(closure: &'a dyn FnMut()) -> Self {
Handler {
h: UnsafeCell::new(closure),
}
}
pub fn call(&self) {
unsafe {
// NOTE: type returned by `self.h.get()` is
// `*mut &'a (dyn std::ops::FnMut() + 'a)`
let h: *mut FnMut() = self.h.get();
h();
}
}
}
unsafe impl<'a> Sync for Handler<'a> {}
fn default_handler() {}
static HANDLER: Handler = Handler {
h: UnsafeCell::new(&default_handler),
};
#[test]
fn call_handler() {
let mut a: u32 = 0;
let foo = move || a += 1;
let mut handler = Handler::new(&foo);
handler.call();
a += 2; // Shouldn't this cause compilation failure because `a`
// was moved into the closure above?
assert_eq!(a, 1);
}
Error
error[E0618]: expected function, found `*mut dyn std::ops::FnMut()`
--> src/lib.rs:19:13
|
18 | let h: *mut FnMut() = self.h.get();
| - `*mut dyn std::ops::FnMut()` defined here
19 | h();
| ^--
| |
| call expression requires function
error[E0277]: expected a `std::ops::Fn<()>` closure, found `(dyn std::ops::FnMut() + 'a)`
--> src/lib.rs:18:35
|
18 | let h: *mut FnMut() = self.h.get();
| ^^^^^^^^^^^^ expected an `Fn<()>` closure, found `(dyn std::ops::FnMut() + 'a)`
|
= help: the trait `std::ops::Fn<()>` is not implemented for `(dyn std::ops::FnMut() + 'a)`
= note: wrap the `(dyn std::ops::FnMut() + 'a)` in a closure with no arguments: `|| { /* code */ }
= note: required because of the requirements on the impl of `std::ops::FnMut<()>` for `&'a (dyn std::ops::FnMut() + 'a)`
= note: required for the cast to the object type `dyn std::ops::FnMut()`
Объяснение: Надеюсь, мои намерения очевидны: я настрою замыкание на HANDLER
в main
, прежде чем войти в цикл занятости, который никогда не завершается. Замыкание непостоянно заимствует материал, необходимый обработчику прерывания для своей работы, предотвращая его использование в других контекстах. Поскольку main
никогда не завершается, выделенные в стеке переменные внутри него фактически равны 'static
, поэтому не должно быть проблем со ссылками на них в любой точке после установки замыкания. Сам обработчик прерываний (не показан) просто вызывает замыкание для выполнения своей работы. Чтобы обойти хранение замыкания (которое не Sized
) в статическом состоянии, мне нужно сохранить ссылку на замыкание. UnsafeCell
не обязательно требуется, но поскольку я использую FnMut()
, его референты должны быть изменяемыми, что приводит к statics require immutable values
при попытке установить default_handler
во время создания static mut HANDLER
.
Вопросы:
После публикации этот код не компилируется. По какой-то причине
присвоение let h: *mut FnMut() = self.h.get()
говорит мне, что это
expected an Fn<()> closure, found (dyn std::ops::FnMut() + 'a)
. Ну, я знаю, почему он нашел этот тип. Но почему он ожидал Fn<()>
?
В тесте call_handler
, почему эта компиляция вообще? foo
замыкание move
s его захваченная переменная a
. Как можно изменить его после определения замыкания? Когда я попробовал этот код с типом, который не реализует Copy
, он терпит неудачу, как и ожидалось, но я откровенно удивлен, что эта черта имеет значение. Разве это не то, что foo
сейчас владеет a
?
Я понимаю, что есть потенциальные проблемы с изменением HANDLER.h
в произвольных точках в коде, но я буду беспокоиться о том, чтобы решить их позже, после того, как появится жизнеспособное подтверждение концепции.