plane.rs 18.3 KB
Newer Older
Guillaume Martres's avatar
Guillaume Martres committed
1
2
3
4
5
6
7
8
9
// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

Luca Barbato's avatar
Luca Barbato committed
10
use std::alloc::{alloc, dealloc, Layout};
Raphaël Zumer's avatar
Raphaël Zumer committed
11
use std::iter::FusedIterator;
12
use std::fmt::{Debug, Display, Formatter};
13
use std::marker::PhantomData;
14
use std::mem;
15
use std::ops::{Index, IndexMut, Range};
Raphaël Zumer's avatar
Raphaël Zumer committed
16

Romain Vimont's avatar
Romain Vimont committed
17
use crate::tiling::*;
Raphaël Zumer's avatar
Raphaël Zumer committed
18
use crate::util::*;
Michael Bebenita's avatar
Michael Bebenita committed
19

Guillaume Martres's avatar
Guillaume Martres committed
20
/// Plane-specific configuration.
21
#[derive(Debug, Clone, PartialEq, Eq)]
Guillaume Martres's avatar
Guillaume Martres committed
22
pub struct PlaneConfig {
Michael Bebenita's avatar
Michael Bebenita committed
23
  pub stride: usize,
fbossen's avatar
fbossen committed
24
  pub alloc_height: usize,
Luca Barbato's avatar
Luca Barbato committed
25
26
  pub width: usize,
  pub height: usize,
Michael Bebenita's avatar
Michael Bebenita committed
27
  pub xdec: usize,
fbossen's avatar
fbossen committed
28
  pub ydec: usize,
29
30
  pub xpad: usize,
  pub ypad: usize,
31
32
  pub xorigin: usize,
  pub yorigin: usize
Guillaume Martres's avatar
Guillaume Martres committed
33
34
35
}

/// Absolute offset in pixels inside a plane
Romain Vimont's avatar
Romain Vimont committed
36
#[derive(Clone, Copy, Debug)]
Guillaume Martres's avatar
Guillaume Martres committed
37
pub struct PlaneOffset {
fbossen's avatar
fbossen committed
38
39
  pub x: isize,
  pub y: isize
Guillaume Martres's avatar
Guillaume Martres committed
40
41
}

Luca Barbato's avatar
Luca Barbato committed
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#[derive(Debug, PartialEq, Eq)]
pub struct PlaneData<T: Pixel> {
  ptr: std::ptr::NonNull<T>,
  _marker: PhantomData<T>,
  len: usize,
}

unsafe impl<T: Pixel + Send> Send for PlaneData<T> { }
unsafe impl<T: Pixel + Sync> Sync for PlaneData<T> { }

impl<T: Pixel> Clone for PlaneData<T> {
  fn clone(&self) -> Self {
    let mut pd = unsafe { Self::new_uninitialized(self.len) };

    pd.copy_from_slice(self);

    pd
  }
}

impl<T: Pixel> std::ops::Deref for PlaneData<T> {
  type Target = [T];

  fn deref(&self) -> &[T] {
    unsafe {
      let p = self.ptr.as_ptr();

      std::slice::from_raw_parts(p, self.len)
    }
  }
}

impl<T: Pixel> std::ops::DerefMut for PlaneData<T> {
  fn deref_mut(&mut self) -> &mut [T] {
    unsafe {
      let p = self.ptr.as_ptr();

      std::slice::from_raw_parts_mut(p, self.len)
    }
  }
}

impl<T: Pixel> std::ops::Drop for PlaneData<T> {
  fn drop(&mut self) {
    unsafe {
87
      dealloc(self.ptr.as_ptr() as *mut u8, Self::layout(self.len));
Luca Barbato's avatar
Luca Barbato committed
88
89
90
91
92
93
94
95
    }
  }
}

impl<T: Pixel> PlaneData<T> {
  /// Data alignment in bytes.
  const DATA_ALIGNMENT_LOG2: usize = 5;

96
97
  unsafe fn layout(len: usize) -> Layout {
    Layout::from_size_align_unchecked(
Luca Barbato's avatar
Luca Barbato committed
98
99
      len * mem::size_of::<T>(),
      1 << Self::DATA_ALIGNMENT_LOG2
100
101
    )
  }
Luca Barbato's avatar
Luca Barbato committed
102

103
  unsafe fn new_uninitialized(len: usize) -> Self {
Luca Barbato's avatar
Luca Barbato committed
104
    let ptr = {
105
      let ptr = alloc(Self::layout(len)) as *mut T;
Luca Barbato's avatar
Luca Barbato committed
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
      std::ptr::NonNull::new_unchecked(ptr)
    };

    PlaneData {
      ptr,
      len,
      _marker: PhantomData
    }
  }

