1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#![feature(try_reserve)]

use std::fmt::{Debug, Display, Formatter};
use std::collections::TryReserveError;

#[cfg(test)]
mod testing;

/// The error type for this crate. It implements std::error::Error
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum WcsError{
    /// the computed capacity exceeding the usize::MAX_VALUE
    CapacityOverflow(TryReserveError),
    ///The memory allocator returned an error
    AllocError(TryReserveError)
}

impl WcsError{
    /// The source error
    pub fn try_reserve_error(&self) -> &TryReserveError{
        match self {
            WcsError::CapacityOverflow(e) => e,
            WcsError::AllocError(e) => e
        }
    }
}

impl Display for WcsError {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        Debug::fmt(&self.try_reserve_error(), f)
    }
}

impl std::error::Error for WcsError{

}

/// Vec::with_capacity(capacity) panics/aborts when the capacity is too large.
/// This is a safer alternative which reports Error using try_reserve_exact.
///
/// ```
/// use with_capacity_safe::{vec_with_capacity_safe, WcsError };
///
/// //let's pretend this is an arbitrary number read from a broken file
/// let number_from_file : usize = 100_000_000_000_000;
///
/// //try to create a 100TB Vec
/// let result : Result<Vec<u8>, _> = vec_with_capacity_safe(number_from_file);
///
/// assert!(result.is_err());
/// ```
pub fn vec_with_capacity_safe<T>(capacity : usize) -> Result<Vec<T>, WcsError>{
    let mut vec = Vec::new();
    match vec.try_reserve_exact(capacity){
        Ok(_) => Ok(vec),
        Err(e) => {
            match e {
                TryReserveError::AllocError { .. } => {
                    Err(WcsError::AllocError(e))
                },
                TryReserveError::CapacityOverflow => {
                    Err(WcsError::CapacityOverflow(e))
                }
            }
        }
    }
}