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 Result,
23 event::{Event, EventFuture},
24 kernel::KernelArgument,
25 usm::{
26 DeviceAllocator, HostAccessible, HostAllocator, SharedAllocator, UsmAlloc, UsmAllocator,
27 },
28};
29
30pub struct UsmBox<T, A: UsmAlloc> {
43 data: NonNull<T>,
44 len: usize,
45 layout: Layout,
46 allocator: A,
47}
48
49impl<T, A: UsmAlloc> UsmBox<T, A> {
50 pub(crate) unsafe fn new(allocator: A, len: usize) -> Self {
53 let layout = Layout::array::<T>(len).unwrap();
54 let ptr = match allocator.allocate(layout.clone()) {
55 Ok(ptr) => ptr,
56 _ => handle_alloc_error(layout),
57 };
58
59 Self {
60 data: ptr.cast(),
61 len,
62 layout,
63 allocator,
64 }
65 }
66
67 pub(crate) fn get_byte_ptr(&self) -> *mut u8 {
68 self.data.as_ptr().cast()
69 }
70
71 pub(crate) fn get_byte_size(&self) -> usize {
72 self.layout.size()
73 }
74
75 pub(crate) fn get_len(&self) -> usize {
76 self.len
77 }
78
79 unsafe fn as_raw_arg_impl(&self) -> &[u8] {
80 let data_ptr: *const NonNull<_> = &self.data;
81 let cast_ptr = data_ptr as *const u8;
82 unsafe { slice::from_raw_parts(cast_ptr, std::mem::size_of_val(&cast_ptr)) }
83 }
84}
85
86impl<T, A: UsmAlloc + HostAccessible> Deref for UsmBox<T, A> {
87 type Target = [T];
88 fn deref(&self) -> &Self::Target {
89 unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) }
90 }
91}
92
93impl<T, A: UsmAlloc + HostAccessible> DerefMut for UsmBox<T, A> {
94 fn deref_mut(&mut self) -> &mut Self::Target {
95 unsafe { slice::from_raw_parts_mut(self.data.as_ptr(), self.len) }
96 }
97}
98
99impl<T, A: UsmAlloc> Drop for UsmBox<T, A> {
100 fn drop(&mut self) {
101 unsafe {
102 self.allocator.deallocate(self.data.cast(), self.layout);
103 }
104 }
105}
106
107pub type HostUsmBox<T> = UsmBox<T, UsmAllocator<HostAllocator>>;
108pub type SharedUsmBox<T> = UsmBox<T, UsmAllocator<SharedAllocator>>;
109pub type DeviceUsmBox<T> = UsmBox<T, UsmAllocator<DeviceAllocator>>;
110
111pub struct EnqueuedUsmBox<T, A: UsmAlloc> {
113 array: UsmBox<T, A>,
114 event: Event,
115}
116
117impl<T, A: UsmAlloc> EnqueuedUsmBox<T, A> {
118 pub(crate) fn new(array: UsmBox<T, A>, event: Event) -> Self {
119 Self { array, event }
120 }
121}
122
123impl<T, A: UsmAlloc> EnqueuedUsmBox<T, A> {
124 pub fn wait(mut self) -> Result<UsmBox<T, A>> {
129 self.event.wait().map(|_| self.array)
130 }
131}
132
133pub type EnqueuedHostUsmBox<T> = EnqueuedUsmBox<T, UsmAllocator<HostAllocator>>;
134pub type EnqueuedSharedUsmBox<T> = EnqueuedUsmBox<T, UsmAllocator<SharedAllocator>>;
135pub type EnqueuedDeviceUsmBox<T> = EnqueuedUsmBox<T, UsmAllocator<DeviceAllocator>>;
136
137#[pin_project]
138pub struct UsmBoxFuture<T, A: UsmAlloc> {
140 array: Option<UsmBox<T, A>>,
141 #[pin]
142 event_future: EventFuture,
143}
144
145impl<T, A: UsmAlloc> Future for UsmBoxFuture<T, A> {
146 type Output = Result<UsmBox<T, A>>;
147 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
148 let this = self.project();
149 this.event_future
150 .poll(cx)
151 .map(|result| result.map(|_| this.array.take().unwrap()))
152 }
153}
154
155impl<T, A: UsmAlloc> IntoFuture for EnqueuedUsmBox<T, A> {
156 type Output = Result<UsmBox<T, A>>;
157 type IntoFuture = UsmBoxFuture<T, A>;
158
159 fn into_future(self) -> Self::IntoFuture {
160 Self::IntoFuture {
161 array: Some(self.array),
162 event_future: self.event.into_future(),
163 }
164 }
165}
166
167pub type HostUsmBoxFuture<T> = UsmBoxFuture<T, UsmAllocator<HostAllocator>>;
168pub type SharedUsmBoxFuture<T> = UsmBoxFuture<T, UsmAllocator<SharedAllocator>>;
169pub type DeviceUsmBoxFuture<T> = UsmBoxFuture<T, UsmAllocator<DeviceAllocator>>;
170
171unsafe impl<T: Pod, A: UsmAlloc> KernelArgument for UsmBox<T, A> {
172 unsafe fn as_raw_arg(&self) -> &[u8] {
173 unsafe { self.as_raw_arg_impl() }
174 }
175}
176
177unsafe impl<T: Pod, A: UsmAlloc> KernelArgument for &UsmBox<T, A> {
178 unsafe fn as_raw_arg(&self) -> &[u8] {
179 unsafe { self.as_raw_arg_impl() }
180 }
181}
182
183unsafe impl<T: Pod, A: UsmAlloc> KernelArgument for &mut UsmBox<T, A> {
184 unsafe fn as_raw_arg(&self) -> &[u8] {
185 unsafe { self.as_raw_arg_impl() }
186 }
187}