  pub fn new(len: usize) -> Self {
    let mut pd = unsafe { Self::new_uninitialized(len) };

    for v in pd.iter_mut() {
      *v = T::cast_from(128);
    }

    pd
  }

  pub fn from_slice(data: &[T]) -> Self {
    let mut pd = unsafe { Self::new_uninitialized(data.len()) };

    pd.copy_from_slice(data);

    pd
  }
}

135
#[derive(Clone, PartialEq, Eq)]
136
pub struct Plane<T: Pixel> {
Luca Barbato's avatar
Luca Barbato committed
137
  pub data: PlaneData<T>,
Michael Bebenita's avatar
Michael Bebenita committed
138
  pub cfg: PlaneConfig
Guillaume Martres's avatar
Guillaume Martres committed
139
140
}

141
142
impl<T: Pixel> Debug for Plane<T>
    where T: Display {
143
  fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
144
145
146
147
    write!(f, "Plane {{ data: [{}, ...], cfg: {:?} }}", self.data[0], self.cfg)
  }
}

148
impl<T: Pixel> Plane<T> {
149
  /// Stride alignment in bytes.
150
  const STRIDE_ALIGNMENT_LOG2: usize = 5;
151

152
153
154
  pub fn new(
    width: usize, height: usize, xdec: usize, ydec: usize, xpad: usize,
    ypad: usize
155
  ) -> Self {
156
157
158
    let xorigin = xpad.align_power_of_two(
      Self::STRIDE_ALIGNMENT_LOG2 + 1 - mem::size_of::<T>()
    );
159
    let yorigin = ypad;
160
161
162
    let stride = (xorigin + width + xpad).align_power_of_two(
      Self::STRIDE_ALIGNMENT_LOG2 + 1 - mem::size_of::<T>()
    );
163
    let alloc_height = yorigin + height + ypad;
Luca Barbato's avatar
Luca Barbato committed
164
165
    let data = PlaneData::new(stride * alloc_height);

166
    Plane {
Luca Barbato's avatar
Luca Barbato committed
167
      data,
168
169
170
171
172
173
174
      cfg: PlaneConfig {
        stride,
        alloc_height,
        width,
        height,
        xdec,
        ydec,
175
176
        xpad,
        ypad,
177
178
179
180
        xorigin,
        yorigin
      }
    }
fbossen's avatar
fbossen committed
181
182
  }

183
184
  pub fn wrap(data: Vec<T>, stride: usize) -> Self {
    let len = data.len();
185

186
    assert!(len % stride == 0);
Luca Barbato's avatar
Luca Barbato committed
187

188
    Self {
Luca Barbato's avatar
Luca Barbato committed
189
      data: PlaneData::from_slice(&data),
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
      cfg: PlaneConfig {
        stride,
        alloc_height: len / stride,
        width: stride,
        height: len / stride,
        xdec: 0,
        ydec: 0,
        xpad: 0,
        ypad: 0,
        xorigin: 0,
        yorigin: 0,
      }
    }
  }

Frank Bossen's avatar
Frank Bossen committed
205
  pub fn pad(&mut self, w: usize, h: usize) {
206
207
    let xorigin = self.cfg.xorigin;
    let yorigin = self.cfg.yorigin;
fbossen's avatar
fbossen committed
208
    let stride = self.cfg.stride;
209
    let alloc_height = self.cfg.alloc_height;
Frank Bossen's avatar
Frank Bossen committed
210
211
    let width = w >> self.cfg.xdec;
    let height = h >> self.cfg.ydec;
fbossen's avatar
fbossen committed
212
213
214

    if xorigin > 0 {
      for y in 0..height {
215
216
217
        let base = (yorigin + y) * stride;
        let fill_val = self.data[base + xorigin];
        for val in &mut self.data[base..base + xorigin] {
218
219
          *val = fill_val;
        }
fbossen's avatar
fbossen committed
220
221
222
223
224
      }
    }

    if xorigin + width < stride {
      for y in 0..height {
225
226
227
        let base = (yorigin + y) * stride + xorigin + width;
        let fill_val = self.data[base - 1];
        for val in &mut self.data[base..base + stride - (xorigin + width)] {
228
229
          *val = fill_val;
        }
fbossen's avatar
fbossen committed
230
231
232
233
      }
    }

    if yorigin > 0 {
234
235
      let (top, bottom) = self.data.split_at_mut(yorigin * stride);
      let src = &bottom[..stride];
236
      for y in 0..yorigin {
237
238
        let dst = &mut top[y * stride..(y + 1) * stride];
        dst.copy_from_slice(src);
fbossen's avatar
fbossen committed
239
240
241
      }
    }

242
243
244
    if yorigin + height < self.cfg.alloc_height {
      let (top, bottom) = self.data.split_at_mut((yorigin + height) * stride);
      let src = &top[(yorigin + height - 1) * stride..];
245
      for y in 0..alloc_height - (yorigin + height) {
246
247
        let dst = &mut bottom[y * stride..(y + 1) * stride];
        dst.copy_from_slice(src);
fbossen's avatar
fbossen committed
248
249
      }
    }
Michael Bebenita's avatar
Michael Bebenita committed
250
  }
Guillaume Martres's avatar
Guillaume Martres committed
251

Romain Vimont's avatar
Romain Vimont committed
252
  pub fn slice(&self, po: PlaneOffset) -> PlaneSlice<'_, T> {
Michael Bebenita's avatar
Michael Bebenita committed
253
    PlaneSlice { plane: self, x: po.x, y: po.y }
Michael Bebenita's avatar
Michael Bebenita committed
254
  }
