memapi2/traits/alloc_temp.rs
1use {
2 crate::{BasicAlloc, Layout, error::Error},
3 core::{
4 fmt::{Debug, Display},
5 ptr::{self, NonNull}
6 }
7};
8
9#[allow(unused_imports)] use crate::error::Cause;
10
11/// A memory allocation interface which may only be able to provide temporary, scoped allocations.
12pub trait AllocTemp {
13 /// The error type returned by this allocator.
14 type Error: From<Error> + Debug + Display;
15
16 /// Attempts to allocate a block of memory fitting the given [`Layout`], and calls `with_mem` on
17 /// the returned pointer on success.
18 ///
19 /// # Errors
20 ///
21 /// Errors are implementation-defined, refer to [`AllocTemp::Error`] and [`Error`].
22 ///
23 /// The standard implementations may return:
24 /// - <code>Err([Error::AllocFailed](Error::AllocFailed)(layout, cause))</code> if allocation
25 /// fails. `cause` is typically [`Cause::Unknown`]. If the `os_err_reporting` feature is
26 /// enabled, it will be <code>[Cause::OSErr]\(oserr\)</code>. In this case, `oserr` will be
27 /// the error from <code>[last_os_error]\(\).[raw_os_error]\(\)</code>.
28 /// - <code>Err([Error::ZeroSizedLayout])</code> if <code>[layout.size()](Layout::size) ==
29 /// 0</code>.
30 /// - <code>Err([Error::CaughtUnwind])</code> if the `catch_unwind` feature is enabled and an
31 /// unwind occurs in a function which is not allowed to unwind.
32 ///
33 /// [last_os_error]: std::io::Error::last_os_error
34 /// [raw_os_error]: std::io::Error::raw_os_error
35 ///
36 /// # Safety
37 ///
38 /// Safety preconditions are implementation defined.
39 unsafe fn alloc_temp<R, F: FnOnce(NonNull<u8>) -> R>(
40 &self,
41 layout: Layout,
42 with_mem: F
43 ) -> Result<R, Self::Error>;
44
45 /// Attempts to allocate a block of zeroed memory fitting the given [`Layout`], and calls
46 /// `with_mem` on the returned pointer on success.
47 ///
48 /// # Errors
49 ///
50 /// Errors are implementation-defined, refer to [`AllocTemp::Error`] and [`Error`].
51 ///
52 /// The standard implementations may return:
53 /// - <code>Err([Error::AllocFailed](Error::AllocFailed)(layout, cause))</code> if allocation
54 /// fails. `cause` is typically [`Cause::Unknown`]. If the `os_err_reporting` feature is
55 /// enabled, it will be <code>[Cause::OSErr]\(oserr\)</code>. In this case, `oserr` will be
56 /// the error from <code>[last_os_error]\(\).[raw_os_error]\(\)</code>.
57 /// - <code>Err([Error::ZeroSizedLayout])</code> if <code>[layout.size()](Layout::size) ==
58 /// 0</code>.
59 /// - <code>Err([Error::CaughtUnwind])</code> if the `catch_unwind` feature is enabled and an
60 /// unwind occurs in a function which is not allowed to unwind.
61 ///
62 /// [last_os_error]: std::io::Error::last_os_error
63 /// [raw_os_error]: std::io::Error::raw_os_error
64 ///
65 /// # Safety
66 ///
67 /// Safety preconditions are implementation defined.
68 #[cfg_attr(miri, track_caller)]
69 unsafe fn zalloc_temp<R, F: FnOnce(NonNull<u8>) -> R>(
70 &self,
71 layout: Layout,
72 with_mem: F
73 ) -> Result<R, Self::Error> {
74 self.alloc_temp(layout, |ptr: NonNull<u8>| {
75 ptr::write_bytes(ptr.as_ptr(), 0, layout.size());
76 with_mem(ptr)
77 })
78 }
79}
80
81impl<A: BasicAlloc> AllocTemp for A {
82 type Error = A::Error;
83
84 #[cfg_attr(miri, track_caller)]
85 #[inline]
86 unsafe fn alloc_temp<R, F: FnOnce(NonNull<u8>) -> R>(
87 &self,
88 layout: Layout,
89 with_mem: F
90 ) -> Result<R, A::Error> {
91 alloc_temp_with(self, layout, with_mem, A::alloc)
92 }
93
94 #[cfg_attr(miri, track_caller)]
95 #[inline]
96 unsafe fn zalloc_temp<R, F: FnOnce(NonNull<u8>) -> R>(
97 &self,
98 layout: Layout,
99 with_mem: F
100 ) -> Result<R, A::Error> {
101 alloc_temp_with(self, layout, with_mem, A::zalloc)
102 }
103}
104
105unsafe fn alloc_temp_with<
106 A: BasicAlloc<Error = E>,
107 R,
108 E: From<Error> + Debug + Display,
109 F: FnOnce(NonNull<u8>) -> R
110>(
111 a: &A,
112 layout: Layout,
113 f: F,
114 alloc: fn(&A, Layout) -> Result<NonNull<u8>, E>
115) -> Result<R, E> {
116 match alloc(a, layout) {
117 Ok(ptr) => {
118 let ret = f(ptr);
119 tri!(do a.try_dealloc(ptr, layout));
120 Ok(ret)
121 }
122 Err(e) => Err(e)
123 }
124}