//! Unsafe operations #[forbid(deprecated_mode)] #[abi = "rust-intrinsic"] extern mod rusti { fn forget(-x: T); fn reinterpret_cast(&&e: T) -> U; } /// Casts the value at `src` to U. The two types must have the same length. #[inline(always)] pub unsafe fn reinterpret_cast(src: &T) -> U { rusti::reinterpret_cast(*src) } /** * Move a thing into the void * * The forget function will take ownership of the provided value but neglect * to run any required cleanup or memory-management operations on it. This * can be used for various acts of magick, particularly when using * reinterpret_cast on pointer types. */ #[inline(always)] pub unsafe fn forget(thing: T) { rusti::forget(move thing); } /** * Force-increment the reference count on a shared box. If used * carelessly, this can leak the box. Use this in conjunction with transmute * and/or reinterpret_cast when such calls would otherwise scramble a box's * reference count */ pub unsafe fn bump_box_refcount(t: @T) { forget(move t); } /** * Transform a value of one type into a value of another type. * Both types must have the same size and alignment. * * # Example * * assert transmute("L") == ~[76u8, 0u8]; */ #[inline(always)] pub unsafe fn transmute(thing: L) -> G { let newthing: G = reinterpret_cast(&thing); forget(move thing); move newthing } /// Coerce an immutable reference to be mutable. #[inline(always)] pub unsafe fn transmute_mut(ptr: &a/T) -> &a/mut T { transmute(move ptr) } /// Coerce a mutable reference to be immutable. #[inline(always)] pub unsafe fn transmute_immut(ptr: &a/mut T) -> &a/T { transmute(move ptr) } /// Coerce a borrowed pointer to have an arbitrary associated region. #[inline(always)] pub unsafe fn transmute_region(ptr: &a/T) -> &b/T { transmute(move ptr) } /// Coerce an immutable reference to be mutable. #[inline(always)] pub unsafe fn transmute_mut_unsafe(ptr: *const T) -> *mut T { transmute(ptr) } /// Coerce an immutable reference to be mutable. #[inline(always)] pub unsafe fn transmute_immut_unsafe(ptr: *const T) -> *T { transmute(ptr) } /// Coerce a borrowed mutable pointer to have an arbitrary associated region. #[inline(always)] pub unsafe fn transmute_mut_region(ptr: &a/mut T) -> &b/mut T { transmute(move ptr) } /// Transforms lifetime of the second pointer to match the first. #[inline(always)] pub unsafe fn copy_lifetime(_ptr: &a/S, ptr: &T) -> &a/T { transmute_region(ptr) } /// Transforms lifetime of the second pointer to match the first. #[inline(always)] pub unsafe fn copy_lifetime_vec(_ptr: &a/[S], ptr: &T) -> &a/T { transmute_region(ptr) } /**************************************************************************** * Tests ****************************************************************************/ #[cfg(test)] pub mod tests { #[test] pub fn test_reinterpret_cast() { assert 1u == unsafe { reinterpret_cast(&1) }; } #[test] pub fn test_bump_box_refcount() { unsafe { let box = @~"box box box"; // refcount 1 bump_box_refcount(box); // refcount 2 let ptr: *int = transmute(box); // refcount 2 let _box1: @~str = reinterpret_cast(&ptr); let _box2: @~str = reinterpret_cast(&ptr); assert *_box1 == ~"box box box"; assert *_box2 == ~"box box box"; // Will destroy _box1 and _box2. Without the bump, this would // use-after-free. With too many bumps, it would leak. } } #[test] pub fn test_transmute() { unsafe { let x = @1; let x: *int = transmute(x); assert *x == 1; let _x: @int = transmute(x); } } #[test] pub fn test_transmute2() { unsafe { assert ~[76u8, 0u8] == transmute(~"L"); } } }