Guillaume Martres's avatar
Guillaume Martres committed
255

Romain Vimont's avatar
Romain Vimont committed
256
  pub fn mut_slice(&mut self, po: PlaneOffset) -> PlaneMutSlice<'_, T> {
Michael Bebenita's avatar
Michael Bebenita committed
257
    PlaneMutSlice { plane: self, x: po.x, y: po.y }
Michael Bebenita's avatar
Michael Bebenita committed
258
259
  }

260
  pub fn as_slice(&self) -> PlaneSlice<'_, T> {
Romain Vimont's avatar
Romain Vimont committed
261
    self.slice(PlaneOffset { x: 0, y: 0 })
262
263
264
  }

  pub fn as_mut_slice(&mut self) -> PlaneMutSlice<'_, T> {
Romain Vimont's avatar
Romain Vimont committed
265
    self.mut_slice(PlaneOffset { x: 0, y: 0 })
266
267
  }

Romain Vimont's avatar
Romain Vimont committed
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  #[inline(always)]
  pub fn region(&self, area: Area) -> PlaneRegion<'_, T> {
    let rect = area.to_rect(
      self.cfg.xdec,
      self.cfg.ydec,
      self.cfg.stride - self.cfg.xorigin as usize,
      self.cfg.alloc_height - self.cfg.yorigin as usize,
    );
    PlaneRegion::new(self, rect)
  }

  #[inline(always)]
  pub fn region_mut(&mut self, area: Area) -> PlaneRegionMut<'_, T> {
    let rect = area.to_rect(
      self.cfg.xdec,
      self.cfg.ydec,
      self.cfg.stride - self.cfg.xorigin as usize,
      self.cfg.alloc_height - self.cfg.yorigin as usize,
    );
    PlaneRegionMut::new(self, rect)
  }

Romain Vimont's avatar
Romain Vimont committed
290
291
292
293
294
295
296
297
298
299
  #[inline(always)]
  pub fn as_region(&self) -> PlaneRegion<'_, T> {
    self.region(Area::StartingAt { x: 0, y: 0 })
  }

  #[inline(always)]
  pub fn as_region_mut(&mut self) -> PlaneRegionMut<'_, T> {
    self.region_mut(Area::StartingAt { x: 0, y: 0 })
  }

300
301
  #[inline]
  fn index(&self, x: usize, y: usize) -> usize {
302
    (y + self.cfg.yorigin) * self.cfg.stride + (x + self.cfg.xorigin)
303
304
  }

305
  #[inline]
