wgpu_types/write_only.rs
1#![deny(
2 elided_lifetimes_in_paths,
3 reason = "make all lifetime relationships around our unsafe code explicit, \
4 because they are important to soundness"
5)]
6
7//! The [`WriteOnly`] type.
8//!
9//! This type gets its own module in order to provide an encapsulation boundary around the
10//! substantial `unsafe` code required to implement [`WriteOnly`].
11//!
12//! Portions of this code and documentation have been copied from the Rust standard library.
13
14use core::{
15 any::TypeId,
16 fmt,
17 marker::PhantomData,
18 mem,
19 ops::{Bound, RangeBounds},
20 ptr::NonNull,
21};
22
23use crate::link_to_wgpu_item;
24
25/// Like `&'a mut T`, but allows only write operations.
26///
27/// This pointer type is obtained from [`BufferViewMut`] and
28/// [`QueueWriteBufferView`].
29/// It is an unfortunate necessity due to the fact that mapped GPU memory may be [write combining],
30/// which means it cannot work normally with all of the things that Rust `&mut` access allows you to
31/// do.
32///
33/// ([`WriteOnly`] can also be used as an interface to write to *uninitialized* memory, but this is
34/// not a feature which `wgpu` currently offers for GPU buffers.)
35///
36/// The methods of `WriteOnly<[T]>` are similar to those available for
37/// [slice references, `&mut [T]`][primitive@slice],
38/// with some changes to ownership intended to minimize the pain of explicit reborrowing.
39///
40// FIXME: Add an introduction to the necessity of explicit reborrowing.
41///
42/// [write combining]: https://en.wikipedia.org/wiki/Write_combining
43#[doc = link_to_wgpu_item!(struct BufferViewMut)]
44#[doc = link_to_wgpu_item!(struct QueueWriteBufferView)]
45pub struct WriteOnly<'a, T: ?Sized> {
46 /// The data which this write-only reference allows **writing** to.
47 ///
48 /// This field is not `&mut T`, because if it were, it would assert to the compiler
49 /// that spurious reads may be inserted, and is is unclear whether those spurious reads
50 /// are acceptable.
51 ptr: NonNull<T>,
52
53 /// Enforces that this type
54 ///
55 /// * is only valid for `'a`
56 /// * is invariant in `T`
57 /// * implements auto traits as a reference to `T`
58 ///
59 /// In theory, [`WriteOnly`] should be *contravariant* in `T`, but this would be tricky
60 /// to implement (`ptr` would need to be type-erased) and is very unlikely to be useful.
61 _phantom: PhantomData<&'a mut T>,
62}
63
64// SAFETY:
65// `WriteOnly<T>` is like `&mut T` in that
66// * It provides only exclusive access to the memory it points to, so `T: Sync` is not required.
67// * Sending it creates the opportunity to send a `T`, so `T: Send` is required.
68unsafe impl<T: ?Sized + Send> Send for WriteOnly<'_, T> {}
69
70// SAFETY:
71// `WriteOnly<T>` does not offer interior mutability itself, and does not ever expose any `&T`,
72// so there is no possibility of unsynchronized access for `!Sync` to protect against.
73unsafe impl<T: ?Sized> Sync for WriteOnly<'_, T> {}
74
75impl<'a, T: ?Sized> WriteOnly<'a, T> {
76 // Note: Every method is marked `#[inline]` because the premise of this API design is that
77 // `WriteOnly` should be, when compiled, as cheap as manipulating `&mut` rather than
78 // having any additional function call cost.
79
80 /// Constructs a [`WriteOnly`] pointer from a raw pointer.
81 ///
82 /// # Safety
83 ///
84 /// By calling [`WriteOnly::new()`], you are giving safe code the opportunity to write to
85 /// this memory if it is given the resulting [`WriteOnly`]. Therefore:
86 ///
87 /// * `ptr` must be valid for ordinary, non-`volatile`, writes.
88 /// (It need not be valid for reads, including reads that occur as part of atomic operations
89 /// — that’s the whole point.)
90 /// * `ptr` must be aligned to at least the alignment of the type `T`.
91 /// * No other accesses to the memory pointed to by `ptr` may be performed until the
92 /// lifetime `'a` ends. (Similar to
93 /// [the conditions to construct `&'a mut T`][std::ptr#pointer-to-reference-conversion].)
94 ///
95 /// The memory pointed to need not contain a valid `T`, but if it does, it still will after
96 /// the `WriteOnly` pointer is used; that is, safe (or sound unsafe) use of `WriteOnly` will not
97 /// “de-initialize” the memory.
98 #[inline]
99 #[must_use]
100 pub const unsafe fn new(ptr: NonNull<T>) -> Self {
101 Self {
102 ptr,
103 _phantom: PhantomData,
104 }
105 }
106
107 /// Constructs a [`WriteOnly`] pointer from an ordinary read-write `&mut` reference.
108 ///
109 /// This may be used to write code which can write either to a mapped GPU buffer or
110 /// normal memory.
111 ///
112 /// # Example
113 ///
114 /// ```
115 /// # use wgpu_types as wgpu;
116 /// fn write_numbers(slice: wgpu::WriteOnly<[u32]>) {
117 /// for (i, mut elem) in slice.into_iter().enumerate() {
118 /// elem.write(i as u32);
119 /// }
120 /// }
121 ///
122 /// let mut buf: [u32; 4] = [0; 4];
123 /// write_numbers(wgpu::WriteOnly::from_mut(&mut buf));
124 /// assert_eq!(buf, [0, 1, 2, 3]);
125 /// ```
126 #[inline]
127 #[must_use]
128 pub const fn from_mut(reference: &mut T) -> Self {
129 // SAFETY: `&mut`’s safety conditions imply ours.
130 // FIXME: Use `NonNull::from_mut()` when MSRV ≥ 1.89.0
131 unsafe { Self::new(NonNull::new_unchecked(&raw mut *reference)) }
132 }
133
134 /// Writes `value` into the memory pointed to by `self`.
135 ///
136 /// This can only be used when `T` is a [`Sized`] type.
137 /// For slices, use [`copy_from_slice()`][Self::copy_from_slice] or
138 /// [`write_iter()`][Self::write_iter] instead.
139 #[inline]
140 pub const fn write(self, value: T)
141 where
142 // Ideally, we want "does not have a destructor" to avoid any need for dropping (which
143 // would imply reading) or forgetting the values that write operations overwrite.
144 // However, there is no such trait bound and `T: Copy` is the closest approximation.
145 T: Copy,
146 {
147 // SAFETY:
148 // `self.ptr` is valid for writes, and `self`’s lifetime ensures the write cannot alias.
149 //
150 // Not forgetting values:
151 // `T` is `Copy`, so overwriting the old value of `*self.ptr` is trivial and does not
152 // forget anything.
153 unsafe { self.ptr.write(value) }
154 }
155
156 /// Returns a raw pointer to the memory this [`WriteOnly`] refers to.
157 ///
158 /// This operation may be used to manually perform writes in situations where the safe API of
159 /// [`WriteOnly`] is not sufficient, e.g. for random access from multiple threads.
160 ///
161 /// You must take care when using this pointer:
162 ///
163 /// * The `WriteOnly` type makes no guarantee that the memory pointed to by this pointer is
164 /// readable or initialized. Therefore, it must not be converted to `&mut T`, nor read any
165 /// other way.
166 /// * You may not write an invalid value unless you also overwrite it with a valid value
167 /// later. That is, you may not make the memory less initialized than it already was.
168 ///
169 /// See also [`as_raw_element_ptr()`][WriteOnly::as_raw_element_ptr], which returns a pointer
170 /// to the first element of a slice.
171 ///
172 /// [write combining]: https://en.wikipedia.org/wiki/Write_combining
173 #[inline]
174 pub const fn as_raw_ptr(&mut self) -> NonNull<T> {
175 self.ptr
176 }
177}
178
179/// Methods for write-only references to slices.
180impl<'a, T> WriteOnly<'a, [T]> {
181 /// Returns the length of the referenced slice; the number of elements that may be written.
182 ///
183 /// # Example
184 ///
185 /// ```
186 /// # use wgpu_types as wgpu;
187 /// let example_slice: &mut [u8] = &mut [0; 10];
188 /// assert_eq!(wgpu::WriteOnly::from_mut(example_slice).len(), example_slice.len());
189 /// ```
190 #[inline]
191 #[must_use]
192 pub const fn len(&self) -> usize {
193 self.ptr.len()
194 }
195
196 /// Returns `true` if the referenced slice has a length of 0.
197 #[inline]
198 #[must_use]
199 pub const fn is_empty(&self) -> bool {
200 self.len() == 0
201 }
202
203 /// Returns another slice reference borrowing from this one,
204 /// covering a sub-range and with a shorter lifetime.
205 ///
206 /// You can also use `.slice(..)` to perform an explicit reborrow without shrinking.
207 ///
208 /// See also [`into_slice()`][Self::into_slice] when the same lifetime is needed.
209 ///
210 /// # Example
211 ///
212 /// ```
213 /// # use wgpu_types as wgpu;
214 /// // Ordinarily you would get a `WriteOnly` from `wgpu::Buffer` instead.
215 /// let mut data: [u8; 9] = [0; 9];
216 /// let mut wo = wgpu::WriteOnly::from_mut(data.as_mut_slice());
217 ///
218 /// wo.slice(..3).copy_from_slice(&[1, 2, 3]);
219 /// wo.slice(3..6).copy_from_slice(&[4, 5, 6]);
220 /// wo.slice(6..).copy_from_slice(&[7, 8, 9]);
221 ///
222 /// assert_eq!(data, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
223 /// ```
224 #[inline]
225 #[must_use]
226 pub fn slice<'b, S: RangeBounds<usize>>(&'b mut self, bounds: S) -> WriteOnly<'b, [T]> {
227 // SAFETY: We are duplicating `self.ptr`, but the lifetime annotations on this function
228 // ensure exclusive access.
229 let reborrow = unsafe { WriteOnly::<'b, [T]>::new(self.ptr) };
230
231 reborrow.into_slice(bounds)
232 }
233
234 /// Shrinks this slice reference in the same way as [`slice()`](Self::slice), but
235 /// consumes `self` and returns a slice reference with the same lifetime,
236 /// instead of a shorter lifetime.
237 #[inline]
238 #[must_use]
239 pub fn into_slice<S: RangeBounds<usize>>(mut self, bounds: S) -> Self {
240 let (checked_start, checked_new_len) =
241 checked_range_to_start_len(self.len(), bounds.start_bound(), bounds.end_bound());
242
243 WriteOnly {
244 // FIXME: When `feature(slice_ptr_get)` <https://github.com/rust-lang/rust/issues/74265>
245 // is stable, replace this with `NonNull::get_unchecked_mut()`.
246 // Unfortunately, we’ll still need to do explicit destructuring of `bounds`
247 // for bounds checking.
248 ptr: NonNull::slice_from_raw_parts(
249 // SAFETY of add(): we already did a bounds check.
250 unsafe { self.as_raw_element_ptr().add(checked_start) },
251 checked_new_len,
252 ),
253 _phantom: PhantomData,
254 }
255 }
256
257 /// Writes the items of `iter` into `self`.
258 ///
259 /// The iterator must produce exactly `self.len()` items.
260 ///
261 /// If the items are in a slice, use [`copy_from_slice()`][Self::copy_from_slice] instead.
262 ///
263 /// # Panics
264 ///
265 /// Panics if `iter` produces more or fewer items than `self.len()`.
266 ///
267 /// # Example
268 ///
269 /// ```
270 /// # use wgpu_types as wgpu;
271 /// // Ordinarily you would get a `WriteOnly` from `wgpu::Buffer` instead.
272 /// let mut buf: [u8; 10] = [0; 10];
273 /// let wo = wgpu::WriteOnly::from_mut(buf.as_mut_slice());
274 ///
275 /// wo.write_iter((1..).take(10));
276 ///
277 /// assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
278 /// ```
279 #[inline]
280 #[track_caller]
281 pub fn write_iter<I>(self, iter: I)
282 where
283 T: Copy, // required by write()
284 I: IntoIterator<Item = T>,
285 {
286 let self_len = self.len();
287 let mut slot_iter = self.into_iter();
288
289 // Call `for_each()` to take advantage of the iterator’s custom implementation, if it has
290 // one. This may be superior to a `for` loop for `chain()`ed iterators and other cases where
291 // the implementation of `Iterator::next()` would need to branch, and is typically
292 // equivalent to a `for` loop for other iterators.
293 iter.into_iter().for_each(|item| {
294 let Some(slot) = slot_iter.next() else {
295 panic!("iterator given to write_iter() produced more than {self_len} elements");
296 };
297
298 slot.write(item);
299 });
300
301 let remaining_len = slot_iter.len();
302 if remaining_len != 0 {
303 panic!(
304 "iterator given to write_iter() produced {iter_len} elements \
305 but must produce {self_len} elements",
306 // infer how many elements the iterator produced by how many of ours were consumed
307 iter_len = self_len - remaining_len,
308 );
309 };
310 }
311
312 /// Writes copies of `value` to every element of `self`.
313 ///
314 /// # Example
315 ///
316 /// ```
317 /// # use wgpu_types as wgpu;
318 /// // Ordinarily you would get a `WriteOnly` from `wgpu::Buffer` instead.
319 /// let mut buf = vec![0; 10];
320 /// let mut wo = wgpu::WriteOnly::from_mut(buf.as_mut_slice());
321 ///
322 /// wo.fill(1);
323 ///
324 /// assert_eq!(buf, [1; 10]);
325 /// ```
326 #[inline]
327 pub fn fill(&mut self, value: T)
328 where
329 // Ideally, we want "does not have a destructor" to avoid any need for dropping (which
330 // would imply reading) or forgetting the values that write operations overwrite.
331 // However, there is no such trait bound and `T: Copy` is the closest approximation.
332 T: Copy + 'static,
333 {
334 let ty = TypeId::of::<T>();
335 if ty == TypeId::of::<u8>() || ty == TypeId::of::<i8>() || ty == TypeId::of::<bool>() {
336 // The type consists of a single _initialized_ byte, so we can call out to
337 // `write_bytes()` (a.k.a. `memset` in C).
338 //
339 // Note that we cannot just check that the size is 1, because some types may allow
340 // uninitialized bytes (trivially, `MaybeUninit<u8>`)
341
342 // SAFETY:
343 // * We just checked that `T` can soundly be transmuted to `u8`.
344 // * `T` is `Copy` so we don’t need to worry about duplicating it with `transmute_copy`.
345 // * `write_bytes()` is given a pointer which is guaranteed by our own invariants
346 // to be valid to write to.
347 unsafe {
348 let value_as_byte = mem::transmute_copy::<T, u8>(&value);
349 self.as_raw_element_ptr()
350 .cast::<u8>()
351 .write_bytes(value_as_byte, self.len());
352 }
353 } else {
354 // Generic loop for all other types.
355 self.slice(..)
356 .into_iter()
357 .for_each(|elem| elem.write(value));
358 }
359 }
360
361 /// Copies all elements from src into `self`.
362 ///
363 /// # Panics
364 ///
365 /// Panics if the length of `src` is not the same as `self`.
366 ///
367 /// # Example
368 ///
369 /// ```
370 /// # use wgpu_types as wgpu;
371 /// // Ordinarily you would get a `WriteOnly` from `wgpu::Buffer` instead.
372 /// let mut buf = vec![0; 5];
373 /// let mut wo = wgpu::WriteOnly::from_mut(buf.as_mut_slice());
374 ///
375 /// wo.copy_from_slice(&[2, 3, 5, 7, 11]);
376 ///
377 /// assert_eq!(*buf, [2, 3, 5, 7, 11]);
378 #[inline]
379 #[track_caller]
380 pub fn copy_from_slice(&mut self, src: &[T])
381 where
382 // Ideally, we want "does not have a destructor" to avoid any need for dropping (which
383 // would imply reading) or forgetting the values that write operations overwrite.
384 // However, there is no such trait bound and `T: Copy` is the closest approximation.
385 T: Copy,
386 {
387 let src_len = src.len();
388 let dst_len = self.len();
389 if src_len != dst_len {
390 // wording chosen to match <[_]>::copy_from_slice()'s message
391 panic!(
392 "source slice length ({src_len}) does not match \
393 destination slice length ({dst_len})"
394 );
395 }
396
397 let src_ptr: *const T = src.as_ptr();
398 let dst_ptr: *mut T = self.as_raw_element_ptr().as_ptr();
399
400 // SAFETY:
401 // * `src_ptr` is readable because it was constructed from a reference.
402 // * `dst_ptr` is writable because that is an invariant of `WriteOnly`.
403 // * `dst_ptr` cannot alias `src_ptr` because `self` is exclusive *and*
404 // because `src_ptr` is immutable.
405 // * We checked that the byte lengths match.
406 // * Lack of data races will be enforced by the type
407 unsafe { dst_ptr.copy_from_nonoverlapping(src_ptr, src.len()) }
408 }
409
410 /// Splits this slice reference into `N`-element arrays, starting at the beginning of the slice,
411 /// and a reference to the remainder with length strictly less than `N`.
412 ///
413 /// This method is analogous to [`<[T]>::as_chunks_mut()`][slice::as_chunks_mut]
414 /// but for `WriteOnly<[T]>` access.
415 /// (It takes ownership instead of `&mut self` in order to avoid reborrowing issues.
416 /// Use [`.slice(..)`][Self::slice] first if reborrowing is needed.)
417 ///
418 /// # Panics
419 ///
420 /// Panics if `N` is zero.
421 ///
422 /// # Example
423 ///
424 /// `into_chunks()` is useful for writing a sequence of elements from CPU memory to GPU memory
425 /// when a transformation is required.
426 /// (If a transformation is not required, use [`WriteOnly::copy_from_slice()`].)
427 ///
428 /// ```
429 /// # use wgpu_types as wgpu;
430 /// fn write_text_as_chars(text: &str, output: wgpu::WriteOnly<[u8]>) {
431 /// let (mut output, _remainder) = output.into_chunks::<{ size_of::<u32>() }>();
432 /// output.write_iter(text.chars().map(|ch| (ch as u32).to_ne_bytes()));
433 /// }
434 /// #
435 /// # let mut buf = [255; 8];
436 /// # write_text_as_chars("hi", wgpu::WriteOnly::from_mut(buf.as_mut_slice()));
437 /// # assert_eq!(
438 /// # buf,
439 /// # [
440 /// # u32::from(b'h').to_ne_bytes(),
441 /// # u32::from(b'i').to_ne_bytes(),
442 /// # ].as_flattened(),
443 /// # );
444 /// ```
445 #[inline]
446 #[must_use]
447 pub fn into_chunks<const N: usize>(self) -> (WriteOnly<'a, [[T; N]]>, WriteOnly<'a, [T]>) {
448 // This implementation is identical to the Rust standard library implementation as of
449 // Rust 1.93.0, except for being broken down into fewer pieces and less uncheckedness.
450
451 assert!(N != 0, "chunk size must be non-zero");
452 let len_in_chunks = self.len() / N;
453 let len_in_elements_rounded_down = len_in_chunks * N;
454 let (multiple_of_n, remainder) = self.split_at(len_in_elements_rounded_down);
455 // SAFETY: We already panicked for zero, and ensured by construction
456 // that the length of the subslice is a multiple of N.
457 let array_slice = unsafe {
458 WriteOnly::new(NonNull::slice_from_raw_parts(
459 multiple_of_n.ptr.cast::<[T; N]>(),
460 len_in_chunks,
461 ))
462 };
463 (array_slice, remainder)
464 }
465
466 /// Divides one write-only slice reference into two at an index.
467 ///
468 /// The first will contain all indices from `[0, mid)` (excluding
469 /// the index `mid` itself) and the second will contain all
470 /// indices from `[mid, len)` (excluding the index `len` itself).
471 ///
472 /// # Panics
473 ///
474 /// Panics if `mid > len`.
475 #[inline]
476 #[must_use]
477 #[track_caller]
478 pub fn split_at(self, mid: usize) -> (WriteOnly<'a, [T]>, WriteOnly<'a, [T]>) {
479 match self.split_at_checked(mid) {
480 Ok(slices) => slices,
481 Err(_) => panic!("mid > len"),
482 }
483 }
484
485 /// Divides one write-only slice reference into two at an index, returning [`Err`] if the
486 /// slice is too short.
487 ///
488 /// If `mid ≤ len`, returns a pair of slices where the first will contain all
489 /// indices from `[0, mid)` (excluding the index `mid` itself) and the
490 /// second will contain all indices from `[mid, len)` (excluding the index
491 /// `len` itself).
492 ///
493 /// Otherwise, if `mid > len`, returns [`Err`] with the original slice.
494 #[inline]
495 pub const fn split_at_checked(self, mid: usize) -> Result<(Self, Self), Self> {
496 if mid <= self.len() {
497 let Self { ptr, _phantom: _ } = self;
498 let element_ptr = ptr.cast::<T>();
499 Ok(unsafe {
500 (
501 Self::new(NonNull::slice_from_raw_parts(element_ptr, mid)),
502 Self::new(NonNull::slice_from_raw_parts(
503 element_ptr.add(mid),
504 ptr.len() - mid,
505 )),
506 )
507 })
508 } else {
509 Err(self)
510 }
511 }
512
513 /// Removes the subslice corresponding to the given range and returns a mutable reference to it.
514 ///
515 /// Returns [`None`] and does not modify the slice if the given range is out of bounds.
516 ///
517 /// # Panics
518 ///
519 /// Panics if `R` is not a one-sided range such as `..n` or `n..`.
520 // (The `OneSidedRange` trait `std` uses to statically enforce this is unstable.)
521 pub fn split_off<R>(&mut self, range: R) -> Option<Self>
522 where
523 R: RangeBounds<usize>,
524 {
525 match (range.start_bound(), range.end_bound()) {
526 (Bound::Included(&mid), Bound::Unbounded) => {
527 match mem::take(self).split_at_checked(mid) {
528 Ok((front, back)) => {
529 *self = front;
530 Some(back)
531 }
532 Err(short) => {
533 *self = short;
534 None
535 }
536 }
537 }
538 (Bound::Excluded(&before_mid), Bound::Unbounded) => {
539 let mid = before_mid.checked_add(1)?;
540 match mem::take(self).split_at_checked(mid) {
541 Ok((front, back)) => {
542 *self = front;
543 Some(back)
544 }
545 Err(short) => {
546 *self = short;
547 None
548 }
549 }
550 }
551 (Bound::Unbounded, Bound::Included(&before_mid)) => {
552 let mid = before_mid.checked_add(1)?;
553 match mem::take(self).split_at_checked(mid) {
554 Ok((front, back)) => {
555 *self = back;
556 Some(front)
557 }
558 Err(short) => {
559 *self = short;
560 None
561 }
562 }
563 }
564 (Bound::Unbounded, Bound::Excluded(&mid)) => {
565 match mem::take(self).split_at_checked(mid) {
566 Ok((front, back)) => {
567 *self = back;
568 Some(front)
569 }
570 Err(short) => {
571 *self = short;
572 None
573 }
574 }
575 }
576 _ => {
577 panic!("split_off() requires a one-sided range")
578 }
579 }
580 }
581
582 /// Shrinks `self` to no longer refer to its first element, and returns a reference to that
583 /// element.
584 ///
585 /// Returns `None` if `self` is empty.
586 #[inline]
587 #[must_use]
588 pub const fn split_off_first(&mut self) -> Option<WriteOnly<'a, T>> {
589 let len = self.len();
590 if let Some(new_len) = len.checked_sub(1) {
591 let ptr: NonNull<T> = self.as_raw_element_ptr();
592
593 // SAFETY: covers exactly everything but the first element
594 *self = unsafe { WriteOnly::new(NonNull::slice_from_raw_parts(ptr.add(1), new_len)) };
595
596 // SAFETY: self was not empty so ptr is not dangling, and we will avoid aliasing
597 Some(unsafe { WriteOnly::new(ptr) })
598 } else {
599 None
600 }
601 }
602
603 /// Shrinks `self` to no longer refer to its last element, and returns a reference to that
604 /// element.
605 ///
606 /// Returns `None` if `self` is empty.
607 #[inline]
608 #[must_use]
609 pub const fn split_off_last(&mut self) -> Option<WriteOnly<'a, T>> {
610 let len = self.len();
611 if let Some(new_len) = len.checked_sub(1) {
612 let ptr: NonNull<T> = self.as_raw_element_ptr();
613
614 // SAFETY: covers exactly everything but the first element
615 *self = unsafe { WriteOnly::new(NonNull::slice_from_raw_parts(ptr, new_len)) };
616
617 // SAFETY: self was not empty so ptr is not dangling, and we will avoid aliasing
618 Some(unsafe { WriteOnly::new(ptr.add(new_len)) })
619 } else {
620 None
621 }
622 }
623
624 /// Reinterprets a reference to `[T]` as a reference to `[U]`.
625 ///
626 /// This may be used, for example, to copy a slice of `struct`s into a `[u8]` buffer.
627 ///
628 /// This method is `unsafe`, can easily be used incorrectly, and its use is often not necessary;
629 /// consider converting your data to bytes explicitly instead.
630 /// Consider using [`.into_chunks()`][Self::into_chunks] instead if possible.
631 /// When this method is used, consider wrapping it in a function that provides a narrower
632 /// type signature that can be safe.
633 ///
634 /// # Safety
635 ///
636 /// All values of type `U` must also be valid values of type `T`.
637 ///
638 /// Note that this is a requirement which is significant even if `T = [u8; N]`.
639 /// For example, if `T` contains any padding (uninitialized) bytes, then it is not valid to
640 /// interpret those bytes as `u8`s, and such a cast is unsound.
641 ///
642 /// A way to ensure soundness of this operation is to ensure that `T` and `U` satisfy traits
643 /// from a helper library, such as `T: bytemuck::AnyBitPattern, U: bytemuck::NoUninit`.
644 ///
645 /// # Panics
646 ///
647 /// Panics if the size of type `U` does not equal the size of type `T`,
648 /// or if the alignment of type `U` is greater than the alignment of type `T`.
649 ///
650 /// This panic occurs regardless of the run-time length or alignment of the slice;
651 /// any call to `cast_elements()` with a particular type `T` and typ` U` will
652 /// either always succeed or always fail.
653 #[inline]
654 #[track_caller]
655 pub unsafe fn cast_elements<U>(self) -> WriteOnly<'a, [U]> {
656 assert_eq!(
657 size_of::<T>(),
658 size_of::<U>(),
659 "sizes of the two element types must be equal"
660 );
661 assert!(
662 align_of::<U>() <= align_of::<T>(),
663 "alignment of the new element type must be \
664 less than or equal to the alignment of the old element type"
665 );
666 unsafe {
667 WriteOnly::new(NonNull::slice_from_raw_parts(
668 self.ptr.cast::<U>(),
669 self.len(),
670 ))
671 }
672 }
673
674 /// Returns a raw pointer to the first element of this [`WriteOnly`] slice reference.
675 ///
676 /// See [`WriteOnly::as_raw_ptr()`] for information on how this pointer is, or is not,
677 /// sound to use.
678 #[inline]
679 pub const fn as_raw_element_ptr(&mut self) -> NonNull<T> {
680 self.ptr.cast::<T>()
681 }
682}
683
684// This impl does not have `T: ?Sized` so we can have a separate impl for slices
685impl<T> fmt::Debug for WriteOnly<'_, T> {
686 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
687 write!(f, "WriteOnly({ty})", ty = core::any::type_name::<T>())
688 }
689}
690impl<T> fmt::Debug for WriteOnly<'_, [T]> {
691 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
692 // We don't format this as `[{ty}; {len}]` in order to not mislead readers into
693 // thinking the type is an array type.
694 write!(
695 f,
696 "WriteOnly([{ty}], len = {len})",
697 ty = core::any::type_name::<T>(),
698 len = self.len(),
699 )
700 }
701}
702
703impl<'a, T> Default for WriteOnly<'a, [T]> {
704 /// Returns an empty slice reference, just like `<&mut [T]>::default()` would.
705 ///
706 /// This may be used as a placeholder value for operations like
707 /// [`mem::take()`][core::mem::take].
708 /// It is equivalent to `WriteOnly::from_mut(&mut [])`.
709 fn default() -> Self {
710 Self::from_mut(&mut [])
711 }
712}
713
714impl<'a, T> Default for WriteOnly<'a, [T; 0]> {
715 fn default() -> Self {
716 Self::from_mut(&mut [])
717 }
718}
719
720impl<'a, 'b: 'a, T: ?Sized> From<&'b mut T> for WriteOnly<'a, T> {
721 /// Equivalent to [`WriteOnly::from_mut()`].
722 fn from(reference: &'a mut T) -> WriteOnly<'a, T> {
723 Self::from_mut(reference)
724 }
725}
726
727// Ideally we'd also implement CoerceUnsized for this same conversion, but that’s unstable.
728// <https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html>
729impl<'a, 'b: 'a, T, const N: usize> From<WriteOnly<'b, [T; N]>> for WriteOnly<'a, [T]> {
730 fn from(array_wo: WriteOnly<'b, [T; N]>) -> WriteOnly<'a, [T]> {
731 WriteOnly {
732 _phantom: PhantomData,
733 ptr: array_wo.ptr, // implicit unsizing coercion of the pointer value
734 }
735 }
736}
737
738impl<'a, T> IntoIterator for WriteOnly<'a, [T]> {
739 type Item = WriteOnly<'a, T>;
740 type IntoIter = WriteOnlyIter<'a, T>;
741
742 /// Produces an iterator over [`WriteOnly<T>`][WriteOnly] for each element of
743 /// this `WriteOnly<[T]>`.
744 ///
745 /// See also [`WriteOnly::write_iter()`] for the case where you already have an iterator
746 /// of data to write.
747 fn into_iter(self) -> Self::IntoIter {
748 WriteOnlyIter { slice: self }
749 }
750}
751impl<'a, T, const N: usize> IntoIterator for WriteOnly<'a, [T; N]> {
752 type Item = WriteOnly<'a, T>;
753 type IntoIter = WriteOnlyIter<'a, T>;
754
755 fn into_iter(self) -> Self::IntoIter {
756 WriteOnlyIter { slice: self.into() }
757 }
758}
759
760/// Iterator over the elements of [`WriteOnly<[T]>`][WriteOnly].
761///
762/// It can be created by calling [`IntoIterator::into_iter()`] on a [`WriteOnly<[T]>`][WriteOnly].
763///
764/// See also [`WriteOnly::write_iter()`].
765pub struct WriteOnlyIter<'a, T> {
766 // Note: This is not the same as a [`slice::IterMut`], and may be less efficient.
767 // We’re being less ambitious in exchange for less unsafe code.
768 slice: WriteOnly<'a, [T]>,
769}
770
771impl<T> fmt::Debug for WriteOnlyIter<'_, T> {
772 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
773 write!(
774 f,
775 "WriteOnlyIter([{ty}], len = {len})",
776 ty = core::any::type_name::<T>(),
777 len = self.len(),
778 )
779 }
780}
781
782impl<'a, T> Iterator for WriteOnlyIter<'a, T> {
783 type Item = WriteOnly<'a, T>;
784
785 fn next(&mut self) -> Option<Self::Item> {
786 self.slice.split_off_first()
787 }
788
789 fn size_hint(&self) -> (usize, Option<usize>) {
790 let len = self.slice.len();
791 (len, Some(len))
792 }
793}
794impl<'a, T> ExactSizeIterator for WriteOnlyIter<'a, T> {}
795
796impl<'a, T> DoubleEndedIterator for WriteOnlyIter<'a, T> {
797 fn next_back(&mut self) -> Option<Self::Item> {
798 self.slice.split_off_last()
799 }
800}
801
802#[track_caller]
803#[inline]
804fn checked_range_to_start_len(
805 len: usize,
806 slice_start: Bound<&usize>,
807 slice_end: Bound<&usize>,
808) -> (usize, usize) {
809 // FIXME: cleaner panic messages
810 let start: usize = match slice_start {
811 Bound::Included(&i) => i,
812 Bound::Excluded(&i) => i
813 .checked_add(1)
814 .expect("range bounds must be in numeric range"),
815 Bound::Unbounded => 0,
816 };
817 let end: usize = match slice_end {
818 Bound::Included(&i) => i
819 .checked_add(1)
820 .expect("range bounds must be in numeric range"),
821 Bound::Excluded(&i) => i,
822 Bound::Unbounded => len,
823 };
824 let new_len: usize = end
825 .checked_sub(start)
826 .expect("range must not have end > start");
827 assert!(end <= len, "provided range was outside slice");
828 // We checked start <= end and end <= len, so we also know that start <= self.len() here.
829
830 (start, new_len)
831}
832
833/// Note: These tests are most useful if run under Miri to detect undefined behavior.
834#[cfg(test)]
835mod tests {
836 use alloc::format;
837 use alloc::string::String;
838 use core::panic::{AssertUnwindSafe, UnwindSafe};
839
840 use super::*;
841
842 /// Helper for tests explicitly checking panics rather than using `#[should_panic]`
843 fn expect_panic(f: impl FnOnce()) -> String {
844 let payload = std::panic::catch_unwind(AssertUnwindSafe(f))
845 .expect_err("function should have panicked");
846
847 match payload.downcast::<String>() {
848 Ok(string) => *string,
849 Err(payload) => {
850 if let Some(&string) = payload.downcast_ref::<&'static str>() {
851 String::from(string)
852 } else {
853 panic!("non-string panic payload with type {:?}", payload.type_id());
854 }
855 }
856 }
857 }
858
859 // Check trait impls, particularly for a `!Sized` pointee type.
860 static_assertions::assert_not_impl_any!(WriteOnly<'static, [u8]>: Clone, Copy);
861 static_assertions::assert_impl_all!(WriteOnly<'static, [u8]>: Send, Sync);
862
863 #[test]
864 fn debug() {
865 let mut arr = [1u8, 2, 3];
866 assert_eq!(
867 format!("{:#?}", WriteOnly::from_mut(&mut arr)),
868 "WriteOnly([u8; 3])"
869 );
870 assert_eq!(
871 format!("{:#?}", WriteOnly::from_mut(arr.as_mut_slice())),
872 "WriteOnly([u8], len = 3)"
873 );
874 assert_eq!(
875 format!("{:#?}", WriteOnly::from_mut(&mut arr[0])),
876 "WriteOnly(u8)"
877 );
878
879 struct NotImplDebug;
880 let mut not = NotImplDebug;
881 assert_eq!(
882 format!("{:#?}", WriteOnly::from_mut(&mut not)),
883 "WriteOnly(wgpu_types::write_only::tests::debug::NotImplDebug)"
884 );
885 }
886
887 #[test]
888 fn default() {
889 let empty = WriteOnly::<[u8]>::default();
890 assert_eq!(empty.len(), 0);
891
892 WriteOnly::<[char; 0]>::default().write([]);
893 }
894
895 #[test]
896 fn array_to_slice() {
897 let mut array = [0u8; 3];
898 let array_wo = WriteOnly::from_mut(&mut array);
899
900 // Ideally this could be an implicit unsizing coercion too, but that's not stable.
901 let mut slice_wo: WriteOnly<'_, [u8]> = array_wo.into();
902 slice_wo.copy_from_slice(&[1, 2, 3]);
903
904 assert_eq!(array, [1, 2, 3]);
905 }
906
907 /// The rest of the tests and examples use `from_mut()` on `[T]` or arrays only,
908 /// so let’s have at least one test of a type that hasn’t got any `[` or `]` in it.
909 #[test]
910 fn from_mut_for_non_slice() {
911 let mut val = 1u32;
912 let wo = WriteOnly::from_mut(&mut val);
913 wo.write(2);
914 assert_eq!(val, 2);
915 }
916
917 /// Test that we can construct an empty `WriteOnly` in const eval.
918 const _: WriteOnly<'static, [u8]> = WriteOnly::from_mut(&mut []);
919
920 /// Test that we can use a non-empty `WriteOnly` in const eval.
921 #[test]
922 fn const_write() {
923 let output = const {
924 let mut array = [0u8; 4];
925 let mut wo = WriteOnly::from_mut(array.as_mut_slice());
926
927 // We can't use iterators in const yet, but we can do this.
928 wo.split_off_first().unwrap().write(1);
929 wo.split_off_first().unwrap().write(2);
930 wo.split_off_first().unwrap().write(3);
931 wo.split_off_first().unwrap().write(4);
932
933 array
934 };
935
936 assert_eq!(output, [1, 2, 3, 4]);
937 }
938
939 #[test]
940 #[should_panic = "iterator given to write_iter() produced 3 elements but must produce 4 elements"]
941 fn write_iter_too_short() {
942 let mut buf = [0u8; 4];
943 let wo = WriteOnly::from_mut(buf.as_mut_slice());
944
945 wo.write_iter(1..=3);
946 }
947
948 #[test]
949 #[should_panic = "iterator given to write_iter() produced more than 4 elements"]
950 fn write_iter_too_long() {
951 let mut buf = [0u8; 4];
952 let wo = WriteOnly::from_mut(buf.as_mut_slice());
953
954 wo.write_iter(1..=5);
955 }
956
957 #[test]
958 fn write_iter_to_empty_slice_success() {
959 let mut buf: [u8; 0] = [];
960 let wo = WriteOnly::from_mut(buf.as_mut_slice());
961
962 // does nothing, but shouldn’t panic
963 wo.write_iter(core::iter::empty());
964 }
965
966 #[test]
967 #[should_panic = "iterator given to write_iter() produced more than 0 elements"]
968 fn write_iter_to_empty_slice_too_long() {
969 let mut buf: [u8; 0] = [];
970 let wo = WriteOnly::from_mut(buf.as_mut_slice());
971 wo.write_iter(core::iter::once(1));
972 }
973
974 /// Tests that the slice length from `into_chunks()` is correct and that iteration works.
975 #[test]
976 fn into_chunks_has_correct_length_and_iterator_iterates() {
977 let mut buf = [0u32; 8];
978
979 let wo = WriteOnly::from_mut(buf.as_mut_slice());
980 assert_eq!(wo.len(), 8);
981
982 let (chunks, remainder): (WriteOnly<'_, [[u32; 4]]>, WriteOnly<'_, [u32]>) =
983 wo.into_chunks::<4>();
984 assert_eq!((chunks.len(), remainder.len()), (2, 0));
985
986 for elem in chunks {
987 elem.write([1, 2, 3, 4]);
988 }
989 assert_eq!(buf, [1, 2, 3, 4, 1, 2, 3, 4]);
990 }
991
992 #[test]
993 fn into_chunks_with_remainder() {
994 let mut buf = [0u8; 5];
995 let wo = WriteOnly::from_mut(buf.as_mut_slice());
996
997 let (mut chunks, mut remainder) = wo.into_chunks::<2>();
998 chunks.fill([1, 2]);
999 remainder.fill(100);
1000
1001 assert_eq!(buf, [1, 2, 1, 2, 100]);
1002 }
1003
1004 #[test]
1005 fn double_ended_iterator() {
1006 let mut buf = [0u8; 3];
1007 let mut iter = WriteOnly::from_mut(buf.as_mut_slice()).into_iter();
1008
1009 iter.next_back().unwrap().write(3);
1010 iter.next().unwrap().write(1);
1011 iter.next_back().unwrap().write(2);
1012
1013 assert!(iter.next().is_none());
1014 assert!(iter.next_back().is_none());
1015 assert_eq!(buf, [1, 2, 3]);
1016 }
1017
1018 /// Test that slicing correctly panics on an out-of-bounds range.
1019 #[test]
1020 #[expect(clippy::reversed_empty_ranges)]
1021 fn slice_bounds_check_failures() {
1022 // RangeBounds isn’t dyn compatible, so we can’t make a list of test cases and have to
1023 // use a generic function.
1024 fn assert_oob(range: impl RangeBounds<usize> + UnwindSafe + fmt::Debug + Clone) {
1025 let panic_message_1 = expect_panic({
1026 let range = range.clone();
1027 let target: WriteOnly<'_, [char]> =
1028 WriteOnly::from_mut(['a', 'b', 'c', 'd'].as_mut_slice());
1029 || {
1030 _ = { target }.slice(range);
1031 }
1032 });
1033 // TODO: have more consistent errors so this assertion can be stronger
1034 assert!(
1035 panic_message_1.contains("range"),
1036 "expected .slice({range:?}) to panic with an out-of-bounds report,
1037 but got {panic_message_1:?}"
1038 );
1039
1040 let panic_message_2 = expect_panic({
1041 let range = range.clone();
1042 let target: WriteOnly<'_, [char]> =
1043 WriteOnly::from_mut(['a', 'b', 'c', 'd'].as_mut_slice());
1044 || {
1045 _ = target.into_slice(range);
1046 }
1047 });
1048 assert!(
1049 panic_message_2.contains("range"),
1050 "expected .into_slice({range:?}) to panic with an out-of-bounds report,
1051 but got {panic_message_2:?}"
1052 );
1053 }
1054
1055 assert_oob(..5);
1056 assert_oob(..=4);
1057 assert_oob(..usize::MAX);
1058 assert_oob(..=usize::MAX);
1059 assert_oob(2..5);
1060 assert_oob(2..=4);
1061 assert_oob(2..usize::MAX);
1062 assert_oob(2..=usize::MAX);
1063 assert_oob(5..4);
1064 assert_oob(5..=3);
1065 }
1066
1067 #[test]
1068 fn slice_full_range() {
1069 let mut buf = [0u8; 4];
1070 let mut wo = WriteOnly::from_mut(buf.as_mut_slice());
1071 let mut wo2 = wo.slice(..);
1072 wo2.fill(7);
1073 assert_eq!(buf, [7, 7, 7, 7]);
1074 }
1075
1076 #[test]
1077 fn split_off_out_of_bounds() {
1078 let mut buf = ['X'; 2];
1079 let mut wo = WriteOnly::from_mut(buf.as_mut_slice());
1080
1081 assert!(wo.split_off(3..).is_none());
1082 assert!(wo.split_off(..3).is_none());
1083
1084 // wo is unchanged by the attempts
1085 assert_eq!(wo.len(), 2);
1086 }
1087
1088 /// Tests [`WriteOnly::split_off()`] with every kind of range it supports.
1089 #[test]
1090 fn split_off_success() {
1091 let mut buf = ['X'; 5];
1092 let mut wo = WriteOnly::from_mut(buf.as_mut_slice());
1093
1094 // this particular combination of `Bound`s has no corresponding `Range*` type
1095 wo.split_off((Bound::Excluded(3), Bound::Unbounded))
1096 .unwrap()
1097 .copy_from_slice(&['e']);
1098 assert_eq!(wo.len(), 4);
1099
1100 wo.split_off((Bound::Included(3), Bound::Unbounded))
1101 .unwrap()
1102 .copy_from_slice(&['d']);
1103 assert_eq!(wo.len(), 3);
1104
1105 wo.split_off(..=0).unwrap().copy_from_slice(&['a']);
1106 assert_eq!(wo.len(), 2);
1107
1108 wo.split_off(..1).unwrap().copy_from_slice(&['b']);
1109 assert_eq!(wo.len(), 1);
1110
1111 wo.copy_from_slice(&['c']);
1112
1113 assert_eq!(buf, ['a', 'b', 'c', 'd', 'e']);
1114 }
1115
1116 #[test]
1117 #[should_panic = "split_off() requires a one-sided range"]
1118 fn split_off_interior_range() {
1119 _ = WriteOnly::from_mut([1, 2, 3].as_mut_slice()).split_off(1..2);
1120 }
1121
1122 /// Tests both [`WriteOnly::split_off_first()`] and [`WriteOnly::split_off_last()`],
1123 /// with the same sequence of operations as [`split_off_success()`].
1124 #[test]
1125 fn split_off_first_and_last_success() {
1126 let mut buf = ['X'; 5];
1127 let mut wo = WriteOnly::from_mut(buf.as_mut_slice());
1128
1129 wo.split_off_last().unwrap().write('e');
1130 wo.split_off_last().unwrap().write('d');
1131 wo.split_off_first().unwrap().write('a');
1132 wo.split_off_first().unwrap().write('b');
1133 wo.copy_from_slice(&['c']);
1134
1135 assert_eq!(buf, ['a', 'b', 'c', 'd', 'e']);
1136 }
1137
1138 #[test]
1139 fn split_off_first_and_last_empty() {
1140 let mut buf: [i32; 0] = [];
1141 let mut wo = WriteOnly::from_mut(buf.as_mut_slice());
1142
1143 assert!(wo.split_off_first().is_none());
1144 assert!(wo.split_off_last().is_none());
1145 }
1146
1147 #[test]
1148 #[should_panic(expected = "sizes of the two element types must be equal")]
1149 fn cast_elements_size_mismatch() {
1150 let mut buf = [0u8; 4];
1151 let wo = WriteOnly::from_mut(buf.as_mut_slice());
1152 unsafe { wo.cast_elements::<u16>() };
1153 }
1154
1155 #[test]
1156 #[should_panic(expected = "alignment of the new element type must be \
1157 less than or equal to the alignment of the old element type")]
1158 fn cast_elements_alignment_mismatch() {
1159 #[repr(align(8))]
1160 struct BigAlign {
1161 _unused: u64,
1162 }
1163
1164 // arrays are only as aligned as their elements
1165 let mut buf = [[0u8; 8]; 1];
1166 let wo = WriteOnly::from_mut(buf.as_mut_slice());
1167
1168 unsafe { wo.cast_elements::<BigAlign>() };
1169 }
1170
1171 // fill() has specialized implementation for byte-like types, so test all those, and
1172 // also a type that isn’t byte sized, and a type that is byte sized but not initialized.
1173 #[test]
1174 fn fill_byte_u8() {
1175 let mut buf = [0u8; 5];
1176 WriteOnly::from_mut(buf.as_mut_slice()).fill(42);
1177 assert_eq!(buf, [42; 5]);
1178 }
1179 #[test]
1180 fn fill_byte_i8() {
1181 let mut buf = [0i8; 5];
1182 WriteOnly::from_mut(buf.as_mut_slice()).fill(-42);
1183 assert_eq!(buf, [-42; 5]);
1184 }
1185 #[test]
1186 fn fill_byte_bool() {
1187 let mut buf = [false; 5];
1188 WriteOnly::from_mut(buf.as_mut_slice()).fill(true);
1189 assert_eq!(buf, [true; 5]);
1190 }
1191 #[test]
1192 fn fill_nonbyte_u16() {
1193 let mut buf = [0u16; 5];
1194 WriteOnly::from_mut(buf.as_mut_slice()).fill(12345);
1195 assert_eq!(buf, [12345; 5]);
1196 }
1197 #[test]
1198 fn fill_nonbyte_uninit() {
1199 let mut buf = [mem::MaybeUninit::<u8>::uninit(); 5];
1200 WriteOnly::from_mut(buf.as_mut_slice()).fill(mem::MaybeUninit::uninit());
1201 // Can't do a comparison, but we can at least let Miri notice if we just did UB.
1202 }
1203}