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}