306
  pub fn row_range(&self, x: isize, y: isize) -> Range<usize> {
307
308
309
310
311
312
313
314
315
316
    debug_assert!(self.cfg.yorigin as isize + y >= 0);
    debug_assert!(self.cfg.xorigin as isize + x >= 0);
    let base_y = (self.cfg.yorigin as isize + y) as usize;
    let base_x = (self.cfg.xorigin as isize + x) as usize;
    let base = base_y * self.cfg.stride + base_x;
    let width = self.cfg.stride - base_x;
    base..base + width
  }


317
  pub fn p(&self, x: usize, y: usize) -> T {
318
    self.data[self.index(x, y)]
fbossen's avatar
fbossen committed
319
320
  }

321
  pub fn data_origin(&self) -> &[T] {
322
    &self.data[self.index(0, 0)..]
fbossen's avatar
fbossen committed
323
324
  }

325
  pub fn data_origin_mut(&mut self) -> &mut [T] {
326
327
    let i = self.index(0, 0);
    &mut self.data[i..]
Michael Bebenita's avatar
Michael Bebenita committed
328
329
330
331
332
333
  }

  pub fn copy_from_raw_u8(
    &mut self, source: &[u8], source_stride: usize, source_bytewidth: usize
  ) {
    let stride = self.cfg.stride;
334
335
336
337
    for (self_row, source_row) in self
      .data_origin_mut()
      .chunks_mut(stride)
      .zip(source.chunks(source_stride))
Michael Bebenita's avatar
Michael Bebenita committed
338
339
340
341
342
    {
      match source_bytewidth {
        1 => for (self_pixel, source_pixel) in
          self_row.iter_mut().zip(source_row.iter())
        {
343
          *self_pixel = T::cast_from(*source_pixel);
Michael Bebenita's avatar
Michael Bebenita committed
344
        },
345
346
347
348
349
350
351
        2 => {
          assert!(mem::size_of::<T>() >= 2, "source bytewidth ({}) cannot fit in Plane<u8>", source_bytewidth);
          for (self_pixel, bytes) in
            self_row.iter_mut().zip(source_row.chunks(2))
          {
            *self_pixel = T::cast_from(u16::cast_from(bytes[1]) << 8 | u16::cast_from(bytes[0]));
          }
Michael Bebenita's avatar
Michael Bebenita committed
352
353
354
355
        },

        _ => {}
      }
Thomas Daede's avatar
Thomas Daede committed
356
    }
Michael Bebenita's avatar
Michael Bebenita committed
357
  }
358

359
  pub fn downsample_from(&mut self, src: &Plane<T>) {
360
361
    let width = self.cfg.width;
    let height = self.cfg.height;
362
363
364
    let xorigin = self.cfg.xorigin;
    let yorigin = self.cfg.yorigin;
    let stride = self.cfg.stride;
365
366
367
368
369

    assert!(width * 2 == src.cfg.width);
    assert!(height * 2 == src.cfg.height);

    for row in 0..height {
370
371
      let base = (yorigin + row) * stride + xorigin;
      let dst = &mut self.data[base..base + width];
372
373
374

      for col in 0..width {
        let mut sum = 0;
375
376
377
378
        sum += u32::cast_from(src.p(2 * col, 2 * row));
        sum += u32::cast_from(src.p(2 * col + 1, 2 * row));
        sum += u32::cast_from(src.p(2 * col, 2 * row + 1));
        sum += u32::cast_from(src.p(2 * col + 1, 2 * row + 1));
379
        let avg = (sum + 2) >> 2;
380
        dst[col] = T::cast_from(avg);
381
382
383
      }
    }
  }
384
385

  /// Iterates over the pixels in the `Plane`, skipping stride data.
386
  pub fn iter(&self) -> PlaneIter<'_, T> {
387
388
389
390
391
    PlaneIter::new(self)
  }
}

#[derive(Debug)]
392
393
pub struct PlaneIter<'a, T: Pixel> {
  plane: &'a Plane<T>,
394
395
396
397
  y: usize,
  x: usize,
}

398
399
400
impl<'a, T: Pixel> PlaneIter<'a, T> {
  pub fn new(plane: &'a Plane<T>) -> Self {
    Self {
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
      plane,
      y: 0,
      x: 0,
    }
  }

  fn width(&self) -> usize {
    self.plane.cfg.width
  }

