Skip to main content

wgpu/api/
buffer.rs

1use alloc::{
2    boxed::Box,
3    string::String,
4    sync::{Arc, Weak},
5    vec::Vec,
6};
7use core::{
8    error, fmt,
9    hash::{Hash, Hasher},
10    num::NonZero,
11    ops::{Bound, Range, RangeBounds},
12};
13use hashbrown::HashSet;
14
15use crate::util::Mutex;
16use crate::*;
17
18/// Handle to a GPU-accessible buffer.
19///
20/// A `Buffer` is a memory allocation for use by the GPU, somewhat analogous to
21/// <code>[Box]&lt;[\[u8\]][primitive@slice]&gt;</code> in Rust.
22/// The contents of buffers are untyped bytes; it is up to the application to
23/// specify the interpretation of the bytes when the buffer is used, in ways
24/// such as [`VertexBufferLayout`].
25/// A single buffer can be used to hold multiple independent pieces of data at
26/// different offsets (e.g. both vertices and indices for one or more meshes).
27///
28/// A `Buffer`'s bytes have "interior mutability": functions like
29/// [`Queue::write_buffer`] or [mapping] a buffer for writing only require a
30/// `&Buffer`, not a `&mut Buffer`, even though they modify its contents. `wgpu`
31/// prevents simultaneous reads and writes of buffer contents using run-time
32/// checks.
33///
34/// Created with [`Device::create_buffer()`] or
35/// [`DeviceExt::create_buffer_init()`].
36///
37/// Corresponds to [WebGPU `GPUBuffer`](https://gpuweb.github.io/gpuweb/#buffer-interface).
38///
39/// [mapping]: Buffer#mapping-buffers
40///
41/// # How to get your data into a buffer
42///
43/// Every `Buffer` starts with all bytes zeroed.
44/// There are many ways to load data into a `Buffer`:
45///
46/// - When creating a buffer, you may set the [`mapped_at_creation`][mac] flag,
47///   then write to its [`get_mapped_range_mut()`][Buffer::get_mapped_range_mut].
48///   This only works when the buffer is created and has not yet been used by
49///   the GPU, but it is all you need for buffers whose contents do not change
50///   after creation.
51///   - You may use [`DeviceExt::create_buffer_init()`] as a convenient way to
52///     do that and copy data from a `&[u8]` you provide.
53/// - After creation, you may use [`Buffer::map_async()`] to map it again;
54///   however, you then need to wait until the GPU is no longer using the buffer
55///   before you begin writing.
56/// - You may use [`CommandEncoder::copy_buffer_to_buffer()`] to copy data into
57///   this buffer from another buffer.
58/// - You may use [`Queue::write_buffer()`] to copy data into the buffer from a
59///   `&[u8]`. This uses a temporary “staging” buffer managed by `wgpu` to hold
60///   the data.
61///   - [`Queue::write_buffer_with()`] allows you to write directly into temporary
62///     storage instead of providing a slice you already prepared, which may
63///     allow *your* code to save the allocation of a [`Vec`] or such.
64/// - You may use [`util::StagingBelt`] to manage a set of temporary buffers.
65///   This may be more efficient than [`Queue::write_buffer_with()`] when you
66///   have many small copies to perform, but requires more steps to use, and
67///   tuning of the belt buffer size.
68/// - You may write your own staging buffer management customized to your
69///   application, based on mapped buffers and
70///   [`CommandEncoder::copy_buffer_to_buffer()`].
71/// - A GPU computation’s results can be stored in a buffer:
72///   - A [compute shader][ComputePipeline] may write to a buffer bound as a
73///     [storage buffer][BufferBindingType::Storage].
74///   - A render pass may render to a texture which is then copied to a buffer
75///     using [`CommandEncoder::copy_texture_to_buffer()`].
76///
77/// # Mapping buffers
78///
79/// If a `Buffer` is created with the appropriate [`usage`], it can be *mapped*:
80/// you can make its contents accessible to the CPU as an ordinary `&[u8]` or
81/// `&mut [u8]` slice of bytes. Buffers created with the
82/// [`mapped_at_creation`][mac] flag set are also mapped initially.
83///
84/// Depending on the hardware, the buffer could be memory shared between CPU and
85/// GPU, so that the CPU has direct access to the same bytes the GPU will
86/// consult; or it may be ordinary CPU memory, whose contents the system must
87/// copy to/from the GPU as needed. This crate's API is designed to work the
88/// same way in either case: at any given time, a buffer is either mapped and
89/// available to the CPU, or unmapped and ready for use by the GPU, but never
90/// both. This makes it impossible for either side to observe changes by the
91/// other immediately, and any necessary transfers can be carried out when the
92/// buffer transitions from one state to the other.
93///
94/// There are two ways to map a buffer:
95///
96/// - If [`BufferDescriptor::mapped_at_creation`] is `true`, then the entire
97///   buffer is mapped when it is created. This is the easiest way to initialize
98///   a new buffer. You can set `mapped_at_creation` on any kind of buffer,
99///   regardless of its [`usage`] flags.
100///
101/// - If the buffer's [`usage`] includes the [`MAP_READ`] or [`MAP_WRITE`]
102///   flags, then you can call `buffer.slice(range).map_async(mode, callback)`
103///   to map the portion of `buffer` given by `range`. This waits for the GPU to
104///   finish using the buffer, and invokes `callback` as soon as the buffer is
105///   safe for the CPU to access.
106///
107/// Once a buffer is mapped:
108///
109/// - You can call `buffer.slice(range).get_mapped_range()` to obtain a
110///   [`BufferView`], which dereferences to a `&[u8]` that you can use to read
111///   the buffer's contents.
112///
113/// - Or, you can call `buffer.slice(range).get_mapped_range_mut()` to obtain a
114///   [`BufferViewMut`], which dereferences to a `&mut [u8]` that you can use to
115///   read and write the buffer's contents.
116///
117/// The given `range` must fall within the mapped portion of the buffer. If you
118/// attempt to access overlapping ranges, even for shared access only, these
119/// methods panic.
120///
121/// While a buffer is mapped, you may not submit any commands to the GPU that
122/// access it. You may record command buffers that use the buffer, but if you
123/// submit them while the buffer is mapped, submission will panic.
124///
125/// When you are done using the buffer on the CPU, you must call
126/// [`Buffer::unmap`] to make it available for use by the GPU again. All
127/// [`BufferView`] and [`BufferViewMut`] views referring to the buffer must be
128/// dropped before you unmap it; otherwise, [`Buffer::unmap`] will panic.
129///
130/// # Example
131///
132/// If `buffer` was created with [`BufferUsages::MAP_WRITE`], we could fill it
133/// with `f32` values like this:
134///
135/// ```
136/// # #[cfg(feature = "noop")]
137/// # let (device, _queue) = wgpu::Device::noop(&wgpu::DeviceDescriptor::default());
138/// # #[cfg(not(feature = "noop"))]
139/// # let device: wgpu::Device = { return; };
140/// #
141/// # let buffer = device.create_buffer(&wgpu::BufferDescriptor {
142/// #     label: None,
143/// #     size: 400,
144/// #     usage: wgpu::BufferUsages::MAP_WRITE,
145/// #     mapped_at_creation: false,
146/// # });
147/// let capturable = buffer.clone();
148/// buffer.map_async(wgpu::MapMode::Write, .., move |result| {
149///     if result.is_ok() {
150///         let mut view = capturable.get_mapped_range_mut(..).unwrap();
151///         let mut floats: wgpu::WriteOnly<[[u8; 4]]> = view.slice(..).into_chunks::<4>().0;
152///         floats.fill(42.0f32.to_ne_bytes());
153///         drop(view);
154///         capturable.unmap();
155///     }
156/// });
157/// ```
158///
159/// This code takes the following steps:
160///
161/// - First, it makes a cloned handle to the buffer for capture by
162///   the callback passed to [`map_async`]. Since a [`map_async`] callback may be
163///   invoked from another thread, interaction between the callback and the
164///   thread calling [`map_async`] generally requires some sort of shared heap
165///   data like this. In real code, there might be an [`Arc`] to some larger
166///   structure that itself owns `buffer`.
167///
168/// - Then, it calls [`Buffer::slice`] to make a [`BufferSlice`] referring to
169///   the buffer's entire contents.
170///
171/// - Next, it calls [`BufferSlice::map_async`] to request that the bytes to
172///   which the slice refers be made accessible to the CPU ("mapped"). This may
173///   entail waiting for previously enqueued operations on `buffer` to finish.
174///   Although [`map_async`] itself always returns immediately, it saves the
175///   callback function to be invoked later.
176///
177/// - When some later call to [`Device::poll`] or [`Instance::poll_all`] (not
178///   shown in this example) determines that the buffer is mapped and ready for
179///   the CPU to use, it invokes the callback function.
180///
181/// - The callback function calls [`Buffer::slice`] and then
182///   [`BufferSlice::get_mapped_range_mut`] to obtain a [`BufferViewMut`], which
183///   dereferences to a `&mut [u8]` slice referring to the buffer's bytes.
184///
185/// - It then uses the [`bytemuck`] crate to turn the `&mut [u8]` into a `&mut
186///   [f32]`, and calls the slice [`fill`] method to fill the buffer with a
187///   useful value.
188///
189/// - Finally, the callback drops the view and calls [`Buffer::unmap`] to unmap
190///   the buffer. In real code, the callback would also need to do some sort of
191///   synchronization to let the rest of the program know that it has completed
192///   its work.
193///
194/// If using [`map_async`] directly is awkward, you may find it more convenient to
195/// use [`Queue::write_buffer`] and [`util::DownloadBuffer::read_buffer`].
196/// However, those each have their own tradeoffs; the asynchronous nature of GPU
197/// execution makes it hard to avoid friction altogether.
198///
199/// [`Arc`]: std::sync::Arc
200/// [`map_async`]: BufferSlice::map_async
201/// [`bytemuck`]: https://crates.io/crates/bytemuck
202/// [`fill`]: slice::fill
203///
204/// ## Mapping buffers on the web
205///
206/// When compiled to WebAssembly and running in a browser content process,
207/// `wgpu` implements its API in terms of the browser's WebGPU implementation.
208/// In this context, `wgpu` is further isolated from the GPU:
209///
210/// - Depending on the browser's WebGPU implementation, mapping and unmapping
211///   buffers probably entails copies between WebAssembly linear memory and the
212///   graphics driver's buffers.
213///
214/// - All modern web browsers isolate web content in its own sandboxed process,
215///   which can only interact with the GPU via interprocess communication (IPC).
216///   Although most browsers' IPC systems use shared memory for large data
217///   transfers, there will still probably need to be copies into and out of the
218///   shared memory buffers.
219///
220/// All of these copies contribute to the cost of buffer mapping in this
221/// configuration.
222///
223/// [`usage`]: BufferDescriptor::usage
224/// [mac]: BufferDescriptor::mapped_at_creation
225/// [`MAP_READ`]: BufferUsages::MAP_READ
226/// [`MAP_WRITE`]: BufferUsages::MAP_WRITE
227/// [`DeviceExt::create_buffer_init()`]: util::DeviceExt::create_buffer_init
228#[derive(Debug, Clone)]
229pub struct Buffer {
230    pub(crate) inner: dispatch::DispatchBuffer,
231    pub(crate) map_context: Arc<Mutex<MapContext>>,
232    // Todo: missing map_state https://www.w3.org/TR/webgpu/#dom-gpubuffer-mapstate
233}
234#[cfg(send_sync)]
235static_assertions::assert_impl_all!(Buffer: Send, Sync);
236
237crate::cmp::impl_eq_ord_hash_proxy!(Buffer => .inner);
238
239impl Buffer {
240    /// Return the binding view of the entire buffer.
241    pub fn as_entire_binding(&self) -> BindingResource<'_> {
242        BindingResource::Buffer(self.as_entire_buffer_binding())
243    }
244
245    /// Return the binding view of the entire buffer.
246    pub fn as_entire_buffer_binding(&self) -> BufferBinding<'_> {
247        BufferBinding {
248            buffer: self,
249            offset: 0,
250            size: None,
251        }
252    }
253
254    /// Get the [`wgpu_hal`] buffer from this `Buffer`.
255    ///
256    /// Find the Api struct corresponding to the active backend in [`wgpu_hal::api`],
257    /// and pass that struct to the to the `A` type parameter.
258    ///
259    /// Returns a guard that dereferences to the type of the hal backend
260    /// which implements [`A::Buffer`].
261    ///
262    /// # Types
263    ///
264    /// The returned type depends on the backend:
265    ///
266    #[doc = crate::macros::hal_type_vulkan!("Buffer")]
267    #[doc = crate::macros::hal_type_metal!("Buffer")]
268    #[doc = crate::macros::hal_type_dx12!("Buffer")]
269    #[doc = crate::macros::hal_type_gles!("Buffer")]
270    ///
271    /// # Deadlocks
272    ///
273    /// - The returned guard holds a read-lock on a device-local "destruction"
274    ///   lock, which will cause all calls to `destroy` to block until the
275    ///   guard is released.
276    ///
277    /// # Errors
278    ///
279    /// This method will return None if:
280    /// - The buffer is not from the backend specified by `A`.
281    /// - The buffer is from [`Backend::BrowserWebGpu`].
282    ///   (Use `Buffer::as_webgpu()` instead.)
283    /// - The buffer is from a custom backend.
284    /// - The buffer has had [`Self::destroy()`] called on it.
285    ///
286    /// # Safety
287    ///
288    /// - The returned resource must not be destroyed unless the guard
289    ///   is the last reference to it and it is not in use by the GPU.
290    ///   The guard and handle may be dropped at any time however.
291    /// - All the safety requirements of wgpu-hal must be upheld.
292    ///
293    /// [`A::Buffer`]: hal::Api::Buffer
294    #[cfg(wgpu_core)]
295    pub unsafe fn as_hal<A: hal::Api>(
296        &self,
297    ) -> Option<impl core::ops::Deref<Target = A::Buffer> + WasmNotSendSync> {
298        let buffer = self.inner.as_core_opt()?;
299        unsafe { buffer.as_hal::<A>() }
300    }
301
302    /// Returns a [`BufferSlice`] referring to the portion of `self`'s contents
303    /// indicated by `bounds`. Regardless of what sort of data `self` stores,
304    /// `bounds` start and end are given in bytes.
305    ///
306    /// A [`BufferSlice`] can be used to supply vertex and index data, or to map
307    /// buffer contents for access from the CPU. See the [`BufferSlice`]
308    /// documentation for details.
309    ///
310    /// The `range` argument can be half or fully unbounded: for example,
311    /// `buffer.slice(..)` refers to the entire buffer, and `buffer.slice(n..)`
312    /// refers to the portion starting at the `n`th byte and extending to the
313    /// end of the buffer.
314    ///
315    /// # Panics
316    ///
317    /// - If `bounds` is outside of the bounds of `self`.
318    #[track_caller]
319    pub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferSlice<'_> {
320        let (offset, size) = range_to_offset_size(bounds, self.size());
321        check_buffer_bounds(self.size(), offset, size);
322        BufferSlice {
323            buffer: self,
324            offset,
325            size,
326        }
327    }
328
329    /// Unmaps the buffer from host memory.
330    ///
331    /// This terminates the effect of all previous [`map_async()`](Self::map_async) operations and
332    /// makes the buffer available for use by the GPU again.
333    ///
334    /// Panics if there is any [`BufferView`] or [`BufferViewMut`] alive.
335    pub fn unmap(&self) {
336        self.map_context.lock().reset();
337        self.inner.unmap();
338    }
339
340    /// Destroy the associated native resources as soon as possible.
341    ///
342    /// Panics if there is any [`BufferView`] or [`BufferViewMut`] alive.
343    pub fn destroy(&self) {
344        self.map_context.lock().reset();
345        self.inner.destroy();
346    }
347
348    /// Returns the length of the buffer allocation in bytes.
349    ///
350    /// This is always equal to the `size` that was specified when creating the buffer.
351    pub fn size(&self) -> BufferAddress {
352        self.inner.size()
353    }
354
355    /// Returns the allowed usages for this `Buffer`.
356    ///
357    /// This is always equal to the `usage` that was specified when creating the buffer.
358    pub fn usage(&self) -> BufferUsages {
359        self.inner.usage()
360    }
361
362    /// Map the buffer to host (CPU) memory, making it available for reading or writing via
363    /// [`get_mapped_range()`](Self::get_mapped_range). The buffer becomes accessible once the
364    /// `callback` is invoked with [`Ok`].
365    ///
366    /// Use this when you want to map the buffer immediately. If you need to submit GPU work that
367    /// uses the buffer before mapping it, use `map_buffer_on_submit` on
368    /// [`CommandEncoder`][CEmbos], [`CommandBuffer`][CBmbos], [`RenderPass`][RPmbos], or
369    /// [`ComputePass`][CPmbos] to schedule the mapping after submission. This avoids extra calls to
370    /// [`Buffer::map_async()`] or [`BufferSlice::map_async()`] and lets you initiate mapping from a
371    /// more convenient place.
372    ///
373    /// For the callback to run, either [`queue.submit(..)`][q::s], [`instance.poll_all(..)`][i::p_a],
374    /// or [`device.poll(..)`][d::p] must be called elsewhere in the runtime, possibly integrated into
375    /// an event loop or run on a separate thread.
376    ///
377    /// The callback runs on the thread that first calls one of the above functions after the GPU work
378    /// completes. There are no restrictions on the code you can run in the callback; however, on native
379    /// the polling call will not return until the callback finishes, so keep callbacks short (set flags,
380    /// send messages, etc.).
381    ///
382    /// While a buffer is mapped, it cannot be used by other commands; at any time, either the GPU or
383    /// the CPU has exclusive access to the buffer’s contents.
384    ///
385    /// This can also be performed using [`BufferSlice::map_async()`].
386    ///
387    /// # Panics
388    ///
389    /// - If the buffer is already mapped.
390    /// - If the buffer’s [`BufferUsages`] do not allow the requested [`MapMode`].
391    /// - If `bounds` is outside of the bounds of `self`.
392    /// - If `bounds` does not start at a multiple of [`MAP_ALIGNMENT`].
393    /// - If `bounds` has a length that is not a multiple of 4 greater than 0.
394    ///
395    /// [CEmbos]: CommandEncoder::map_buffer_on_submit
396    /// [CBmbos]: CommandBuffer::map_buffer_on_submit
397    /// [RPmbos]: RenderPass::map_buffer_on_submit
398    /// [CPmbos]: ComputePass::map_buffer_on_submit
399    /// [q::s]: Queue::submit
400    /// [i::p_a]: Instance::poll_all
401    /// [d::p]: Device::poll
402    pub fn map_async<S: RangeBounds<BufferAddress>>(
403        &self,
404        mode: MapMode,
405        bounds: S,
406        callback: impl FnOnce(Result<(), BufferAsyncError>) + WasmNotSend + 'static,
407    ) {
408        self.slice(bounds).map_async(mode, callback)
409    }
410
411    /// Gain read-only access to the bytes of a [mapped] [`Buffer`].
412    ///
413    /// Returns a [`BufferView`] referring to the buffer range represented by
414    /// `self`. See the documentation for [`BufferView`] for details.
415    ///
416    /// `bounds` may be less than the bounds passed to [`Self::map_async()`],
417    /// and multiple views may be obtained and used simultaneously as long as they do not overlap.
418    ///
419    /// This can also be performed using [`BufferSlice::get_mapped_range()`].
420    ///
421    /// # Errors
422    ///
423    /// - If `bounds` is outside of the bounds of `self`.
424    /// - If `bounds` does not start at a multiple of [`MAP_ALIGNMENT`].
425    /// - If `bounds` has a length that is not a multiple of 4 greater than 0.
426    /// - If the buffer to which `self` refers is not currently [mapped].
427    /// - If you try to create a view which overlaps an existing [`BufferViewMut`].
428    ///
429    /// [mapped]: Buffer#mapping-buffers
430    #[track_caller]
431    pub fn get_mapped_range<S: RangeBounds<BufferAddress>>(
432        &self,
433        bounds: S,
434    ) -> Result<BufferView, MapRangeError> {
435        self.slice(bounds).get_mapped_range()
436    }
437
438    /// Gain write access to the bytes of a [mapped] [`Buffer`].
439    ///
440    /// Returns a [`BufferViewMut`] referring to the buffer range represented by
441    /// `self`. See the documentation for [`BufferViewMut`] for more details.
442    ///
443    /// `bounds` may be less than the bounds passed to [`Self::map_async()`],
444    /// and multiple views may be obtained and used simultaneously as long as they do not overlap.
445    ///
446    /// This can also be performed using [`BufferSlice::get_mapped_range_mut()`].
447    ///
448    /// # Errors
449    ///
450    /// - If `bounds` is outside of the bounds of `self`.
451    /// - If `bounds` does not start at a multiple of [`MAP_ALIGNMENT`].
452    /// - If `bounds` has a length that is not a multiple of 4 greater than 0.
453    /// - If the buffer to which `self` refers is not currently [mapped].
454    /// - If you try to create a view which overlaps an existing [`BufferView`] or [`BufferViewMut`].
455    ///
456    /// [mapped]: Buffer#mapping-buffers
457    #[track_caller]
458    pub fn get_mapped_range_mut<S: RangeBounds<BufferAddress>>(
459        &self,
460        bounds: S,
461    ) -> Result<BufferViewMut, MapRangeError> {
462        self.slice(bounds).get_mapped_range_mut()
463    }
464
465    #[cfg(custom)]
466    /// Returns custom implementation of Buffer (if custom backend and is internally T)
467    pub fn as_custom<T: custom::BufferInterface>(&self) -> Option<&T> {
468        self.inner.as_custom()
469    }
470
471    /// Returns the underlying [`webgpu::GpuBuffer`] handle if this `Buffer`
472    /// is on the WebGPU backend, otherwise `None`.
473    #[cfg(webgpu)]
474    pub fn as_webgpu(&self) -> Option<&webgpu::GpuBuffer> {
475        self.inner.as_webgpu_opt().map(|wb| &wb.inner)
476    }
477}
478
479#[cfg(wgpu_core)]
480impl Buffer {
481    /// Create a new buffer of wgpu from a wgpu-core buffer.
482    ///
483    /// # Arguments
484    ///
485    /// - `core_buffer` - wgpu-core buffer.
486    /// - `mapped_range` - Current state of mapped buffer if any.
487    /// - `device` - The device that owns the buffer.
488    ///
489    /// # Panics
490    ///
491    /// Panics if device does not match the device of the core buffer.
492    ///
493    /// # Safety
494    ///
495    /// The caller must ensure that the current state of the wgpu-core buffer is compatible with the provided `mapped_range`.
496    /// Changes to the wgpu-core buffer's state after this call may lead to undefined behavior if they are not compatible with the provided `mapped_range`.
497    pub unsafe fn from_core(
498        core_buffer: alloc::sync::Arc<wgc::resource::Buffer>,
499        mapped: Option<MappingInfo>,
500        device: &Device,
501    ) -> Self {
502        use wgc::resource::ParentDevice;
503
504        core_buffer.same_device(&device.as_core().unwrap()).unwrap();
505        Self {
506            inner: crate::backend::wgpu_core::CoreBuffer::from_core(core_buffer).into(),
507            map_context: MapContext::new(mapped, &device.buffers),
508        }
509    }
510
511    /// Returns the underlying wgpu-core buffer if this `Buffer` is on the wgpu-core backend, otherwise `None`.
512    ///
513    /// # Safety
514    ///
515    /// Returning the underlying wgpu-core buffer allows for direct manipulation of the buffer's state,
516    /// which can lead to undefined behavior if not done carefully.
517    /// The caller must ensure that any operations performed on the returned buffer are compatible with the current state of the `Buffer` and its mapping context
518    /// or not use this buffer after calling this function.
519    pub unsafe fn as_core(&self) -> Option<alloc::sync::Arc<wgc::resource::Buffer>> {
520        self.inner.as_core_opt().map(|cd| cd.as_core())
521    }
522}
523
524/// A slice of a [`Buffer`], to be mapped, used for vertex or index data, or the like.
525///
526/// You can create a `BufferSlice` by calling [`Buffer::slice`]:
527///
528/// ```no_run
529/// # let buffer: wgpu::Buffer = todo!();
530/// let slice = buffer.slice(10..20);
531/// ```
532///
533/// This returns a slice referring to the second ten bytes of `buffer`. To get a
534/// slice of the entire `Buffer`:
535///
536/// ```no_run
537/// # let buffer: wgpu::Buffer = todo!();
538/// let whole_buffer_slice = buffer.slice(..);
539/// ```
540///
541/// You can pass buffer slices to methods like [`RenderPass::set_vertex_buffer`]
542/// and [`RenderPass::set_index_buffer`] to indicate which portion of the buffer
543/// a draw call should consult. You can also convert it to a [`BufferBinding`]
544/// with `.try_into()`, which fails if the slice length is 0.
545///
546/// To access the slice's contents on the CPU, you must first [map] the buffer,
547/// and then call [`BufferSlice::get_mapped_range`] or
548/// [`BufferSlice::get_mapped_range_mut`] to obtain a view of the slice's
549/// contents. See the documentation on [mapping][map] for more details,
550/// including example code.
551///
552/// Unlike a Rust shared slice `&[T]`, whose existence guarantees that
553/// nobody else is modifying the `T` values to which it refers, a
554/// [`BufferSlice`] doesn't guarantee that the buffer's contents aren't
555/// changing. You can still record and submit commands operating on the
556/// buffer while holding a [`BufferSlice`]. A [`BufferSlice`] simply
557/// represents a certain range of the buffer's bytes.
558///
559/// The `BufferSlice` type is unique to the Rust API of `wgpu`. In the WebGPU
560/// specification, an offset and size are specified as arguments to each call
561/// working with the [`Buffer`], instead.
562///
563/// [map]: Buffer#mapping-buffers
564#[derive(Copy, Clone, Debug, PartialEq)]
565pub struct BufferSlice<'a> {
566    pub(crate) buffer: &'a Buffer,
567    pub(crate) offset: BufferAddress,
568    pub(crate) size: BufferAddress,
569}
570#[cfg(send_sync)]
571static_assertions::assert_impl_all!(BufferSlice<'_>: Send, Sync);
572
573impl<'a> BufferSlice<'a> {
574    /// Return another [`BufferSlice`] referring to the portion of `self`'s contents
575    /// indicated by `bounds`.
576    ///
577    /// The `range` argument can be half or fully unbounded: for example,
578    /// `buffer.slice(..)` refers to the entire buffer, and `buffer.slice(n..)`
579    /// refers to the portion starting at the `n`th byte and extending to the
580    /// end of the buffer.
581    ///
582    /// # Panics
583    ///
584    /// - If `bounds` is outside of the bounds of `self`.
585    #[track_caller]
586    pub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferSlice<'a> {
587        let (offset, size) = range_to_offset_size(bounds, self.size);
588        check_buffer_bounds(self.size, offset, size);
589        BufferSlice {
590            buffer: self.buffer,
591            offset: self.offset + offset, // check_buffer_bounds ensures this does not overflow
592            size,                         // check_buffer_bounds ensures this is essentially min()
593        }
594    }
595
596    /// Map the buffer to host (CPU) memory, making it available for reading or writing via
597    /// [`get_mapped_range()`](Self::get_mapped_range). The buffer becomes accessible once the
598    /// `callback` is invoked with [`Ok`].
599    ///
600    /// Use this when you want to map the buffer immediately. If you need to submit GPU work that
601    /// uses the buffer before mapping it, use `map_buffer_on_submit` on
602    /// [`CommandEncoder`][CEmbos], [`CommandBuffer`][CBmbos], [`RenderPass`][RPmbos], or
603    /// [`ComputePass`][CPmbos] to schedule the mapping after submission. This avoids extra calls to
604    /// [`Buffer::map_async()`] or [`BufferSlice::map_async()`] and lets you initiate mapping from a
605    /// more convenient place.
606    ///
607    /// For the callback to run, either [`queue.submit(..)`][q::s], [`instance.poll_all(..)`][i::p_a],
608    /// or [`device.poll(..)`][d::p] must be called elsewhere in the runtime, possibly integrated into
609    /// an event loop or run on a separate thread.
610    ///
611    /// The callback runs on the thread that first calls one of the above functions after the GPU work
612    /// completes. There are no restrictions on the code you can run in the callback; however, on native
613    /// the polling call will not return until the callback finishes, so keep callbacks short (set flags,
614    /// send messages, etc.).
615    ///
616    /// While a buffer is mapped, it cannot be used by other commands; at any time, either the GPU or
617    /// the CPU has exclusive access to the buffer’s contents.
618    ///
619    /// This can also be performed using [`Buffer::map_async()`].
620    ///
621    /// # Panics
622    ///
623    /// - If the buffer’s [`BufferUsages`] do not allow the requested [`MapMode`].
624    /// - If the beginning of this slice is not aligned to [`MAP_ALIGNMENT`] within the buffer.
625    /// - If the length of this slice is not a multiple of 4.
626    ///
627    /// [CEmbos]: CommandEncoder::map_buffer_on_submit
628    /// [CBmbos]: CommandBuffer::map_buffer_on_submit
629    /// [RPmbos]: RenderPass::map_buffer_on_submit
630    /// [CPmbos]: ComputePass::map_buffer_on_submit
631    /// [q::s]: Queue::submit
632    /// [i::p_a]: Instance::poll_all
633    /// [d::p]: Device::poll
634    pub fn map_async(
635        &self,
636        mode: MapMode,
637        callback: impl FnOnce(Result<(), BufferAsyncError>) + WasmNotSend + 'static,
638    ) {
639        let mut mc = self.buffer.map_context.lock();
640        if mc.mapped.is_some() {
641            // Buffer is already mapped; fail
642            drop(mc);
643            callback(Err(BufferAsyncError));
644            return;
645        }
646
647        let end = self.offset + self.size;
648        mc.mapped = Some(MappingInfo {
649            range: self.offset..end,
650            kind: mode,
651        });
652        drop(mc); // release the lock of map_context as callback can call lock it again
653
654        self.buffer
655            .inner
656            .map_async(mode, self.offset..end, Box::new(callback));
657    }
658
659    /// Gain read-only access to the bytes of a [mapped] [`Buffer`].
660    ///
661    /// Returns a [`BufferView`] referring to the buffer range represented by
662    /// `self`. See the documentation for [`BufferView`] for details.
663    ///
664    /// Multiple views may be obtained and used simultaneously as long as they are from
665    /// non-overlapping slices.
666    ///
667    /// This can also be performed using [`Buffer::get_mapped_range()`].
668    ///
669    /// # Errors
670    ///
671    /// - If the beginning of this slice is not aligned to [`MAP_ALIGNMENT`] within the buffer.
672    /// - If the length of this slice is not a multiple of 4.
673    /// - If the buffer to which `self` refers is not currently [mapped].
674    /// - If you try to create a view which overlaps an existing [`BufferViewMut`].
675    ///
676    /// [mapped]: Buffer#mapping-buffers
677    #[track_caller]
678    pub fn get_mapped_range(&self) -> Result<BufferView, MapRangeError> {
679        let subrange = Subrange::new(self.offset, self.size, RangeMappingKind::Immutable);
680        let range = self.buffer.inner.get_mapped_range(subrange.index.clone())?;
681        self.buffer.map_context.lock().validate_and_add(subrange)?;
682        Ok(BufferView {
683            buffer: self.buffer.clone(),
684            size: self.size,
685            offset: self.offset,
686            inner: range,
687        })
688    }
689
690    /// Gain write-only access to the bytes of a [mapped] [`Buffer`].
691    ///
692    /// Returns a [`BufferViewMut`] referring to the buffer range represented by
693    /// `self`. See the documentation for [`BufferViewMut`] for more details.
694    ///
695    /// Multiple views may be obtained and used simultaneously as long as they are from
696    /// non-overlapping slices.
697    ///
698    /// This can also be performed using [`Buffer::get_mapped_range_mut()`].
699    ///
700    /// # Errors
701    ///
702    /// - If the beginning of this slice is not aligned to [`MAP_ALIGNMENT`] within the buffer.
703    /// - If the length of this slice is not a multiple of 4.
704    /// - If the buffer to which `self` refers is not currently [mapped].
705    /// - If you try to create a view which overlaps an existing [`BufferView`] or [`BufferViewMut`].
706    ///
707    /// [mapped]: Buffer#mapping-buffers
708    #[track_caller]
709    pub fn get_mapped_range_mut(&self) -> Result<BufferViewMut, MapRangeError> {
710        let subrange = Subrange::new(self.offset, self.size, RangeMappingKind::Mutable);
711        let range = self.buffer.inner.get_mapped_range(subrange.index.clone())?;
712        self.buffer.map_context.lock().validate_and_add(subrange)?;
713        Ok(BufferViewMut {
714            buffer: self.buffer.clone(),
715            size: self.size,
716            offset: self.offset,
717            inner: range,
718        })
719    }
720
721    /// Returns the buffer this is a slice of.
722    ///
723    /// You should usually not need to call this, and if you received the buffer from code you
724    /// do not control, you should refrain from accessing the buffer outside the bounds of the
725    /// slice. Nevertheless, it’s possible to get this access, so this method makes it simple.
726    pub fn buffer(&self) -> &'a Buffer {
727        self.buffer
728    }
729
730    /// Returns the offset in [`Self::buffer()`] this slice starts at.
731    pub fn offset(&self) -> BufferAddress {
732        self.offset
733    }
734
735    /// Returns the size of this slice.
736    pub fn size(&self) -> BufferAddress {
737        self.size
738    }
739}
740
741impl<'a> TryFrom<BufferSlice<'a>> for crate::BufferBinding<'a> {
742    type Error = ();
743
744    /// Convert a [`BufferSlice`] to an equivalent [`BufferBinding`],
745    /// provided that it will be used without a dynamic offset.
746    fn try_from(value: BufferSlice<'a>) -> Result<Self, Self::Error> {
747        Ok(BufferBinding {
748            buffer: value.buffer,
749            offset: value.offset,
750            size: Some(NonZero::new(value.size()).ok_or(())?),
751        })
752    }
753}
754
755impl<'a> TryFrom<BufferSlice<'a>> for crate::BindingResource<'a> {
756    type Error = ();
757
758    /// Convert a [`BufferSlice`] to an equivalent [`BindingResource::Buffer`],
759    /// provided that it will be used without a dynamic offset.
760    fn try_from(value: BufferSlice<'a>) -> Result<Self, Self::Error> {
761        Ok(crate::BindingResource::Buffer(
762            crate::BufferBinding::try_from(value)?,
763        ))
764    }
765}
766
767fn range_overlaps(a: &Range<BufferAddress>, b: &Range<BufferAddress>) -> bool {
768    a.start < b.end && b.start < a.end
769}
770
771fn range_contains(a: &Range<BufferAddress>, b: &Range<BufferAddress>) -> bool {
772    a.start <= b.start && a.end >= b.end
773}
774
775#[derive(Debug, Copy, Clone)]
776enum RangeMappingKind {
777    Mutable,
778    Immutable,
779}
780
781impl RangeMappingKind {
782    /// Returns true if a range of this kind can touch the same bytes as a range of the other kind.
783    ///
784    /// This is Rust's Mutable XOR Shared rule.
785    fn allowed_concurrently_with(self, other: Self) -> bool {
786        matches!(
787            (self, other),
788            (RangeMappingKind::Immutable, RangeMappingKind::Immutable)
789        )
790    }
791}
792
793#[derive(Debug, Clone)]
794struct Subrange {
795    index: Range<BufferAddress>,
796    kind: RangeMappingKind,
797}
798
799impl Subrange {
800    fn new(offset: BufferAddress, size: BufferAddress, kind: RangeMappingKind) -> Self {
801        Self {
802            index: offset..(offset + size),
803            kind,
804        }
805    }
806}
807
808impl fmt::Display for Subrange {
809    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
810        write!(
811            f,
812            "{}..{} ({:?})",
813            self.index.start, self.index.end, self.kind
814        )
815    }
816}
817
818/// Represents information about current mapping.
819#[derive(Debug)]
820pub struct MappingInfo {
821    /// The range of the buffer that is mapped.
822    ///
823    /// All [`BufferView`]s and [`BufferViewMut`]s must fall within this range.
824    pub(crate) range: Range<BufferAddress>,
825    /// The mode in which the buffer is mapped.
826    pub(crate) kind: MapMode,
827}
828
829/// The mapped portion of a buffer, if any, and its outstanding views.
830///
831/// This ensures that views fall within the mapped range and don't overlap.
832#[derive(Debug)]
833pub(crate) struct MapContext {
834    /// This becomes Some(...) when the buffer is mapped at creation time, and
835    /// when you call `map_async` on some [`BufferSlice`] (so technically, it
836    /// indicates the data that is *or has been requested to be* mapped.)
837    mapped: Option<MappingInfo>,
838
839    /// The ranges covered by all outstanding [`BufferView`]s and
840    /// [`BufferViewMut`]s. These are non-overlapping, and are all contained
841    /// within `mapped_range`.
842    sub_ranges: Vec<Subrange>,
843
844    /// The set of buffers that are currently alive on the device.
845    /// This is used to ensure that all buffers are unmapped before the device is destroyed.
846    ///
847    /// We keep it here
848    device_buffers: Arc<Mutex<HashSet<WeakMapContext>>>,
849}
850
851#[derive(Debug, Clone)]
852pub(crate) struct WeakMapContext(Weak<Mutex<MapContext>>);
853
854impl Eq for WeakMapContext {}
855impl PartialEq for WeakMapContext {
856    fn eq(&self, other: &Self) -> bool {
857        self.0.ptr_eq(&other.0)
858    }
859}
860
861impl Hash for WeakMapContext {
862    fn hash<H: Hasher>(&self, state: &mut H) {
863        self.0.as_ptr().hash(state);
864    }
865}
866
867impl WeakMapContext {
868    fn alive(&self) -> bool {
869        self.0.strong_count() > 0
870    }
871
872    pub(crate) fn unmap(&self) {
873        if let Some(map_context) = self.0.upgrade() {
874            map_context.lock().reset();
875        }
876    }
877}
878
879impl RangeMappingKind {
880    fn mode(&self) -> MapMode {
881        match self {
882            RangeMappingKind::Immutable => MapMode::Read,
883            RangeMappingKind::Mutable => MapMode::Write,
884        }
885    }
886}
887
888impl MapContext {
889    /// Creates a new `MapContext`.
890    ///
891    /// For [`mapped_at_creation`] buffers, pass the full buffer range in the
892    /// `mapped_range` argument. For other buffers, pass `None`.
893    ///
894    /// [`mapped_at_creation`]: BufferDescriptor::mapped_at_creation
895    pub(crate) fn new(
896        mapped: Option<MappingInfo>,
897        device_buffers: &Arc<Mutex<HashSet<WeakMapContext>>>,
898    ) -> Arc<Mutex<Self>> {
899        let result = Arc::new(Mutex::new(Self {
900            mapped,
901            sub_ranges: Vec::new(),
902            device_buffers: Arc::clone(device_buffers),
903        }));
904        device_buffers
905            .lock()
906            .insert(WeakMapContext(Arc::downgrade(&result)));
907        result
908    }
909
910    /// Record that the buffer is no longer mapped.
911    fn reset(&mut self) {
912        self.mapped = None;
913
914        assert!(
915            self.sub_ranges.is_empty(),
916            "You cannot unmap a buffer that still has accessible mapped views"
917        );
918    }
919
920    /// Record that the `size` bytes of the buffer at `offset` are now viewed.
921    ///
922    /// # Errors
923    ///
924    /// This returns an error if the given range is invalid.
925    fn validate_and_add(&mut self, new_sub: Subrange) -> Result<(), MapRangeError> {
926        let Some(mapped) = self.mapped.as_ref() else {
927            return Err(MapRangeError(
928                "tried to call get_mapped_range(_mut) on an unmapped buffer".into(),
929            ));
930        };
931        if mapped.kind != new_sub.kind.mode() {
932            return Err(MapRangeError(alloc::format!(
933                "tried to call get_mapped_range(_mut) on a buffer that was mapped for {:?}, \
934                 but the requested range is for {:?}",
935                mapped.kind,
936                new_sub.kind.mode()
937            )));
938        }
939        if !range_contains(&mapped.range, &new_sub.index) {
940            return Err(MapRangeError(alloc::format!(
941                "tried to call get_mapped_range(_mut) on a range that is not entirely mapped. \
942                 Attempted to get range {}, but the mapped range is {}..{}",
943                new_sub,
944                mapped.range.start,
945                mapped.range.end
946            )));
947        }
948        // This check is essential for avoiding undefined behavior: it is the
949        // only thing that ensures that `&mut` references to the buffer's
950        // contents don't alias anything else.
951        for sub in self.sub_ranges.iter() {
952            if range_overlaps(&sub.index, &new_sub.index)
953                && !sub.kind.allowed_concurrently_with(new_sub.kind)
954            {
955                return Err(MapRangeError(alloc::format!(
956                    "tried to call get_mapped_range(_mut) on a range that has already \
957                     been mapped and would break Rust memory aliasing rules. Attempted \
958                     to get range {}, and the conflicting range is {}",
959                    new_sub,
960                    sub
961                )));
962            }
963        }
964        self.sub_ranges.push(new_sub);
965        Ok(())
966    }
967
968    /// Record that the `size` bytes of the buffer at `offset` are no longer viewed.
969    ///
970    /// # Panics
971    ///
972    /// This panics if the given range does not exactly match one previously
973    /// passed to [`MapContext::validate_and_add`].
974    pub(crate) fn remove(&mut self, offset: BufferAddress, size: BufferAddress) {
975        let end = offset + size;
976
977        let index = self
978            .sub_ranges
979            .iter()
980            .position(|r| r.index == (offset..end))
981            .expect("unable to remove range from map context");
982        self.sub_ranges.swap_remove(index);
983    }
984}
985
986impl Drop for MapContext {
987    fn drop(&mut self) {
988        self.device_buffers.lock().retain(|f| f.alive());
989    }
990}
991
992/// Describes a [`Buffer`].
993///
994/// For use with [`Device::create_buffer`].
995///
996/// Corresponds to [WebGPU `GPUBufferDescriptor`](
997/// https://gpuweb.github.io/gpuweb/#dictdef-gpubufferdescriptor).
998pub type BufferDescriptor<'a> = wgt::BufferDescriptor<Label<'a>>;
999static_assertions::assert_impl_all!(BufferDescriptor<'_>: Send, Sync);
1000
1001/// Error occurred when trying to async map a buffer.
1002#[derive(Clone, PartialEq, Eq, Debug)]
1003pub struct BufferAsyncError;
1004static_assertions::assert_impl_all!(BufferAsyncError: Send, Sync);
1005
1006impl fmt::Display for BufferAsyncError {
1007    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1008        write!(f, "Error occurred when trying to async map a buffer")
1009    }
1010}
1011
1012impl error::Error for BufferAsyncError {}
1013
1014/// Error returned by [`BufferSlice::get_mapped_range`] and [`BufferSlice::get_mapped_range_mut`].
1015///
1016/// Corresponds to the `OperationError` thrown by
1017/// [`getMappedRange()`](https://gpuweb.github.io/gpuweb/#dom-gpubuffer-getmappedrange)
1018/// in the WebGPU spec.
1019#[derive(Clone, Debug)]
1020pub struct MapRangeError(pub(crate) String);
1021static_assertions::assert_impl_all!(MapRangeError: Send, Sync);
1022
1023impl fmt::Display for MapRangeError {
1024    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1025        write!(f, "Buffer view error: {}", self.0)
1026    }
1027}
1028
1029impl error::Error for MapRangeError {}
1030
1031/// A read-only view of a mapped buffer's bytes.
1032///
1033/// To get a `BufferView`, first [map] the buffer, and then
1034/// call `buffer.slice(range).get_mapped_range()`.
1035///
1036/// `BufferView` dereferences to `&[u8]`, so you can use all the usual Rust
1037/// slice methods to access the buffer's contents. It also implements
1038/// `AsRef<[u8]>`, if that's more convenient.
1039///
1040/// Before the buffer can be unmapped, all `BufferView`s observing it
1041/// must be dropped. Otherwise, the call to [`Buffer::unmap`] or [`Buffer::destroy`]
1042/// or [`Device::destroy`] will panic. On native buffer destruction on device lost will
1043/// block until all views are dropped, thus it's recommended to not keep views alive
1044/// across [`Device::poll`], [`Queue::submit`] or [`Surface::configure`] to prevent deadlocks.
1045///
1046/// For example code, see the documentation on [mapping buffers][map].
1047///
1048/// [map]: Buffer#mapping-buffers
1049/// [`map_async`]: BufferSlice::map_async
1050#[derive(Debug)]
1051pub struct BufferView {
1052    // we need to drop BufferMappedRange before Buffer,
1053    // so that the buffer is not unmapped while the view is still alive
1054    inner: dispatch::DispatchBufferMappedRange,
1055    // `buffer, offset, size` are similar to `BufferSlice`, except that they own the buffer.
1056    buffer: Buffer,
1057    offset: BufferAddress,
1058    size: BufferAddress,
1059}
1060
1061/// A write-only view of a mapped buffer's bytes.
1062///
1063/// To get a `BufferViewMut`, first [map] the buffer, and then
1064/// call `buffer.slice(range).get_mapped_range_mut()`.
1065///
1066/// Because Rust has no write-only reference type
1067/// (`&[u8]` is read-only and `&mut [u8]` is read-write),
1068/// this type does not dereference to a slice in the way that [`BufferView`] does.
1069/// Instead, [`.slice()`][BufferViewMut::slice] returns a special [`WriteOnly`] pointer type,
1070/// and there are also a few convenience methods such as [`BufferViewMut::copy_from_slice()`].
1071///
1072/// Before the buffer can be unmapped, all `BufferViewMut`s observing it
1073/// must be dropped. Otherwise, the call to [`Buffer::unmap`] or [`Buffer::destroy`]
1074/// or [`Device::destroy`] will panic. On native buffer destruction on device lost will
1075/// block until all views are dropped, thus it's recommended to not keep views alive
1076/// across [`Device::poll`], [`Queue::submit`] or [`Surface::configure`] to prevent deadlocks.
1077///
1078/// For example code, see the documentation on [mapping buffers][map].
1079///
1080/// [map]: Buffer#mapping-buffers
1081#[derive(Debug)]
1082pub struct BufferViewMut {
1083    // we need to drop BufferMappedRange before Buffer,
1084    // so that the buffer is not unmapped while the view is still alive
1085    inner: dispatch::DispatchBufferMappedRange,
1086    // `buffer, offset, size` are similar to `BufferSlice`, except that they own the buffer.
1087    buffer: Buffer,
1088    offset: BufferAddress,
1089    size: BufferAddress,
1090}
1091
1092// `BufferView` simply dereferences. `BufferViewMut` cannot, because mapped memory may be
1093// write-combining memory <https://en.wikipedia.org/wiki/Write_combining>,
1094// and not support the expected behavior of atomic accesses.
1095// Further context: <https://github.com/gfx-rs/wgpu/issues/8897>
1096
1097impl core::ops::Deref for BufferView {
1098    type Target = [u8];
1099
1100    #[inline]
1101    fn deref(&self) -> &[u8] {
1102        // SAFETY: this is a read mapping
1103        unsafe { self.inner.read_slice() }
1104    }
1105}
1106
1107impl AsRef<[u8]> for BufferView {
1108    #[inline]
1109    fn as_ref(&self) -> &[u8] {
1110        self
1111    }
1112}
1113
1114impl Drop for BufferView {
1115    fn drop(&mut self) {
1116        self.buffer
1117            .map_context
1118            .lock()
1119            .remove(self.offset, self.size);
1120    }
1121}
1122
1123impl Drop for BufferViewMut {
1124    fn drop(&mut self) {
1125        self.buffer
1126            .map_context
1127            .lock()
1128            .remove(self.offset, self.size);
1129    }
1130}
1131
1132#[cfg(webgpu)]
1133impl BufferView {
1134    /// Provides the same data as dereferencing the view, but as a `Uint8Array` in js.
1135    /// This can be MUCH faster than dereferencing the view which copies the data into
1136    /// the Rust / wasm heap.
1137    pub fn as_uint8array(&self) -> &js_sys::Uint8Array {
1138        self.inner.as_uint8array()
1139    }
1140}
1141
1142/// These methods are equivalent to the methods of the same names on [`WriteOnly`].
1143impl BufferViewMut {
1144    /// Returns the length of this view; the number of bytes to be written.
1145    pub fn len(&self) -> usize {
1146        // cannot fail because we can't actually map more than isize::MAX bytes
1147        usize::try_from(self.size).unwrap()
1148    }
1149
1150    /// Returns `true` if the view has a length of 0.
1151    ///
1152    /// Note that this is currently impossible.
1153    pub fn is_empty(&self) -> bool {
1154        self.len() == 0
1155    }
1156
1157    /// Returns a [`WriteOnly`] reference to a portion of this.
1158    ///
1159    /// `.slice(..)` can be used to access the whole data.
1160    pub fn slice<'a, S: RangeBounds<usize>>(&'a mut self, bounds: S) -> WriteOnly<'a, [u8]> {
1161        // SAFETY: this is a write mapping
1162        unsafe { self.inner.write_slice() }.into_slice(bounds)
1163    }
1164
1165    /// Copies all elements from src into `self`.
1166    ///
1167    /// The length of `src` must be the same as `self`.
1168    ///
1169    /// This method is equivalent to
1170    /// [`self.slice(..).copy_from_slice(src)`][WriteOnly::copy_from_slice].
1171    pub fn copy_from_slice(&mut self, src: &[u8]) {
1172        self.slice(..).copy_from_slice(src)
1173    }
1174}
1175
1176#[track_caller]
1177fn check_buffer_bounds(
1178    whole_size: BufferAddress,
1179    slice_offset: BufferAddress,
1180    slice_size: BufferAddress,
1181) {
1182    if slice_offset > whole_size {
1183        panic!(
1184            "slice offset {} is out of range for buffer of size {}",
1185            slice_offset, whole_size
1186        );
1187    }
1188
1189    // Detect integer overflow.
1190    let end = slice_offset.checked_add(slice_size);
1191    if end.is_none_or(|end| end > whole_size) {
1192        panic!(
1193            "slice offset {} size {} is out of range for buffer of size {}",
1194            slice_offset, slice_size, whole_size
1195        );
1196    }
1197}
1198
1199#[track_caller]
1200pub(crate) fn range_to_offset_size<S: RangeBounds<BufferAddress>>(
1201    bounds: S,
1202    whole_size: BufferAddress,
1203) -> (BufferAddress, BufferAddress) {
1204    let offset = match bounds.start_bound() {
1205        Bound::Included(&bound) => bound,
1206        Bound::Excluded(&bound) => bound + 1,
1207        Bound::Unbounded => 0,
1208    };
1209    let size = match bounds.end_bound() {
1210        Bound::Included(&bound) => bound + 1 - offset,
1211        Bound::Excluded(&bound) => bound - offset,
1212        Bound::Unbounded => whole_size - offset,
1213    };
1214
1215    (offset, size)
1216}
1217
1218#[cfg(test)]
1219mod tests {
1220    use super::{check_buffer_bounds, range_overlaps, range_to_offset_size};
1221
1222    #[test]
1223    fn range_to_offset_size_works() {
1224        let whole = 100;
1225
1226        assert_eq!(range_to_offset_size(0..2, whole), (0, 2));
1227        assert_eq!(range_to_offset_size(2..5, whole), (2, 3));
1228        assert_eq!(range_to_offset_size(.., whole), (0, whole));
1229        assert_eq!(range_to_offset_size(21.., whole), (21, whole - 21));
1230        assert_eq!(range_to_offset_size(0.., whole), (0, whole));
1231        assert_eq!(range_to_offset_size(..21, whole), (0, 21));
1232    }
1233
1234    #[test]
1235    fn check_buffer_bounds_works_for_end_in_range() {
1236        check_buffer_bounds(200, 100, 50);
1237        check_buffer_bounds(200, 100, 100);
1238        check_buffer_bounds(u64::MAX, u64::MAX - 100, 100);
1239        check_buffer_bounds(u64::MAX, 0, u64::MAX);
1240        check_buffer_bounds(u64::MAX, 1, u64::MAX - 1);
1241        // Test empty buffer slices
1242        check_buffer_bounds(0, 0, 0);
1243        check_buffer_bounds(u64::MAX, u64::MAX, 0);
1244    }
1245
1246    #[test]
1247    #[should_panic]
1248    fn check_buffer_bounds_panics_for_end_over_size() {
1249        check_buffer_bounds(200, 100, 101);
1250    }
1251
1252    #[test]
1253    #[should_panic]
1254    fn check_buffer_bounds_panics_for_end_wraparound() {
1255        check_buffer_bounds(u64::MAX, 1, u64::MAX);
1256    }
1257
1258    #[test]
1259    fn range_overlapping() {
1260        // First range to the left
1261        assert_eq!(range_overlaps(&(0..1), &(1..3)), false);
1262        // First range overlaps left edge
1263        assert_eq!(range_overlaps(&(0..2), &(1..3)), true);
1264        // First range completely inside second
1265        assert_eq!(range_overlaps(&(1..2), &(0..3)), true);
1266        // First range completely surrounds second
1267        assert_eq!(range_overlaps(&(0..3), &(1..2)), true);
1268        // First range overlaps right edge
1269        assert_eq!(range_overlaps(&(1..3), &(0..2)), true);
1270        // First range entirely to the right
1271        assert_eq!(range_overlaps(&(2..3), &(0..2)), false);
1272    }
1273}