一种特定泛型类型的专用方法

时间:2018-01-07 09:18:29

标签: generics rust template-specialization

我正在为C库编写一个包装器而且我写了很多像CVecOf<anything>这样的类型:

#[repr(C)]
pub struct CVecOfPoint {
    pub array: *mut Point2i,
    pub size: usize,
}

impl CVecOfPoint {
    pub fn rustify(&self) -> Vec<Point2i> {
        (0..self.size)
            .map(|i| unsafe { *(self.array.offset(i as isize)) })
            .collect::<Vec<_>>()
    }
}

#[repr(C)]
pub struct CVecOfPoints {
    pub array: *mut CVecOfPoint,
    pub size: usize,
}

impl CVecOfPoints {
    pub fn rustify(&self) -> Vec<Vec<Point2i>> {
        (0..self.size)
            .map(|i| unsafe {
                let vec = &*self.array.offset(i as isize);
                vec.rustify()
            })
            .collect::<Vec<_>>()
    }
}

pub struct CVecOfPointsOfPoints;
pub struct CVecOfPointsOfPointsOfPoints; 
pub struct CVecOfPointsOfPointsOfPointsOfPoints;

我想只使用以下映射规则编写CVec<T>

rustify :=
   T -> T
   CVec<T> -> Vec<T>

因此CVecOfPointsOfPointsOfPointsOfPoints只是CVec<CVec<CVec<CVec<Cvec<Point>>>>>

感谢@ red75prime,我写了以下内容,但它需要一个不稳定的功能:

#![feature(specialization)]
#![deny(trivial_casts)]

use std::fmt::Debug;
use std::mem;

#[repr(C)]
#[derive(Debug)]
pub struct CVec<T: Sized> {
    array: *mut T,
    size: usize,
}

unsafe fn unpack_unsafe<T, R>(v: &CVec<T>) -> Vec<R> {
    (0..v.size)
        .map(|i| mem::transmute_copy(&*v.array.offset(i as isize)))
        .collect()
}

pub fn unpack<T, U, F>(v: &CVec<T>, mut f: F) -> Vec<U>
where
    F: FnMut(&T) -> U,
{
    (0..v.size)
        .map(|i| unsafe { f(&*v.array.offset(i as isize)) })
        .collect()
}

trait Unpack {
    type R: Debug;
    fn unpack(&self) -> Vec<Self::R>;
}

impl<T: Debug> Unpack for CVec<T> {
    default type R = T;
    default fn unpack(&self) -> Vec<Self::R> {
        unsafe { unpack_unsafe(self) }
    }
}

impl<T: Unpack + Debug> Unpack for CVec<T> {
    type R = Vec<T::R>;
    fn unpack(&self) -> Vec<Self::R> {
        unpack(self, |v| v.unpack())
    }
}

fn main() {
    let mut vs = [1, 2, 3];
    let mut v1 = CVec {
        array: vs.as_mut_ptr(),
        size: vs.len(),
    };
    let mut v2 = CVec {
        array: &mut v1 as *mut _,
        size: 1,
    };
    let mut v3 = CVec {
        array: &mut v2 as *mut _,
        size: 1,
    };
    let v4 = CVec {
        array: &mut v3 as *mut _,
        size: 1,
    };
    let v = v4.unpack();
    println!("{:?}", v);

    let ptr: *mut () = &mut v3 as *mut _ as *mut _;
}

是否可以使用稳定的编译器重写它?

重要提示:CVec<T>实施Drop因为它必须释放已分配的array内存,因此它不能是Copy

1 个答案:

答案 0 :(得分:2)

在稳定的Rust实现中,traits不能相交,我们不能使用负性状边界。这使得直接实现变得不可能,如:

impl<T: Copy> Unpack for CVec<T> { // copies elements  } 
impl<T: Unpack> Unpack for CVec<T> { // calls `unpack` for elements }

但我们可以修改特征并使用CVec未实现Copy的事实。

我认为以下代码是不言自明的。

#[repr(C)]
#[derive(Debug, Clone)]
pub struct CVec<T: Sized> {
    array: *mut T,
    size: usize,
}

// Unsafe because CVec is not guaranteed to contain valid pointer and size
unsafe fn unpack<T, U, F>(v: &CVec<T>, mut f: F) -> Vec<U>
where
    F: FnMut(&T) -> U,
{
    (0..v.size)
        .map(|i| f(&*v.array.offset(i as isize)))
        .collect()
}

trait Unpack {
    type Out;
    unsafe fn unpack(&self) -> Self::Out;
}

impl<T: Unpack> Unpack for CVec<T> {
    type Out = Vec<T::Out>;
    unsafe fn unpack(&self) -> Self::Out {
        unpack(self, |e| e.unpack())
    }
}

impl<T: Copy> Unpack for T {
    type Out = T;
    unsafe fn unpack(&self) -> Self::Out {
        *self
    }
}

Playground