From d1e091a27a6ee0d32fcda0830ec5f9a7ad585d9e Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sun, 19 May 2013 14:08:27 +1000 Subject: [PATCH 1/2] Add Ptr::to_option method --- src/libcore/ptr.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index e116dc0194310..6254d3349d3d9 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -13,6 +13,7 @@ use cast; use libc; use libc::{c_void, size_t}; +use option::{Option, Some, None}; use sys; #[cfg(not(test))] use cmp::{Eq, Ord}; @@ -209,6 +210,7 @@ pub unsafe fn array_each(arr: **T, cb: &fn(*T)) { pub trait Ptr { fn is_null(&const self) -> bool; fn is_not_null(&const self) -> bool; + fn to_option(&const self) -> Option; fn offset(&self, count: uint) -> Self; } @@ -222,6 +224,14 @@ impl Ptr for *T { #[inline(always)] fn is_not_null(&const self) -> bool { is_not_null(*self) } + /// Returns `None` if the pointer is null, or else returns the value wrapped in `Some`. + #[inline(always)] + fn to_option(&const self) -> Option { + if self.is_null() { None } else { + Some(unsafe { **self }) + } + } + /// Calculates the offset from a pointer. #[inline(always)] fn offset(&self, count: uint) -> *T { offset(*self, count) } @@ -237,6 +247,14 @@ impl Ptr for *mut T { #[inline(always)] fn is_not_null(&const self) -> bool { is_not_null(*self) } + /// Returns `None` if the pointer is null, or else returns the value wrapped in `Some`. + #[inline(always)] + fn to_option(&const self) -> Option { + if self.is_null() { None } else { + Some(unsafe { **self }) + } + } + /// Calculates the offset from a mutable pointer. #[inline(always)] fn offset(&self, count: uint) -> *mut T { mut_offset(*self, count) } @@ -423,6 +441,21 @@ pub mod ptr_tests { assert!(mq.is_not_null()); } + #[test] + #[allow(unused_mut)] + fn test_to_option() { + let p: *int = null(); + assert_eq!(p.to_option(), None); + + let q: *int = &2; + assert_eq!(q.to_option(), Some(2)); + + let p: *mut int = mut_null(); + assert_eq!(p.to_option(), None); + + let q: *mut int = &mut 2; + assert_eq!(q.to_option(), Some(2)); + } #[test] fn test_ptr_array_each_with_len() { From eef03c39cf2f25f2e2182a68d0fcad14f378d5ac Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 20 May 2013 22:07:11 +1000 Subject: [PATCH 2/2] Update to stop unsolicited copying and mark methods as unsafe --- src/libcore/ptr.rs | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 6254d3349d3d9..dfd3858436410 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -210,7 +210,7 @@ pub unsafe fn array_each(arr: **T, cb: &fn(*T)) { pub trait Ptr { fn is_null(&const self) -> bool; fn is_not_null(&const self) -> bool; - fn to_option(&const self) -> Option; + unsafe fn to_option(&const self) -> Option<&T>; fn offset(&self, count: uint) -> Self; } @@ -224,11 +224,20 @@ impl Ptr for *T { #[inline(always)] fn is_not_null(&const self) -> bool { is_not_null(*self) } - /// Returns `None` if the pointer is null, or else returns the value wrapped in `Some`. + /// + /// Returns `None` if the pointer is null, or else returns the value wrapped + /// in `Some`. + /// + /// # Safety Notes + /// + /// While this method is useful for null-safety, it is important to note + /// that this is still an unsafe operation because the returned value could + /// be pointing to invalid memory. + /// #[inline(always)] - fn to_option(&const self) -> Option { + unsafe fn to_option(&const self) -> Option<&T> { if self.is_null() { None } else { - Some(unsafe { **self }) + Some(cast::transmute(*self)) } } @@ -247,11 +256,20 @@ impl Ptr for *mut T { #[inline(always)] fn is_not_null(&const self) -> bool { is_not_null(*self) } - /// Returns `None` if the pointer is null, or else returns the value wrapped in `Some`. + /// + /// Returns `None` if the pointer is null, or else returns the value wrapped + /// in `Some`. + /// + /// # Safety Notes + /// + /// While this method is useful for null-safety, it is important to note + /// that this is still an unsafe operation because the returned value could + /// be pointing to invalid memory. + /// #[inline(always)] - fn to_option(&const self) -> Option { + unsafe fn to_option(&const self) -> Option<&T> { if self.is_null() { None } else { - Some(unsafe { **self }) + Some(cast::transmute(*self)) } } @@ -442,19 +460,19 @@ pub mod ptr_tests { } #[test] - #[allow(unused_mut)] fn test_to_option() { let p: *int = null(); + // FIXME (#6641): Usage of unsafe methods in safe code doesn't cause an error. assert_eq!(p.to_option(), None); let q: *int = &2; - assert_eq!(q.to_option(), Some(2)); + assert_eq!(q.to_option().unwrap(), &2); // FIXME (#6641) let p: *mut int = mut_null(); - assert_eq!(p.to_option(), None); + assert_eq!(p.to_option(), None); // FIXME (#6641) let q: *mut int = &mut 2; - assert_eq!(q.to_option(), Some(2)); + assert_eq!(q.to_option().unwrap(), &2); // FIXME (#6641) } #[test]