cubecl_environment/bytes/
shared_arc.rs1use super::{
24 AccessError, AccessPolicy, AllocationController, AllocationProperty, Bytes, SplitError,
25 default_controller::{MAX_ALIGN, NativeAllocationController},
26};
27use crate::sync::Arc;
28use alloc::boxed::Box;
29use core::mem::MaybeUninit;
30use spin::Once;
31
32pub struct SharedAllocationController {
37 inner: Arc<Bytes>,
39 offset: usize,
41 len: usize,
43 controller: Once<Box<dyn AllocationController>>,
45}
46
47impl SharedAllocationController {
48 pub(crate) fn new(inner: Arc<Bytes>, offset: usize, len: usize) -> Self {
50 debug_assert!(
51 offset + len <= inner.len(),
52 "shared view must stay within the bounds of the inner bytes"
53 );
54 Self {
55 inner,
56 offset,
57 len,
58 controller: Once::new(),
59 }
60 }
61
62 fn view(&self) -> &[u8] {
64 &self.inner[self.offset..self.offset + self.len]
65 }
66
67 fn init_mutable(&self) -> &dyn AllocationController {
70 &**self.controller.call_once(|| {
71 Box::new(
73 NativeAllocationController::alloc_with_data(self.view(), MAX_ALIGN)
74 .expect("failed to allocate copy-on-write buffer for shared bytes"),
75 ) as Box<dyn AllocationController>
76 })
77 }
78}
79
80impl AllocationController for SharedAllocationController {
81 fn alloc_align(&self) -> usize {
82 if self.controller.is_completed() {
83 MAX_ALIGN
84 } else {
85 self.inner.align()
88 }
89 }
90
91 fn property(&self) -> AllocationProperty {
92 self.inner.property()
93 }
94
95 fn may_alias_mutable_storage(&self) -> bool {
96 match self.controller.get() {
97 Some(controller) => controller.may_alias_mutable_storage(),
98 None => self.inner.may_alias_mutable_storage(),
99 }
100 }
101
102 fn capacity(&self) -> usize {
104 self.len
105 }
106
107 fn memory(&self, policy: AccessPolicy) -> Result<&[MaybeUninit<u8>], AccessError> {
108 match self.controller.get() {
109 Some(controller) => controller.memory(policy),
111 None => {
112 let slice = self.view();
114 Ok(unsafe { core::slice::from_raw_parts(slice.as_ptr().cast(), slice.len()) })
117 }
118 }
119 }
120
121 unsafe fn memory_mut(
122 &mut self,
123 policy: AccessPolicy,
124 ) -> Result<&mut [MaybeUninit<u8>], AccessError> {
125 if !self.controller.is_completed() && !policy.copy_allowed() {
127 return Err(AccessError::WouldCopy);
128 }
129 self.init_mutable();
131
132 let controller = self
135 .controller
136 .get_mut()
137 .expect("controller must be set after init_mutable");
138 unsafe { controller.memory_mut(policy) }
139 }
140
141 fn split(
142 &mut self,
143 offset: usize,
144 ) -> Result<(Box<dyn AllocationController>, Box<dyn AllocationController>), SplitError> {
145 if self.controller.is_completed() {
146 return Err(SplitError::Unsupported);
148 }
149 if offset > self.len {
151 return Err(SplitError::InvalidOffset);
152 }
153
154 let left = SharedAllocationController::new(self.inner.clone(), self.offset, offset);
155 let right = SharedAllocationController::new(
156 self.inner.clone(),
157 self.offset + offset,
158 self.len - offset,
159 );
160
161 Ok((Box::new(left), Box::new(right)))
162 }
163
164 fn view(&self, start: usize, end: usize) -> Option<Box<dyn AllocationController>> {
165 if self.controller.is_completed() {
166 return None;
168 }
169 if start > end || end > self.len {
170 return None;
171 }
172
173 Some(Box::new(SharedAllocationController::new(
174 self.inner.clone(),
175 self.offset + start,
176 end - start,
177 )))
178 }
179
180 fn duplicate(&self) -> Option<Box<dyn AllocationController>> {
181 if self.controller.is_completed() {
182 return None;
184 }
185
186 Some(Box::new(SharedAllocationController::new(
187 self.inner.clone(),
188 self.offset,
189 self.len,
190 )))
191 }
192
193 unsafe fn copy_into(&self, buf: &mut [u8]) {
194 match self.controller.get() {
195 Some(controller) => {
196 let memory = controller
197 .memory(AccessPolicy::default())
198 .expect("shared: host access failed");
199 let copy_len = buf.len().min(memory.len());
200 let data =
202 unsafe { core::slice::from_raw_parts(memory.as_ptr().cast::<u8>(), copy_len) };
203 buf[..copy_len].copy_from_slice(data);
204 }
205 None => {
206 let src = self.view();
207 let copy_len = buf.len().min(src.len());
208 buf[..copy_len].copy_from_slice(&src[..copy_len]);
209 }
210 }
211 }
212}
213
214#[cfg(all(test, feature = "std"))]
216mod tests {
217 use super::super::{AccessError, Bytes, Reader, SplitPolicy, Writer};
218 use alloc::vec;
219
220 #[test_log::test]
221 fn test_shared_no_copy_write_errors_until_cow() {
222 let mut shared = Bytes::from_elems(vec![1u8, 2, 3, 4]).shared();
223
224 assert_eq!(
226 shared.write(Writer::new().no_copy()).err(),
227 Some(AccessError::WouldCopy)
228 );
229 assert_eq!(shared.read(Reader::new().no_copy()).unwrap(), &[1, 2, 3, 4]);
231
232 shared.write(Writer::new()).unwrap()[0] = 9;
234 assert!(shared.write(Writer::new().no_copy()).is_ok());
236 assert_eq!(&shared[..], &[9, 2, 3, 4]);
237 }
238
239 #[test_log::test]
240 fn test_shared_is_zero_copy_view() {
241 let bytes = Bytes::from_elems(vec![1u8, 2, 3, 4]);
242 let shared = bytes.shared();
243 assert_eq!(&shared[..], &[1, 2, 3, 4]);
244 assert_eq!(shared.len(), 4);
245 }
246
247 #[test_log::test]
248 fn test_shared_clone_is_cheap_and_equal() {
249 let shared = Bytes::from_elems(vec![10u32, 20, 30]).shared();
250 let clone = shared.clone();
251 assert_eq!(&shared[..], &clone[..]);
252 }
253
254 #[test_log::test]
255 fn test_shared_try_into_vec_never_succeeds() {
256 let shared = Bytes::from_elems(vec![1u8, 2, 3, 4]).shared();
257 assert!(shared.try_into_vec::<u8>().is_err());
258 }
259
260 #[test_log::test]
261 fn test_shared_split() {
262 let shared = Bytes::from_elems(vec![0u8, 1, 2, 3, 4, 5, 6, 7]).shared();
263 let (left, right) = shared.split(3, SplitPolicy::Shared).unwrap();
264 assert_eq!(&left[..], &[0, 1, 2]);
265 assert_eq!(&right[..], &[3, 4, 5, 6, 7]);
266 }
267
268 #[test_log::test]
269 fn test_shared_split_then_clone() {
270 let shared = Bytes::from_elems(vec![0u8, 1, 2, 3, 4, 5]).shared();
271 let (left, right) = shared.split(2, SplitPolicy::Shared).unwrap();
272 assert_eq!(&left.clone()[..], &[0, 1]);
273 assert_eq!(&right.clone()[..], &[2, 3, 4, 5]);
274 }
275
276 #[test_log::test]
277 fn test_shared_view_is_zero_copy() {
278 let shared = Bytes::from_elems(vec![0u8, 1, 2, 3, 4, 5]).shared();
279 let view = shared.view(1, 4).unwrap();
280 assert_eq!(&view[..], &[1, 2, 3]);
281 assert_eq!(&shared[..], &[0, 1, 2, 3, 4, 5]);
283 assert!(view.try_into_vec::<u8>().is_err());
284 }
285
286 #[test_log::test]
287 fn test_shared_copy_on_write() {
288 let shared = Bytes::from_elems(vec![1u8, 2, 3, 4]).shared();
289 let mut clone = shared.clone();
290 clone[0] = 99;
291
292 assert_eq!(&clone[..], &[99, 2, 3, 4]);
294 assert_eq!(&shared[..], &[1, 2, 3, 4]);
295 }
296
297 #[test_log::test]
298 fn test_shared_extend() {
299 let mut shared = Bytes::from_elems(vec![1u8, 2, 3]).shared();
300 shared.extend_from_byte_slice(&[4, 5, 6]);
301 assert_eq!(&shared[..], &[1, 2, 3, 4, 5, 6]);
302 }
303}