yzx_core/
buf_alloc.rs

1/*
2 * Description: Traits for allocating buffer storage.
3 *
4 * Copyright (C) 2025 d@nny mc² <dmc2@hypnicjerk.ai>
5 * SPDX-License-Identifier: AGPL-3.0-or-later
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published
9 * by the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19 */
20
21//! Traits for allocating buffer storage.
22
23use core::{mem, num, ops};
24
25pub trait BufferAllocator {
26  type Buffer<'source>: ops::DerefMut<Target=[mem::MaybeUninit<u8>]>
27  where Self: 'source;
28  type Error;
29
30  fn alloc<'source>(
31    &'source self,
32    size: num::NonZeroUsize,
33  ) -> Result<Self::Buffer<'source>, Self::Error>;
34}
35
36#[cfg(feature = "allocator-api")]
37pub mod allocator_api {
38  use core::{
39    alloc::{AllocError, Allocator, Layout, LayoutError},
40    error, fmt, mem, num, ops, ptr,
41  };
42
43  pub struct AllocBuf<'source, A>
44  where A: Allocator
45  {
46    allocation: ptr::NonNull<[u8]>,
47    layout: Layout,
48    allocator: &'source A,
49  }
50
51  impl<'source, A> ops::Deref for AllocBuf<'source, A>
52  where A: Allocator
53  {
54    type Target = [mem::MaybeUninit<u8>];
55    #[inline(always)]
56    fn deref(&self) -> &[mem::MaybeUninit<u8>] { unsafe { self.allocation.as_uninit_slice() } }
57  }
58
59  impl<'source, A> ops::DerefMut for AllocBuf<'source, A>
60  where A: Allocator
61  {
62    #[inline(always)]
63    fn deref_mut(&mut self) -> &mut [mem::MaybeUninit<u8>] {
64      unsafe { self.allocation.as_uninit_slice_mut() }
65    }
66  }
67
68  impl<'source, A> ops::Drop for AllocBuf<'source, A>
69  where A: Allocator
70  {
71    fn drop(&mut self) {
72      unsafe {
73        self
74          .allocator
75          .deallocate(self.allocation.cast(), self.layout);
76      }
77    }
78  }
79
80  #[derive(Debug)]
81  pub enum AllocatorError {
82    Alloc(AllocError),
83    Layout(LayoutError),
84  }
85
86  impl From<AllocError> for AllocatorError {
87    #[inline(always)]
88    fn from(e: AllocError) -> Self { Self::Alloc(e) }
89  }
90
91  impl From<LayoutError> for AllocatorError {
92    #[inline(always)]
93    fn from(e: LayoutError) -> Self { Self::Layout(e) }
94  }
95
96  impl fmt::Display for AllocatorError {
97    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98      match self {
99        Self::Alloc(e) => fmt::Display::fmt(e, f),
100        Self::Layout(e) => fmt::Display::fmt(e, f),
101      }
102    }
103  }
104
105  impl error::Error for AllocatorError {
106    fn source(&self) -> Option<&(dyn error::Error+'static)> {
107      match self {
108        Self::Alloc(e) => Some(e),
109        Self::Layout(e) => Some(e),
110      }
111    }
112  }
113
114  impl<A> super::BufferAllocator for A
115  where A: Allocator
116  {
117    type Buffer<'source>
118      = AllocBuf<'source, A>
119    where Self: 'source;
120    type Error = AllocatorError;
121
122    fn alloc<'source>(
123      &'source self,
124      size: num::NonZeroUsize,
125    ) -> Result<Self::Buffer<'source>, Self::Error> {
126      let layout = Layout::array::<u8>(size.get())?;
127      let allocation = self.allocate(layout)?;
128      Ok(AllocBuf {
129        allocation,
130        layout,
131        allocator: self,
132      })
133    }
134  }
135}