wgpu/api/
buffer.rs

1use std::{
2    error, fmt,
3    ops::{Bound, Deref, DerefMut, Range, RangeBounds},
4    sync::Arc,
5    thread,
6};
7
8use parking_lot::Mutex;
9
10use crate::context::DynContext;
11use crate::*;
12
13/// Handle to a GPU-accessible buffer.
14///
15/// Created with [`Device::create_buffer`] or
16/// [`DeviceExt::create_buffer_init`](util::DeviceExt::create_buffer_init).
17///
18/// Corresponds to [WebGPU `GPUBuffer`](https://gpuweb.github.io/gpuweb/#buffer-interface).
19///
20/// A `Buffer`'s bytes have "interior mutability": functions like
21/// [`Queue::write_buffer`] or [mapping] a buffer for writing only require a
22/// `&Buffer`, not a `&mut Buffer`, even though they modify its contents. `wgpu`
23/// prevents simultaneous reads and writes of buffer contents using run-time
24/// checks.
25///
26/// [mapping]: Buffer#mapping-buffers
27///
28/// # Mapping buffers
29///
30/// If a `Buffer` is created with the appropriate [`usage`], it can be *mapped*:
31/// you can make its contents accessible to the CPU as an ordinary `&[u8]` or
32/// `&mut [u8]` slice of bytes. Buffers created with the
33/// [`mapped_at_creation`][mac] flag set are also mapped initially.
34///
35/// Depending on the hardware, the buffer could be memory shared between CPU and
36/// GPU, so that the CPU has direct access to the same bytes the GPU will
37/// consult; or it may be ordinary CPU memory, whose contents the system must
38/// copy to/from the GPU as needed. This crate's API is designed to work the
39/// same way in either case: at any given time, a buffer is either mapped and
40/// available to the CPU, or unmapped and ready for use by the GPU, but never
41/// both. This makes it impossible for either side to observe changes by the
42/// other immediately, and any necessary transfers can be carried out when the
43/// buffer transitions from one state to the other.
44///
45/// There are two ways to map a buffer:
46///
47/// - If [`BufferDescriptor::mapped_at_creation`] is `true`, then the entire
48///   buffer is mapped when it is created. This is the easiest way to initialize
49///   a new buffer. You can set `mapped_at_creation` on any kind of buffer,
50///   regardless of its [`usage`] flags.
51///
52/// - If the buffer's [`usage`] includes the [`MAP_READ`] or [`MAP_WRITE`]
53///   flags, then you can call `buffer.slice(range).map_async(mode, callback)`
54///   to map the portion of `buffer` given by `range`. This waits for the GPU to
55///   finish using the buffer, and invokes `callback` as soon as the buffer is
56///   safe for the CPU to access.
57///
58/// Once a buffer is mapped:
59///
60/// - You can call `buffer.slice(range).get_mapped_range()` to obtain a
61///   [`BufferView`], which dereferences to a `&[u8]` that you can use to read
62///   the buffer's contents.
63///
64/// - Or, you can call `buffer.slice(range).get_mapped_range_mut()` to obtain a
65///   [`BufferViewMut`], which dereferences to a `&mut [u8]` that you can use to
66///   read and write the buffer's contents.
67///
68/// The given `range` must fall within the mapped portion of the buffer. If you
69/// attempt to access overlapping ranges, even for shared access only, these
70/// methods panic.
71///
72/// While a buffer is mapped, you may not submit any commands to the GPU that
73/// access it. You may record command buffers that use the buffer, but if you
74/// submit them while the buffer is mapped, submission will panic.
75///
76/// When you are done using the buffer on the CPU, you must call
77/// [`Buffer::unmap`] to make it available for use by the GPU again. All
78/// [`BufferView`] and [`BufferViewMut`] views referring to the buffer must be
79/// dropped before you unmap it; otherwise, [`Buffer::unmap`] will panic.
80///
81/// # Example
82///
83/// If `buffer` was created with [`BufferUsages::MAP_WRITE`], we could fill it
84/// with `f32` values like this:
85///
86/// ```no_run
87/// # mod bytemuck {
88/// #     pub fn cast_slice_mut(bytes: &mut [u8]) -> &mut [f32] { todo!() }
89/// # }
90/// # let device: wgpu::Device = todo!();
91/// # let buffer: wgpu::Buffer = todo!();
92/// let buffer = std::sync::Arc::new(buffer);
93/// let capturable = buffer.clone();
94/// buffer.slice(..).map_async(wgpu::MapMode::Write, move |result| {
95///     if result.is_ok() {
96///         let mut view = capturable.slice(..).get_mapped_range_mut();
97///         let floats: &mut [f32] = bytemuck::cast_slice_mut(&mut view);
98///         floats.fill(42.0);
99///         drop(view);
100///         capturable.unmap();
101///     }
102/// });
103/// ```
104///
105/// This code takes the following steps:
106///
107/// - First, it moves `buffer` into an [`Arc`], and makes a clone for capture by
108///   the callback passed to [`map_async`]. Since a [`map_async`] callback may be
109///   invoked from another thread, interaction between the callback and the
110///   thread calling [`map_async`] generally requires some sort of shared heap
111///   data like this. In real code, the [`Arc`] would probably own some larger
112///   structure that itself owns `buffer`.
113///
114/// - Then, it calls [`Buffer::slice`] to make a [`BufferSlice`] referring to
115///   the buffer's entire contents.
116///
117/// - Next, it calls [`BufferSlice::map_async`] to request that the bytes to
118///   which the slice refers be made accessible to the CPU ("mapped"). This may
119///   entail waiting for previously enqueued operations on `buffer` to finish.
120///   Although [`map_async`] itself always returns immediately, it saves the
121///   callback function to be invoked later.
122///
123/// - When some later call to [`Device::poll`] or [`Instance::poll_all`] (not
124///   shown in this example) determines that the buffer is mapped and ready for
125///   the CPU to use, it invokes the callback function.
126///
127/// - The callback function calls [`Buffer::slice`] and then
128///   [`BufferSlice::get_mapped_range_mut`] to obtain a [`BufferViewMut`], which
129///   dereferences to a `&mut [u8]` slice referring to the buffer's bytes.
130///
131/// - It then uses the [`bytemuck`] crate to turn the `&mut [u8]` into a `&mut
132///   [f32]`, and calls the slice [`fill`] method to fill the buffer with a
133///   useful value.
134///
135/// - Finally, the callback drops the view and calls [`Buffer::unmap`] to unmap
136///   the buffer. In real code, the callback would also need to do some sort of
137///   synchronization to let the rest of the program know that it has completed
138///   its work.
139///
140/// If using [`map_async`] directly is awkward, you may find it more convenient to
141/// use [`Queue::write_buffer`] and [`util::DownloadBuffer::read_buffer`].
142/// However, those each have their own tradeoffs; the asynchronous nature of GPU
143/// execution makes it hard to avoid friction altogether.
144///
145/// [`Arc`]: std::sync::Arc
146/// [`map_async`]: BufferSlice::map_async
147/// [`bytemuck`]: https://crates.io/crates/bytemuck
148/// [`fill`]: slice::fill
149///
150/// ## Mapping buffers on the web
151///
152/// When compiled to WebAssembly and running in a browser content process,
153/// `wgpu` implements its API in terms of the browser's WebGPU implementation.
154/// In this context, `wgpu` is further isolated from the GPU:
155///
156/// - Depending on the browser's WebGPU implementation, mapping and unmapping
157///   buffers probably entails copies between WebAssembly linear memory and the
158///   graphics driver's buffers.
159///
160/// - All modern web browsers isolate web content in its own sandboxed process,
161///   which can only interact with the GPU via interprocess communication (IPC).
162///   Although most browsers' IPC systems use shared memory for large data
163///   transfers, there will still probably need to be copies into and out of the
164///   shared memory buffers.
165///
166/// All of these copies contribute to the cost of buffer mapping in this
167/// configuration.
168///
169/// [`usage`]: BufferDescriptor::usage
170/// [mac]: BufferDescriptor::mapped_at_creation
171/// [`MAP_READ`]: BufferUsages::MAP_READ
172/// [`MAP_WRITE`]: BufferUsages::MAP_WRITE
173#[derive(Debug)]
174pub struct Buffer {
175    pub(crate) context: Arc<C>,
176    pub(crate) data: Box<Data>,
177    pub(crate) map_context: Mutex<MapContext>,
178    pub(crate) size: wgt::BufferAddress,
179    pub(crate) usage: BufferUsages,
180    // Todo: missing map_state https://www.w3.org/TR/webgpu/#dom-gpubuffer-mapstate
181}
182#[cfg(send_sync)]
183static_assertions::assert_impl_all!(Buffer: Send, Sync);
184
185super::impl_partialeq_eq_hash!(Buffer);
186
187impl Buffer {
188    /// Return the binding view of the entire buffer.
189    pub fn as_entire_binding(&self) -> BindingResource<'_> {
190        BindingResource::Buffer(self.as_entire_buffer_binding())
191    }
192
193    /// Return the binding view of the entire buffer.
194    pub fn as_entire_buffer_binding(&self) -> BufferBinding<'_> {
195        BufferBinding {
196            buffer: self,
197            offset: 0,
198            size: None,
199        }
200    }
201
202    /// Returns the inner hal Buffer using a callback. The hal buffer will be `None` if the
203    /// backend type argument does not match with this wgpu Buffer
204    ///
205    /// # Safety
206    ///
207    /// - The raw handle obtained from the hal Buffer must not be manually destroyed
208    #[cfg(wgpu_core)]
209    pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Buffer>) -> R, R>(
210        &self,
211        hal_buffer_callback: F,
212    ) -> R {
213        if let Some(ctx) = self
214            .context
215            .as_any()
216            .downcast_ref::<crate::backend::ContextWgpuCore>()
217        {
218            unsafe {
219                ctx.buffer_as_hal::<A, F, R>(
220                    crate::context::downcast_ref(self.data.as_ref()),
221                    hal_buffer_callback,
222                )
223            }
224        } else {
225            hal_buffer_callback(None)
226        }
227    }
228
229    /// Return a slice of a [`Buffer`]'s bytes.
230    ///
231    /// Return a [`BufferSlice`] referring to the portion of `self`'s contents
232    /// indicated by `bounds`. Regardless of what sort of data `self` stores,
233    /// `bounds` start and end are given in bytes.
234    ///
235    /// A [`BufferSlice`] can be used to supply vertex and index data, or to map
236    /// buffer contents for access from the CPU. See the [`BufferSlice`]
237    /// documentation for details.
238    ///
239    /// The `range` argument can be half or fully unbounded: for example,
240    /// `buffer.slice(..)` refers to the entire buffer, and `buffer.slice(n..)`
241    /// refers to the portion starting at the `n`th byte and extending to the
242    /// end of the buffer.
243    pub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferSlice<'_> {
244        let (offset, size) = range_to_offset_size(bounds);
245        check_buffer_bounds(self.size, offset, size);
246        BufferSlice {
247            buffer: self,
248            offset,
249            size,
250        }
251    }
252
253    /// Flushes any pending write operations and unmaps the buffer from host memory.
254    pub fn unmap(&self) {
255        self.map_context.lock().reset();
256        DynContext::buffer_unmap(&*self.context, self.data.as_ref());
257    }
258
259    /// Destroy the associated native resources as soon as possible.
260    pub fn destroy(&self) {
261        DynContext::buffer_destroy(&*self.context, self.data.as_ref());
262    }
263
264    /// Returns the length of the buffer allocation in bytes.
265    ///
266    /// This is always equal to the `size` that was specified when creating the buffer.
267    pub fn size(&self) -> BufferAddress {
268        self.size
269    }
270
271    /// Returns the allowed usages for this `Buffer`.
272    ///
273    /// This is always equal to the `usage` that was specified when creating the buffer.
274    pub fn usage(&self) -> BufferUsages {
275        self.usage
276    }
277}
278
279/// A slice of a [`Buffer`], to be mapped, used for vertex or index data, or the like.
280///
281/// You can create a `BufferSlice` by calling [`Buffer::slice`]:
282///
283/// ```no_run
284/// # let buffer: wgpu::Buffer = todo!();
285/// let slice = buffer.slice(10..20);
286/// ```
287///
288/// This returns a slice referring to the second ten bytes of `buffer`. To get a
289/// slice of the entire `Buffer`:
290///
291/// ```no_run
292/// # let buffer: wgpu::Buffer = todo!();
293/// let whole_buffer_slice = buffer.slice(..);
294/// ```
295///
296/// You can pass buffer slices to methods like [`RenderPass::set_vertex_buffer`]
297/// and [`RenderPass::set_index_buffer`] to indicate which portion of the buffer
298/// a draw call should consult.
299///
300/// To access the slice's contents on the CPU, you must first [map] the buffer,
301/// and then call [`BufferSlice::get_mapped_range`] or
302/// [`BufferSlice::get_mapped_range_mut`] to obtain a view of the slice's
303/// contents. See the documentation on [mapping][map] for more details,
304/// including example code.
305///
306/// Unlike a Rust shared slice `&[T]`, whose existence guarantees that
307/// nobody else is modifying the `T` values to which it refers, a
308/// [`BufferSlice`] doesn't guarantee that the buffer's contents aren't
309/// changing. You can still record and submit commands operating on the
310/// buffer while holding a [`BufferSlice`]. A [`BufferSlice`] simply
311/// represents a certain range of the buffer's bytes.
312///
313/// The `BufferSlice` type is unique to the Rust API of `wgpu`. In the WebGPU
314/// specification, an offset and size are specified as arguments to each call
315/// working with the [`Buffer`], instead.
316///
317/// [map]: Buffer#mapping-buffers
318#[derive(Copy, Clone, Debug)]
319pub struct BufferSlice<'a> {
320    pub(crate) buffer: &'a Buffer,
321    pub(crate) offset: BufferAddress,
322    pub(crate) size: Option<BufferSize>,
323}
324#[cfg(send_sync)]
325static_assertions::assert_impl_all!(BufferSlice<'_>: Send, Sync);
326
327impl<'a> BufferSlice<'a> {
328    /// Map the buffer. Buffer is ready to map once the callback is called.
329    ///
330    /// For the callback to complete, either `queue.submit(..)`, `instance.poll_all(..)`, or `device.poll(..)`
331    /// must be called elsewhere in the runtime, possibly integrated into an event loop or run on a separate thread.
332    ///
333    /// The callback will be called on the thread that first calls the above functions after the gpu work
334    /// has completed. There are no restrictions on the code you can run in the callback, however on native the
335    /// call to the function will not complete until the callback returns, so prefer keeping callbacks short
336    /// and used to set flags, send messages, etc.
337    pub fn map_async(
338        &self,
339        mode: MapMode,
340        callback: impl FnOnce(Result<(), BufferAsyncError>) + WasmNotSend + 'static,
341    ) {
342        let mut mc = self.buffer.map_context.lock();
343        assert_eq!(mc.initial_range, 0..0, "Buffer is already mapped");
344        let end = match self.size {
345            Some(s) => self.offset + s.get(),
346            None => mc.total_size,
347        };
348        mc.initial_range = self.offset..end;
349
350        DynContext::buffer_map_async(
351            &*self.buffer.context,
352            self.buffer.data.as_ref(),
353            mode,
354            self.offset..end,
355            Box::new(callback),
356        )
357    }
358
359    /// Gain read-only access to the bytes of a [mapped] [`Buffer`].
360    ///
361    /// Return a [`BufferView`] referring to the buffer range represented by
362    /// `self`. See the documentation for [`BufferView`] for details.
363    ///
364    /// # Panics
365    ///
366    /// - This panics if the buffer to which `self` refers is not currently
367    ///   [mapped].
368    ///
369    /// - If you try to create overlapping views of a buffer, mutable or
370    ///   otherwise, `get_mapped_range` will panic.
371    ///
372    /// [mapped]: Buffer#mapping-buffers
373    pub fn get_mapped_range(&self) -> BufferView<'a> {
374        let end = self.buffer.map_context.lock().add(self.offset, self.size);
375        let data = DynContext::buffer_get_mapped_range(
376            &*self.buffer.context,
377            self.buffer.data.as_ref(),
378            self.offset..end,
379        );
380        BufferView { slice: *self, data }
381    }
382
383    /// Synchronously and immediately map a buffer for reading. If the buffer is not immediately mappable
384    /// through [`BufferDescriptor::mapped_at_creation`] or [`BufferSlice::map_async`], will fail.
385    ///
386    /// This is useful when targeting WebGPU and you want to pass mapped data directly to js.
387    /// Unlike `get_mapped_range` which unconditionally copies mapped data into the wasm heap,
388    /// this function directly hands you the ArrayBuffer that we mapped the data into in js.
389    ///
390    /// This is only available on WebGPU, on any other backends this will return `None`.
391    #[cfg(webgpu)]
392    pub fn get_mapped_range_as_array_buffer(&self) -> Option<js_sys::ArrayBuffer> {
393        self.buffer
394            .context
395            .as_any()
396            .downcast_ref::<crate::backend::ContextWebGpu>()
397            .map(|ctx| {
398                let buffer_data = crate::context::downcast_ref(self.buffer.data.as_ref());
399                let end = self.buffer.map_context.lock().add(self.offset, self.size);
400                ctx.buffer_get_mapped_range_as_array_buffer(buffer_data, self.offset..end)
401            })
402    }
403
404    /// Gain write access to the bytes of a [mapped] [`Buffer`].
405    ///
406    /// Return a [`BufferViewMut`] referring to the buffer range represented by
407    /// `self`. See the documentation for [`BufferViewMut`] for more details.
408    ///
409    /// # Panics
410    ///
411    /// - This panics if the buffer to which `self` refers is not currently
412    ///   [mapped].
413    ///
414    /// - If you try to create overlapping views of a buffer, mutable or
415    ///   otherwise, `get_mapped_range_mut` will panic.
416    ///
417    /// [mapped]: Buffer#mapping-buffers
418    pub fn get_mapped_range_mut(&self) -> BufferViewMut<'a> {
419        let end = self.buffer.map_context.lock().add(self.offset, self.size);
420        let data = DynContext::buffer_get_mapped_range(
421            &*self.buffer.context,
422            self.buffer.data.as_ref(),
423            self.offset..end,
424        );
425        BufferViewMut {
426            slice: *self,
427            data,
428            readable: self.buffer.usage.contains(BufferUsages::MAP_READ),
429        }
430    }
431}
432
433/// The mapped portion of a buffer, if any, and its outstanding views.
434///
435/// This ensures that views fall within the mapped range and don't overlap, and
436/// also takes care of turning `Option<BufferSize>` sizes into actual buffer
437/// offsets.
438#[derive(Debug)]
439pub(crate) struct MapContext {
440    /// The overall size of the buffer.
441    ///
442    /// This is just a convenient copy of [`Buffer::size`].
443    pub(crate) total_size: BufferAddress,
444
445    /// The range of the buffer that is mapped.
446    ///
447    /// This is `0..0` if the buffer is not mapped. This becomes non-empty when
448    /// the buffer is mapped at creation time, and when you call `map_async` on
449    /// some [`BufferSlice`] (so technically, it indicates the portion that is
450    /// *or has been requested to be* mapped.)
451    ///
452    /// All [`BufferView`]s and [`BufferViewMut`]s must fall within this range.
453    pub(crate) initial_range: Range<BufferAddress>,
454
455    /// The ranges covered by all outstanding [`BufferView`]s and
456    /// [`BufferViewMut`]s. These are non-overlapping, and are all contained
457    /// within `initial_range`.
458    sub_ranges: Vec<Range<BufferAddress>>,
459}
460
461impl MapContext {
462    pub(crate) fn new(total_size: BufferAddress) -> Self {
463        Self {
464            total_size,
465            initial_range: 0..0,
466            sub_ranges: Vec::new(),
467        }
468    }
469
470    /// Record that the buffer is no longer mapped.
471    fn reset(&mut self) {
472        self.initial_range = 0..0;
473
474        assert!(
475            self.sub_ranges.is_empty(),
476            "You cannot unmap a buffer that still has accessible mapped views"
477        );
478    }
479
480    /// Record that the `size` bytes of the buffer at `offset` are now viewed.
481    ///
482    /// Return the byte offset within the buffer of the end of the viewed range.
483    ///
484    /// # Panics
485    ///
486    /// This panics if the given range overlaps with any existing range.
487    fn add(&mut self, offset: BufferAddress, size: Option<BufferSize>) -> BufferAddress {
488        let end = match size {
489            Some(s) => offset + s.get(),
490            None => self.initial_range.end,
491        };
492        assert!(self.initial_range.start <= offset && end <= self.initial_range.end);
493        // This check is essential for avoiding undefined behavior: it is the
494        // only thing that ensures that `&mut` references to the buffer's
495        // contents don't alias anything else.
496        for sub in self.sub_ranges.iter() {
497            assert!(
498                end <= sub.start || offset >= sub.end,
499                "Intersecting map range with {sub:?}"
500            );
501        }
502        self.sub_ranges.push(offset..end);
503        end
504    }
505
506    /// Record that the `size` bytes of the buffer at `offset` are no longer viewed.
507    ///
508    /// # Panics
509    ///
510    /// This panics if the given range does not exactly match one previously
511    /// passed to [`add`].
512    ///
513    /// [`add]`: MapContext::add
514    fn remove(&mut self, offset: BufferAddress, size: Option<BufferSize>) {
515        let end = match size {
516            Some(s) => offset + s.get(),
517            None => self.initial_range.end,
518        };
519
520        let index = self
521            .sub_ranges
522            .iter()
523            .position(|r| *r == (offset..end))
524            .expect("unable to remove range from map context");
525        self.sub_ranges.swap_remove(index);
526    }
527}
528
529/// Describes a [`Buffer`].
530///
531/// For use with [`Device::create_buffer`].
532///
533/// Corresponds to [WebGPU `GPUBufferDescriptor`](
534/// https://gpuweb.github.io/gpuweb/#dictdef-gpubufferdescriptor).
535pub type BufferDescriptor<'a> = wgt::BufferDescriptor<Label<'a>>;
536static_assertions::assert_impl_all!(BufferDescriptor<'_>: Send, Sync);
537
538/// Error occurred when trying to async map a buffer.
539#[derive(Clone, PartialEq, Eq, Debug)]
540pub struct BufferAsyncError;
541static_assertions::assert_impl_all!(BufferAsyncError: Send, Sync);
542
543impl fmt::Display for BufferAsyncError {
544    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
545        write!(f, "Error occurred when trying to async map a buffer")
546    }
547}
548
549impl error::Error for BufferAsyncError {}
550
551/// Type of buffer mapping.
552#[derive(Debug, Clone, Copy, Eq, PartialEq)]
553pub enum MapMode {
554    /// Map only for reading
555    Read,
556    /// Map only for writing
557    Write,
558}
559static_assertions::assert_impl_all!(MapMode: Send, Sync);
560
561/// A read-only view of a mapped buffer's bytes.
562///
563/// To get a `BufferView`, first [map] the buffer, and then
564/// call `buffer.slice(range).get_mapped_range()`.
565///
566/// `BufferView` dereferences to `&[u8]`, so you can use all the usual Rust
567/// slice methods to access the buffer's contents. It also implements
568/// `AsRef<[u8]>`, if that's more convenient.
569///
570/// Before the buffer can be unmapped, all `BufferView`s observing it
571/// must be dropped. Otherwise, the call to [`Buffer::unmap`] will panic.
572///
573/// For example code, see the documentation on [mapping buffers][map].
574///
575/// [map]: Buffer#mapping-buffers
576/// [`map_async`]: BufferSlice::map_async
577#[derive(Debug)]
578pub struct BufferView<'a> {
579    slice: BufferSlice<'a>,
580    data: Box<dyn crate::context::BufferMappedRange>,
581}
582
583impl std::ops::Deref for BufferView<'_> {
584    type Target = [u8];
585
586    #[inline]
587    fn deref(&self) -> &[u8] {
588        self.data.slice()
589    }
590}
591
592impl AsRef<[u8]> for BufferView<'_> {
593    #[inline]
594    fn as_ref(&self) -> &[u8] {
595        self.data.slice()
596    }
597}
598
599/// A write-only view of a mapped buffer's bytes.
600///
601/// To get a `BufferViewMut`, first [map] the buffer, and then
602/// call `buffer.slice(range).get_mapped_range_mut()`.
603///
604/// `BufferViewMut` dereferences to `&mut [u8]`, so you can use all the usual
605/// Rust slice methods to access the buffer's contents. It also implements
606/// `AsMut<[u8]>`, if that's more convenient.
607///
608/// It is possible to read the buffer using this view, but doing so is not
609/// recommended, as it is likely to be slow.
610///
611/// Before the buffer can be unmapped, all `BufferViewMut`s observing it
612/// must be dropped. Otherwise, the call to [`Buffer::unmap`] will panic.
613///
614/// For example code, see the documentation on [mapping buffers][map].
615///
616/// [map]: Buffer#mapping-buffers
617#[derive(Debug)]
618pub struct BufferViewMut<'a> {
619    slice: BufferSlice<'a>,
620    data: Box<dyn crate::context::BufferMappedRange>,
621    readable: bool,
622}
623
624impl AsMut<[u8]> for BufferViewMut<'_> {
625    #[inline]
626    fn as_mut(&mut self) -> &mut [u8] {
627        self.data.slice_mut()
628    }
629}
630
631impl Deref for BufferViewMut<'_> {
632    type Target = [u8];
633
634    fn deref(&self) -> &Self::Target {
635        if !self.readable {
636            log::warn!("Reading from a BufferViewMut is slow and not recommended.");
637        }
638
639        self.data.slice()
640    }
641}
642
643impl DerefMut for BufferViewMut<'_> {
644    fn deref_mut(&mut self) -> &mut Self::Target {
645        self.data.slice_mut()
646    }
647}
648
649impl Drop for BufferView<'_> {
650    fn drop(&mut self) {
651        self.slice
652            .buffer
653            .map_context
654            .lock()
655            .remove(self.slice.offset, self.slice.size);
656    }
657}
658
659impl Drop for BufferViewMut<'_> {
660    fn drop(&mut self) {
661        self.slice
662            .buffer
663            .map_context
664            .lock()
665            .remove(self.slice.offset, self.slice.size);
666    }
667}
668
669impl Drop for Buffer {
670    fn drop(&mut self) {
671        if !thread::panicking() {
672            self.context.buffer_drop(self.data.as_ref());
673        }
674    }
675}
676
677fn check_buffer_bounds(
678    buffer_size: BufferAddress,
679    offset: BufferAddress,
680    size: Option<BufferSize>,
681) {
682    // A slice of length 0 is invalid, so the offset must not be equal to or greater than the buffer size.
683    if offset >= buffer_size {
684        panic!(
685            "slice offset {} is out of range for buffer of size {}",
686            offset, buffer_size
687        );
688    }
689
690    if let Some(size) = size {
691        // Detect integer overflow.
692        let end = offset.checked_add(size.get());
693        if end.map_or(true, |end| end > buffer_size) {
694            panic!(
695                "slice offset {} size {} is out of range for buffer of size {}",
696                offset, size, buffer_size
697            );
698        }
699    }
700}
701
702fn range_to_offset_size<S: RangeBounds<BufferAddress>>(
703    bounds: S,
704) -> (BufferAddress, Option<BufferSize>) {
705    let offset = match bounds.start_bound() {
706        Bound::Included(&bound) => bound,
707        Bound::Excluded(&bound) => bound + 1,
708        Bound::Unbounded => 0,
709    };
710    let size = match bounds.end_bound() {
711        Bound::Included(&bound) => Some(bound + 1 - offset),
712        Bound::Excluded(&bound) => Some(bound - offset),
713        Bound::Unbounded => None,
714    }
715    .map(|size| BufferSize::new(size).expect("Buffer slices can not be empty"));
716
717    (offset, size)
718}
719
720#[cfg(test)]
721mod tests {
722    use super::{check_buffer_bounds, range_to_offset_size, BufferSize};
723
724    #[test]
725    fn range_to_offset_size_works() {
726        assert_eq!(range_to_offset_size(0..2), (0, BufferSize::new(2)));
727        assert_eq!(range_to_offset_size(2..5), (2, BufferSize::new(3)));
728        assert_eq!(range_to_offset_size(..), (0, None));
729        assert_eq!(range_to_offset_size(21..), (21, None));
730        assert_eq!(range_to_offset_size(0..), (0, None));
731        assert_eq!(range_to_offset_size(..21), (0, BufferSize::new(21)));
732    }
733
734    #[test]
735    #[should_panic]
736    fn range_to_offset_size_panics_for_empty_range() {
737        range_to_offset_size(123..123);
738    }
739
740    #[test]
741    #[should_panic]
742    fn range_to_offset_size_panics_for_unbounded_empty_range() {
743        range_to_offset_size(..0);
744    }
745
746    #[test]
747    #[should_panic]
748    fn check_buffer_bounds_panics_for_offset_at_size() {
749        check_buffer_bounds(100, 100, None);
750    }
751
752    #[test]
753    fn check_buffer_bounds_works_for_end_in_range() {
754        check_buffer_bounds(200, 100, BufferSize::new(50));
755        check_buffer_bounds(200, 100, BufferSize::new(100));
756        check_buffer_bounds(u64::MAX, u64::MAX - 100, BufferSize::new(100));
757        check_buffer_bounds(u64::MAX, 0, BufferSize::new(u64::MAX));
758        check_buffer_bounds(u64::MAX, 1, BufferSize::new(u64::MAX - 1));
759    }
760
761    #[test]
762    #[should_panic]
763    fn check_buffer_bounds_panics_for_end_over_size() {
764        check_buffer_bounds(200, 100, BufferSize::new(101));
765    }
766
767    #[test]
768    #[should_panic]
769    fn check_buffer_bounds_panics_for_end_wraparound() {
770        check_buffer_bounds(u64::MAX, 1, BufferSize::new(u64::MAX));
771    }
772}