]> git.lizzy.rs Git - rust.git/commitdiff
Return Result instead of Option in alloc::Layout constructors
authorSimon Sapin <simon.sapin@exyr.org>
Wed, 4 Apr 2018 14:03:46 +0000 (16:03 +0200)
committerSimon Sapin <simon.sapin@exyr.org>
Thu, 12 Apr 2018 20:53:13 +0000 (22:53 +0200)
src/liballoc/raw_vec.rs
src/libcore/alloc.rs
src/libstd/collections/hash/table.rs
src/libstd/error.rs

index d7c30925f1a6a26d6041027893faa2acf566750b..18aaf1de08e9c4ace6eff1778d731e9801d14b4b 100644 (file)
@@ -422,7 +422,7 @@ pub fn try_reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize)
 
             // Nothing we can really do about these checks :(
             let new_cap = used_cap.checked_add(needed_extra_cap).ok_or(CapacityOverflow)?;
-            let new_layout = Layout::array::<T>(new_cap).ok_or(CapacityOverflow)?;
+            let new_layout = Layout::array::<T>(new_cap).map_err(|_| CapacityOverflow)?;
 
             alloc_guard(new_layout.size())?;
 
@@ -530,7 +530,7 @@ pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize)
             }
 
             let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?;
-            let new_layout = Layout::array::<T>(new_cap).ok_or(CapacityOverflow)?;
+            let new_layout = Layout::array::<T>(new_cap).map_err(|_| CapacityOverflow)?;
 
              // FIXME: may crash and burn on over-reserve
             alloc_guard(new_layout.size())?;
