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 306 307 308 309 310 311 312 313 314 315 316
  #[inline]
  fn row_range(&self, x: isize, y: isize) -> Range<usize> {
    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
    );
  }
}