  fn height(&self) -> usize {
    self.plane.cfg.height
  }
}

416
417
impl<'a, T: Pixel> Iterator for PlaneIter<'a, T> {
  type Item = T;
418
419

  fn next(&mut self) -> Option<<Self as Iterator>::Item> {
420
    if self.y == self.height() {
421
422
423
424
425
426
427
428
429
430
431
      return None;
    }
    let pixel = self.plane.p(self.x, self.y);
    if self.x == self.width() - 1 {
      self.x = 0;
      self.y += 1;
    } else {
      self.x += 1;
    }
    Some(pixel)
  }
Guillaume Martres's avatar
Guillaume Martres committed
432
433
}

434
#[derive(Clone, Copy, Debug)]
435
436
pub struct PlaneSlice<'a, T: Pixel> {
  pub plane: &'a Plane<T>,
fbossen's avatar
fbossen committed
437
438
  pub x: isize,
  pub y: isize
Guillaume Martres's avatar
Guillaume Martres committed
439
440
}

441
442
pub struct IterWidth<'a, T: Pixel> {
    ps: PlaneSlice<'a, T>,
443
444
445
    width: usize,
}

446
447
impl<'a, T: Pixel> Iterator for IterWidth<'a, T> {
    type Item = &'a [T];
448
449

    #[inline]
450
    fn next(&mut self) -> Option<Self::Item> {
451
452
        let x = self.ps.plane.cfg.xorigin as isize + self.ps.x;
        let y = self.ps.plane.cfg.yorigin as isize + self.ps.y;
453
454
455
456
457
458
459
460
461
462
        let stride = self.ps.plane.cfg.stride;
        let base = y as usize * stride + x as usize;

        if self.ps.plane.data.len() < base + self.width {
            None
        } else {
            self.ps.y += 1;
            Some(&self.ps.plane.data[base..base + self.width])
        }
    }
463
464
465
466
467
468
469

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let size = self.ps.plane.cfg.height - self.ps.y as usize;

        (size, Some(size))
    }
470
471
}

472
impl<'a, T: Pixel> ExactSizeIterator for IterWidth<'a, T> { }
473

474
impl<'a, T: Pixel> FusedIterator for IterWidth<'a, T> { }
475

476
pub struct RowsIter<'a, T: Pixel> {
477
478
479
  plane: &'a Plane<T>,
  x: isize,
  y: isize,
480
481
482
483
484
485
}

impl<'a, T: Pixel> Iterator for RowsIter<'a, T> {
  type Item = &'a [T];

  fn next(&mut self) -> Option<Self::Item> {
486
    if self.plane.cfg.height as isize > self.y {
487
      // cannot directly return self.ps.row(row) due to lifetime issue
488
489
490
      let range = self.plane.row_range(self.x, self.y);
      self.y += 1;
      Some(&self.plane.data[range])
491
492
493
494
495
496
    } else {
      None
    }
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
497
498
    let remaining = self.plane.cfg.height as isize - self.y;
    debug_assert!(remaining >= 0);
499
500
501
502
503
504
505
506
507
    let remaining = remaining as usize;

    (remaining, Some(remaining))
  }
}

impl<'a, T: Pixel> ExactSizeIterator for RowsIter<'a, T> {}
impl<'a, T: Pixel> FusedIterator for RowsIter<'a, T> {}

508
impl<'a, T: Pixel> PlaneSlice<'a, T> {
509
  pub fn as_ptr(&self) -> *const T {
510
    self[0].as_ptr()
511
512
  }

513
514
  pub fn rows_iter(&self) -> RowsIter<'_, T> {
    RowsIter {
515
516
517
      plane: self.plane,
      x: self.x,
      y: self.y,
518
519
520
    }
  }

521
  pub fn clamp(&self) -> PlaneSlice<'a, T> {
522
523
524
525
526
527
528
529
530
531
532
533
534
    PlaneSlice {
      plane: self.plane,
      x: self
        .x
        .min(self.plane.cfg.width as isize)
        .max(-(self.plane.cfg.xorigin as isize)),
      y: self
        .y
        .min(self.plane.cfg.height as isize)
        .max(-(self.plane.cfg.yorigin as isize))
    }
  }

535
  pub fn iter_width(&self, width: usize) -> IterWidth<'a, T> {
