如何固定 RefCell 内容?
how to pin RefCell contents?
我有一个结构 MyAsyncStream 和 tokio::io::AsyncWrite 实现:
impl<S: AsyncRead + AsyncWrite + Unpin> AsyncWrite for MyAsyncStream<S> {
fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<Result<usize>> {
....
}
我还有 MyAsyncStreamWrapper:
struct MyAsyncStreamWrapper{inner: MyAsyncStream}
现在我想为 MyAsyncStreamWrapper 实现 AnotherTrait 特征,方法如下:
impl AnotherTrait for MyAsyncStreamWrapper {
fn poll_send_to<B>(self: Pin<&Self>, cx: &mut Context<'_>, buf: &[u8], addr: B,) -> Poll<Result<usize, Self::Error>> {
Pin::new(&mut self.inner).poll_write(cx, buf)
}
....
}
在这个方法实现中,我想在里面调用poll_write。但是,不幸的是,它们在自身可变性上是不同的:Pin<&mut Self> vs Pin<&Self>。正如预期的那样,它无法编译。
这种情况有惯用的 "workaround" 吗?我的想法是将 inner 包装到 Mutex 中,这样我就可以在非可变上下文中使用可变 MyAsyncStream:
MyAsyncStreamWrapper{inner: Mutex<RefCell<MyAsyncStream>>}
...
fn poll_send_to<B>(mut self: Pin<&Self>, cx: &mut Context<'_>, buf: &[u8], addr: B,) -> Poll<Result<usize, Self::Error>> {
let rc = self.stream.lock().unwrap();
let ref mut inner = rc.borrow();
let pin = Pin::new(inner);
pin.poll_write(cx, buf);
}
...
但是,不幸的是,它也没有编译,出现以下错误:
pin.poll_write(cx, buf);
^^^^^^^^^^ method not found in `std::pin::Pin<&mut std::cell::RefMut<'_, MyAsyncStream>>`
正确的方法是什么?
取消引用然后重新借用似乎可行:
use std::cell::RefCell;
use std::pin::Pin;
use std::sync::Mutex;
fn main() {
let a = Mutex::new(RefCell::new(42));
let rc = a.lock().unwrap();
let mut inner = rc.borrow_mut();
let pinned = Pin::new(&mut *inner);
print_type_name(pinned);
}
fn print_type_name<T>(_: T) {
println!("{}", std::any::type_name::<T>());
}
输出类型为core::pin::Pin<&mut i32>
。
也就是说,在异步上下文中使用像 Mutex
这样的阻塞同步原语可能不是一个好主意。如果可能,最好让 poll_send_to
带一个 Pin<&mut Self>
参数。
我有一个结构 MyAsyncStream 和 tokio::io::AsyncWrite 实现:
impl<S: AsyncRead + AsyncWrite + Unpin> AsyncWrite for MyAsyncStream<S> {
fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<Result<usize>> {
....
}
我还有 MyAsyncStreamWrapper:
struct MyAsyncStreamWrapper{inner: MyAsyncStream}
现在我想为 MyAsyncStreamWrapper 实现 AnotherTrait 特征,方法如下:
impl AnotherTrait for MyAsyncStreamWrapper {
fn poll_send_to<B>(self: Pin<&Self>, cx: &mut Context<'_>, buf: &[u8], addr: B,) -> Poll<Result<usize, Self::Error>> {
Pin::new(&mut self.inner).poll_write(cx, buf)
}
....
}
在这个方法实现中,我想在里面调用poll_write。但是,不幸的是,它们在自身可变性上是不同的:Pin<&mut Self> vs Pin<&Self>。正如预期的那样,它无法编译。
这种情况有惯用的 "workaround" 吗?我的想法是将 inner 包装到 Mutex 中,这样我就可以在非可变上下文中使用可变 MyAsyncStream:
MyAsyncStreamWrapper{inner: Mutex<RefCell<MyAsyncStream>>}
...
fn poll_send_to<B>(mut self: Pin<&Self>, cx: &mut Context<'_>, buf: &[u8], addr: B,) -> Poll<Result<usize, Self::Error>> {
let rc = self.stream.lock().unwrap();
let ref mut inner = rc.borrow();
let pin = Pin::new(inner);
pin.poll_write(cx, buf);
}
...
但是,不幸的是,它也没有编译,出现以下错误:
pin.poll_write(cx, buf);
^^^^^^^^^^ method not found in `std::pin::Pin<&mut std::cell::RefMut<'_, MyAsyncStream>>`
正确的方法是什么?
取消引用然后重新借用似乎可行:
use std::cell::RefCell;
use std::pin::Pin;
use std::sync::Mutex;
fn main() {
let a = Mutex::new(RefCell::new(42));
let rc = a.lock().unwrap();
let mut inner = rc.borrow_mut();
let pinned = Pin::new(&mut *inner);
print_type_name(pinned);
}
fn print_type_name<T>(_: T) {
println!("{}", std::any::type_name::<T>());
}
输出类型为core::pin::Pin<&mut i32>
。
也就是说,在异步上下文中使用像 Mutex
这样的阻塞同步原语可能不是一个好主意。如果可能,最好让 poll_send_to
带一个 Pin<&mut Self>
参数。