index 23532c6172189d74934fd33856d01cb4f1bfe4e7..0acaf54e0d92be7b3d9d67a8ae40597ea3280788 100644 (file)
@@ -94,9 +94,9 @@ impl Layout {
     ///    must not overflow (i.e. the rounded value must be less than
     ///    `usize::MAX`).
     #[inline]
-    pub fn from_size_align(size: usize, align: usize) -> Option<Layout> {
+    pub fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
         if !align.is_power_of_two() {
-            return None;
+            return Err(LayoutErr { private: () });
         }
 
         // (power-of-two implies align != 0.)
@@ -114,11 +114,11 @@ pub fn from_size_align(size: usize, align: usize) -> Option<Layout> {
         // Above implies that checking for summation overflow is both
         // necessary and sufficient.
         if size > usize::MAX - (align - 1) {
-            return None;
+            return Err(LayoutErr { private: () });
         }
 
         unsafe {
-            Some(Layout::from_size_align_unchecked(size, align))
+            Ok(Layout::from_size_align_unchecked(size, align))
         }
     }
 
@@ -130,7 +130,7 @@ pub fn from_size_align(size: usize, align: usize) -> Option<Layout> {
     /// a power-of-two nor `size` aligned to `align` fits within the
     /// address space (i.e. the `Layout::from_size_align` preconditions).
     #[inline]
-    pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout {
+    pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
         Layout { size: size, align: align }
     }
 
@@ -229,15 +229,17 @@ pub fn padding_needed_for(&self, align: usize) -> usize {
     ///
     /// On arithmetic overflow, returns `None`.
     #[inline]
-    pub fn repeat(&self, n: usize) -> Option<(Self, usize)> {
-        let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?;
-        let alloc_size = padded_size.checked_mul(n)?;
+    pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
+        let padded_size = self.size.checked_add(self.padding_needed_for(self.align))
+            .ok_or(LayoutErr { private: () })?;
+        let alloc_size = padded_size.checked_mul(n)
+            .ok_or(LayoutErr { private: () })?;
 
         // We can assume that `self.align` is a power-of-two.
         // Furthermore, `alloc_size` has already been rounded up
         // to a multiple of `self.align`; therefore, the call to
         // `Layout::from_size_align` below should never panic.
-        Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size))
+        Ok((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size))
     }
 
     /// Creates a layout describing the record for `self` followed by
@@ -251,17 +253,19 @@ pub fn repeat(&self, n: usize) -> Option<(Self, usize)> {
     /// (assuming that the record itself starts at offset 0).
     ///
     /// On arithmetic overflow, returns `None`.
-    pub fn extend(&self, next: Self) -> Option<(Self, usize)> {
+    pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
         let new_align = cmp::max(self.align, next.align);
         let realigned = Layout::from_size_align(self.size, new_align)?;
 
         let pad = realigned.padding_needed_for(next.align);
 
-        let offset = self.size.checked_add(pad)?;
-        let new_size = offset.checked_add(next.size)?;
+        let offset = self.size.checked_add(pad)
+            .ok_or(LayoutErr { private: () })?;
+        let new_size = offset.checked_add(next.size)
+            .ok_or(LayoutErr { private: () })?;
 
         let layout = Layout::from_size_align(new_size, new_align)?;
-        Some((layout, offset))
+        Ok((layout, offset))
     }
 
     /// Creates a layout describing the record for `n` instances of
@@ -276,8 +280,8 @@ pub fn extend(&self, next: Self) -> Option<(Self, usize)> {
     /// aligned.
     ///
     /// On arithmetic overflow, returns `None`.
-    pub fn repeat_packed(&self, n: usize) -> Option<Self> {
-        let size = self.size().checked_mul(n)?;
+    pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutErr> {
+        let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?;
         Layout::from_size_align(size, self.align)
     }
 
@@ -296,16 +300,17 @@ pub fn repeat_packed(&self, n: usize) -> Option<Self> {
     ///  `extend`.)
     ///
     /// On arithmetic overflow, returns `None`.
-    pub fn extend_packed(&self, next: Self) -> Option<(Self, usize)> {
-        let new_size = self.size().checked_add(next.size())?;
+    pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
+        let new_size = self.size().checked_add(next.size())
+            .ok_or(LayoutErr { private: () })?;
         let layout = Layout::from_size_align(new_size, self.align)?;
-        Some((layout, self.size()))
+        Ok((layout, self.size()))
     }
 
     /// Creates a layout describing the record for a `[T; n]`.
     ///
     /// On arithmetic overflow, returns `None`.
-    pub fn array<T>(n: usize) -> Option<Self> {
+    pub fn array<T>(n: usize) -> Result<Self, LayoutErr> {
         Layout::new::<T>()
             .repeat(n)
             .map(|(k, offs)| {
@@ -315,6 +320,20 @@ pub fn array<T>(n: usize) -> Option<Self> {
     }
 }
 
+/// The parameters given to `Layout::from_size_align` do not satisfy
+/// its documented constraints.
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct LayoutErr {
+    private: ()
+}
+
+// (we need this for downstream impl of trait Error)
+impl fmt::Display for LayoutErr {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str("invalid parameters to Layout::from_size_align")
+    }
+}
+
 /// The `AllocErr` error specifies whether an allocation failure is
 /// specifically due to resource exhaustion or if it is due to
 /// something wrong when combining the given input arguments with this
@@ -990,7 +1009,7 @@ fn alloc_array<T>(&mut self, n: usize) -> Result<NonNull<T>, AllocErr>
         where Self: Sized
     {
         match Layout::array::<T>(n) {
-            Some(ref layout) if layout.size() > 0 => {
+            Ok(ref layout) if layout.size() > 0 => {
                 unsafe {
                     self.alloc(layout.clone())
                         .map(|p| {
@@ -1041,7 +1060,7 @@ unsafe fn realloc_array<T>(&mut self,
         where Self: Sized
     {
         match (Layout::array::<T>(n_old), Layout::array::<T>(n_new), ptr.as_ptr()) {
-            (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => {
+            (Ok(ref k_old), Ok(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => {
                 self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone())
                     .map(|p| NonNull::new_unchecked(p as *mut T))
             }
@@ -1076,7 +1095,7 @@ unsafe fn dealloc_array<T>(&mut self, ptr: NonNull<T>, n: usize) -> Result<(), A
     {
         let raw_ptr = ptr.as_ptr() as *mut u8;
         match Layout::array::<T>(n) {
-            Some(ref k) if k.size() > 0 => {
+            Ok(ref k) if k.size() > 0 => {
                 Ok(self.dealloc(raw_ptr, k.clone()))
             }
             _ => {
index e9bdd4e7d07ea8bb942b6756fa4cbe7297048a5d..502637051434e0e871ff3cd37c0b25855232b192 100644 (file)
@@ -755,7 +755,7 @@ unsafe fn try_new_uninitialized(capacity: usize) -> Result<RawTable<K, V>, Colle
         }
 
         let buffer = Global.alloc(Layout::from_size_align(size, alignment)
-            .ok_or(CollectionAllocErr::CapacityOverflow)?)?;
+            .map_err(|_| CollectionAllocErr::CapacityOverflow)?)?;
 
         let hashes = buffer as *mut HashUint;
 
index ec55a3c021a8090d92dd58a078329edeae272565..3c209928d432aa38a9b5c92995b96cc13fbc4367 100644 (file)
@@ -57,7 +57,7 @@
 use char;
 use core::array;
 use fmt::{self, Debug, Display};
-use heap::{AllocErr, CannotReallocInPlace};
+use heap::{AllocErr, LayoutErr, CannotReallocInPlace};
 use mem::transmute;
 use num;
 use str;
@@ -247,6 +247,15 @@ fn description(&self) -> &str {
     }
 }
 
+#[unstable(feature = "allocator_api",
+           reason = "the precise API and guarantees it provides may be tweaked.",
+           issue = "32838")]
+impl Error for LayoutErr {
+    fn description(&self) -> &str {
+        "invalid parameters to Layout::from_size_align"
+    }
+}
+
 #[unstable(feature = "allocator_api",
            reason = "the precise API and guarantees it provides may be tweaked.",
            issue = "32838")]