1use std::{
10 alloc::{Layout, handle_alloc_error},
11 ops::{Deref, DerefMut},
12 pin::Pin,
13 ptr::NonNull,
14 slice,
15 task::{Context, Poll},
16};
17
18use bytemuck::Pod;
19use pin_project::pin_project;
20
21use crate::{
22 event::{Event, EventFuture},
23 kernel::KernelArgument,
24 usm::{
25 DeviceAllocator, HostAccessible, HostAllocator, SharedAllocator, UsmAlloc, UsmAllocator,
26 },
27};
28
29pub struct Buffer<T, A: UsmAlloc> {
42 data: NonNull<T>,
43 len: usize,
44 layout: Layout,
45 allocator: A,
46}
47
48impl<T, A: UsmAlloc> Buffer<T, A> {
49 pub(crate) unsafe fn new(allocator: A, len: usize) -> Self {
52 let layout = Layout::array::<T>(len).unwrap();
53 let ptr = match allocator.allocate(layout.clone()) {
54 Ok(ptr) => ptr,
55 _ => handle_alloc_error(layout),
56 };
57
58 Self {
59 data: ptr.cast(),
60 len,
61 layout,
62 allocator,
63 }
64 }
65
66 pub(crate) fn get_byte_ptr(&self) -> *mut u8 {
67 self.data.as_ptr().cast()
68 }
69
70 pub(crate) fn get_byte_size(&self) -> usize {
71 self.layout.size()
72 }
73
74 pub(crate) fn get_len(&self) -> usize {
75 self.len
76 }
77
78 unsafe fn as_raw_arg_impl(&self) -> &[u8] {
79 let data_ptr: *const NonNull<_> = &self.data;
80 let cast_ptr = data_ptr as *const u8;
81 unsafe { slice::from_raw_parts(cast_ptr, std::mem::size_of_val(&cast_ptr)) }
82 }
83}
84
85impl<T, A: UsmAlloc + HostAccessible> Deref for Buffer<T, A> {
86 type Target = [T];
87 fn deref(&self) -> &Self::Target {
88 unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) }
89 }
90}
91
92impl<T, A: UsmAlloc + HostAccessible> DerefMut for Buffer<T, A> {
93 fn deref_mut(&mut self) -> &mut Self::Target {
94 unsafe { slice::from_raw_parts_mut(self.data.as_ptr(), self.len) }
95 }
96}
97
98impl<T, A: UsmAlloc> Drop for Buffer<T, A> {
99 fn drop(&mut self) {
100 unsafe {
101 self.allocator.deallocate(self.data.cast(), self.layout);
102 }
103 }
104}
105
106pub type HostBuffer<T> = Buffer<T, UsmAllocator<HostAllocator>>;
107pub type SharedBuffer<T> = Buffer<T, UsmAllocator<SharedAllocator>>;
108pub type DeviceBuffer<T> = Buffer<T, UsmAllocator<DeviceAllocator>>;
109
110pub struct EnqueuedBuffer<T, A: UsmAlloc> {
112 buffer: Buffer<T, A>,
113 event: Event,
114}
115
116impl<T, A: UsmAlloc> EnqueuedBuffer<T, A> {
117 pub(crate) fn new(buffer: Buffer<T, A>, event: Event) -> Self {
118 Self { buffer, event }
119 }
120}
121
122impl<T, A: UsmAlloc> EnqueuedBuffer<T, A> {
123 pub fn wait(mut self) -> Buffer<T, A> {
125 self.event.wait();
126 self.buffer
127 }
128}
129
130pub type EnqueuedHostBuffer<T> = EnqueuedBuffer<T, UsmAllocator<HostAllocator>>;
131pub type EnqueuedSharedBuffer<T> = EnqueuedBuffer<T, UsmAllocator<SharedAllocator>>;
132pub type EnqueuedDeviceBuffer<T> = EnqueuedBuffer<T, UsmAllocator<DeviceAllocator>>;
133
134#[pin_project]
135pub struct BufferFuture<T, A: UsmAlloc> {
137 buffer: Option<Buffer<T, A>>,
138 #[pin]
139 event_future: EventFuture,
140}
141
142impl<T, A: UsmAlloc> Future for BufferFuture<T, A> {
143 type Output = Buffer<T, A>;
144 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
145 let this = self.project();
146 this.event_future
147 .poll(cx)
148 .map(|_| this.buffer.take().unwrap())
149 }
150}
151
152impl<T, A: UsmAlloc> IntoFuture for EnqueuedBuffer<T, A> {
153 type Output = Buffer<T, A>;
154 type IntoFuture = BufferFuture<T, A>;
155
156 fn into_future(self) -> Self::IntoFuture {
157 Self::IntoFuture {
158 buffer: Some(self.buffer),
159 event_future: self.event.into_future(),
160 }
161 }
162}
163
164pub type HostBufferFuture<T> = BufferFuture<T, UsmAllocator<HostAllocator>>;
165pub type SharedBufferFuture<T> = BufferFuture<T, UsmAllocator<SharedAllocator>>;
166pub type DeviceBufferFuture<T> = BufferFuture<T, UsmAllocator<DeviceAllocator>>;
167
168unsafe impl<T: Pod, A: UsmAlloc> KernelArgument for Buffer<T, A> {
169 unsafe fn as_raw_arg(&self) -> &[u8] {
170 unsafe { self.as_raw_arg_impl() }
171 }
172}
173
174unsafe impl<T: Pod, A: UsmAlloc> KernelArgument for &Buffer<T, A> {
175 unsafe fn as_raw_arg(&self) -> &[u8] {
176 unsafe { self.as_raw_arg_impl() }
177 }
178}
179
180unsafe impl<T: Pod, A: UsmAlloc> KernelArgument for &mut Buffer<T, A> {
181 unsafe fn as_raw_arg(&self) -> &[u8] {
182 unsafe { self.as_raw_arg_impl() }
183 }
184}