Я пытаюсь создать следующий дизайн для закрепленной самореференциальной структуры:
use std::future::Future;
use std::marker::PhantomPinned;
use std::pin::Pin;
struct Data {}
struct DataResult {}
async fn my_async(data: &Data) -> DataResult {
todo!()
}
/// Container for a pinned struct, where in inner future
/// contains a reference to self.data.
struct MyAsyncContainer<F: Future<Output = DataResult>> {
data: Data,
fut: Option<F>,
unpin: PhantomPinned,
}
impl<F: Future<Output = DataResult>> MyAsyncContainer<F> {
fn new(data: Data) -> Self {
Self {
data,
fut: None,
unpin: PhantomPinned,
}
}
fn start<'a, A>(self: Pin<&'a mut Self>, func: A)
where
A: FnOnce(&'a Data) -> F,
{
let this = unsafe { self.get_unchecked_mut() };
// ????
let fut = func(&this.data);
// self is pinned, but fut is not (yet),
// so this should be safe
this.fut = Some(fut);
}
}
fn main() {
let data = Data {};
let mut container = MyAsyncContainer::new(data);
let pinned = unsafe { Pin::new_unchecked(&mut container) };
pinned.start(my_async);
}
Функция start
компилируется, но когда я пытаюсь скомпилировать функцию main
, я получить следующую ошибку:
error[E0597]: `container` does not live long enough
--> src/main.rs:48:46
|
48 | let pinned = unsafe { Pin::new_unchecked(&mut container) };
| ^^^^^^^^^^^^^^ borrowed value does not live long enough
49 | pinned.start(my_async);
50 | }
| -
| |
| `container` dropped here while still borrowed
| borrow might be used here, when `container` is dropped and runs the destructor for type `MyAsyncContainer<impl std::future::Future>`
Есть ли способ заставить самоссылочную структуру, подобную этой, работать правильно?
Я действительно рассматривал просто использование функции asyn c, например, так :
async fn my_async(data: &Data) -> DataResult {
todo!()
}
async fn data_wrapper(data: Data) -> DataResult {
my_async(&data).await
}
Проблема в том, что мне нужно, чтобы будущий тип был именуемым, потому что он встроен в другую структуру как часть большой библиотеки asyn c.
У меня есть читать Как использовать структуру Pin с само-ссылочными структурами? но это не ответило на мой вопрос, хотя пункты о необработанных указателях были полезны. Ключевое отличие, которое, я думаю, не охватывается этими примерами, - это функция my_async
, которая требует для получения части данных по ссылке. Я не могу передать указатель на него, и мне не ясно, как перевести указатель на ссылку с правильным временем жизни. В частности, необходимо запретить my_async
работу на &'static data
и утечку ссылки.