Skip to main content

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}