简体   繁体   English

为 slices/`?Sized` 实现 `Deref`

[英]Implementing `Deref` for slices/`?Sized`

I'm working on a library implementing allocators ( https://github.com/JonathanWoollett-Light/array-allocators ) which can be used in shared memory.我正在开发一个实现分配器 ( https://github.com/JonathanWoollett-Light/array-allocators ) 的库,它可以在共享 memory 中使用。

I have a type which currently implements Deref and DerefMut on T: Sized and need it to implement on T: ?Sized to support slices.我有一个当前在T: Sized上实现DerefDerefMut的类型,需要它在T: ?Sized上实现以支持切片。

This type is TypedLinkedListArrayWrapper :这种类型是TypedLinkedListArrayWrapper

pub struct TypedLinkedListArrayWrapper<'a, const N: usize, T: ?Sized> {
    pub wrapper: LinkedListArrayWrapper<'a, N>,
    __marker: PhantomData<T>,
}

which implements Deref and DerefMut :它实现DerefDerefMut

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() }
    }
}

If I change T to be T:?Sized here I get the errors如果我将T更改为T:?Sized here 我得到错误

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

This is on top of LinkedListArrayWrapper :这是在LinkedListArrayWrapper之上:

pub struct LinkedListArrayWrapper<'a, const N: usize> {
    allocator: &'a LinkedListArrayAllocator<N>,
    index: usize,
    size: usize,
}

which implements Deref and DerefMut :它实现DerefDerefMut

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]
    }
}

where LinkedListArrayBlock is:其中LinkedListArrayBlock是:

pub struct LinkedListArrayBlock {
    size: usize,
    next: Option<usize>,
}

How can I do this?我怎样才能做到这一点?

So I found a solution.所以我找到了解决方案。

An important topic here relates to https://doc.rust-lang.org/std/ptr/trait.Pointee.html .这里的一个重要主题涉及https://doc.rust-lang.org/std/ptr/trait.Pointee.html Unfortunately this is nightly and requires #![feature(ptr_metadata)] .不幸的是,这是每晚的,需要#![feature(ptr_metadata)]

A solution is to use a custom type for slices to embed the meta data needed for a slice:一种解决方案是使用切片的自定义类型来嵌入切片所需的元数据:

pub struct SliceLinkedListArrayWrapper<'a, const N: usize, T> {
    pub wrapper: LinkedListArrayWrapper<'a, N>,
    pub len: usize,
    __marker: PhantomData<T>,
}
impl<'a, const N: usize, T> Deref for SliceLinkedListArrayWrapper<'a, N, T> {
    type Target = [T];

    fn deref(&self) -> &Self::Target {
        unsafe { &*std::ptr::from_raw_parts(std::ptr::addr_of!(*self.wrapper).cast(), self.len) }
    }
}
impl<'a, const N: usize, T> DerefMut for SliceLinkedListArrayWrapper<'a, N, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe {
            &mut *std::ptr::from_raw_parts_mut(
                std::ptr::addr_of_mut!(*self.wrapper).cast(),
                self.len,
            )
        }
    }
}

A more generalized solution is likely possible although may be awkward.尽管可能很尴尬,但更通用的解决方案可能是可行的。

The specific problem here is that .cast() requires the target type to be Sized .这里的具体问题是.cast()要求目标类型为Sized The reason can be found in the issue introducing the method:原因可以在方法介绍的issue中找到:

Like with NonNull::cast , the input pointed type does not need to be Sized but the output pointed type does, because we wouldn't know what appropriate pointer metadata (slice length, trait object vtable, …) to insert.NonNull::cast一样,输入指向类型不需要Sized ,但 output 指向类型需要,因为我们不知道要插入什么合适的指针元数据(切片长度、特征 object vtable,...)。

With that out of the way, I don't understand what you're trying to accomplish.有了这个,我不明白你想要完成什么。 At all.完全没有。 It seems like you're trying to use a slice of LinkedListArrayBlock as backing storage for T ?似乎您正在尝试使用一片LinkedListArrayBlock作为T的后备存储? That seems very dubious and wildly unsound.这似乎非常可疑,而且非常不合理。 And even if it weren't you can't cast between fat pointers arbitrarily and have it make sense.即使不是这样,你也不能在胖指针之间任意转换并让它有意义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM