我正在开发一个实现分配器的库(https://github.com/JonathanWoollett-Light/array-allocators),它可以在共享内存中使用。
我有一个当前在T: Sized
上实现Deref
和DerefMut
的类型,需要它在T: ?Sized
上实现以支持切片。
此类型为TypedLinkedListArrayWrapper
:
pub struct TypedLinkedListArrayWrapper<'a, const N: usize, T: ?Sized> {
pub wrapper: LinkedListArrayWrapper<'a, N>,
__marker: PhantomData<T>,
}
它实现了Deref
和DerefMut
:
impl<'a, const N: usize, T> Deref for TypedLinkedListArrayWrapper<'a, N, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*(self.wrapper.deref() as *const [LinkedListArrayBlock]).cast() }
}
}
impl<'a, const N: usize, T> DerefMut for TypedLinkedListArrayWrapper<'a, N, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(self.wrapper.deref_mut() as *mut [LinkedListArrayBlock]).cast() }
}
}
如果将T
更改为T:?Sized
,则会出现以下错误
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> src/linked_list.rs:166:54
|
162 | impl<'a, const N: usize, T: ?Sized> Deref for TypedLinkedListArrayWrapper<'a, N, T> {
| - this type parameter needs to be `std::marker::Sized`
...
166 | unsafe { &*std::ptr::addr_of!(*self.wrapper).cast() }
| ^^^^ doesn't have a size known at compile-time
|
note: required by a bound in `ptr::const_ptr::<impl *const T>::cast`
--> /home/jonathan/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/const_ptr.rs:60:23
|
60 | pub const fn cast<U>(self) -> *const U {
| ^ required by this bound in `ptr::const_ptr::<impl *const T>::cast`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
162 - impl<'a, const N: usize, T: ?Sized> Deref for TypedLinkedListArrayWrapper<'a, N, T> {
162 + impl<'a, const N: usize, T> Deref for TypedLinkedListArrayWrapper<'a, N, T> {
|
For more information about this error, try `rustc --explain E0277`.
error: could not compile `array-allocators` due to previous error
这是在LinkedListArrayWrapper
之上:
pub struct LinkedListArrayWrapper<'a, const N: usize> {
allocator: &'a LinkedListArrayAllocator<N>,
index: usize,
size: usize,
}
它实现了Deref
和DerefMut
:
impl<'a, const N: usize> Deref for LinkedListArrayWrapper<'a, N> {
type Target = [LinkedListArrayBlock];
fn deref(&self) -> &Self::Target {
let allocator = unsafe { &*self.allocator.0.get() };
&allocator.data[self.index..self.index + self.size]
}
}
impl<'a, const N: usize> DerefMut for LinkedListArrayWrapper<'a, N> {
fn deref_mut(&mut self) -> &mut Self::Target {
let allocator = unsafe { &mut *self.allocator.0.get() };
&mut allocator.data[self.index..self.index + self.size]
}
}
其中LinkedListArrayBlock
为:
pub struct LinkedListArrayBlock {
size: usize,
next: Option<usize>,
}
我该怎么做呢?
2条答案
按热度按时间qhhrdooz1#
所以我找到了解决办法。
这里的一个重要主题与https://doc.rust-lang.org/std/ptr/trait.Pointee.html有关。不幸的是,这是每晚的,需要
#![feature(ptr_metadata)]
。一种解决方案是使用切片的自定义类型来嵌入切片所需的 meta数据:
更一般化的解决方案可能是可能的,尽管可能是笨拙的。
ha5z0ras2#
这里的具体问题是
.cast()
要求目标类型为Sized
,原因可以在issue介绍方法中找到:与
NonNull::cast
一样,输入指针类型不需要是Sized
,但输出指针类型需要,因为我们不知道要插入什么样的指针元数据(切片长度、trait对象vtable等)。撇开这些不谈,我完全不明白你想干什么。看起来你想用
LinkedListArrayBlock
的一个切片作为T
的后备存储?这看起来非常可疑,而且非常不合理。即使不是这样,你也不能在胖指针之间随意地进行转换,让它有意义。