2015-09-28 55 views
5

我寫了一些代碼。它的工作原理...但它是安全的嗎?鑄造任意類型的安全使用

use std::mem; 
use std::ptr; 
use std::marker::PhantomData; 

struct Atomic<T: Copy>(AtomicUsize, PhantomData<T>); 

impl<T: Copy> Atomic<T> { 
    unsafe fn encode(src: T) -> usize { 
     assert!(mem::size_of::<T>() <= mem::size_of::<usize>()); 

     let mut dst = 0; 
     ptr::write(&mut dst as *mut usize as *mut T, src); 
     dst 
    } 

    unsafe fn decode(src: usize) -> T { 
     assert!(mem::size_of::<T>() <= mem::size_of::<usize>()); 
     ptr::read(&src as *const usize as *const T) 
    } 

    fn new(val: T) -> Atomic<T> { 
     unsafe { 
      Atomic(AtomicUsize::new(Self::encode(val)), PhantomData) 
     } 
    } 

    fn load(&self, order: Ordering) -> T { 
     unsafe { Self::decode(self.0.load(order)) } 
    } 

    fn store(&self, val: T, order: Ordering) { 
     unsafe { self.0.store(Self::encode(val), order) } 
    } 
} 

impl<T: Copy + Default> Default for Atomic<T> { 
    fn default() -> Atomic<T> { 
     Self::new(T::default()) 
    } 
} 

正如你所看到的,我寫一個任意Copy值足夠小的尺寸爲usize,並在Atomic左右出貨。然後我讀出它作爲一個新的價值。

實質上,我使用usize作爲大小爲size_of::<usize>()的內存塊。

如果這是安全的,那麼下一步就是考慮更好的操作。

unsafe trait PackedInt {} 
unsafe impl PackedInt for u8 {} 
unsafe impl PackedInt for i8 {} 
unsafe impl PackedInt for u32 {} 
unsafe impl PackedInt for i32 {} 
unsafe impl PackedInt for u64 {} 
unsafe impl PackedInt for i64 {} 

impl<T: Copy + PackedInt> Atomic<T> { 
    fn compare_and_swap(&self, current: T, new: T, order: Ordering) -> T { 
     unsafe { 
      Self::decode(self.0.compare_and_swap(
       Self::encode(current), 
       Self::encode(new), 
       order 
      )) 
     } 
    } 

    fn fetch_add(&self, val: T, order: Ordering) -> T { 
     unsafe { 
      Self::decode(self.0.fetch_add(Self::encode(val), order)) 
     } 
    } 

    fn fetch_sub(&self, val: T, order: Ordering) -> T { 
     unsafe { 
      Self::decode(self.0.fetch_sub(Self::encode(val), order)) 
     } 
    } 
} 

這些當然並不總是溢出特別懂事(因爲兩個「平等」的價值可能因T之外位比較不等),但他們似乎仍然明確的...我認爲。

那麼,這是安全的,爲什麼?

+0

你是指[安全的鏽定義](http://doc.rust-lang.org/reference.html#behavior-not-considered-unsafe)(也相關,[未定義的行爲](http ://doc.rust-lang.org/reference.html#behavior-considered-undefined))?或者你的意思是更普遍的「安全」類型? – Shepmaster

+0

鏽的定義,主要是。但是,對特別令人驚訝但技術上安全的問題的評論將是一個不錯的補充。大端系統*上的 – Veedrac

回答

2

這幾乎是安全的......但不完全。你可能只考慮使用整數和浮點數的Atomic,但引用也是Copy。用戶可以輕鬆地使用輕鬆的加載和存儲在Atomic<&&u32>上導致崩潰。

在附註上,您的fetch_addfetch_sub在big-endian系統上無法正常工作。

+1

* - 如果有一種方式讓CI生態系統(如TravisCI)能夠測試{x86,ARM,...}和{big,little} -endian系統以及我熟悉的{32,64}位支持。 – Shepmaster

+0

好抓!使用'struct Atomic <'a,T:Copy +'a>(AtomicUsize,PhantomData <(&'a mut T,T)>);'似乎解決了第一個問題。 :) – Veedrac