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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use {
crate::{error::Error, layout::Layout, traits::alloc::BasicAlloc},
::core::{
convert::From,
fmt::{Debug, Display},
ops::FnOnce,
ptr::{self, NonNull},
result::Result::{self, Err, Ok}
}
};
#[allow(unused_imports)] use crate::error::Cause;
/// A memory allocation interface which may only be able to provide temporary, scoped allocations.
pub trait AllocTemp {
/// The error type returned by this allocator.
type Error: From<Error> + Debug + Display;
/// Attempts to allocate a block of memory fitting the given [`Layout`], and calls `with_mem` on
/// the returned pointer on success.
///
/// # Errors
///
/// Errors are implementation-defined, refer to [`AllocTemp::Error`] and [`Error`].
///
/// The standard implementations may return:
/// - <code>Err([Error::AllocFailed]\(layout, cause\))</code> if allocation fails. `cause` is
/// typically [`Cause::Unknown`]. If the `os_err_reporting` feature is enabled, it will be
/// <code>[Cause::OSErr]\(oserr\)</code>. In this case, `oserr` will be the error from
/// <code>[last_os_error]\(\).[raw_os_error]\(\)</code>.
/// - <code>Err([Error::ZeroSizedLayout])</code> if <code>[layout.size()](Layout::size) ==
/// 0</code>.
/// - <code>Err([Error::CaughtUnwind])</code> if the `catch_unwind` feature is enabled and an
/// unwind occurs in a function which is not allowed to unwind.
///
/// [last_os_error]: ::std::io::Error::last_os_error
/// [raw_os_error]: ::std::io::Error::raw_os_error
///
/// # Safety
///
/// Safety preconditions are implementation defined.
unsafe fn alloc_temp<R, F: FnOnce(NonNull<u8>) -> R>(
&self,
layout: Layout,
with_mem: F
) -> Result<R, Self::Error>;
/// Attempts to allocate a block of zeroed memory fitting the given [`Layout`], and calls
/// `with_mem` on the returned pointer on success.
///
/// # Errors
///
/// Errors are implementation-defined, refer to [`AllocTemp::Error`] and [`Error`].
///
/// The standard implementations may return:
/// - <code>Err([Error::AllocFailed]\(layout, cause\))</code> if allocation fails. `cause` is
/// typically [`Cause::Unknown`]. If the `os_err_reporting` feature is enabled, it will be
/// <code>[Cause::OSErr]\(oserr\)</code>. In this case, `oserr` will be the error from
/// <code>[last_os_error]\(\).[raw_os_error]\(\)</code>.
/// - <code>Err([Error::ZeroSizedLayout])</code> if <code>[layout.size()](Layout::size) ==
/// 0</code>.
/// - <code>Err([Error::CaughtUnwind])</code> if the `catch_unwind` feature is enabled and an
/// unwind occurs in a function which is not allowed to unwind.
///
/// [last_os_error]: ::std::io::Error::last_os_error
/// [raw_os_error]: ::std::io::Error::raw_os_error
///
/// # Safety
///
/// Safety preconditions are implementation defined.
#[cfg_attr(miri, track_caller)]
unsafe fn zalloc_temp<R, F: FnOnce(NonNull<u8>) -> R>(
&self,
layout: Layout,
with_mem: F
) -> Result<R, Self::Error> {
self.alloc_temp(layout, |ptr: NonNull<u8>| {
ptr::write_bytes(ptr.as_ptr(), 0, layout.size());
with_mem(ptr)
})
}
}
impl<A: BasicAlloc> AllocTemp for A {
type Error = A::Error;
#[cfg_attr(miri, track_caller)]
#[inline]
unsafe fn alloc_temp<R, F: FnOnce(NonNull<u8>) -> R>(
&self,
layout: Layout,
with_mem: F
) -> Result<R, A::Error> {
alloc_temp_with(self, layout, with_mem, A::alloc)
}
#[cfg_attr(miri, track_caller)]
#[inline]
unsafe fn zalloc_temp<R, F: FnOnce(NonNull<u8>) -> R>(
&self,
layout: Layout,
with_mem: F
) -> Result<R, A::Error> {
alloc_temp_with(self, layout, with_mem, A::zalloc)
}
}
unsafe fn alloc_temp_with<
A: BasicAlloc<Error = E>,
R,
E: From<Error> + Debug + Display,
F: FnOnce(NonNull<u8>) -> R
>(
a: &A,
layout: Layout,
f: F,
alloc: fn(&A, Layout) -> Result<NonNull<u8>, E>
) -> Result<R, E> {
match alloc(a, layout) {
Ok(ptr) => {
let ret = f(ptr);
tri!(do a.try_dealloc(ptr, layout));
Ok(ret)
}
Err(e) => Err(e)
}
}