Ho scritto del codice. Funziona ... ma è sicuro?Sicurezza di trasmettere tipi arbitrari da utilizzare
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())
}
}
Come potete vedere, scrivo un Copy
valore arbitrario di piccola taglia abbastanza in un usize
, e la nave intorno in un Atomic
. Allora lo leggo come un nuovo valore.
In sostanza utilizzo lo usize
come blocco di memoria di dimensioni size_of::<usize>()
.
Se questo è sicuro, il passaggio successivo è considerare le operazioni più elaborate.
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))
}
}
}
Queste non sono ovviamente sempre particolarmente sensibile overflow (poiché due valori "uguali" potrebbero confrontare disuguale causa bit al di fuori del T
), ma ancora sembrano ben definiti ... Credo.
Quindi, questo è sicuro e perché?
Ti riferisci alla [definizione di sicurezza di Rust] (http://doc.rust-lang.org/reference.html#behavior-not-considered-unsafe) (anche rilevante, il [comportamento non definito] (http : //doc.rust-lang.org/reference.html#behavior-considered-undefined))? O intendi un tipo più generale di "sicurezza"? – Shepmaster
La definizione di ruggine, per lo più. Commenti su problemi particolarmente sorprendenti ma tecnicamente sicuri sarebbero comunque una bella aggiunta. – Veedrac