1use std::{fmt::Debug, marker::PhantomData};
7
8use crate::{
9 error::Result,
10 image::internal::DistinctRowsIndexes,
11 util::{CACHE_LINE_BYTE_SIZE, MemoryGuard, MemoryTracker, tracing_wrappers::*},
12};
13
14use super::{ImageDataType, OwnedRawImage, RawImageRect, RawImageRectMut, Rect};
15
16#[cfg(feature = "allow-unsafe")]
23#[inline(always)]
24pub(super) fn cast_row<T: ImageDataType>(row: &[u8]) -> &[T] {
25 let new_len = row.len() / std::mem::size_of::<T>();
26 debug_assert!(row.len().is_multiple_of(std::mem::size_of::<T>()));
27 debug_assert!((row.as_ptr() as usize).is_multiple_of(std::mem::align_of::<T>()));
28 #[allow(unsafe_code)]
29 unsafe {
37 std::slice::from_raw_parts(row.as_ptr().cast::<T>(), new_len)
38 }
39}
40
41#[cfg(not(feature = "allow-unsafe"))]
42#[inline(always)]
43pub(super) fn cast_row<T: ImageDataType>(row: &[u8]) -> &[T] {
44 bytemuck::cast_slice(row)
45}
46
47#[cfg(feature = "allow-unsafe")]
49#[inline(always)]
50pub(super) fn cast_row_mut<T: ImageDataType>(row: &mut [u8]) -> &mut [T] {
51 let new_len = row.len() / std::mem::size_of::<T>();
52 debug_assert!(row.len().is_multiple_of(std::mem::size_of::<T>()));
53 debug_assert!((row.as_ptr() as usize).is_multiple_of(std::mem::align_of::<T>()));
54 #[allow(unsafe_code)]
55 unsafe {
57 std::slice::from_raw_parts_mut(row.as_mut_ptr().cast::<T>(), new_len)
58 }
59}
60
61#[cfg(not(feature = "allow-unsafe"))]
62#[inline(always)]
63pub(super) fn cast_row_mut<T: ImageDataType>(row: &mut [u8]) -> &mut [T] {
64 bytemuck::cast_slice_mut(row)
65}
66
67#[repr(transparent)]
68pub struct Image<T: ImageDataType> {
69 raw: OwnedRawImage,
72 _ph: PhantomData<T>,
73}
74
75impl<T: ImageDataType> Image<T> {
76 #[instrument(ret, err)]
77 pub fn new_with_padding(
78 size: (usize, usize),
79 offset: (usize, usize),
80 padding: (usize, usize),
81 ) -> Result<Image<T>> {
82 let s = T::DATA_TYPE_ID.size();
83 let img = OwnedRawImage::new_zeroed_with_padding(
84 (size.0 * s, size.1),
85 (offset.0 * s, offset.1),
86 (padding.0 * s, padding.1),
87 )?;
88 Ok(Self::from_raw(img))
89 }
90
91 #[instrument(ret, err)]
92 pub fn new(size: (usize, usize)) -> Result<Image<T>> {
93 Self::new_with_padding(size, (0, 0), (0, 0))
94 }
95
96 pub fn new_uninit(size: (usize, usize)) -> Result<Image<T>> {
104 let s = T::DATA_TYPE_ID.size();
105 let img = OwnedRawImage::new_uninit((size.0 * s, size.1))?;
106 Ok(Self::from_raw(img))
107 }
108
109 pub fn new_with_value(size: (usize, usize), value: T) -> Result<Image<T>> {
110 let mut ret = Self::new(size)?;
113 ret.fill(value);
114 Ok(ret)
115 }
116
117 pub fn allocation_size(size: (usize, usize)) -> u64 {
120 let (width, height) = size;
121 if width == 0 || height == 0 {
122 return 0;
123 }
124 let bytes_per_row = width.saturating_mul(T::DATA_TYPE_ID.size());
125 let bytes_between_rows =
126 bytes_per_row.div_ceil(CACHE_LINE_BYTE_SIZE) * CACHE_LINE_BYTE_SIZE;
127 let total = (height - 1)
128 .saturating_mul(bytes_between_rows)
129 .saturating_add(bytes_per_row);
130 total as u64
131 }
132
133 #[instrument(ret, err)]
136 pub fn new_tracked(size: (usize, usize), tracker: &MemoryTracker) -> Result<Image<T>> {
137 let alloc_size = Self::allocation_size(size);
138 tracker.try_allocate(alloc_size)?;
139 let guard = MemoryGuard::new(tracker.clone(), alloc_size);
141 let mut img = Self::new(size)?;
142 img.raw.set_tracker(tracker.clone(), alloc_size);
143 guard.disarm(); Ok(img)
145 }
146
147 #[instrument(ret, err)]
150 pub fn new_with_padding_tracked(
151 size: (usize, usize),
152 offset: (usize, usize),
153 padding: (usize, usize),
154 tracker: &MemoryTracker,
155 ) -> Result<Image<T>> {
156 let total_width = size.0.saturating_add(offset.0).saturating_add(padding.0);
157 let total_height = size.1.saturating_add(offset.1).saturating_add(padding.1);
158 let alloc_size = Self::allocation_size((total_width, total_height));
159 tracker.try_allocate(alloc_size)?;
160 let guard = MemoryGuard::new(tracker.clone(), alloc_size);
161 let mut img = Self::new_with_padding(size, offset, padding)?;
162 img.raw.set_tracker(tracker.clone(), alloc_size);
163 guard.disarm();
164 Ok(img)
165 }
166
167 #[inline]
168 pub fn size(&self) -> (usize, usize) {
169 (
170 self.raw.byte_size().0 / T::DATA_TYPE_ID.size(),
171 self.raw.byte_size().1,
172 )
173 }
174
175 pub fn offset(&self) -> (usize, usize) {
176 (
177 self.raw.byte_offset().0 / T::DATA_TYPE_ID.size(),
178 self.raw.byte_offset().1,
179 )
180 }
181
182 pub fn padding(&self) -> (usize, usize) {
183 (
184 self.raw.byte_padding().0 / T::DATA_TYPE_ID.size(),
185 self.raw.byte_padding().1,
186 )
187 }
188
189 pub fn fill(&mut self, v: T) {
190 if self.size().0 == 0 {
191 return;
192 }
193 for y in 0..self.size().1 {
194 self.row_mut(y).fill(v);
195 }
196 }
197
198 #[inline]
199 pub fn get_rect_including_padding_mut(&mut self, rect: Rect) -> ImageRectMut<'_, T> {
200 ImageRectMut::from_raw(
201 self.raw
202 .get_rect_including_padding_mut(rect.to_byte_rect(T::DATA_TYPE_ID)),
203 )
204 }
205
206 #[inline]
207 pub fn get_rect_including_padding(&mut self, rect: Rect) -> ImageRect<'_, T> {
208 ImageRect::from_raw(
209 self.raw
210 .get_rect_including_padding(rect.to_byte_rect(T::DATA_TYPE_ID)),
211 )
212 }
213
214 #[inline]
215 pub fn get_rect_mut(&mut self, rect: Rect) -> ImageRectMut<'_, T> {
216 ImageRectMut::from_raw(self.raw.get_rect_mut(rect.to_byte_rect(T::DATA_TYPE_ID)))
217 }
218
219 #[inline]
220 pub fn get_rect(&self, rect: Rect) -> ImageRect<'_, T> {
221 ImageRect::from_raw(self.raw.get_rect(rect.to_byte_rect(T::DATA_TYPE_ID)))
222 }
223
224 pub fn try_clone(&self) -> Result<Self> {
225 Ok(Self::from_raw(self.raw.try_clone()?))
226 }
227
228 pub fn into_raw(self) -> OwnedRawImage {
229 self.raw
230 }
231
232 pub fn from_raw(raw: OwnedRawImage) -> Self {
233 const { assert!(CACHE_LINE_BYTE_SIZE.is_multiple_of(T::DATA_TYPE_ID.size())) };
234 assert!(raw.data.is_aligned(T::DATA_TYPE_ID.size()));
235 assert!(
236 raw.byte_offset().0.is_multiple_of(T::DATA_TYPE_ID.size()),
237 "image byte offset must be aligned to element size"
238 );
239 Image {
240 raw,
241 _ph: PhantomData,
242 }
243 }
244
245 #[inline(always)]
246 pub fn row(&self, row: usize) -> &[T] {
247 cast_row(self.raw.row(row))
248 }
249
250 #[inline(always)]
251 pub fn row_mut(&mut self, row: usize) -> &mut [T] {
252 cast_row_mut(self.raw.row_mut(row))
253 }
254
255 #[inline(always)]
259 pub fn distinct_full_rows_mut<I: DistinctRowsIndexes>(
260 &mut self,
261 rows: I,
262 ) -> I::CastOutput<'_, T> {
263 let rows = self.raw.data.distinct_rows_mut(rows);
264 I::cast_rows(rows)
265 }
266
267 pub fn all_rows_mut(&mut self) -> Vec<&mut [T]> {
271 let (bytes_per_row, num_rows, bytes_between_rows) = self.raw.data.dimensions();
272 if num_rows == 0 {
273 return Vec::new();
274 }
275 let data = self.raw.data.data_slice_mut();
276 let mut result = Vec::with_capacity(num_rows);
279 split_rows_into(
280 data,
281 bytes_per_row,
282 bytes_between_rows,
283 num_rows,
284 &mut result,
285 );
286 result
287 }
288}
289
290fn split_rows_into<'a, T: ImageDataType>(
298 data: &'a mut [u8],
299 bytes_per_row: usize,
300 bytes_between_rows: usize,
301 num_rows: usize,
302 out: &mut Vec<&'a mut [T]>,
303) {
304 let mut remaining: Option<&'a mut [u8]> = Some(data);
305 for i in 0..num_rows {
306 let data = remaining.take().unwrap();
307 if i < num_rows - 1 {
308 let (head, tail) = data.split_at_mut(bytes_between_rows);
309 out.push(cast_row_mut(&mut head[..bytes_per_row]));
310 remaining = Some(tail);
311 } else {
312 out.push(cast_row_mut(&mut data[..bytes_per_row]));
313 }
314 }
315}
316
317#[derive(Clone, Copy)]
318pub struct ImageRect<'a, T: ImageDataType> {
319 raw: RawImageRect<'a>,
321 _ph: PhantomData<T>,
322}
323
324impl<'a, T: ImageDataType> ImageRect<'a, T> {
325 #[inline(always)]
326 pub fn rect(&self, rect: Rect) -> ImageRect<'a, T> {
327 Self::from_raw(self.raw.rect(rect.to_byte_rect(T::DATA_TYPE_ID)))
328 }
329
330 #[inline]
331 pub fn size(&self) -> (usize, usize) {
332 (
333 self.raw.byte_size().0 / T::DATA_TYPE_ID.size(),
334 self.raw.byte_size().1,
335 )
336 }
337
338 #[inline(always)]
339 pub fn row(&self, row: usize) -> &'a [T] {
340 cast_row(self.raw.row(row))
343 }
344
345 pub fn iter(&self) -> impl Iterator<Item = T> + '_ {
346 (0..self.size().1).flat_map(|x| self.row(x).iter().cloned())
347 }
348
349 pub fn into_raw(self) -> RawImageRect<'a> {
350 self.raw
351 }
352
353 #[inline]
354 pub fn from_raw(raw: RawImageRect<'a>) -> Self {
355 const { assert!(CACHE_LINE_BYTE_SIZE.is_multiple_of(T::DATA_TYPE_ID.size())) };
356 assert!(raw.is_aligned(T::DATA_TYPE_ID.size()));
357 ImageRect {
358 raw,
359 _ph: PhantomData,
360 }
361 }
362}
363
364pub struct ImageRectMut<'a, T: ImageDataType> {
365 raw: RawImageRectMut<'a>,
367 _ph: PhantomData<T>,
368}
369
370impl<'a, T: ImageDataType> ImageRectMut<'a, T> {
371 #[inline]
372 pub fn rect(&'a mut self, rect: Rect) -> ImageRectMut<'a, T> {
373 Self::from_raw(self.raw.rect_mut(rect.to_byte_rect(T::DATA_TYPE_ID)))
374 }
375
376 #[inline]
377 pub fn size(&self) -> (usize, usize) {
378 (
379 self.raw.byte_size().0 / T::DATA_TYPE_ID.size(),
380 self.raw.byte_size().1,
381 )
382 }
383
384 #[inline(always)]
385 pub fn row(&mut self, row: usize) -> &mut [T] {
386 cast_row_mut(self.raw.row(row))
387 }
388
389 pub fn as_rect(&'a self) -> ImageRect<'a, T> {
390 ImageRect::from_raw(self.raw.as_rect())
391 }
392
393 pub fn into_raw(self) -> RawImageRectMut<'a> {
394 self.raw
395 }
396
397 #[inline]
398 pub fn from_raw(raw: RawImageRectMut<'a>) -> Self {
399 const { assert!(CACHE_LINE_BYTE_SIZE.is_multiple_of(T::DATA_TYPE_ID.size())) };
400 assert!(raw.is_aligned(T::DATA_TYPE_ID.size()));
401 ImageRectMut {
402 raw,
403 _ph: PhantomData,
404 }
405 }
406}
407
408impl<T: ImageDataType> Debug for Image<T> {
409 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
410 write!(
411 f,
412 "{:?} {}x{}",
413 T::DATA_TYPE_ID,
414 self.size().0,
415 self.size().1
416 )
417 }
418}
419
420impl<T: ImageDataType> Debug for ImageRect<'_, T> {
421 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
422 write!(
423 f,
424 "{:?} rect {}x{}",
425 T::DATA_TYPE_ID,
426 self.size().0,
427 self.size().1
428 )
429 }
430}
431
432impl<T: ImageDataType> Debug for ImageRectMut<'_, T> {
433 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
434 write!(
435 f,
436 "{:?} mutrect {}x{}",
437 T::DATA_TYPE_ID,
438 self.size().0,
439 self.size().1
440 )
441 }
442}