Skip to main content

image_texel/image/
data.rs

1//! Buffers that can work with unaligned underlying data.
2//!
3//! These are mostly for IO purposes since most compute algorithms are not expected to support
4//! interactions with these buffers. However, these buffers support more generalized layouts with
5//! the goal of admitting a description of arbitrary external resources. In consequence, these
6//! buffers interact by references only.
7//!
8//! ## Design constraints
9//!
10//! - Many methods completely disregard some of the layouts. When we write into an `Image` for
11//!   instance, we treat it just as a container for bytes under the _input_ layout. We do not
12//!   interact with the target's layout at all. In these cases we request a `Bytes` layout as an
13//!   explicit opt-in. You can [`decay`][`Image::decay`] all buffer types to conveniently do so at
14//!   the call site.
15//! - The API may be suggestive, in terms of types, that the layout of an `Image` may be mutated by
16//!   interpreting it as a write target of, e.g. `Image<Relocated<Plane>>`. This however is still
17//!   wrong. When we write of course the aliasing of other planes is not considered. And we never
18//!   read the relocation offset, again just disregarding any existing layout data. This is a big
19//!   trap. The design around this is that methods are split into two parts. Those that do *not* take
20//!   target layouts into account are inherent methods on [`AsCopySource`] and [`AsCopyTarget`]
21//!   respectively. Those that do are located directly on the images such as [`Image::assign`]. This
22//!   is not perfect, see deeper considerations on planes in the following.
23//!
24//! ## Open Design issues
25//!
26//! - Atomic inputs are probably valuable but we can not command users to use our own atomic type.
27//!   Since atomic sizes must not mix, these kinds of buffers require different copy methods for
28//!   each single kind of underlying atomic! Not providing these however risks users doing unsound
29//!   things, such as improperly casting any of their atomic buffers to `[u8]` or [`Cell`] or
30//!   something.
31//! - To expand on layouts, of course it is also improper to expect that the input buffer contains
32//!   enough data for the whole image, instead it is probably just that single plane. This messes
33//!   with the expectations and types involved in the 'copy engine' implementation detail. What is
34//!   missing is a discoverable way that hands the plane index to some engine and then resolves the
35//!   necessary [`Relocated::offset`] when consuming the target. This should somehow not duplicate too
36//!   many interfaces, and really we want to avoid the confusion of having both available, right?
37//! - Writing the plane of an allocated image is common, but rather not straightforward. When the
38//!   input data has different layout we must modify the containing layout's definition of this
39//!   plane, which may fail of course and is not a generic operation at all. It could also entail
40//!   relocating some other planes which is far more work than the simple copy engine. So that
41//!   should be out-of-scope for the data transfer itself but then ergonomics should have a way to
42//!   ensure reserved space for a particular plane in advance.
43//! - Do we stack strategies, and how? In particular when copying an array of planes each of which
44//!   are matrices we want to copy everything row-by-row but right now this would require a
45//!   specialized engine for `impl Planar<impl MatrixLayout>` instead of being able to compose.
46//! - Think of blitting. When we write multiple planes, the input data can contain them completely
47//!   unaligned but this can not be expressed with properly planar layouts. We not a 'packed
48//!   planes' type or so that does not implement `PlaneOf` in terms of `Relocated<T>`.
49//!
50mod sealed {
51    use crate::buf::{atomic_buf, buf, cell_buf};
52    use crate::layout::Layout;
53    use core::ops::Range;
54
55    pub trait LayoutEngineCore {
56        type Layout: Layout;
57
58        fn consume_layout(&mut self) -> Self::Layout;
59
60        /// The byte ranges in the data buffer.
61        fn buffer_ranges(&self) -> impl Iterator<Item = Range<usize>>;
62
63        /// The base offset in the image.
64        ///
65        /// This should be such that the final image can be interpreted with [`Self::layout`].
66        fn image_offset(&self) -> usize;
67    }
68
69    pub trait Loadable {
70        fn load_from_buf(&mut self, buffer: &buf, what: Range<usize>, at: usize);
71        fn load_from_cell(&mut self, buffer: &cell_buf, what: Range<usize>, at: usize);
72        fn load_from_atomic(&mut self, buffer: &atomic_buf, what: Range<usize>, at: usize);
73    }
74
75    pub trait Storable {
76        fn store_to_buf(&self, buffer: &mut buf, what: Range<usize>, at: usize);
77        fn store_to_cell(&self, buffer: &cell_buf, what: Range<usize>, at: usize);
78        fn store_to_atomic(&self, buffer: &atomic_buf, what: Range<usize>, at: usize);
79    }
80
81    /// So we can abstract over the invocations of `Loadable::load_from_{buf,cell,atomic}`.
82    pub(crate) trait LoadSource {
83        fn load(&mut self, into: &mut dyn Loadable, what: Range<usize>, at: usize);
84    }
85
86    /// So we can abstract over the invocations of `Storable::store_to_{buf,cell,atomic}`.
87    pub(crate) trait StoreTarget {
88        fn store(&mut self, into: &dyn Storable, what: Range<usize>, at: usize);
89    }
90
91    impl LoadSource for &'_ buf {
92        fn load(&mut self, into: &mut dyn Loadable, what: Range<usize>, at: usize) {
93            into.load_from_buf(self, what, at)
94        }
95    }
96
97    impl LoadSource for &'_ cell_buf {
98        fn load(&mut self, into: &mut dyn Loadable, what: Range<usize>, at: usize) {
99            into.load_from_cell(self, what, at)
100        }
101    }
102
103    impl LoadSource for &'_ atomic_buf {
104        fn load(&mut self, into: &mut dyn Loadable, what: Range<usize>, at: usize) {
105            into.load_from_atomic(self, what, at)
106        }
107    }
108
109    impl StoreTarget for &'_ mut buf {
110        fn store(&mut self, into: &dyn Storable, what: Range<usize>, at: usize) {
111            into.store_to_buf(self, what, at)
112        }
113    }
114
115    impl StoreTarget for &'_ cell_buf {
116        fn store(&mut self, into: &dyn Storable, what: Range<usize>, at: usize) {
117            into.store_to_cell(self, what, at)
118        }
119    }
120
121    impl StoreTarget for &'_ atomic_buf {
122        fn store(&mut self, into: &dyn Storable, what: Range<usize>, at: usize) {
123            into.store_to_atomic(self, what, at)
124        }
125    }
126}
127
128use core::{cell::Cell, ops::Range};
129use sealed::{Loadable, Storable};
130
131use crate::buf::{atomic_buf, buf, cell_buf, AtomicBuffer, Buffer, CellBuffer};
132use crate::image::{
133    AtomicImage, AtomicImageRef, CellImage, CellImageRef, Image, ImageMut, ImageRef,
134};
135use crate::layout::{AlignedOffset, Bytes, Layout, Relocated};
136use crate::{texels, BufferReuseError};
137
138/// A buffer with layout, not aligned to any particular boundary.
139pub struct DataRef<'lt, Layout = Bytes> {
140    data: &'lt [u8],
141    layout: Layout,
142    offset: usize,
143}
144
145/// A mutable buffer with layout, not aligned to any particular boundary.
146pub struct DataMut<'lt, Layout = Bytes> {
147    data: &'lt mut [u8],
148    layout: Layout,
149    offset: usize,
150}
151
152/// A cell buffer with layout, not aligned to any particular boundary.
153pub struct DataCells<'lt, Layout = Bytes> {
154    data: &'lt [Cell<u8>],
155    layout: Layout,
156    offset: usize,
157}
158
159/// Borrows from a data source to read from it data into images.
160///
161/// The type parameter is the layout engine which defines the byte spans of data to be copied and
162/// in doing so controls the overhead of the operation. Note that the type must implement a sealed
163/// trait for all the main algorithms. The respective constructors on [`DataRef`], [`DataMut`],
164/// [`DataCells`]  choose this parameter.
165pub struct AsCopySource<'lt, E> {
166    inner: &'lt dyn Storable,
167    engine: E,
168}
169
170/// Borrows from a mutable data source to fill it with data from mages.
171///
172/// The type parameter is the layout engine which defines the byte spans of data to be copied and
173/// in doing so controls the overhead of the operation. Note that the type must implement a sealed
174/// trait for all the main algorithms. The respective constructors on [`DataRef`], [`DataMut`],
175/// [`DataCells`]  choose this parameter.
176pub struct AsCopyTarget<'lt, E> {
177    inner: &'lt mut dyn Loadable,
178    engine: E,
179}
180
181/// Documents the different layout engines.
182///
183/// This trait requires a sealed trait, it exists for documentation.
184pub trait LayoutEngine: sealed::LayoutEngineCore {}
185
186impl<'lt> DataRef<'lt, Bytes> {
187    /// Treat a whole input buffer as image bytes.
188    pub fn new(data: &'lt [u8]) -> Self {
189        DataRef {
190            data,
191            layout: Bytes(core::mem::size_of_val(data)),
192            offset: 0,
193        }
194    }
195}
196
197impl<'lt, L> DataRef<'lt, L> {
198    /// Construct from an explicit layout.
199    ///
200    /// This wraps an underlying buffer which has image data of the indicated layout from its
201    /// `start` byte onwards.
202    pub fn with_layout_at(data: &'lt [u8], layout: L, start: usize) -> Option<Self>
203    where
204        L: Layout,
205    {
206        Some(data)
207            .filter(|data| {
208                if let Some(partial) = data.get(start..) {
209                    <dyn Layout>::fits_data(&layout, partial)
210                } else {
211                    false
212                }
213            })
214            .map(|data| DataRef {
215                data,
216                layout,
217                offset: Default::default(),
218            })
219    }
220
221    /// An adapter reading from the data as one contiguous chunk.
222    ///
223    /// See [`RangeEngine`] for more explanations.
224    pub fn as_source(&self) -> AsCopySource<'_, RangeEngine<L>>
225    where
226        L: Clone + Layout,
227    {
228        AsCopySource {
229            inner: &self.data,
230            engine: RangeEngine::new(&self.layout, self.offset),
231        }
232    }
233}
234
235impl Storable for &'_ [u8] {
236    #[track_caller]
237    fn store_to_buf(&self, buffer: &mut buf, what: Range<usize>, into: usize) {
238        let len = what.len();
239        let target = &mut buffer.as_bytes_mut()[into..][..len];
240        let source = &self[what.start..what.end];
241        target.copy_from_slice(source);
242    }
243
244    fn store_to_cell(&self, buffer: &cell_buf, what: Range<usize>, into: usize) {
245        let len = what.len();
246        let target = &buffer.as_texels(texels::U8).as_slice_of_cells()[into..][..len];
247        let source = &self[what.start..what.end];
248        texels::U8.store_cell_slice(target, source);
249    }
250
251    fn store_to_atomic(&self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
252        let len = what.len();
253        let target = buffer.index(texels::U8.to_range(into..into + len).unwrap());
254        let source = &self[what.start..what.end];
255        texels::U8.store_atomic_slice(target, source);
256    }
257}
258
259impl<'lt> DataMut<'lt, Bytes> {
260    /// Treat a whole input buffer as image bytes.
261    pub fn new(data: &'lt mut [u8]) -> Self {
262        DataMut {
263            layout: Bytes(core::mem::size_of_val(data)),
264            data,
265            offset: 0,
266        }
267    }
268}
269
270impl<'lt, L> DataMut<'lt, L> {
271    /// Construct from an explicit layout.
272    ///
273    /// This wraps an underlying mutable buffer which has image data of the indicated layout from
274    /// its `start` byte onwards.
275    pub fn with_layout_at(data: &'lt mut [u8], layout: L, start: usize) -> Option<Self>
276    where
277        L: Layout,
278    {
279        Some(data)
280            .filter(|data| {
281                if let Some(partial) = data.get(start..) {
282                    <dyn Layout>::fits_data(&layout, partial)
283                } else {
284                    false
285                }
286            })
287            .map(|data| DataMut {
288                data,
289                layout,
290                offset: start,
291            })
292    }
293
294    /// An adapter reading from the data as one contiguous chunk.
295    ///
296    /// See [`RangeEngine`] for more explanations.
297    pub fn as_source(&self) -> AsCopySource<'_, RangeEngine<L>>
298    where
299        L: Clone + Layout,
300    {
301        AsCopySource {
302            inner: &self.data,
303            engine: RangeEngine::new(&self.layout, self.offset),
304        }
305    }
306
307    /// An adapter writing to this buffer in one contiguous chunk.
308    ///
309    /// See [`RangeEngine`] for more explanations.
310    pub fn as_target(&mut self) -> AsCopyTarget<'_, RangeEngine<L>>
311    where
312        L: Clone + Layout,
313    {
314        AsCopyTarget {
315            inner: &mut self.data,
316            engine: RangeEngine::new(&self.layout, self.offset),
317        }
318    }
319}
320
321impl Storable for &'_ mut [u8] {
322    #[track_caller]
323    fn store_to_buf(&self, buffer: &mut buf, what: Range<usize>, into: usize) {
324        let len = what.len();
325        let target = &mut buffer.as_bytes_mut()[into..][..len];
326        let source = &self[what.start..what.end];
327        target.copy_from_slice(source);
328    }
329
330    fn store_to_cell(&self, buffer: &cell_buf, what: Range<usize>, into: usize) {
331        let len = what.len();
332        let source = &buffer.as_texels(texels::U8).as_slice_of_cells()[into..][..len];
333        let target = &self[what.start..what.end];
334        texels::U8.store_cell_slice(source, target);
335    }
336
337    fn store_to_atomic(&self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
338        let len = what.len();
339        let target = buffer.index(texels::U8.to_range(into..into + len).unwrap());
340        let source = &self[what.start..what.end];
341        texels::U8.store_atomic_slice(target, source);
342    }
343}
344
345impl Loadable for &'_ mut [u8] {
346    #[track_caller]
347    fn load_from_buf(&mut self, buffer: &buf, what: Range<usize>, into: usize) {
348        let len = what.len();
349        let source = &buffer.as_bytes()[into..][..len];
350        let target = &mut self[what.start..what.end];
351        target.copy_from_slice(source);
352    }
353
354    fn load_from_cell(&mut self, buffer: &cell_buf, what: Range<usize>, into: usize) {
355        let len = what.len();
356        let source = &buffer.as_texels(texels::U8).as_slice_of_cells()[into..][..len];
357        let target = &mut self[what.start..what.end];
358        texels::U8.load_cell_slice(source, target);
359    }
360
361    fn load_from_atomic(&mut self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
362        let len = what.len();
363        let source = buffer.index(texels::U8.to_range(into..into + len).unwrap());
364        let target = &mut self[what.start..what.end];
365        texels::U8.load_atomic_slice(source, target);
366    }
367}
368
369impl<'lt> DataCells<'lt, Bytes> {
370    /// Treat a whole input buffer as image bytes.
371    pub fn new(data: &'lt [Cell<u8>]) -> Self {
372        DataCells {
373            layout: Bytes(core::mem::size_of_val(data)),
374            data,
375            offset: 0,
376        }
377    }
378}
379
380impl<'lt, L> DataCells<'lt, L> {
381    /// Verifies the data against the layout before construction.
382    ///
383    /// This wraps an shared buffer which has image data of the indicated layout from its `start`
384    /// byte onwards.
385    pub fn with_layout_at(data: &'lt [Cell<u8>], layout: L, start: usize) -> Option<Self>
386    where
387        L: Layout,
388    {
389        Some(data)
390            .filter(|data| {
391                if let Some(partial) = data.get(start..) {
392                    <dyn Layout>::fits_data(&layout, partial)
393                } else {
394                    false
395                }
396            })
397            .map(|data| DataCells {
398                data,
399                layout,
400                offset: Default::default(),
401            })
402    }
403
404    /// An adapter reading from the data as one contiguous chunk.
405    ///
406    /// See [`RangeEngine`] for more explanations.
407    pub fn as_source(&self) -> AsCopySource<'_, RangeEngine<L>>
408    where
409        L: Clone + Layout,
410    {
411        AsCopySource {
412            inner: &self.data,
413            engine: RangeEngine::new(&self.layout, self.offset),
414        }
415    }
416
417    /// An adapter writing to this buffer in one contiguous chunk.
418    ///
419    /// See [`RangeEngine`] for more explanations.
420    pub fn as_target(&mut self) -> AsCopyTarget<'_, RangeEngine<L>>
421    where
422        L: Clone + Layout,
423    {
424        AsCopyTarget {
425            inner: &mut self.data,
426            engine: RangeEngine::new(&self.layout, self.offset),
427        }
428    }
429}
430
431impl Storable for &'_ [Cell<u8>] {
432    #[track_caller]
433    fn store_to_buf(&self, buffer: &mut buf, what: Range<usize>, into: usize) {
434        let len = what.len();
435        let target = &mut buffer.as_bytes_mut()[into..][..len];
436        let source = &self[what.start..what.end];
437        crate::texels::U8.load_cell_slice(source, target);
438    }
439
440    #[track_caller]
441    fn store_to_cell(&self, buffer: &cell_buf, what: Range<usize>, into: usize) {
442        let len = what.len();
443        let source = &buffer.as_texels(texels::U8).as_slice_of_cells()[into..][..len];
444        let target = &self[what.start..what.end];
445        texels::U8.cell_memory_copy(source, target);
446    }
447
448    #[track_caller]
449    fn store_to_atomic(&self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
450        let len = what.len();
451        let target = buffer.index(texels::U8.to_range(into..into + len).unwrap());
452        let source = &self[what.start..what.end];
453        texels::U8.store_atomic_from_cells(target, source);
454    }
455}
456
457impl Loadable for &'_ [Cell<u8>] {
458    #[track_caller]
459    fn load_from_buf(&mut self, buffer: &buf, what: Range<usize>, into: usize) {
460        let len = what.len();
461        let source = &buffer.as_bytes()[into..][..len];
462        let target = &self[what.start..what.end];
463        texels::U8.store_cell_slice(target, source);
464    }
465
466    fn load_from_cell(&mut self, buffer: &cell_buf, what: Range<usize>, into: usize) {
467        let len = what.len();
468        let source = &buffer.as_texels(texels::U8).as_slice_of_cells()[into..][..len];
469        let target = &self[what.start..what.end];
470        texels::U8.cell_memory_copy(source, target);
471    }
472
473    fn load_from_atomic(&mut self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
474        let len = what.len();
475        let source = buffer.index(texels::U8.to_range(into..into + len).unwrap());
476        let target = &self[what.start..what.end];
477        texels::U8.load_atomic_to_cells(source, target);
478    }
479}
480
481impl<'buf, E: LayoutEngine> AsCopySource<'buf, E> {
482    /// Offset the target location of this copy operation, to anther planar location.
483    pub fn and_relocated(self, offset: AlignedOffset) -> AsCopySource<'buf, RelocateEngine<E>>
484    where
485        E::Layout: Clone,
486    {
487        AsCopySource {
488            inner: self.inner,
489            engine: RelocateEngine {
490                inner: self.engine,
491                offset,
492            },
493        }
494    }
495}
496
497impl<E: LayoutEngine> AsCopySource<'_, E> {
498    fn engine_to_buf_at(&self, buffer: impl sealed::StoreTarget) {
499        // Make sure we compile this once per iterator type and buffer type combination. Then for
500        // instance there is only one such instance for all LayoutEngine types instead of one per
501        // different layout.
502        #[inline(never)]
503        fn ranges_to_buf_at(
504            ranges: impl Iterator<Item = Range<usize>>,
505            store: &dyn Storable,
506            mut buffer: impl sealed::StoreTarget,
507            offset: usize,
508        ) {
509            for range in ranges {
510                buffer.store(store, range, offset)
511            }
512        }
513
514        ranges_to_buf_at(
515            self.engine.buffer_ranges(),
516            self.inner,
517            buffer,
518            self.engine.image_offset(),
519        );
520    }
521
522    /// Write to an image, changing the layout in the process.
523    ///
524    /// Reallocates the image buffer when necessary to ensure that the allocated buffer fits the
525    /// new data's layout.
526    pub fn write_to_image(mut self, buffer: Image<Bytes>) -> Image<E::Layout> {
527        let mut buffer = buffer.with_layout(self.engine.consume_layout());
528        self.engine_to_buf_at(buffer.as_capacity_buf_mut());
529        buffer
530    }
531
532    /// Write to a mutable borrowed buffer with layout.
533    ///
534    /// First verifies that the data will fit into the target. Then returns `Some` with a new
535    /// reference to the target buffer that is using the data's layout. Otherwise, returns `None`.
536    pub fn write_to_mut<'data>(
537        mut self,
538        buffer: ImageMut<'data, Bytes>,
539    ) -> Option<ImageMut<'data, E::Layout>> {
540        let mut buffer = buffer.with_layout(self.engine.consume_layout())?;
541        self.engine_to_buf_at(buffer.as_mut_buf());
542        Some(buffer)
543    }
544
545    /// Write to an image, changing the layout in the process.
546    ///
547    /// Fails when allocated buffer does not fits the new data's layout.
548    pub fn write_to_cell_image(mut self, buffer: CellImage<Bytes>) -> Option<CellImage<E::Layout>>
549    where
550        E::Layout: Clone + Layout,
551    {
552        let buffer = buffer.try_with_layout(self.engine.consume_layout()).ok()?;
553        self.engine_to_buf_at(buffer.as_capacity_cell_buf());
554        Some(buffer)
555    }
556
557    /// Write to a locally shared buffer with layout.
558    ///
559    /// First verifies that the data will fit into the target. Then returns `Some` with a new
560    /// reference to the target buffer that is using the data's layout. Otherwise, returns `None`.
561    pub fn write_to_cell_ref<'data>(
562        mut self,
563        buffer: CellImageRef<'data, Bytes>,
564    ) -> Option<CellImageRef<'data, E::Layout>> {
565        let buffer = buffer.checked_with_layout(self.engine.consume_layout())?;
566        self.engine_to_buf_at(buffer.as_cell_buf());
567        Some(buffer)
568    }
569
570    /// Write to an image, changing the layout in the process.
571    ///
572    /// Fails when allocated buffer does not fits the new data's layout.
573    pub fn write_to_atomic_image(
574        mut self,
575        buffer: AtomicImage<Bytes>,
576    ) -> Option<AtomicImage<E::Layout>>
577    where
578        E::Layout: Clone + Layout,
579    {
580        let buffer = buffer.try_with_layout(self.engine.consume_layout()).ok()?;
581        self.engine_to_buf_at(buffer.as_capacity_atomic_buf());
582        Some(buffer)
583    }
584
585    /// Write to a mutable borrowed buffer with layout.
586    ///
587    /// First verifies that the data will fit into the target. Then returns `Some` with a new
588    /// reference to the target buffer that is using the data's layout. Otherwise, returns `None`.
589    pub fn write_to_atomic_ref<'data>(
590        mut self,
591        buffer: AtomicImageRef<'data, Bytes>,
592    ) -> Option<AtomicImageRef<'data, E::Layout>>
593    where
594        E::Layout: Clone + Layout,
595    {
596        let buffer = buffer.checked_with_layout(self.engine.consume_layout())?;
597        self.engine_to_buf_at(buffer.as_capacity_atomic_buf());
598        Some(buffer)
599    }
600}
601
602impl Storable for Buffer {
603    #[track_caller]
604    fn store_to_buf(&self, buffer: &mut buf, what: Range<usize>, into: usize) {
605        <&'_ [u8]>::store_to_buf(&self.as_bytes(), buffer, what, into)
606    }
607
608    #[track_caller]
609    fn store_to_cell(&self, buffer: &cell_buf, what: Range<usize>, into: usize) {
610        <&'_ [u8]>::store_to_cell(&self.as_bytes(), buffer, what, into)
611    }
612
613    #[track_caller]
614    fn store_to_atomic(&self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
615        <&'_ [u8]>::store_to_atomic(&self.as_bytes(), buffer, what, into)
616    }
617}
618
619impl Loadable for Buffer {
620    #[track_caller]
621    fn load_from_buf(&mut self, buffer: &buf, what: Range<usize>, into: usize) {
622        <&'_ mut [u8]>::load_from_buf(&mut self.as_bytes_mut(), buffer, what, into)
623    }
624
625    fn load_from_cell(&mut self, buffer: &cell_buf, what: Range<usize>, into: usize) {
626        <&'_ mut [u8]>::load_from_cell(&mut self.as_bytes_mut(), buffer, what, into)
627    }
628
629    fn load_from_atomic(&mut self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
630        <&'_ mut [u8]>::load_from_atomic(&mut self.as_bytes_mut(), buffer, what, into)
631    }
632}
633
634impl<L> Image<L> {
635    /// Write to an image, changing the layout in the process.
636    ///
637    /// Allocates, contrary to `assign` functions on shared and reference types, if the allocated
638    /// buffer does not fit the new data's layout. Then copies data and assigns the layout to the
639    /// image buffer.
640    ///
641    /// Consider [`AsCopySource::write_to_mut`] with the whole [`Image::as_mut`] buffer when you
642    /// want to instead ignore the keep the current layout and only copy data. See
643    /// [`AsCopySource::write_to_image`] for changing the layout type in the process.
644    pub fn assign<E>(&mut self, mut data: AsCopySource<'_, E>)
645    where
646        E: LayoutEngine<Layout = L>,
647        L: Layout,
648    {
649        let layout = data.engine.consume_layout();
650        *self.layout_mut_unguarded() = layout;
651        self.ensure_layout();
652        data.engine_to_buf_at(self.as_capacity_buf_mut());
653    }
654
655    /// An adapter reading from the data as one contiguous chunk.
656    ///
657    /// See [`RangeEngine`] for more explanations.
658    pub fn as_source(&self) -> AsCopySource<'_, RangeEngine<L>>
659    where
660        L: Clone + Layout,
661    {
662        AsCopySource {
663            inner: self.inner.get(),
664            engine: RangeEngine::new(self.layout(), 0),
665        }
666    }
667
668    /// An adapter writing to this buffer in one contiguous chunk.
669    ///
670    /// See [`RangeEngine`] for more explanations.
671    pub fn as_target(&mut self) -> AsCopyTarget<'_, RangeEngine<L>>
672    where
673        L: Clone + Layout,
674    {
675        AsCopyTarget {
676            engine: RangeEngine::new(self.layout(), 0),
677            inner: self.inner.get_mut(),
678        }
679    }
680}
681
682impl Storable for &'_ buf {
683    #[track_caller]
684    fn store_to_buf(&self, buffer: &mut buf, what: Range<usize>, into: usize) {
685        <&'_ [u8]>::store_to_buf(&self.as_bytes(), buffer, what, into)
686    }
687
688    #[track_caller]
689    fn store_to_cell(&self, buffer: &cell_buf, what: Range<usize>, into: usize) {
690        <&'_ [u8]>::store_to_cell(&self.as_bytes(), buffer, what, into)
691    }
692
693    #[track_caller]
694    fn store_to_atomic(&self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
695        <&'_ [u8]>::store_to_atomic(&self.as_bytes(), buffer, what, into)
696    }
697}
698
699impl Storable for &'_ mut buf {
700    #[track_caller]
701    fn store_to_buf(&self, buffer: &mut buf, what: Range<usize>, into: usize) {
702        <&'_ [u8]>::store_to_buf(&self.as_bytes(), buffer, what, into)
703    }
704
705    #[track_caller]
706    fn store_to_cell(&self, buffer: &cell_buf, what: Range<usize>, into: usize) {
707        <&'_ [u8]>::store_to_cell(&self.as_bytes(), buffer, what, into)
708    }
709
710    #[track_caller]
711    fn store_to_atomic(&self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
712        <&'_ [u8]>::store_to_atomic(&self.as_bytes(), buffer, what, into)
713    }
714}
715
716impl Loadable for &'_ mut buf {
717    #[track_caller]
718    fn load_from_buf(&mut self, buffer: &buf, what: Range<usize>, into: usize) {
719        <&'_ mut [u8]>::load_from_buf(&mut self.as_bytes_mut(), buffer, what, into)
720    }
721
722    fn load_from_cell(&mut self, buffer: &cell_buf, what: Range<usize>, into: usize) {
723        <&'_ mut [u8]>::load_from_cell(&mut self.as_bytes_mut(), buffer, what, into)
724    }
725
726    fn load_from_atomic(&mut self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
727        <&'_ mut [u8]>::load_from_atomic(&mut self.as_bytes_mut(), buffer, what, into)
728    }
729}
730
731impl<L> ImageMut<'_, L> {
732    /// Write to an image, changing the layout in the process.
733    ///
734    /// Returns an error and keeps the current layout unchanged if the allocated buffer does not
735    /// fit the new data's layout. Otherwise copies data and assigns the layout to the image
736    /// buffer.
737    ///
738    /// See [`AsCopySource::write_to_mut`] for changing the layout type in the process.
739    pub fn assign<E>(&mut self, mut data: AsCopySource<'_, E>) -> Result<(), BufferReuseError>
740    where
741        E: LayoutEngine<Layout = L>,
742        L: Layout,
743    {
744        let layout = data.engine.consume_layout();
745        self.try_set_layout(layout)?;
746        data.engine_to_buf_at(self.as_capacity_buf_mut());
747        Ok(())
748    }
749
750    /// An adapter reading from the data as one contiguous chunk.
751    ///
752    /// See [`RangeEngine`] for more explanations.
753    pub fn as_source(&self) -> AsCopySource<'_, RangeEngine<L>>
754    where
755        L: Clone + Layout,
756    {
757        AsCopySource {
758            inner: self.inner.get(),
759            engine: RangeEngine::new(self.layout(), 0),
760        }
761    }
762
763    /// An adapter writing to this buffer in one contiguous chunk.
764    ///
765    /// See [`RangeEngine`] for more explanations.
766    pub fn as_target(&mut self) -> AsCopyTarget<'_, RangeEngine<L>>
767    where
768        L: Clone + Layout,
769    {
770        AsCopyTarget {
771            engine: RangeEngine::new(self.layout(), 0),
772            inner: self.inner.get_mut(),
773        }
774    }
775}
776
777impl<L> ImageRef<'_, L> {
778    /// An adapter reading from the data as one contiguous chunk.
779    ///
780    /// See [`RangeEngine`] for more explanations.
781    pub fn as_source(&self) -> AsCopySource<'_, RangeEngine<L>>
782    where
783        L: Clone + Layout,
784    {
785        AsCopySource {
786            inner: self.inner.get(),
787            engine: RangeEngine::new(self.layout(), 0),
788        }
789    }
790}
791
792impl Storable for CellBuffer {
793    #[track_caller]
794    fn store_to_buf(&self, buffer: &mut buf, what: Range<usize>, into: usize) {
795        <&'_ cell_buf>::store_to_buf(&&**self, buffer, what, into)
796    }
797
798    #[track_caller]
799    fn store_to_cell(&self, buffer: &cell_buf, what: Range<usize>, into: usize) {
800        <&'_ cell_buf>::store_to_cell(&&**self, buffer, what, into)
801    }
802
803    #[track_caller]
804    fn store_to_atomic(&self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
805        <&'_ cell_buf>::store_to_atomic(&&**self, buffer, what, into)
806    }
807}
808
809impl Loadable for CellBuffer {
810    #[track_caller]
811    fn load_from_buf(&mut self, buffer: &buf, what: Range<usize>, into: usize) {
812        <&'_ cell_buf>::load_from_buf(&mut &**self, buffer, what, into)
813    }
814
815    fn load_from_cell(&mut self, buffer: &cell_buf, what: Range<usize>, into: usize) {
816        <&'_ cell_buf>::load_from_cell(&mut &**self, buffer, what, into)
817    }
818
819    fn load_from_atomic(&mut self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
820        <&'_ cell_buf>::load_from_atomic(&mut &**self, buffer, what, into)
821    }
822}
823
824impl<L> CellImage<L> {
825    /// Write to this image, modifying the view of layout in the process.
826    ///
827    /// Returns an error and keeps the current layout unchanged if the allocated buffer does not
828    /// fit the new data's layout. Otherwise copies data and assigns the layout to the image
829    /// buffer.
830    ///
831    /// Consider [`AsCopySource::write_to_cell_ref`] with the whole [`Self::as_ref`] buffer when you
832    /// want to instead ignore the keep the current layout and only copy data. See
833    /// [`AsCopySource::write_to_cell_image`] for changing the layout type in the process.
834    pub fn assign<E>(&mut self, mut data: AsCopySource<'_, E>) -> Result<(), BufferReuseError>
835    where
836        E: LayoutEngine<Layout = L>,
837        L: Layout,
838    {
839        let layout = data.engine.consume_layout();
840        self.try_set_layout(layout)?;
841        data.engine_to_buf_at(self.as_capacity_cell_buf());
842        Ok(())
843    }
844
845    /// An adapter reading from the data as one contiguous chunk.
846    ///
847    /// See [`RangeEngine`] for more explanations.
848    pub fn as_source(&self) -> AsCopySource<'_, RangeEngine<L>>
849    where
850        L: Clone + Layout,
851    {
852        AsCopySource {
853            inner: self.inner.get(),
854            engine: RangeEngine::new(self.layout(), 0),
855        }
856    }
857
858    /// An adapter writing to this buffer in one contiguous chunk.
859    ///
860    /// See [`RangeEngine`] for more explanations.
861    pub fn as_target(&mut self) -> AsCopyTarget<'_, RangeEngine<L>>
862    where
863        L: Clone + Layout,
864    {
865        AsCopyTarget {
866            engine: RangeEngine::new(self.layout(), 0),
867            inner: self.inner.get_mut(),
868        }
869    }
870}
871
872impl Storable for &'_ cell_buf {
873    #[track_caller]
874    fn store_to_buf(&self, buffer: &mut buf, what: Range<usize>, into: usize) {
875        let inner = self.as_texels(texels::U8).as_slice_of_cells();
876        <&'_ [Cell<u8>]>::store_to_buf(&inner, buffer, what, into)
877    }
878
879    #[track_caller]
880    fn store_to_cell(&self, buffer: &cell_buf, what: Range<usize>, into: usize) {
881        let inner = self.as_texels(texels::U8).as_slice_of_cells();
882        <&'_ [Cell<u8>]>::store_to_cell(&inner, buffer, what, into)
883    }
884
885    #[track_caller]
886    fn store_to_atomic(&self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
887        let inner = self.as_texels(texels::U8).as_slice_of_cells();
888        <&'_ [Cell<u8>]>::store_to_atomic(&inner, buffer, what, into)
889    }
890}
891
892impl Loadable for &'_ cell_buf {
893    #[track_caller]
894    fn load_from_buf(&mut self, buffer: &buf, what: Range<usize>, into: usize) {
895        let mut inner = self.as_texels(texels::U8).as_slice_of_cells();
896        <&'_ [Cell<u8>]>::load_from_buf(&mut inner, buffer, what, into)
897    }
898
899    fn load_from_cell(&mut self, buffer: &cell_buf, what: Range<usize>, into: usize) {
900        let mut inner = self.as_texels(texels::U8).as_slice_of_cells();
901        <&'_ [Cell<u8>]>::load_from_cell(&mut inner, buffer, what, into)
902    }
903
904    fn load_from_atomic(&mut self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
905        let mut inner = self.as_texels(texels::U8).as_slice_of_cells();
906        <&'_ [Cell<u8>]>::load_from_atomic(&mut inner, buffer, what, into)
907    }
908}
909
910impl<L> CellImageRef<'_, L> {
911    /// Write to this image, modifying the view of layout in the process.
912    ///
913    /// Returns an error and keeps the current layout unchanged if the allocated buffer does not
914    /// fit the new data's layout. Otherwise copies data and assigns the layout to the image
915    /// buffer.
916    ///
917    /// See [`AsCopySource::write_to_cell_image`] for changing the layout type in the process.
918    pub fn assign<E>(&mut self, mut data: AsCopySource<'_, E>) -> Result<(), BufferReuseError>
919    where
920        E: LayoutEngine<Layout = L>,
921        L: Layout,
922    {
923        let layout = data.engine.consume_layout();
924        self.try_set_layout(layout)?;
925        data.engine_to_buf_at(self.as_capacity_cell_buf());
926        Ok(())
927    }
928
929    /// An adapter reading from the data as one contiguous chunk.
930    ///
931    /// See [`RangeEngine`] for more explanations.
932    pub fn as_source(&self) -> AsCopySource<'_, RangeEngine<L>>
933    where
934        L: Clone + Layout,
935    {
936        AsCopySource {
937            inner: self.inner.get(),
938            engine: RangeEngine::new(self.layout(), 0),
939        }
940    }
941
942    /// An adapter writing to this buffer in one contiguous chunk.
943    ///
944    /// See [`RangeEngine`] for more explanations.
945    pub fn as_target(&mut self) -> AsCopyTarget<'_, RangeEngine<L>>
946    where
947        L: Clone + Layout,
948    {
949        AsCopyTarget {
950            engine: RangeEngine::new(self.layout(), 0),
951            inner: self.inner.get_mut(),
952        }
953    }
954}
955
956impl Storable for AtomicBuffer {
957    #[track_caller]
958    fn store_to_buf(&self, buffer: &mut buf, what: Range<usize>, into: usize) {
959        <&'_ atomic_buf>::store_to_buf(&&**self, buffer, what, into)
960    }
961
962    #[track_caller]
963    fn store_to_cell(&self, buffer: &cell_buf, what: Range<usize>, into: usize) {
964        <&'_ atomic_buf>::store_to_cell(&&**self, buffer, what, into)
965    }
966
967    #[track_caller]
968    fn store_to_atomic(&self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
969        <&'_ atomic_buf>::store_to_atomic(&&**self, buffer, what, into)
970    }
971}
972
973impl Loadable for AtomicBuffer {
974    #[track_caller]
975    fn load_from_buf(&mut self, buffer: &buf, what: Range<usize>, into: usize) {
976        <&'_ atomic_buf>::load_from_buf(&mut &**self, buffer, what, into)
977    }
978
979    fn load_from_cell(&mut self, buffer: &cell_buf, what: Range<usize>, into: usize) {
980        <&'_ atomic_buf>::load_from_cell(&mut &**self, buffer, what, into)
981    }
982
983    fn load_from_atomic(&mut self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
984        <&'_ atomic_buf>::load_from_atomic(&mut &**self, buffer, what, into)
985    }
986}
987
988impl<L> AtomicImage<L> {
989    /// Write to this image, modifying the view of layout in the process.
990    ///
991    /// Returns an error and keeps the current layout unchanged if the allocated buffer does not
992    /// fit the new data's layout. Otherwise copies data and assigns the layout to the image
993    /// buffer.
994    ///
995    /// Consider [`AsCopySource::write_to_atomic_ref`] with the whole [`Self::as_ref`] buffer when
996    /// you want to instead ignore the keep the current layout and only copy data. See
997    /// [`AsCopySource::write_to_atomic_image`] for changing the layout type in the process.
998    pub fn assign<E>(&mut self, mut data: AsCopySource<'_, E>) -> Result<(), BufferReuseError>
999    where
1000        E: LayoutEngine<Layout = L>,
1001        L: Layout,
1002    {
1003        let layout = data.engine.consume_layout();
1004        self.try_set_layout(layout)?;
1005        data.engine_to_buf_at(self.as_capacity_atomic_buf());
1006        Ok(())
1007    }
1008
1009    /// An adapter reading from the data as one contiguous chunk.
1010    ///
1011    /// See [`RangeEngine`] for more explanations.
1012    pub fn as_source(&self) -> AsCopySource<'_, RangeEngine<L>>
1013    where
1014        L: Clone + Layout,
1015    {
1016        AsCopySource {
1017            inner: self.inner.get(),
1018            engine: RangeEngine::new(self.layout(), 0),
1019        }
1020    }
1021
1022    /// An adapter writing to this buffer in one contiguous chunk.
1023    ///
1024    /// See [`RangeEngine`] for more explanations.
1025    pub fn as_target(&mut self) -> AsCopyTarget<'_, RangeEngine<L>>
1026    where
1027        L: Clone + Layout,
1028    {
1029        AsCopyTarget {
1030            engine: RangeEngine::new(self.layout(), 0),
1031            inner: self.inner.get_mut(),
1032        }
1033    }
1034}
1035
1036impl Storable for &'_ atomic_buf {
1037    #[track_caller]
1038    fn store_to_buf(&self, buffer: &mut buf, what: Range<usize>, into: usize) {
1039        let len = what.len();
1040        let target = &mut buffer.as_bytes_mut()[into..][..len];
1041        let source = self.index(texels::U8.to_range(what).unwrap());
1042        texels::U8.load_atomic_slice(source, target);
1043    }
1044
1045    #[track_caller]
1046    fn store_to_cell(&self, buffer: &cell_buf, what: Range<usize>, into: usize) {
1047        let len = what.len();
1048        let target = &buffer.as_texels(texels::U8).as_slice_of_cells()[into..][..len];
1049        let source = self.index(texels::U8.to_range(what).unwrap());
1050        texels::U8.load_atomic_to_cells(source, target);
1051    }
1052
1053    #[track_caller]
1054    fn store_to_atomic(&self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
1055        let len = what.len();
1056        let target = buffer.index(texels::U8.to_range(into..into + len).unwrap());
1057        let source = self.index(texels::U8.to_range(what).unwrap());
1058        texels::U8.atomic_memory_move(source, target);
1059    }
1060}
1061
1062impl Loadable for &'_ atomic_buf {
1063    #[track_caller]
1064    fn load_from_buf(&mut self, buffer: &buf, what: Range<usize>, into: usize) {
1065        let len = what.len();
1066        let source = &buffer.as_bytes()[into..][..len];
1067        let target = self.index(texels::U8.to_range(what).unwrap());
1068        texels::U8.store_atomic_slice(target, source);
1069    }
1070
1071    fn load_from_cell(&mut self, buffer: &cell_buf, what: Range<usize>, into: usize) {
1072        let len = what.len();
1073        let source = &buffer.as_texels(texels::U8).as_slice_of_cells()[into..][..len];
1074        let target = self.index(texels::U8.to_range(what).unwrap());
1075        texels::U8.store_atomic_from_cells(target, source);
1076    }
1077
1078    fn load_from_atomic(&mut self, buffer: &atomic_buf, what: Range<usize>, into: usize) {
1079        let len = what.len();
1080        let source = buffer.index(texels::U8.to_range(into..into + len).unwrap());
1081        let target = self.index(texels::U8.to_range(what).unwrap());
1082        texels::U8.atomic_memory_move(source, target);
1083    }
1084}
1085
1086impl<L> AtomicImageRef<'_, L> {
1087    /// Write to this image, modifying the view of layout in the process.
1088    ///
1089    /// Returns an error and keeps the current layout unchanged if the allocated buffer does not
1090    /// fit the new data's layout. Otherwise copies data and assigns the layout to the image
1091    /// buffer.
1092    ///
1093    /// See [`AsCopySource::write_to_atomic_ref`] for changing the layout type in the process.
1094    pub fn assign<E>(&mut self, mut data: AsCopySource<'_, E>) -> Result<(), BufferReuseError>
1095    where
1096        E: LayoutEngine<Layout = L>,
1097        L: Layout,
1098    {
1099        let layout = data.engine.consume_layout();
1100        self.try_set_layout(layout)?;
1101        data.engine_to_buf_at(self.as_capacity_atomic_buf());
1102        Ok(())
1103    }
1104
1105    /// An adapter reading from the data as one contiguous chunk.
1106    ///
1107    /// See [`RangeEngine`] for more explanations.
1108    pub fn as_source(&self) -> AsCopySource<'_, RangeEngine<L>>
1109    where
1110        L: Clone + Layout,
1111    {
1112        AsCopySource {
1113            inner: self.inner.get(),
1114            engine: RangeEngine::new(self.layout(), 0),
1115        }
1116    }
1117
1118    /// An adapter writing to this buffer in one contiguous chunk.
1119    ///
1120    /// See [`RangeEngine`] for more explanations.
1121    pub fn as_target(&mut self) -> AsCopyTarget<'_, RangeEngine<L>>
1122    where
1123        L: Clone + Layout,
1124    {
1125        AsCopyTarget {
1126            engine: RangeEngine::new(self.layout(), 0),
1127            inner: self.inner.get_mut(),
1128        }
1129    }
1130}
1131
1132impl<E: LayoutEngine> AsCopyTarget<'_, E> {
1133    fn engine_from_buf_at(&mut self, buffer: impl sealed::LoadSource) {
1134        // Make sure we compile this once per iterator type and buffer type combination. Then for
1135        // instance there is only one such instance for all LayoutEngine types instead of one per
1136        // different layout.
1137        #[inline(never)]
1138        fn ranges_from_buf_at(
1139            ranges: impl Iterator<Item = Range<usize>>,
1140            store: &mut dyn Loadable,
1141            mut buffer: impl sealed::LoadSource,
1142            offset: usize,
1143        ) {
1144            for range in ranges {
1145                buffer.load(store, range, offset)
1146            }
1147        }
1148
1149        ranges_from_buf_at(
1150            self.engine.buffer_ranges(),
1151            self.inner,
1152            buffer,
1153            self.engine.image_offset(),
1154        );
1155    }
1156
1157    /// Read out data from a borrowed buffer.
1158    ///
1159    /// This reads data up to our layout. It does not interpret the data with the layout of
1160    /// the argument buffer.
1161    pub fn read_from_ref(&mut self, buffer: ImageRef<'_, Bytes>) {
1162        self.engine_from_buf_at(buffer.as_buf());
1163    }
1164
1165    /// Read out data from a borrowed buffer.
1166    ///
1167    /// This reads data up to our layout. It does not interpret the data with the layout of
1168    /// the argument buffer.
1169    pub fn read_from_cell_ref(&mut self, buffer: CellImageRef<'_, Bytes>) {
1170        self.engine_from_buf_at(buffer.as_cell_buf());
1171    }
1172
1173    /// Read out data from a borrowed buffer.
1174    ///
1175    /// This reads data up to our layout. It does not interpret the data with the layout of
1176    /// the argument buffer.
1177    pub fn read_from_atomic_ref(&mut self, buffer: CellImageRef<'_, Bytes>) {
1178        self.engine_from_buf_at(buffer.as_cell_buf());
1179    }
1180}
1181
1182/// Copies all bytes within the bounds of a layout.
1183///
1184/// This strategy will do a single copy, of the appropriate type for the targets buffer type, to
1185/// transfer all the raw byte data of the image. This is optimal if the layout is supposed to be
1186/// the first or only plane and does not contain any other internal padding buffers either.
1187pub struct RangeEngine<L> {
1188    inner: Option<L>,
1189    bytes: [Range<usize>; 1],
1190}
1191
1192/// Applies an interior copy strategy but the bytes in the image are written to another plane.
1193pub struct RelocateEngine<Inner: sealed::LayoutEngineCore> {
1194    inner: Inner,
1195    offset: AlignedOffset,
1196}
1197
1198impl<L: Layout> LayoutEngine for RangeEngine<L> {}
1199
1200impl<L: Layout> RangeEngine<L> {
1201    fn new(layout: &L, offset: usize) -> Self
1202    where
1203        L: Clone,
1204    {
1205        let byte_len = layout.byte_len();
1206        let bytes = [offset..offset + byte_len];
1207
1208        RangeEngine {
1209            inner: Some(layout.clone()),
1210            bytes,
1211        }
1212    }
1213}
1214
1215impl<L: Layout> sealed::LayoutEngineCore for RangeEngine<L> {
1216    type Layout = L;
1217
1218    fn consume_layout(&mut self) -> L {
1219        self.inner
1220            .take()
1221            .expect("Protocol error, layout polled twice")
1222    }
1223
1224    // Return a `Cloned<slice::Iter>`, not an array iterator. Note we aim to reduce the number of
1225    // distinct iterator types between all layout engines, even for distinct layouts etc. This is
1226    // compatible as best as possible and misses the loop in copy at most once..
1227    #[allow(refining_impl_trait)]
1228    fn buffer_ranges(&self) -> core::iter::Cloned<core::slice::Iter<'_, Range<usize>>> {
1229        (&self.bytes[..]).iter().cloned()
1230    }
1231
1232    fn image_offset(&self) -> usize {
1233        0
1234    }
1235}
1236
1237impl<I: sealed::LayoutEngineCore> LayoutEngine for RelocateEngine<I> {}
1238
1239impl<I: sealed::LayoutEngineCore> sealed::LayoutEngineCore for RelocateEngine<I> {
1240    type Layout = Relocated<I::Layout>;
1241
1242    fn consume_layout(&mut self) -> Self::Layout {
1243        Relocated {
1244            inner: self.inner.consume_layout(),
1245            offset: self.offset,
1246        }
1247    }
1248
1249    fn buffer_ranges(&self) -> impl Iterator<Item = Range<usize>> {
1250        self.inner.buffer_ranges()
1251    }
1252
1253    fn image_offset(&self) -> usize {
1254        self.inner.image_offset() + self.offset.get()
1255    }
1256}