536
537
538
    IterWidth { ps: *self, width }
  }

539
  pub fn subslice(&self, xo: usize, yo: usize) -> PlaneSlice<'a, T> {
540
541
542
543
544
    PlaneSlice {
      plane: self.plane,
      x: self.x + xo as isize,
      y: self.y + yo as isize
    }
Jean-Marc Valin's avatar
Jean-Marc Valin committed
545
546
  }

Monty's avatar
Monty committed
547
548
549
550
551
552
553
554
  pub fn reslice(&self, xo: isize, yo: isize) -> PlaneSlice<'a, T> {
    PlaneSlice {
      plane: self.plane,
      x: self.x + xo,
      y: self.y + yo
    }
  }

Michael Bebenita's avatar
Michael Bebenita committed
555
  /// A slice starting i pixels above the current one.
556
  pub fn go_up(&self, i: usize) -> PlaneSlice<'a, T> {
fbossen's avatar
fbossen committed
557
    PlaneSlice { plane: self.plane, x: self.x, y: self.y - i as isize }
Michael Bebenita's avatar
Michael Bebenita committed
558
559
560
  }

  /// A slice starting i pixels to the left of the current one.
561
  pub fn go_left(&self, i: usize) -> PlaneSlice<'a, T> {
fbossen's avatar
fbossen committed
562
    PlaneSlice { plane: self.plane, x: self.x - i as isize, y: self.y }
Michael Bebenita's avatar
Michael Bebenita committed
563
  }
Guillaume Martres's avatar
Guillaume Martres committed
564

565
  pub fn p(&self, add_x: usize, add_y: usize) -> T {
566
567
568
569
    let new_y =
      (self.y + add_y as isize + self.plane.cfg.yorigin as isize) as usize;
    let new_x =
      (self.x + add_x as isize + self.plane.cfg.xorigin as isize) as usize;
Michael Bebenita's avatar
Michael Bebenita committed
570
571
    self.plane.data[new_y * self.plane.cfg.stride + new_x]
  }
Guillaume Martres's avatar
Guillaume Martres committed
572
573
}

574
575
576
impl<'a, T: Pixel> Index<usize> for PlaneSlice<'a, T> {
  type Output = [T];
  fn index(&self, index: usize) -> &Self::Output {
577
578
    let range = self.plane.row_range(self.x, self.y + index as isize);
    &self.plane.data[range]
579
580
581
  }
}

582
583
pub struct PlaneMutSlice<'a, T: Pixel> {
  pub plane: &'a mut Plane<T>,
fbossen's avatar
fbossen committed
584
585
  pub x: isize,
  pub y: isize
Guillaume Martres's avatar
Guillaume Martres committed
586
587
}

588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
pub struct RowsIterMut<'a, T: Pixel> {
  plane: *mut Plane<T>,
  x: isize,
  y: isize,
  phantom: PhantomData<&'a mut Plane<T>>,
}

impl<'a, T: Pixel> Iterator for RowsIterMut<'a, T> {
  type Item = &'a mut [T];

  fn next(&mut self) -> Option<Self::Item> {
    // there could not be a concurrent call using a mutable reference to the plane
    let plane = unsafe { &mut *self.plane };
    if plane.cfg.height as isize > self.y {
      // cannot directly return self.ps.row(row) due to lifetime issue
      let range = plane.row_range(self.x, self.y);
      self.y += 1;
      Some(&mut plane.data[range])
    } else {
      None
    }
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    // there could not be a concurrent call using a mutable reference to the plane
    let plane = unsafe { &mut *self.plane };
    let remaining = plane.cfg.height as isize - self.y;
    debug_assert!(remaining >= 0);
    let remaining = remaining as usize;

    (remaining, Some(remaining))
  }
}

impl<'a, T: Pixel> ExactSizeIterator for RowsIterMut<'a, T> {}
impl<'a, T: Pixel> FusedIterator for RowsIterMut<'a, T> {}

625
impl<'a, T: Pixel> PlaneMutSlice<'a, T> {
626
  pub fn as_ptr(&self) -> *const T {
627
    self[0].as_ptr()
628
629
630
  }

