image_texel/image/cell.rs
1//! Defines the containers operating on `!Sync` shared bytes.
2//!
3//! Re-exported at its super `image` module.
4use crate::buf::{cell_buf, CellBuffer};
5use crate::image::{raw::RawImage, Image, IntoPlanesError};
6use crate::layout::{Bytes, Decay, Layout, Mend, PlaneOf, Relocate, SliceLayout, Take, TryMend};
7use crate::texel::{constants::U8, MAX_ALIGN};
8use crate::{BufferReuseError, Texel, TexelBuffer};
9use core::cell::Cell;
10
11/// A container of allocated bytes, parameterized over the layout.
12///
13/// This is a unsynchronized, shared equivalent to [`Image`][`crate::image::Image`]. That is the
14/// buffer of bytes of this container is shared between clones of this value but can not be sent
15/// between threads. In particular the same buffer may be owned and viewed with different layouts.
16///
17/// # Examples
18///
19/// As a type with shared ownership over the underling buffer, this type can be cloned very
20/// cheaply. Such duplicates refer to the same buffer, making changes in one visible to the other.
21///
22/// ```
23/// use image_texel::{image::CellImage, layout::Matrix};
24/// let matrix = Matrix::<u8>::width_and_height(16, 16).unwrap();
25/// let image: CellImage<_> = CellImage::new(matrix);
26///
27/// let another_reference = image.clone();
28/// assert!(CellImage::ptr_eq(&image, &another_reference));
29///
30/// another_reference.as_slice().as_slice_of_cells()[0].set(0xff);
31/// let value = image.as_slice().as_slice_of_cells()[0].get();
32/// assert_eq!(value, 0xff);
33/// ```
34#[derive(Clone, PartialEq, Eq)]
35pub struct CellImage<Layout = Bytes> {
36 pub(super) inner: RawImage<CellBuffer, Layout>,
37}
38
39/// A partial view of an atomic image.
40///
41/// Note that this requires its underlying buffer to be highly aligned! For that reason it is not
42/// possible to take a reference at an arbitrary number of bytes. Values of this type are created
43/// by calling [`CellImage::as_ref`] or [`CellImage::checked_to_ref`].
44#[derive(Clone, PartialEq, Eq)]
45pub struct CellImageRef<'buf, Layout = &'buf Bytes> {
46 pub(super) inner: RawImage<&'buf cell_buf, Layout>,
47}
48
49/// Image methods for all layouts.
50impl<L: Layout> CellImage<L> {
51 /// Create a new image for a specific layout.
52 pub fn new(layout: L) -> Self {
53 RawImage::<CellBuffer, L>::new(layout).into()
54 }
55
56 /// Create a new image with initial byte content.
57 pub fn with_bytes(layout: L, bytes: &[u8]) -> Self {
58 RawImage::with_contents(bytes, layout).into()
59 }
60
61 /// Create a new image with initial texel contents.
62 ///
63 /// The memory is reused as much as possible. If the layout is too large for the buffer then
64 /// the remainder is filled up with zeroed bytes.
65 pub fn with_buffer<T>(layout: L, bytes: TexelBuffer<T>) -> Self {
66 let (buffer, layout) = RawImage::from_buffer(Bytes(0), bytes.into_inner())
67 .with_layout(layout)
68 .into_parts();
69 RawImage::from_buffer(layout, CellBuffer::from(buffer)).into()
70 }
71
72 /// Change the layer of the image.
73 ///
74 /// Call [`CellImage::fits`] to check if this will work beforehand. Returns an `Err` with the
75 /// original image if the buffer does not fit the new layout. Returns `Ok` with the new image
76 /// if the buffer does fit. Never reallocates the buffer, the new image will always alias any
77 /// other image sharing the buffer.
78 ///
79 /// This returns a [`BufferReuseError`] with information about the exceeded limits. If you need
80 /// the prior value then you can make a [`CellImage::clone`]` of it, it is cheap.
81 pub fn try_with_layout<M>(self, layout: M) -> Result<CellImage<M>, BufferReuseError>
82 where
83 M: Layout,
84 {
85 let requested = layout.byte_len();
86 match self.inner.try_reinterpret(layout) {
87 Ok(raw) => Ok(raw.into()),
88 Err(err) => Err(BufferReuseError {
89 capacity: err.as_capacity_cell_buf().len(),
90 requested: Some(requested),
91 }),
92 }
93 }
94
95 /// Attempt to modify the layout to a new value, without modifying its type.
96 ///
97 /// Returns an `Err` if the layout does not fit the underlying buffer. Otherwise returns `Ok`
98 /// and overwrites the layout accordingly.
99 ///
100 /// TODO: public name and provide a `set_capacity` for `L = Bytes`?
101 pub(crate) fn try_set_layout(&mut self, layout: L) -> Result<(), BufferReuseError>
102 where
103 L: Layout,
104 {
105 self.inner.try_reuse(layout)
106 }
107
108 /// Decay into a image with less specific layout.
109 ///
110 /// See the [`Decay`] trait for an explanation of this operation.
111 ///
112 /// # Example
113 ///
114 /// The common layouts define ways to decay into a dynamically typed variant.
115 ///
116 /// ```
117 /// # use image_texel::{image::CellImage, layout::Matrix, layout};
118 /// let matrix = Matrix::<u8>::width_and_height(32, 32).unwrap();
119 /// let image: CellImage<layout::Matrix<u8>> = CellImage::new(matrix);
120 ///
121 /// // to turn hide the `u8` type but keep width, height, texel layout
122 /// let as_bytes: CellImage<layout::MatrixBytes> = image.clone().decay();
123 /// assert_eq!(as_bytes.layout().width(), 32);
124 /// assert_eq!(as_bytes.layout().height(), 32);
125 /// ```
126 ///
127 /// See also [`CellImage::mend`] and [`CellImage::try_mend`] for operations that reverse
128 /// the effects.
129 ///
130 /// Can also be used to forget specifics of the layout, turning the image into a more general
131 /// container type. For example, to use a uniform type as an allocated buffer waiting on reuse.
132 ///
133 /// ```
134 /// # use image_texel::{image::CellImage, layout::Matrix, layout};
135 /// let matrix = Matrix::<u8>::width_and_height(32, 32).unwrap();
136 ///
137 /// // Can always decay to a byte buffer.
138 /// let bytes: CellImage = CellImage::new(matrix).decay();
139 /// let _: &layout::Bytes = bytes.layout();
140 /// ```
141 ///
142 /// [`Decay`]: ../layout/trait.Decay.html
143 pub fn decay<M>(self) -> CellImage<M>
144 where
145 M: Decay<L>,
146 M: Layout,
147 {
148 self.inner
149 .checked_decay()
150 .unwrap_or_else(super::decay_failed)
151 .into()
152 }
153
154 /// Like [`Self::decay`]` but returns `None` rather than panicking. While this is strictly
155 /// speaking a violation of the trait contract, you may want to handle this yourself.
156 pub fn checked_decay<M>(self) -> Option<CellImage<M>>
157 where
158 M: Decay<L>,
159 M: Layout,
160 {
161 Some(self.inner.checked_decay()?.into())
162 }
163
164 /// Copy all bytes to a newly allocated image.
165 ///
166 /// Note this will allocate a buffer according to the capacity length of this reference, not
167 /// merely the layout. When this is not the intention, consider first adjusting the buffer by
168 /// reference with [`Self::as_ref`].
169 ///
170 /// # Examples
171 ///
172 /// Here we make an independent copy of a pixel matrix image.
173 ///
174 /// ```
175 /// use image_texel::image::{CellImage, Image};
176 /// use image_texel::layout::{PlaneMatrices, Matrix};
177 /// use image_texel::texels::U8;
178 ///
179 /// let matrix = Matrix::from_width_height(U8, 8, 8).unwrap();
180 /// let buffer = CellImage::new(matrix);
181 ///
182 /// // … some code to initialize those planes.
183 /// # let mut buffer = buffer;
184 /// # let data = &buffer.as_cell_buf()[U8.to_range(0..8).unwrap()];
185 /// # U8.store_cell_slice(data, b"not zero");
186 /// # let buffer = buffer;
187 ///
188 /// let clone_of: Image<_> = buffer.clone().into_owned();
189 ///
190 /// assert!(clone_of.as_bytes() == buffer.as_cell_buf());
191 /// ```
192 pub fn into_owned(self) -> Image<L> {
193 self.inner.into_owned().into()
194 }
195
196 /// Move the bytes into a new image.
197 ///
198 /// Afterwards, `self` will refer to an empty but unique new buffer.
199 pub fn take(&mut self) -> CellImage<L>
200 where
201 L: Take,
202 {
203 self.inner.take().into()
204 }
205
206 /// Strengthen the layout of the image.
207 ///
208 /// See the [`Mend`] trait for an explanation of this operation.
209 ///
210 /// [`Mend`]: ../layout/trait.Mend.html
211 pub fn mend<Item>(self, mend: Item) -> CellImage<Item::Into>
212 where
213 Item: Mend<L>,
214 L: Take,
215 {
216 let new_layout = mend.mend(self.inner.layout());
217 self.inner.mogrify_layout(|_| new_layout).into()
218 }
219
220 /// Strengthen the layout of the image.
221 ///
222 /// See the [`Mend`] trait for an explanation of this operation.
223 ///
224 /// This is a fallible operation. In case of success returns `Ok` and the byte buffer of the
225 /// image is moved into the result. When mending fails this method returns `Err` and the buffer
226 /// is kept by this image.
227 ///
228 /// [`Mend`]: ../layout/trait.Mend.html
229 pub fn try_mend<Item>(&mut self, mend: Item) -> Result<CellImage<Item::Into>, Item::Err>
230 where
231 Item: TryMend<L>,
232 L: Take,
233 {
234 let new_layout = mend.try_mend(self.inner.layout())?;
235 Ok(self.inner.take().mogrify_layout(|_| new_layout).into())
236 }
237}
238
239/// Image methods that do not require a layout.
240impl<L> CellImage<L> {
241 /// Check if the buffer could accommodate another layout without reallocating.
242 pub fn fits(&self, layout: &impl Layout) -> bool {
243 self.inner.fits(layout)
244 }
245
246 /// Check if two images refer to the same buffer.
247 ///
248 /// Note that two buffers can use different layout types to describe their share of the data or
249 /// even to refer to the same data in different ways.
250 pub fn ptr_eq<O>(&self, other: &CellImage<O>) -> bool {
251 CellBuffer::ptr_eq(self.inner.get(), other.inner.get())
252 }
253
254 /// Get a reference to the underlying buffer.
255 pub fn as_cell_buf(&self) -> &cell_buf
256 where
257 L: Layout,
258 {
259 self.inner.as_cell_buf()
260 }
261
262 /// Get a reference to the aligned unstructured bytes of the image.
263 ///
264 /// Note that this may return more bytes than required for the specific layout for various
265 /// reasons. See also [`Self::make_mut`].
266 pub fn as_capacity_cell_buf(&self) -> &cell_buf {
267 self.inner.as_capacity_cell_buf()
268 }
269
270 /// Get a mutable reference to all allocated bytes if this image does not alias any other.
271 ///
272 /// # Example
273 ///
274 /// ```
275 /// use image_texel::{image::CellImage, layout::Matrix};
276 ///
277 /// let layout = Matrix::<[u8; 4]>::width_and_height(10, 10).unwrap();
278 /// let mut image = CellImage::new(layout);
279 /// assert!(image.get_mut().is_some());
280 ///
281 /// let mut clone_of = image.clone();
282 /// assert!(image.get_mut().is_none());
283 /// ```
284 pub fn get_mut(&mut self) -> Option<&mut cell_buf> {
285 self.inner.get_mut().get_mut()
286 }
287
288 /// Ensure this image does not alias any other.
289 ///
290 /// Then returns a mutable reference to all the bytes allocated in the buffer.
291 ///
292 /// # Example
293 ///
294 /// ```
295 /// use image_texel::{image::CellImage, layout::Matrix, texels::U8};
296 /// let texel = U8.array::<4>();
297 ///
298 /// let layout = Matrix::<[u8; 4]>::width_and_height(10, 10).unwrap();
299 /// let image = CellImage::new(layout);
300 ///
301 /// let mut clone_of = image.clone();
302 /// let atomic_mut_buf = clone_of.make_mut();
303 ///
304 /// // Now these are independent buffers.
305 /// atomic_mut_buf.as_texels(texel).as_slice_of_cells()[0].set([0xff; 4]);
306 /// assert_ne!(image.as_slice().as_slice_of_cells()[0].get(), [0xff; 4]);
307 ///
308 /// // With mutable reference we initialized the new buffer.
309 /// assert_eq!(clone_of.as_slice().as_slice_of_cells()[0].get(), [0xff; 4]);
310 /// ```
311 pub fn make_mut(&mut self) -> &mut cell_buf {
312 self.inner.get_mut().make_mut()
313 }
314
315 /// View this buffer as a slice of texels.
316 ///
317 /// This reinterprets the bytes of the buffer. It can be used to view the buffer as any kind of
318 /// pixel, regardless of its association with the layout. Use it with care.
319 ///
320 /// An alternative way to get a slice of texels when a layout has an inherent texel type is
321 /// [`Self::as_slice`].
322 pub fn as_texels<P>(&self, texel: Texel<P>) -> &'_ Cell<[P]>
323 where
324 L: Layout,
325 {
326 self.as_ref().into_texels(texel)
327 }
328
329 /// View this buffer as a slice of its inherent pixels.
330 pub fn as_slice(&self) -> &'_ Cell<[L::Sample]>
331 where
332 L: SliceLayout,
333 {
334 self.as_ref().into_slice()
335 }
336
337 /// Get a reference to the layout.
338 pub fn layout(&self) -> &L {
339 self.inner.layout()
340 }
341
342 /// Get a mutable reference to the layout.
343 ///
344 /// Be mindful not to modify the layout to exceed the allocated size. This does not cause any
345 /// unsoundness but might lead to panics when calling other methods.
346 pub fn layout_mut_unguarded(&mut self) -> &mut L {
347 self.inner.layout_mut_unguarded()
348 }
349
350 /// Get a view of this image.
351 pub fn as_ref(&self) -> CellImageRef<'_, &'_ L> {
352 self.inner.as_deref().into()
353 }
354
355 /// Get a view of this image, if the alternate layout fits.
356 pub fn checked_to_ref<M: Layout>(&self, layout: M) -> Option<CellImageRef<'_, M>> {
357 self.as_ref().checked_with_layout(layout)
358 }
359
360 /*
361 /// Get a single texel from a raster image.
362 #[deprecated = "Do not use yet"]
363 pub fn get_texel<P>(&self, _: Coord) -> Option<P>
364 where
365 L: Raster<P>,
366 {
367 todo!("Failure of the Raster trait");
368 }
369
370 /// Put a single texel to a raster image.
371 #[deprecated = "Do not use yet"]
372 pub fn put_texel<P>(&mut self, _: Coord, _: P)
373 where
374 L: RasterMut<P>,
375 {
376 todo!("Failure of the Raster trait");
377 }
378
379 /// Call a function on each texel of this raster image.
380 ///
381 /// The order of evaluation is _not_ defined although certain layouts may offer more specific
382 /// guarantees. In general, one can expect that layouts call the function in a cache-efficient
383 /// manner if they are aware of a better iteration strategy.
384 pub fn shade<P>(&mut self, _: impl FnMut(u32, u32, &mut P))
385 where
386 L: RasterMut<P>,
387 {
388 todo!()
389 }
390 */
391}
392
393impl<'data, L> CellImageRef<'data, L> {
394 /// Get a reference to the underlying buffer.
395 pub fn as_cell_buf(&self) -> &cell_buf
396 where
397 L: Layout,
398 {
399 self.inner.as_cell_buf()
400 }
401
402 /// Get a reference to the complete underlying buffer, ignoring the layout.
403 pub fn as_capacity_cell_buf(&self) -> &cell_buf {
404 self.inner.get()
405 }
406
407 pub fn layout(&self) -> &L {
408 self.inner.layout()
409 }
410
411 /// Get a view of this image.
412 pub fn as_ref(&self) -> CellImageRef<'_, &'_ L> {
413 self.inner.as_deref().into()
414 }
415
416 /// Check if a call to [`CellImageRef::checked_with_layout`] would succeed.
417 pub fn fits(&self, other: &impl Layout) -> bool {
418 self.inner.fits(other)
419 }
420
421 /// Change this view to a different layout.
422 ///
423 /// This returns `Some` if the layout fits the underlying data, and `None` otherwise. Use
424 /// [`CellImageRef::fits`] to check this property in a separate call. Note that the new layout
425 /// need not be related to the old layout in any other way.
426 ///
427 /// # Usage
428 ///
429 /// ```rust
430 /// # fn not_main() -> Option<()> {
431 /// use image_texel::{image::CellImage, layout::Matrix, layout::Bytes};
432 ///
433 /// let layout = Matrix::<[u8; 4]>::width_and_height(10, 10).unwrap();
434 /// let image = CellImage::new(layout);
435 ///
436 /// let reference = image.as_ref();
437 ///
438 /// let as_bytes = reference.checked_with_layout(Bytes(400))?;
439 /// assert!(matches!(as_bytes.layout(), Bytes(400)));
440 ///
441 /// // But not if we request too much.
442 /// assert!(as_bytes.checked_with_layout(Bytes(500)).is_none());
443 ///
444 /// # Some(()) }
445 /// # fn main() { not_main(); }
446 /// ```
447 pub fn checked_with_layout<M>(self, layout: M) -> Option<CellImageRef<'data, M>>
448 where
449 M: Layout,
450 {
451 Some(self.inner.try_reinterpret(layout).ok()?.into())
452 }
453
454 /// Attempt to modify the layout to a new value, without modifying its type.
455 ///
456 /// Returns an `Err` if the layout does not fit the underlying buffer. Otherwise returns `Ok`
457 /// and overwrites the layout accordingly.
458 ///
459 /// TODO: public name and provide a `set_capacity` for `L = Bytes`?
460 pub(crate) fn try_set_layout(&mut self, layout: L) -> Result<(), BufferReuseError>
461 where
462 L: Layout,
463 {
464 self.inner.try_reuse(layout)
465 }
466
467 /// Decay into a image with less specific layout.
468 ///
469 /// See [`CellImage::decay`].
470 pub fn decay<M>(self) -> CellImageRef<'data, M>
471 where
472 M: Decay<L>,
473 M: Layout,
474 {
475 self.inner
476 .checked_decay()
477 .unwrap_or_else(super::decay_failed)
478 .into()
479 }
480
481 /// Decay into a image with less specific layout.
482 ///
483 /// See [`CellImage::checked_decay`].
484 pub fn checked_decay<M>(self) -> Option<CellImageRef<'data, M>>
485 where
486 M: Decay<L>,
487 M: Layout,
488 {
489 Some(self.inner.checked_decay()?.into())
490 }
491
492 /// Copy all bytes to a newly allocated image.
493 ///
494 /// Note this will allocate a buffer according to the capacity length of this reference, not
495 /// merely the layout. When this is not the intention, consider calling [`Self::split_layout`]
496 /// or [`Self::truncate_layout`] respectively.
497 ///
498 /// # Examples
499 ///
500 /// Here we make an independent copy of a pixel matrix image.
501 ///
502 /// ```
503 /// use image_texel::image::{CellImage, Image};
504 /// use image_texel::layout::{PlaneMatrices, Matrix};
505 /// use image_texel::texels::U8;
506 ///
507 /// let matrix = Matrix::from_width_height(U8, 8, 8).unwrap();
508 /// let buffer = CellImage::new(PlaneMatrices::<_, 2>::from_repeated(matrix));
509 ///
510 /// // … some code to initialize those planes.
511 /// # let [plane] = buffer.as_ref().into_planes([1]).unwrap();
512 /// # let data = &plane.as_cell_buf()[U8.to_range(0..8).unwrap()];
513 /// # U8.store_cell_slice(data, b"not zero");
514 ///
515 /// let [plane1] = buffer.as_ref().into_planes([1]).unwrap();
516 /// let clone_of: Image<_> = plane1.clone().into_owned();
517 ///
518 /// assert!(clone_of.as_bytes() == plane1.as_cell_buf());
519 /// ```
520 pub fn into_owned(self) -> Image<L> {
521 self.inner.into_owned().into()
522 }
523
524 /// Get a slice of the individual samples in the layout.
525 pub fn as_slice(&self) -> &'_ Cell<[L::Sample]>
526 where
527 L: SliceLayout,
528 {
529 self.as_texels(self.inner.layout().sample())
530 }
531
532 /// View this buffer as a slice of pixels.
533 ///
534 /// This reinterprets the bytes of the buffer. It can be used to view the buffer as any kind of
535 /// pixel, regardless of its association with the layout. Use it with care.
536 ///
537 /// An alternative way to get a slice of texels when a layout has an inherent texel type is
538 /// [`Self::as_slice`].
539 pub fn as_texels<P>(&self, pixel: Texel<P>) -> &'_ Cell<[P]>
540 where
541 L: Layout,
542 {
543 self.inner.as_cell_buf().as_texels(pixel)
544 }
545
546 /// Turn into a slice of the individual samples in the layout.
547 ///
548 /// This preserves the lifetime with which the layout is borrowed from the underlying image,
549 /// and the `ImageMut` need not stay alive.
550 pub fn into_bytes(self) -> alloc::vec::Vec<u8>
551 where
552 L: Layout,
553 {
554 let (buffer, layout) = self.inner.into_parts();
555 let len = layout.byte_len();
556 let mut target = alloc::vec![0; len];
557 let source = buffer.truncate(len).as_texels(U8);
558 U8.cell_memory_copy(
559 source.as_slice_of_cells(),
560 Cell::from_mut(&mut target[..]).as_slice_of_cells(),
561 );
562 target
563 }
564
565 /// Turn into a slice of the individual samples in the layout.
566 ///
567 /// This preserves the lifetime with which the layout is borrowed from the underlying image,
568 /// and the `ImageMut` need not stay alive.
569 pub fn into_slice(self) -> &'data Cell<[L::Sample]>
570 where
571 L: SliceLayout,
572 {
573 let sample = self.inner.layout().sample();
574 self.into_texels(sample)
575 }
576
577 /// View this buffer as a slice of pixels.
578 ///
579 /// This reinterprets the bytes of the buffer. It can be used to view the buffer as any kind of
580 /// pixel, regardless of its association with the layout. Use it with care.
581 ///
582 /// An alternative way to get a slice of texels when a layout has an inherent texel type is
583 /// [`Self::as_texels`].
584 pub fn into_texels<P>(self, pixel: Texel<P>) -> &'data Cell<[P]>
585 where
586 L: Layout,
587 {
588 let (buffer, layout) = self.inner.into_parts();
589 let byte_len = layout.byte_len();
590 buffer.truncate(byte_len).as_texels(pixel)
591 }
592
593 /*
594 /// Retrieve a single texel from a raster image.
595 #[deprecated = "Do not use yet"]
596 pub fn get_texel<P>(&self, _: Coord) -> Option<P>
597 where
598 L: Raster<P>,
599 {
600 todo!("Failure of the Raster trait");
601 }
602
603 /// Retrieve a single texel from a raster image.
604 #[deprecated = "Do not use yet"]
605 pub fn put_texel<P>(&self, _: Coord) -> Option<P>
606 where
607 L: Raster<P>,
608 {
609 todo!("Failure of the Raster trait");
610 }
611 */
612
613 /// Split off all unused bytes at the tail of the layout.
614 pub fn split_layout(&mut self) -> CellImageRef<'data, Bytes>
615 where
616 L: Layout,
617 {
618 // Need to roundup to correct alignment.
619 let size = self.inner.layout().byte_len();
620 let round_up = size.next_multiple_of(MAX_ALIGN);
621 let buffer = self.inner.get_mut();
622
623 if round_up > buffer.len() {
624 return RawImage::from_buffer(Bytes(0), cell_buf::new(&[])).into();
625 }
626
627 let (initial, next) = buffer.split_at(round_up);
628 *buffer = initial;
629
630 RawImage::from_buffer(Bytes(next.len()), next).into()
631 }
632
633 /// Remove all past-the-layout bytes.
634 ///
635 /// This is a utility to combine with pipelining. It is equivalent to calling
636 /// [`Self::split_layout`] and discarding that result.
637 pub fn truncate_layout(mut self) -> Self
638 where
639 L: Layout,
640 {
641 let _ = self.split_layout();
642 self
643 }
644
645 /// Split this reference into independent planes.
646 ///
647 /// If any plane fails their indexing operation or would not be aligned to the required
648 /// alignment or any plane layouts would overlap, an error is returned. The planes are returned
649 /// in the order of the descriptors.
650 ///
651 /// FIXME: the layout type is not what we want. For instance, with `PlaneMatrices` we get a
652 /// plane type of `Relocated<Matrix<_>>` but when we relocate that to `0` then we would really
653 /// prefer having a simple `Matrix<_>` as the layout type.
654 ///
655 /// # Examples
656 ///
657 /// A layout describing a matrix array can be split:
658 ///
659 /// ```
660 /// use image_texel::image::{CellImage, CellImageRef};
661 /// use image_texel::layout::{PlaneMatrices, Matrix};
662 /// use image_texel::texels::U8;
663 ///
664 /// let mat = Matrix::from_width_height(U8, 8, 8).unwrap();
665 /// let buffer = CellImage::new(PlaneMatrices::<_, 2>::from_repeated(mat));
666 /// let image: CellImageRef<'_, _> = buffer.as_ref();
667 ///
668 /// let [p0, p1] = buffer.as_ref().into_planes([0, 1]).unwrap();
669 /// ```
670 ///
671 /// You may select the same plane twice:
672 ///
673 pub fn into_planes<const N: usize, D>(
674 self,
675 descriptors: [D; N],
676 ) -> Result<[CellImageRef<'data, D::Plane>; N], IntoPlanesError>
677 where
678 D: PlaneOf<L>,
679 D::Plane: Relocate,
680 {
681 let layout = self.layout();
682 let mut planes = descriptors.map(|d| {
683 let plane = <D as PlaneOf<L>>::get_plane(d, layout);
684 let empty_buf = cell_buf::new(&[]);
685 (plane, empty_buf)
686 });
687
688 let (mut buffer, _) = self.inner.into_parts();
689
690 for plane in &mut planes {
691 let Some(layout) = &mut plane.0 else {
692 continue;
693 };
694
695 let skip_by = layout.byte_offset();
696
697 // FIXME: do we want failure reasons?
698 if skip_by % MAX_ALIGN != 0 {
699 plane.0 = None;
700 continue;
701 }
702
703 if buffer.len() < skip_by {
704 plane.0 = None;
705 continue;
706 }
707
708 layout.relocate(Default::default());
709 let len = layout.byte_len().div_ceil(MAX_ALIGN) * MAX_ALIGN;
710
711 // Check this before we consume the buffer. This way the tail can still be used by
712 // following layouts, we ignore this.
713 if buffer.len() - skip_by < len {
714 plane.0 = None;
715 continue;
716 }
717
718 let (_pre, tail) = buffer.split_at(skip_by);
719 let (img_buf, _post) = tail.split_at(len);
720
721 plane.1 = img_buf;
722 buffer = tail;
723 }
724
725 let planes = IntoPlanesError::from_array(planes)?;
726 Ok(planes.map(|(layout, buffer)| RawImage::from_buffer(layout, buffer).into()))
727 }
728}
729
730impl<L> From<RawImage<CellBuffer, L>> for CellImage<L> {
731 fn from(image: RawImage<CellBuffer, L>) -> Self {
732 CellImage { inner: image }
733 }
734}
735
736impl<'lt, L> From<RawImage<&'lt cell_buf, L>> for CellImageRef<'lt, L> {
737 fn from(image: RawImage<&'lt cell_buf, L>) -> Self {
738 CellImageRef { inner: image }
739 }
740}