  pub fn as_mut_ptr(&mut self) -> *mut T {
631
    self[0].as_mut_ptr()
632
633
  }

634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
  pub fn rows_iter(&self) -> RowsIter<'_, T> {
    RowsIter {
      plane: self.plane,
      x: self.x,
      y: self.y,
    }
  }

  pub fn rows_iter_mut(&mut self) -> RowsIterMut<'_, T> {
    RowsIterMut {
      plane: self.plane as *mut Plane<T>,
      x: self.x,
      y: self.y,
      phantom: PhantomData,
    }
  }

651
  // FIXME: code duplication with PlaneSlice
652
  pub fn p(&self, add_x: usize, add_y: usize) -> T {
653
654
655
656
    let new_y =
      (self.y + add_y as isize + self.plane.cfg.yorigin as isize) as usize;
    let new_x =
      (self.x + add_x as isize + self.plane.cfg.xorigin as isize) as usize;
Michael Bebenita's avatar
Michael Bebenita committed
657
658
    self.plane.data[new_y * self.plane.cfg.stride + new_x]
  }
Guillaume Martres's avatar
Guillaume Martres committed
659
}
660
661
662
663

impl<'a, T: Pixel> Index<usize> for PlaneMutSlice<'a, T> {
  type Output = [T];
  fn index(&self, index: usize) -> &Self::Output {
664
665
    let range = self.plane.row_range(self.x, self.y + index as isize);
    &self.plane.data[range]
666
667
668
669
670
  }
}

impl<'a, T: Pixel> IndexMut<usize> for PlaneMutSlice<'a, T> {
  fn index_mut(&mut self, index: usize) -> &mut Self::Output {
671
672
    let range = self.plane.row_range(self.x, self.y + index as isize);
    &mut self.plane.data[range]
673
674
  }
}
Romain Vimont's avatar
Romain Vimont committed
675
676
677
678
679

#[cfg(test)]
pub mod test {
  use super::*;

Luca Barbato's avatar
Luca Barbato committed
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
  #[test]
  fn copy_from_raw_u8() {
    let mut plane = Plane::wrap(
    vec![
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 1, 2, 3, 4, 0, 0,
        0, 0, 8, 7, 6, 5, 0, 0,
        0, 0, 9, 8, 7, 6, 0, 0,
        0, 0, 2, 3, 4, 5, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
    ], 8);

    let input = vec![42u8; 64];

    plane.copy_from_raw_u8(&input, 8, 1);

    println!("{:?}", &plane.data[..10]);

    assert_eq!(&input[..64], &plane.data[..64]);
  }

Romain Vimont's avatar
Romain Vimont committed
704
705
706
  #[test]
  fn test_plane_pad() {
    let mut plane = Plane::<u8> {
Luca Barbato's avatar
Luca Barbato committed
707
      data: PlaneData::from_slice(&vec![
Romain Vimont's avatar
Romain Vimont committed
708
709
710
711
712
713
714
715
716
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 1, 2, 3, 4, 0, 0,
        0, 0, 8, 7, 6, 5, 0, 0,
        0, 0, 9, 8, 7, 6, 0, 0,
        0, 0, 2, 3, 4, 5, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
Luca Barbato's avatar
Luca Barbato committed
717
      ]),
Romain Vimont's avatar
Romain Vimont committed
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
      cfg: PlaneConfig {
        stride: 8,
        alloc_height: 9,
        width: 4,
        height: 4,
        xdec: 0,
        ydec: 0,
        xpad: 0,
        ypad: 0,
        xorigin: 2,
        yorigin: 3,
      },
    };
    plane.pad(4, 4);
    assert_eq!(
733
734
      &[
        1u8, 1, 1, 2, 3, 4, 4, 4,
Romain Vimont's avatar
Romain Vimont committed
735
736
737
738
739
740
741
742
        1, 1, 1, 2, 3, 4, 4, 4,
        1, 1, 1, 2, 3, 4, 4, 4,
        1, 1, 1, 2, 3, 4, 4, 4,
        8, 8, 8, 7, 6, 5, 5, 5,
        9, 9, 9, 8, 7, 6, 6, 6,
        2, 2, 2, 3, 4, 5, 5, 5,
        2, 2, 2, 3, 4, 5, 5, 5,
        2, 2, 2, 3, 4, 5, 5, 5,
743
744
      ][..],
      &plane.data[..]
Romain Vimont's avatar
Romain Vimont committed
745
746
747
    );
  }
}