<commit_before>use super::errors::{ErrorKind, Result};
use super::types::WadTextureHeader;
use byteorder::{LittleEndian, ReadBytesExt};
use failchain::{ensure, ResultExt};
use math::Vec2;
use std::vec::Vec;

pub const MAX_IMAGE_SIZE: usize = 4096;

pub struct Image {
    width: usize,
    height: usize,
    x_offset: isize,
    y_offset: isize,
    pixels: Vec<u16>,
}

impl Image {
    pub fn new(width: usize, height: usize) -> Result<Self> {
        ensure!(
            width <= MAX_IMAGE_SIZE && height <= MAX_IMAGE_SIZE,
            ErrorKind::image_too_large(width, height),
        );
        Ok(Self {
            width,
            height,
            x_offset: 0,
            y_offset: 0,
            pixels: vec![0xff00; width * height],
        })
    }

    pub fn new_from_header(header: &WadTextureHeader) -> Result<Self> {
        Self::new(header.width as usize, header.height as usize)
    }

    #[cfg_attr(feature = "cargo-clippy", allow(clippy::needless_range_loop))]
    pub fn from_buffer(buffer: &[u8]) -> Result<Self> {
        let mut reader = buffer;
        let width = reader
            .read_u16::<LittleEndian>()
            .chain_err(|| ErrorKind::CorruptWad("Image missing width.".to_owned()))?
            as usize;
        let height = reader
            .read_u16::<LittleEndian>()
            .chain_err(|| ErrorKind::CorruptWad("Image missing height.".to_owned()))?
            as usize;
        ensure!(
            width <= MAX_IMAGE_SIZE && height <= MAX_IMAGE_SIZE,
            ErrorKind::image_too_large(width, height),
        );

        let x_offset = reader
            .read_i16::<LittleEndian>()
            .chain_err(|| ErrorKind::CorruptWad("Image missing x offset".to_owned()))?
            as isize;
        let y_offset = reader
            .read_i16::<LittleEndian>()
            .chain_err(|| ErrorKind::CorruptWad("Image missing y offset".to_owned()))?
            as isize;

        let mut pixels = vec![!0; width * height];

        // Process each column of the image.
        for i_column in 0..width {
            // Each column is defined as a number of vertical `runs' which are
            // defined starting at `offset' in the buffer.
            let offset = reader
                .read_u32::<LittleEndian>()
                .chain_err(|| ErrorKind::unfinished_image_column(i_column, None, width, height))?
                as isize;
            ensure!(
                offset < buffer.len() as isize,
                ErrorKind::CorruptWad,
                "Invalid image column offset in {}, offset={}, size={}.",
                i_column,
                offset,
                buffer.len()
            );
            let mut source = buffer[offset as usize..].iter();
            let mut i_run = 0;
            loop {
                // The first byte contains the vertical coordinate of the run's
                // start.
                let row_start = *source.next().ok_or_else(|| {
                    ErrorKind::unfinished_image_column(i_column, Some(i_run), width, height)
                })? as usize;

                // The special value of 255 means this is the last run in the
                // column, so move on to the next one.
                if row_start == 255 {
                    break;
                }

                // The second byte is the length of this run. Skip an additional
                // byte which is ignored for some reason.
                let run_length = *source.next().ok_or_else(|| {
                    ErrorKind::CorruptWad(format!(
                        "Missing image run length: column {}, run {}",
                        i_column, i_run
                    ))
                })? as usize;

                // Check that the run fits in the image.
                ensure!(
                    row_start + run_length <= height,
                    ErrorKind::CorruptWad,
                    "Image run too big: column {}, run {} ({} +{}), size {}x{}",
                    i_column,
                    i_run,
                    row_start,
                    run_length,
                    width,
                    height,
                );

                // An ignored padding byte.
                ensure!(
                    source.next().is_some(),
                    ErrorKind::CorruptWad,
                    "Image missing padding byte 1: column {}, run {}",
                    i_column,
                    i_run
                );

                // Iterator to the beginning of the run in `pixels`. Guaranteed to be in bounds
                // by the check above.
                let mut destination = pixels[row_start * width + i_column..]
                    .chunks_mut(width)
                    .map(|row| &mut row[0])
                    .take(run_length);

                // Copy the bytes from source to destination, but first check there's enough of
                // those left.
                ensure!(
                    source.size_hint().0 >= run_length,
                    ErrorKind::CorruptWad,
                    "Image source underrun: column {}, run {} ({}, +{}), bytes left {}",
                    i_column,
                    i_run,
                    row_start,
                    run_length,
                    source.size_hint().0
                );
                for dest_pixel in &mut destination {
                    *dest_pixel = u16::from(*source.next().expect("missing pixel despite check"));
                }

                // And another ignored byte after the run.
                ensure!(
                    source.next().is_some(),
                    ErrorKind::CorruptWad,
                    "Image missing padding byte 2: column {}, run {}",
                    i_column,
                    i_run
                );
                i_run += 1;
            }
        }

        Ok(Self {
            width,
            height,
            x_offset,
            y_offset,
            pixels,
        })
    }

    pub fn blit(&mut self, source: &Self, offset: Vec2<isize>, ignore_transparency: bool) {
        // Figure out the region in source which is not out of bounds when
        // copied into self.
        let y_start = if offset[1] < 0 {
            (-offset[1]) as usize
        } else {
            0
        };
        let x_start = if offset[0] < 0 {
            (-offset[0]) as usize
        } else {
            0
        };
        let y_end = if self.height as isize > source.height as isize + offset[1] {
            source.height
        } else {
            (self.height as isize - offset[1]) as usize
        };
        let x_end = if self.width as isize > source.width as isize + offset[0] {
            source.width
        } else {
            (self.width as isize - offset[0]) as usize
        };

        let src_pitch = source.width as usize;
        let dest_pitch = self.width as usize;
        let copy_width = x_end - x_start;
        let copy_height = (y_end - y_start) as usize;
        let (x_start, y_start) = (x_start as usize, y_start as usize);

        let src_rows = &source.pixels[x_start + y_start * src_pitch..];
        let src_rows = src_rows
            .chunks(src_pitch)
            .take(copy_height)
            .map(|row| &row[..copy_width]);

        let dest_rows = &mut self.pixels[(x_start as isize + offset[0]) as usize
            + (y_start as isize + offset[1]) as usize * dest_pitch..];
        let dest_rows = dest_rows
            .chunks_mut(dest_pitch)
            .take(copy_height)
            .map(|row| &mut row[..copy_width]);

        if ignore_transparency {
            // If we don't care about transparency we can copy row by row.
            for (dest_row, source_row) in dest_rows.zip(src_rows) {
                dest_row.copy_from_slice(source_row);
            }
        } else {
            // Only copy pixels whose high bits are not set.
            for (dest_row, source_row) in dest_rows.zip(src_rows) {
                for (dest_pixel, &source_pixel) in dest_row.iter_mut().zip(source_row.iter()) {
                    // `Blending' is a simple copy/no copy, but using bit ops we can avoid
                    // branching.
                    let blend = 0u16.wrapping_sub(source_pixel >> 15);
                    *dest_pixel = (source_pixel & !blend) | (*dest_pixel & blend);
                }
            }
        }
    }

    pub fn x_offset(&self) -> isize {
        self.x_offset
    }
    pub fn y_offset(&self) -> isize {
        self.y_offset
    }

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

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

    pub fn size(&self) -> Vec2<usize> {
        Vec2::new(self.width, self.height)
    }

    pub fn num_pixels(&self) -> usize {
        self.pixels.len()
    }

    pub fn pixels(&self) -> &[u16] {
        &self.pixels
    }

    pub fn into_pixels(self) -> Vec<u16> {
        self.pixels
    }
}
<commit_msg>wad: add bounds checking to image blititng<commit_after>use super::errors::{ErrorKind, Result};
use super::types::WadTextureHeader;
use byteorder::{LittleEndian, ReadBytesExt};
use failchain::{ensure, ResultExt};
use log::{debug, warn};
use math::Vec2;
use std::vec::Vec;

pub const MAX_IMAGE_SIZE: usize = 4096;

pub struct Image {
    width: usize,
    height: usize,
    x_offset: isize,
    y_offset: isize,
    pixels: Vec<u16>,
}

impl Image {
    pub fn new(width: usize, height: usize) -> Result<Self> {
        ensure!(
            width <= MAX_IMAGE_SIZE && height <= MAX_IMAGE_SIZE,
            ErrorKind::image_too_large(width, height),
        );
        Ok(Self {
            width,
            height,
            x_offset: 0,
            y_offset: 0,
            pixels: vec![0xff00; width * height],
        })
    }

    pub fn new_from_header(header: &WadTextureHeader) -> Result<Self> {
        Self::new(header.width as usize, header.height as usize)
    }

    #[cfg_attr(feature = "cargo-clippy", allow(clippy::needless_range_loop))]
    pub fn from_buffer(buffer: &[u8]) -> Result<Self> {
        let mut reader = buffer;
        let width = reader
            .read_u16::<LittleEndian>()
            .chain_err(|| ErrorKind::CorruptWad("Image missing width.".to_owned()))?
            as usize;
        let height = reader
            .read_u16::<LittleEndian>()
            .chain_err(|| ErrorKind::CorruptWad("Image missing height.".to_owned()))?
            as usize;
        ensure!(
            width <= MAX_IMAGE_SIZE && height <= MAX_IMAGE_SIZE,
            ErrorKind::image_too_large(width, height),
        );

        let x_offset = reader
            .read_i16::<LittleEndian>()
            .chain_err(|| ErrorKind::CorruptWad("Image missing x offset".to_owned()))?
            as isize;
        let y_offset = reader
            .read_i16::<LittleEndian>()
            .chain_err(|| ErrorKind::CorruptWad("Image missing y offset".to_owned()))?
            as isize;

        let mut pixels = vec![!0; width * height];

        // Process each column of the image.
        for i_column in 0..width {
            // Each column is defined as a number of vertical `runs' which are
            // defined starting at `offset' in the buffer.
            let offset = reader
                .read_u32::<LittleEndian>()
                .chain_err(|| ErrorKind::unfinished_image_column(i_column, None, width, height))?
                as isize;
            ensure!(
                offset < buffer.len() as isize,
                ErrorKind::CorruptWad,
                "Invalid image column offset in {}, offset={}, size={}.",
                i_column,
                offset,
                buffer.len()
            );
            let mut source = buffer[offset as usize..].iter();
            let mut i_run = 0;
            loop {
                // The first byte contains the vertical coordinate of the run's
                // start.
                let row_start = *source.next().ok_or_else(|| {
                    ErrorKind::unfinished_image_column(i_column, Some(i_run), width, height)
                })? as usize;

                // The special value of 255 means this is the last run in the
                // column, so move on to the next one.
                if row_start == 255 {
                    break;
                }

                // The second byte is the length of this run. Skip an additional
                // byte which is ignored for some reason.
                let run_length = *source.next().ok_or_else(|| {
                    ErrorKind::CorruptWad(format!(
                        "Missing image run length: column {}, run {}",
                        i_column, i_run
                    ))
                })? as usize;

                // Check that the run fits in the image.
                ensure!(
                    row_start + run_length <= height,
                    ErrorKind::CorruptWad,
                    "Image run too big: column {}, run {} ({} +{}), size {}x{}",
                    i_column,
                    i_run,
                    row_start,
                    run_length,
                    width,
                    height,
                );

                // An ignored padding byte.
                ensure!(
                    source.next().is_some(),
                    ErrorKind::CorruptWad,
                    "Image missing padding byte 1: column {}, run {}",
                    i_column,
                    i_run
                );

                // Iterator to the beginning of the run in `pixels`. Guaranteed to be in bounds
                // by the check above.
                let mut destination = pixels[row_start * width + i_column..]
                    .chunks_mut(width)
                    .map(|row| &mut row[0])
                    .take(run_length);

                // Copy the bytes from source to destination, but first check there's enough of
                // those left.
                ensure!(
                    source.size_hint().0 >= run_length,
                    ErrorKind::CorruptWad,
                    "Image source underrun: column {}, run {} ({}, +{}), bytes left {}",
                    i_column,
                    i_run,
                    row_start,
                    run_length,
                    source.size_hint().0
                );
                for dest_pixel in &mut destination {
                    *dest_pixel = u16::from(*source.next().expect("missing pixel despite check"));
                }

                // And another ignored byte after the run.
                ensure!(
                    source.next().is_some(),
                    ErrorKind::CorruptWad,
                    "Image missing padding byte 2: column {}, run {}",
                    i_column,
                    i_run
                );
                i_run += 1;
            }
        }

        Ok(Self {
            width,
            height,
            x_offset,
            y_offset,
            pixels,
        })
    }

    pub fn blit(&mut self, source: &Self, offset: Vec2<isize>, ignore_transparency: bool) {
        // Figure out the region in source which is not out of bounds when
        // copied into self.
        if offset[0] >= self.width as isize || offset[1] >= self.height as isize {
            warn!(
                "Fully out of bounds blit {:?} in {}x{}",
                offset, self.width, self.height
            );
            return;
        }

        let y_start = if offset[1] < 0 {
            (-offset[1]) as usize
        } else {
            0
        };
        let x_start = if offset[0] < 0 {
            (-offset[0]) as usize
        } else {
            0
        };
        let y_end = if self.height as isize > source.height as isize + offset[1] {
            source.height
        } else {
            (self.height as isize - offset[1]) as usize
        };
        let x_end = if self.width as isize > source.width as isize + offset[0] {
            source.width
        } else {
            (self.width as isize - offset[0]) as usize
        };

        debug!(
            "Blit {}x{} <- {}x{} +{}x{} ({}x{} - {}x{})",
            self.width,
            self.height,
            source.width,
            source.height,
            offset[0],
            offset[1],
            x_start,
            x_end,
            y_start,
            y_end
        );

        let src_pitch = source.width as usize;
        let dest_pitch = self.width as usize;
        let copy_width = x_end - x_start;
        let copy_height = (y_end - y_start) as usize;
        let (x_start, y_start) = (x_start as usize, y_start as usize);

        let src_rows = &source.pixels[x_start + y_start * src_pitch..];
        let src_rows = src_rows
            .chunks(src_pitch)
            .take(copy_height)
            .map(|row| &row[..copy_width]);

        let dest_rows = &mut self.pixels[(x_start as isize + offset[0]) as usize
            + (y_start as isize + offset[1]) as usize * dest_pitch..];
        let dest_rows = dest_rows
            .chunks_mut(dest_pitch)
            .take(copy_height)
            .map(|row| &mut row[..copy_width]);

        if ignore_transparency {
            // If we don't care about transparency we can copy row by row.
            for (dest_row, source_row) in dest_rows.zip(src_rows) {
                dest_row.copy_from_slice(source_row);
            }
        } else {
            // Only copy pixels whose high bits are not set.
            for (dest_row, source_row) in dest_rows.zip(src_rows) {
                for (dest_pixel, &source_pixel) in dest_row.iter_mut().zip(source_row.iter()) {
                    // `Blending' is a simple copy/no copy, but using bit ops we can avoid
                    // branching.
                    let blend = 0u16.wrapping_sub(source_pixel >> 15);
                    *dest_pixel = (source_pixel & !blend) | (*dest_pixel & blend);
                }
            }
        }
    }

    pub fn x_offset(&self) -> isize {
        self.x_offset
    }
    pub fn y_offset(&self) -> isize {
        self.y_offset
    }

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

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

    pub fn size(&self) -> Vec2<usize> {
        Vec2::new(self.width, self.height)
    }

    pub fn num_pixels(&self) -> usize {
        self.pixels.len()
    }

    pub fn pixels(&self) -> &[u16] {
        &self.pixels
    }

    pub fn into_pixels(self) -> Vec<u16> {
        self.pixels
    }
}
<|endoftext|>


<commit_before>macro_rules! not_none {
    ($bytes:expr) => {
        match $bytes {
            Some(bytes) => bytes,
            None => return Err(Box::new($crate::types::impls::option::UnexpectedNullError {
                msg: "Unexpected null for non-null column".to_string(),
            })),
        }
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! expression_impls {
    ($Source:ident -> $Target:ty) => {
        expression_impls!($Source -> $Target, unsized);

        impl $crate::expression::AsExpression<$Source> for $Target {
            type Expression = $crate::expression::bound::Bound<$Source, Self>;

            fn as_expression(self) -> Self::Expression {
                $crate::expression::bound::Bound::new(self)
            }
        }

        impl $crate::expression::AsExpression<$crate::types::Nullable<$Source>> for $Target {
            type Expression = $crate::expression::bound::Bound<$crate::types::Nullable<$Source>, Self>;

            fn as_expression(self) -> Self::Expression {
                $crate::expression::bound::Bound::new(self)
            }
        }
    };

    ($Source:ident -> $Target:ty, unsized) => {
        impl<'expr> $crate::expression::AsExpression<$Source> for &'expr $Target {
            type Expression = $crate::expression::bound::Bound<$Source, Self>;

            fn as_expression(self) -> Self::Expression {
                $crate::expression::bound::Bound::new(self)
            }
        }

        impl<'expr, 'expr2> $crate::expression::AsExpression<$Source> for &'expr2 &'expr $Target {
            type Expression = $crate::expression::bound::Bound<$Source, Self>;

            fn as_expression(self) -> Self::Expression {
                $crate::expression::bound::Bound::new(self)
            }
        }

        impl<'expr> $crate::expression::AsExpression<$crate::types::Nullable<$Source>> for &'expr $Target {
            type Expression = $crate::expression::bound::Bound<$crate::types::Nullable<$Source>, Self>;

            fn as_expression(self) -> Self::Expression {
                $crate::expression::bound::Bound::new(self)
            }
        }

        impl<'expr, 'expr2> $crate::expression::AsExpression<$crate::types::Nullable<$Source>> for &'expr2 &'expr $Target {
            type Expression = $crate::expression::bound::Bound<$crate::types::Nullable<$Source>, Self>;

            fn as_expression(self) -> Self::Expression {
                $crate::expression::bound::Bound::new(self)
            }
        }

        impl<DB> $crate::types::ToSql<$crate::types::Nullable<$Source>, DB> for $Target where
            DB: $crate::backend::Backend + $crate::types::HasSqlType<$Source>,
            $Target: $crate::types::ToSql<$Source, DB>,
        {
            fn to_sql<W: ::std::io::Write>(&self, out: &mut $crate::types::ToSqlOutput<W, DB>) -> Result<$crate::types::IsNull, Box<::std::error::Error+Send+Sync>> {
                $crate::types::ToSql::<$Source, DB>::to_sql(self, out)
            }
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! queryable_impls {
    ($Source:ident -> $Target:ty) => {
        impl<DB> $crate::types::FromSqlRow<$Source, DB> for $Target where
            DB: $crate::backend::Backend + $crate::types::HasSqlType<$Source>,
            $Target: $crate::types::FromSql<$Source, DB>,
        {
            fn build_from_row<R: $crate::row::Row<DB>>(row: &mut R) -> Result<Self, Box<::std::error::Error+Send+Sync>> {
                $crate::types::FromSql::<$Source, DB>::from_sql(row.take())
            }
        }

        impl<DB> $crate::query_source::Queryable<$Source, DB> for $Target where
            DB: $crate::backend::Backend + $crate::types::HasSqlType<$Source>,
            $Target: $crate::types::FromSqlRow<$Source, DB>,
        {
            type Row = Self;

            fn build(row: Self::Row) -> Self {
                row
            }
        }
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! primitive_impls {
    ($Source:ident -> (, $($rest:tt)*)) => {
        primitive_impls!($Source -> ($($rest)*));
    };

    ($Source:ident -> (sqlite: ($tpe:ident) $($rest:tt)*)) => {
        #[cfg(feature = "sqlite")]
        impl $crate::types::HasSqlType<$Source> for $crate::sqlite::Sqlite {
            fn metadata(_: &()) -> $crate::sqlite::SqliteType {
                $crate::sqlite::SqliteType::$tpe
            }
        }

        primitive_impls!($Source -> ($($rest)*));
    };

    ($Source:ident -> (pg: ($oid:expr, $array_oid:expr) $($rest:tt)*)) => {
        #[cfg(feature = "postgres")]
        impl $crate::types::HasSqlType<$Source> for $crate::pg::Pg {
            fn metadata(_: &$crate::pg::PgMetadataLookup) -> $crate::pg::PgTypeMetadata {
                $crate::pg::PgTypeMetadata {
                    oid: $oid,
                    array_oid: $array_oid,
                }
            }
        }

        primitive_impls!($Source -> ($($rest)*));
    };

    ($Source:ident -> (mysql: ($tpe:ident) $($rest:tt)*)) => {
        #[cfg(feature = "mysql")]
        impl $crate::types::HasSqlType<$Source> for $crate::mysql::Mysql {
            fn metadata(_: &()) -> $crate::mysql::MysqlType {
                $crate::mysql::MysqlType::$tpe
            }
        }

        primitive_impls!($Source -> ($($rest)*));
    };

    // Done implementing type metadata, no body
    ($Source:ident -> ()) => {
    };

    ($Source:ident -> ($Target:ty, $($rest:tt)+)) => {
        primitive_impls!($Source -> $Target);
        primitive_impls!($Source -> ($($rest)+));
    };

    ($Source:ident -> $Target:ty) => {
        primitive_impls!($Source);
        queryable_impls!($Source -> $Target);
        expression_impls!($Source -> $Target);
    };

    ($Source:ident) => {
        impl $crate::query_builder::QueryId for $Source {
            type QueryId = Self;

            const HAS_STATIC_QUERY_ID: bool = true;
        }

        impl $crate::types::NotNull for $Source {
        }

        impl $crate::types::SingleValue for $Source {
        }
    }
}

mod date_and_time;
pub mod floats;
mod integers;
pub mod option;
mod primitives;
mod tuples;
mod decimal;
<commit_msg>Use ::std::result::Result instead of Result in some macros<commit_after>macro_rules! not_none {
    ($bytes:expr) => {
        match $bytes {
            Some(bytes) => bytes,
            None => return Err(Box::new($crate::types::impls::option::UnexpectedNullError {
                msg: "Unexpected null for non-null column".to_string(),
            })),
        }
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! expression_impls {
    ($Source:ident -> $Target:ty) => {
        expression_impls!($Source -> $Target, unsized);

        impl $crate::expression::AsExpression<$Source> for $Target {
            type Expression = $crate::expression::bound::Bound<$Source, Self>;

            fn as_expression(self) -> Self::Expression {
                $crate::expression::bound::Bound::new(self)
            }
        }

        impl $crate::expression::AsExpression<$crate::types::Nullable<$Source>> for $Target {
            type Expression = $crate::expression::bound::Bound<$crate::types::Nullable<$Source>, Self>;

            fn as_expression(self) -> Self::Expression {
                $crate::expression::bound::Bound::new(self)
            }
        }
    };

    ($Source:ident -> $Target:ty, unsized) => {
        impl<'expr> $crate::expression::AsExpression<$Source> for &'expr $Target {
            type Expression = $crate::expression::bound::Bound<$Source, Self>;

            fn as_expression(self) -> Self::Expression {
                $crate::expression::bound::Bound::new(self)
            }
        }

        impl<'expr, 'expr2> $crate::expression::AsExpression<$Source> for &'expr2 &'expr $Target {
            type Expression = $crate::expression::bound::Bound<$Source, Self>;

            fn as_expression(self) -> Self::Expression {
                $crate::expression::bound::Bound::new(self)
            }
        }

        impl<'expr> $crate::expression::AsExpression<$crate::types::Nullable<$Source>> for &'expr $Target {
            type Expression = $crate::expression::bound::Bound<$crate::types::Nullable<$Source>, Self>;

            fn as_expression(self) -> Self::Expression {
                $crate::expression::bound::Bound::new(self)
            }
        }

        impl<'expr, 'expr2> $crate::expression::AsExpression<$crate::types::Nullable<$Source>> for &'expr2 &'expr $Target {
            type Expression = $crate::expression::bound::Bound<$crate::types::Nullable<$Source>, Self>;

            fn as_expression(self) -> Self::Expression {
                $crate::expression::bound::Bound::new(self)
            }
        }

        impl<DB> $crate::types::ToSql<$crate::types::Nullable<$Source>, DB> for $Target where
            DB: $crate::backend::Backend + $crate::types::HasSqlType<$Source>,
            $Target: $crate::types::ToSql<$Source, DB>,
        {
            fn to_sql<W: ::std::io::Write>(&self, out: &mut $crate::types::ToSqlOutput<W, DB>) -> ::std::result::Result<$crate::types::IsNull, Box<::std::error::Error+Send+Sync>> {
                $crate::types::ToSql::<$Source, DB>::to_sql(self, out)
            }
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! queryable_impls {
    ($Source:ident -> $Target:ty) => {
        impl<DB> $crate::types::FromSqlRow<$Source, DB> for $Target where
            DB: $crate::backend::Backend + $crate::types::HasSqlType<$Source>,
            $Target: $crate::types::FromSql<$Source, DB>,
        {
            fn build_from_row<R: $crate::row::Row<DB>>(row: &mut R) -> ::std::result::Result<Self, Box<::std::error::Error+Send+Sync>> {
                $crate::types::FromSql::<$Source, DB>::from_sql(row.take())
            }
        }

        impl<DB> $crate::query_source::Queryable<$Source, DB> for $Target where
            DB: $crate::backend::Backend + $crate::types::HasSqlType<$Source>,
            $Target: $crate::types::FromSqlRow<$Source, DB>,
        {
            type Row = Self;

            fn build(row: Self::Row) -> Self {
                row
            }
        }
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! primitive_impls {
    ($Source:ident -> (, $($rest:tt)*)) => {
        primitive_impls!($Source -> ($($rest)*));
    };

    ($Source:ident -> (sqlite: ($tpe:ident) $($rest:tt)*)) => {
        #[cfg(feature = "sqlite")]
        impl $crate::types::HasSqlType<$Source> for $crate::sqlite::Sqlite {
            fn metadata(_: &()) -> $crate::sqlite::SqliteType {
                $crate::sqlite::SqliteType::$tpe
            }
        }

        primitive_impls!($Source -> ($($rest)*));
    };

    ($Source:ident -> (pg: ($oid:expr, $array_oid:expr) $($rest:tt)*)) => {
        #[cfg(feature = "postgres")]
        impl $crate::types::HasSqlType<$Source> for $crate::pg::Pg {
            fn metadata(_: &$crate::pg::PgMetadataLookup) -> $crate::pg::PgTypeMetadata {
                $crate::pg::PgTypeMetadata {
                    oid: $oid,
                    array_oid: $array_oid,
                }
            }
        }

        primitive_impls!($Source -> ($($rest)*));
    };

    ($Source:ident -> (mysql: ($tpe:ident) $($rest:tt)*)) => {
        #[cfg(feature = "mysql")]
        impl $crate::types::HasSqlType<$Source> for $crate::mysql::Mysql {
            fn metadata(_: &()) -> $crate::mysql::MysqlType {
                $crate::mysql::MysqlType::$tpe
            }
        }

        primitive_impls!($Source -> ($($rest)*));
    };

    // Done implementing type metadata, no body
    ($Source:ident -> ()) => {
    };

    ($Source:ident -> ($Target:ty, $($rest:tt)+)) => {
        primitive_impls!($Source -> $Target);
        primitive_impls!($Source -> ($($rest)+));
    };

    ($Source:ident -> $Target:ty) => {
        primitive_impls!($Source);
        queryable_impls!($Source -> $Target);
        expression_impls!($Source -> $Target);
    };

    ($Source:ident) => {
        impl $crate::query_builder::QueryId for $Source {
            type QueryId = Self;

            const HAS_STATIC_QUERY_ID: bool = true;
        }

        impl $crate::types::NotNull for $Source {
        }

        impl $crate::types::SingleValue for $Source {
        }
    }
}

mod date_and_time;
pub mod floats;
mod integers;
pub mod option;
mod primitives;
mod tuples;
mod decimal;
<|endoftext|>


<commit_before>#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
enum Token {
    Mine = b'*',
    Empty = b' ',
}

impl Into<char> for Token {
    fn into(self) -> char {
        self as u8 as char
    }
}

impl Token {
    fn from(c: char) -> Result<Token, ()> {
        match c {
            '*' => Ok(Token::Mine),
            ' ' => Ok(Token::Empty),
            _ => Err(()),
        }
    }
}

struct Board {
    field: Vec<Vec<Token>>,
}

impl Board {
    fn new(minefield: &[&str]) -> Self {
        let field = minefield
            .iter()
            .map(|row| row.chars().map(|char| Token::from(char).unwrap()).collect())
            .collect();
        Board { field }
    }

    fn annotate(&self) -> Vec<String> {
        return self
            .field
            .iter()
            .enumerate()
            .map(|(row, _)| self.annotate_row(row))
            .collect();
    }

    fn annotate_row(&self, y: usize) -> String {
        let row = &self.field[y];
        return row
            .iter()
            .enumerate()
            .map(|(x, _)| self.annotate_token(y, x))
            .collect();
    }

    fn annotate_token(&self, y: usize, x: usize) -> char {
        let token = self.field[y][x];
        match token {
            Token::Mine => Token::Mine.into(),
            Token::Empty => {
                let neighbor_mines = self.num_neighbor_mines(y as u32, x as u32);
                if neighbor_mines == 0 {
                    return ' ';
                } else {
                    return (b'0' + neighbor_mines as u8) as char;
                };
            }
        }
    }

    fn num_neighbor_mines(&self, y: u32, x: u32) -> usize {
        return self
            .get_neighbors(y, x)
            .iter()
            .filter(|neighbor| neighbor == &&&Token::Mine)
            .count();
    }

    fn get_neighbors(&self, y: u32, x: u32) -> Vec<&Token> {
        let mut neighbors = Vec::new();
        let y = y as i32;
        let x = x as i32;

        let delta_ys: Vec<i32> = (-1..=1).collect();
        for delta_y in delta_ys {
            let delta_xs: Vec<i32> = (-1..=1).collect();
            for delta_x in delta_xs {
                if delta_y == 0 && delta_x == 0 {
                    continue;
                }
                if y + delta_y < 0 || y + delta_y >= self.num_rows() as i32 {
                    continue;
                }
                if x + delta_x < 0 || x + delta_x >= self.num_cols() as i32 {
                    continue;
                }
                let neighbor = &self.field[(y + delta_y) as usize][(x + delta_x) as usize];
                neighbors.push(neighbor)
            }
        }

        neighbors
    }

    fn num_rows(&self) -> usize {
        return self.field.len();
    }

    fn num_cols(&self) -> usize {
        return self.field[0].len();
    }
}

pub fn annotate(minefield: &[&str]) -> Vec<String> {
    let board = Board::new(minefield);
    return board.annotate();
}
<commit_msg>Minor rename<commit_after>#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
enum Token {
    Mine = b'*',
    Empty = b' ',
}

impl Into<char> for Token {
    fn into(self) -> char {
        self as u8 as char
    }
}

impl Token {
    fn from(c: char) -> Result<Token, ()> {
        match c {
            '*' => Ok(Token::Mine),
            ' ' => Ok(Token::Empty),
            _ => Err(()),
        }
    }
}

struct Board {
    field: Vec<Vec<Token>>,
}

impl Board {
    fn new(minefield: &[&str]) -> Self {
        let field = minefield
            .iter()
            .map(|row| row.chars().map(|char| Token::from(char).unwrap()).collect())
            .collect();
        Board { field }
    }

    fn annotate(&self) -> Vec<String> {
        return self
            .field
            .iter()
            .enumerate()
            .map(|(row, _)| self.annotate_row(row))
            .collect();
    }

    fn annotate_row(&self, y: usize) -> String {
        let row = &self.field[y];
        return row
            .iter()
            .enumerate()
            .map(|(x, _)| self.annotate_location(y, x))
            .collect();
    }

    fn annotate_location(&self, y: usize, x: usize) -> char {
        let token = self.field[y][x];
        match token {
            Token::Mine => Token::Mine.into(),
            Token::Empty => {
                let neighbor_mines = self.num_neighbor_mines(y as u32, x as u32);
                if neighbor_mines == 0 {
                    return ' ';
                } else {
                    return (b'0' + neighbor_mines as u8) as char;
                };
            }
        }
    }

    fn num_neighbor_mines(&self, y: u32, x: u32) -> usize {
        return self
            .get_neighbors(y, x)
            .iter()
            .filter(|neighbor| neighbor == &&&Token::Mine)
            .count();
    }

    fn get_neighbors(&self, y: u32, x: u32) -> Vec<&Token> {
        let mut neighbors = Vec::new();
        let y = y as i32;
        let x = x as i32;

        let delta_ys: Vec<i32> = (-1..=1).collect();
        for delta_y in delta_ys {
            let delta_xs: Vec<i32> = (-1..=1).collect();
            for delta_x in delta_xs {
                if delta_y == 0 && delta_x == 0 {
                    continue;
                }
                if y + delta_y < 0 || y + delta_y >= self.num_rows() as i32 {
                    continue;
                }
                if x + delta_x < 0 || x + delta_x >= self.num_cols() as i32 {
                    continue;
                }
                let neighbor = &self.field[(y + delta_y) as usize][(x + delta_x) as usize];
                neighbors.push(neighbor)
            }
        }

        neighbors
    }

    fn num_rows(&self) -> usize {
        return self.field.len();
    }

    fn num_cols(&self) -> usize {
        return self.field[0].len();
    }
}

pub fn annotate(minefield: &[&str]) -> Vec<String> {
    let board = Board::new(minefield);
    return board.annotate();
}
<|endoftext|>


<commit_before>#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
enum Token {
    Mine = b'*',
    Empty = b' ',
}

impl Into<char> for Token {
    fn into(self) -> char {
        self as u8 as char
    }
}

impl Token {
    fn from(c: char) -> Result<Token, ()> {
        match c {
            '*' => Ok(Token::Mine),
            ' ' => Ok(Token::Empty),
            _ => Err(()),
        }
    }
}

struct Board {
    field: Vec<Vec<Token>>,
}

impl Board {
    fn new(minefield: &[&str]) -> Self {
        let mut field: Vec<Vec<Token>> = Vec::new();

        for row in minefield {
            let mut field_row: Vec<Token> = Vec::new();
            for char in row.chars() {
                let token = Token::from(char).unwrap();
                field_row.push(token);
            }
            field.push(field_row);
        }
        Board { field }
    }

    fn annotated(&self) -> Vec<String> {
        let mut annotated: Vec<String> = Vec::new();

        for (y, row) in self.field.iter().enumerate() {
            let mut annotated_row = String::new();
            for (x, token) in row.iter().enumerate() {
                match token {
                    Token::Mine => annotated_row.push(Token::Mine.into()),
                    Token::Empty => {
                        let neighbor_mines = self.num_neighbor_mines(y as u32, x as u32);
                        let annotated_location = if neighbor_mines == 0 {
                            " ".to_string()
                        } else {
                            neighbor_mines.to_string()
                        };
                        annotated_row.push_str(&annotated_location)
                    }
                }
            }
            annotated.push(annotated_row)
        }

        annotated
    }

    fn num_neighbor_mines(&self, y: u32, x: u32) -> usize {
        return self
            .get_neighbors(y, x)
            .iter()
            .filter(|neighbor| neighbor == &&&Token::Mine)
            .count();
    }

    fn get_neighbors(&self, y: u32, x: u32) -> Vec<&Token> {
        let mut neighbors = Vec::new();
        let y = y as i32;
        let x = x as i32;

        let delta_ys: Vec<i32> = (-1..=1).collect();
        for delta_y in delta_ys {
            let delta_xs: Vec<i32> = (-1..=1).collect();
            for delta_x in delta_xs {
                if delta_y == 0 && delta_x == 0 {
                    continue;
                }
                if y + delta_y < 0 || y + delta_y >= self.field.len() as i32 {
                    continue;
                }
                if x + delta_x < 0 || x + delta_x >= self.field[0].len() as i32 {
                    continue;
                }
                let neighbor = &self.field[(y + delta_y) as usize][(x + delta_x) as usize];
                neighbors.push(neighbor)
            }
        }

        neighbors
    }
}

pub fn annotate(minefield: &[&str]) -> Vec<String> {
    let board = Board::new(minefield);
    return board.annotated();
}
<commit_msg>Extract num_rows() and num_cols()<commit_after>#[derive(Clone, Copy, PartialEq)]
#[repr(u8)]
enum Token {
    Mine = b'*',
    Empty = b' ',
}

impl Into<char> for Token {
    fn into(self) -> char {
        self as u8 as char
    }
}

impl Token {
    fn from(c: char) -> Result<Token, ()> {
        match c {
            '*' => Ok(Token::Mine),
            ' ' => Ok(Token::Empty),
            _ => Err(()),
        }
    }
}

struct Board {
    field: Vec<Vec<Token>>,
}

impl Board {
    fn new(minefield: &[&str]) -> Self {
        let mut field: Vec<Vec<Token>> = Vec::new();

        for row in minefield {
            let mut field_row: Vec<Token> = Vec::new();
            for char in row.chars() {
                let token = Token::from(char).unwrap();
                field_row.push(token);
            }
            field.push(field_row);
        }
        Board { field }
    }

    fn annotated(&self) -> Vec<String> {
        let mut annotated: Vec<String> = Vec::new();

        for (y, row) in self.field.iter().enumerate() {
            let mut annotated_row = String::new();
            for (x, token) in row.iter().enumerate() {
                match token {
                    Token::Mine => annotated_row.push(Token::Mine.into()),
                    Token::Empty => {
                        let neighbor_mines = self.num_neighbor_mines(y as u32, x as u32);
                        let annotated_location = if neighbor_mines == 0 {
                            " ".to_string()
                        } else {
                            neighbor_mines.to_string()
                        };
                        annotated_row.push_str(&annotated_location)
                    }
                }
            }
            annotated.push(annotated_row)
        }

        annotated
    }

    fn num_neighbor_mines(&self, y: u32, x: u32) -> usize {
        return self
            .get_neighbors(y, x)
            .iter()
            .filter(|neighbor| neighbor == &&&Token::Mine)
            .count();
    }

    fn get_neighbors(&self, y: u32, x: u32) -> Vec<&Token> {
        let mut neighbors = Vec::new();
        let y = y as i32;
        let x = x as i32;

        let delta_ys: Vec<i32> = (-1..=1).collect();
        for delta_y in delta_ys {
            let delta_xs: Vec<i32> = (-1..=1).collect();
            for delta_x in delta_xs {
                if delta_y == 0 && delta_x == 0 {
                    continue;
                }
                if y + delta_y < 0 || y + delta_y >= self.num_rows() as i32 {
                    continue;
                }
                if x + delta_x < 0 || x + delta_x >= self.num_cols() as i32 {
                    continue;
                }
                let neighbor = &self.field[(y + delta_y) as usize][(x + delta_x) as usize];
                neighbors.push(neighbor)
            }
        }

        neighbors
    }

    fn num_rows(&self) -> usize {
        return self.field.len();
    }

    fn num_cols(&self) -> usize {
        return self.field[0].len();
    }
}

pub fn annotate(minefield: &[&str]) -> Vec<String> {
    let board = Board::new(minefield);
    return board.annotated();
}
<|endoftext|>


<commit_before>use crate::graphic::uniform::GlUniform;
use crate::graphic::GlProgram;
use crate::opengl;
use crate::opengl::types::{GLint, GLuint};
use cgmath::Vector2;
use image::{GenericImageView, ImageBuffer, LumaA, Pixel, Rgba, SubImage};
use num_integer::Integer;
use std::convert::{TryFrom, TryInto};
use std::ffi::{c_void, CString};
use std::marker::PhantomData;
use std::rc::Rc;

/// A square texture that functions like a moving window into a larger texture.
/// Incrementality is achieved by using wraparound indexing and overwriting the
/// parts that moved off the texture with the newly loaded parts.
/// See `https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter02.html`,
/// section 2.4 for an illustration, but note that this page does not describe
/// the present implementation, which is simpler.
/// Also publishes an `<texture_name>_texture_offset` uniform whose unit is
/// pixels (not UV coordinates).
///
/// I'm told that a more efficient alternative would be to use a PBO (pixel
/// buffer object), so a future version could use that instead.
pub struct GlMovingWindowTexture
 {
    id: GLuint,
    gl: Rc<opengl::Gl>,
    size: u32,
    texture_unit: u32,
    u_texture_offset: GlUniform<Vector2<i32>>,
    pixel_type: PhantomData
,
}

/// Specifies the offsets in the destination, as well as the image to be pasted
/// there.
struct UpdateRegion<'a, P: Pixel + 'static> {
    x: u32,
    y: u32,
    pixels: SubImage<&'a ImageBuffer>,
}

impl<'a, P: Pixel + 'static> UpdateRegion<'a, P> {
    /// Splits an image with offset into update regions. See
    /// [`incremental_update()`] for a detailed explanation.
    /// This works not only for full-width/full-height strips, but
    /// here are vertical (left) and horizontal (right) strips
    /// visualized:
    ///
    /// ```text
    ///     +---+-+
    ///     | 3 |4|
    ///     +---+-+              +---+---------+
    ///     |   | |              | 3 |    4    |
    ///     | 1 |2|              +---+---------+
    ///     |   | |              | 1 |    2    |
    ///     +---+-+              +---+---------+
    ///        |                        |
    ///        V                        V
    /// +-+-------+---+          +---------+---+
    /// | |       |   |          |    2    | 1 |
    /// |2|       | 1 |          +---------+---+
    /// | |       |   |          |             |
    /// +-+       +---+          +---------+---+
    /// |4|       | 3 |          |    4    | 3 |
    /// +-+-------+---+          +---------+---+
    /// ```
    ///
    /// x is right and y is up, so the origin of the image is the lower left
    /// corner of region 1.

    pub fn new_regions(
        xoff: u32,
        yoff: u32,
        size: u32,
        pixels: &'a ImageBuffer,
    ) -> [UpdateRegion<'a, P>; 4] {
        // Check invariant
        debug_assert!(xoff < size && yoff <= size);
        // These variables are named after the regions they apply to. For
        // instance, regions 1 and 3 share the same width.
        let width_1_3 = pixels.width().min(size - xoff);
        let width_2_4 = pixels.width() - width_1_3;
        let height_1_2 = pixels.height().min(size - yoff);
        let height_3_4 = pixels.height() - height_1_2;
        [
            UpdateRegion {
                x: xoff,
                y: yoff,
                pixels: pixels.view(0, 0, width_1_3, height_1_2),
            },
            UpdateRegion {
                x: 0,
                y: yoff,
                pixels: pixels.view(width_1_3, 0, width_2_4, height_1_2),
            },
            UpdateRegion {
                x: xoff,
                y: 0,
                pixels: pixels.view(0, height_1_2, width_1_3, height_3_4),
            },
            UpdateRegion {
                x: 0,
                y: 0,
                pixels: pixels.view(width_1_3, height_1_2, width_2_4, height_3_4),
            },
        ]
    }
}

impl
 GlMovingWindowTexture

where
    P: TextureFormat + 'static,
    P::Subpixel: 'static + std::fmt::Debug,
{
    /// The texture_unit parameter is just a sequence number for textures
    pub fn new(
        program: &GlProgram,
        gl: Rc<opengl::Gl>,
        name: &str,
        size: u32,
        texture_unit: u32,
        pixels: ImageBuffer,
    ) -> Self {
        let mut id = 0;
        let name_c = CString::new(name).unwrap();
        unsafe {
            gl.UseProgram(program.id);
            let loc = gl.GetUniformLocation(program.id, name_c.as_ptr());
            gl.Uniform1i(loc, i32::try_from(texture_unit).unwrap());

            gl.GenTextures(1, &mut id);
            gl.BindTexture(opengl::TEXTURE_2D, id);

            // Enable wraparound addressing
            gl.TexParameteri(
                opengl::TEXTURE_2D,
                opengl::TEXTURE_WRAP_S,
                opengl::REPEAT as i32,
            );
            gl.TexParameteri(
                opengl::TEXTURE_2D,
                opengl::TEXTURE_WRAP_T,
                opengl::REPEAT as i32,
            );

            // Intended for exact pixel fetching, no interpolation needed
            gl.TexParameteri(
                opengl::TEXTURE_2D,
                opengl::TEXTURE_MIN_FILTER,
                opengl::NEAREST as i32,
            );
            gl.TexParameteri(
                opengl::TEXTURE_2D,
                opengl::TEXTURE_MAG_FILTER,
                opengl::NEAREST as i32,
            );
            // For an explanation of the different parameters, see
            // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml
            gl.TexImage2D(
                opengl::TEXTURE_2D,
                0, // level
                P::INTERNALFORMAT,
                size as i32, // width
                size as i32, // height
                0,           // border
                P::FORMAT,
                P::DTYPE,
                pixels.into_raw().as_ptr() as *const c_void,
            );
        }

        let u_texture_offset = GlUniform::new(
            &program,
            &format!("{}_texture_offset", name),
            Vector2::new(0, 0),
        );

        GlMovingWindowTexture {
            id,
            gl,
            size,
            texture_unit,
            u_texture_offset,
            pixel_type: PhantomData,
        }
    }

    /// Let's say the texture window has moved left and up. The new pixels that
    /// are now inside the window are passed as a vertical and a horizontal
    /// strip. Here they are in the texture window:
    /// ```text
    /// +-----+------------+
    /// |#####|############| <- hori_strip
    /// +-----|------------+
    /// |#####|            |
    /// |#####|            |
    /// |#####|            |
    /// +-----+------------+
    ///    ^
    ///    |
    ///   vert_strip
    /// ```
    ///
    /// You can see that they are redundant where they overlap. This is not
    /// handled to keep the code from becoming more complex. Also, either may
    /// be empty, which is the case for purely horizontal/vertical shifts.
    ///
    /// These strips have to be inserted correctly into the OpenGL texture,
    /// which starts not at 0 but at `texture_offset` because of wrapping indexing.
    /// Updating that texture from such a strip can typically not be done in one
    /// step, but requires breaking it into up to four subregions. This is
    /// because OpenGL textures can be read with wrapping indexing, but not
    /// written with wrapping indexing, so we need to do it ourselves.
    /// Let's look at the vertical strip:
    ///
    /// ```text
    /// <- width ->
    /// +---+-+
    /// | 3 |4|
    /// +---+-+
    /// |   | |  vert_strip
    /// | 1 |2|
    /// |   | |
    /// +---+-+
    /// ```
    ///
    /// Wraparound at the right texture edge causes the split into regions 1/3
    /// vs 2/4, and wraparound at the upper texture edge causes the split into
    /// regions 1/2 vs 3/4.
    /// Here's the texture with the vert_strip placed correctly:
    ///
    /// ```text
    /// <- self.size ->
    /// +-+-------+---+
    /// | |       |   |
    /// |2|       | 1 |
    /// | |       |   |
    /// +-+       +---+ <- texture_offset.y
    /// |4|       | 3 |
    /// +-+-------+---+
    ///           ^
    ///           |
    ///           xoff
    /// ```
    ///
    /// `xoff` is not equal to `texture_offset.x` if the texture moved right.
    ///
    /// The way this is handled is by creating regions as if they always need
    /// splitting, and skipping empty regions that result from that.
    pub fn incremental_update(
        &mut self,
        delta_x: i32,
        delta_y: i32,
        vert_strip: ImageBuffer,
        hori_strip: ImageBuffer,
    ) {
        // Calculate the updated texture offset, which is always in [0; self.size)
        let x_after_update =
            (self.u_texture_offset.value.x + delta_x).mod_floor(&i32::try_from(self.size).unwrap());
        let y_after_update =
            (self.u_texture_offset.value.y + delta_y).mod_floor(&i32::try_from(self.size).unwrap());
        let texture_offset_after_update = Vector2::new(x_after_update, y_after_update);

        // The vertical region's x coordinate needs to be the "lower" (but not
        // really, because of wraparound, so don't use min) of the old and new
        // horizontal texture offset. Why? If delta_x > 0 and we use the new
        // offset, we'll overwrite the wrong data. The y coordinate is just the
        // new vertical texture offset however, which may not seem intuitive.
        // You can convince yourself by staring at the illustration in section
        // 2.4 of the page linked above,
        // https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter02.html,
        // remembering that y is up and recalling where the L shape originates.
        // If that doesn't help, draw an image with named pixels and a texture
        // window in it and perform a few updates in different directions,
        // noting where the L-shaped region (aka vert_strip + hori_strip) are
        // placed in the texture.
        let vert_x = if delta_x > 0 {
            self.u_texture_offset.value.x
        } else {
            x_after_update
        };
        let hori_y = if delta_y > 0 {
            self.u_texture_offset.value.y
        } else {
            y_after_update
        };
        let vert_regions = UpdateRegion::new_regions(
            vert_x.try_into().unwrap(),
            y_after_update.try_into().unwrap(),
            self.size,
            &vert_strip,
        );
        let hori_regions = UpdateRegion::new_regions(
            x_after_update.try_into().unwrap(),
            hori_y.try_into().unwrap(),
            self.size,
            &hori_strip,
        );
        let regions = vert_regions.iter().chain(hori_regions.iter());

        // Now we can overwrite the old texture offset
        self.u_texture_offset.value = texture_offset_after_update;

        unsafe {
            self.gl.ActiveTexture(opengl::TEXTURE0 + self.texture_unit);
            self.gl.BindTexture(opengl::TEXTURE_2D, self.id);
            for r in regions {
                let width = i32::try_from(r.pixels.width()).unwrap();
                let height = i32::try_from(r.pixels.height()).unwrap();
                if height * width == 0 {
                    continue;
                }
                let image = r.pixels.to_image();
                // For an explanation of the different parameters, see
                // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexSubImage2D.xhtml
                self.gl.TexSubImage2D(
                    opengl::TEXTURE_2D,
                    0, // level
                    i32::try_from(r.x).unwrap(),
                    i32::try_from(r.y).unwrap(),
                    width,
                    height,
                    P::FORMAT,
                    P::DTYPE,
                    image.into_raw().as_ptr() as *const c_void,
                );
            }
        }
    }

    /// Updates the offset and binds the texture
    pub fn submit(&self) {
        self.u_texture_offset.submit();
    }
}

/// Trait to associate pixel formats with OpenGL constants
pub trait TextureFormat: Pixel {
    const INTERNALFORMAT: GLint;
    const FORMAT: GLuint;
    const DTYPE: GLuint;
}

impl TextureFormat for LumaA<f32> {
    const INTERNALFORMAT: GLint = opengl::RG32F as GLint;
    const FORMAT: GLuint = opengl::RG;
    const DTYPE: GLuint = opengl::FLOAT;
}

impl TextureFormat for Rgba<u8> {
    const INTERNALFORMAT: GLint = opengl::RGBA8 as GLint;
    const FORMAT: GLuint = opengl::RGBA;
    const DTYPE: GLuint = opengl::UNSIGNED_BYTE;
}

#[cfg(test)]
mod tests {
    use super::*;
    use image::GenericImage;

    #[test]
    fn test_regions() {
        let test_src = ImageBuffer::from_fn(16, 16, |x, y| Rgba::<u8>([x as u8, y as u8, 0, 255]));
        let regions = UpdateRegion::new_regions(4, 7, 16, &test_src);

        let mut dest = ImageBuffer::from_pixel(16, 16, Rgba::<u8>([0, 0, 0, 0]));
        for r in &regions {
            dest.copy_from(&r.pixels, r.x as u32, r.y as u32);
        }
        let reference = ImageBuffer::from_fn(16, 16, |x, y| {
            Rgba::<u8>([(x + 16 - 4) as u8 % 16, (y + 16 - 7) as u8 % 16, 0, 255])
        });
        assert!(dest.pixels().eq(reference.pixels()));
    }
}
<commit_msg>sdl_viewer: Bind texture in submit() (#383)<commit_after>use crate::graphic::uniform::GlUniform;
use crate::graphic::GlProgram;
use crate::opengl;
use crate::opengl::types::{GLint, GLuint};
use cgmath::Vector2;
use image::{GenericImageView, ImageBuffer, LumaA, Pixel, Rgba, SubImage};
use num_integer::Integer;
use std::convert::{TryFrom, TryInto};
use std::ffi::{c_void, CString};
use std::marker::PhantomData;
use std::rc::Rc;

/// A square texture that functions like a moving window into a larger texture.
/// Incrementality is achieved by using wraparound indexing and overwriting the
/// parts that moved off the texture with the newly loaded parts.
/// See `https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter02.html`,
/// section 2.4 for an illustration, but note that this page does not describe
/// the present implementation, which is simpler.
/// Also publishes an `<texture_name>_texture_offset` uniform whose unit is
/// pixels (not UV coordinates).
///
/// I'm told that a more efficient alternative would be to use a PBO (pixel
/// buffer object), so a future version could use that instead.
pub struct GlMovingWindowTexture
 {
    id: GLuint,
    gl: Rc<opengl::Gl>,
    size: u32,
    texture_unit: u32,
    u_texture_offset: GlUniform<Vector2<i32>>,
    pixel_type: PhantomData
,
}

/// Specifies the offsets in the destination, as well as the image to be pasted
/// there.
struct UpdateRegion<'a, P: Pixel + 'static> {
    x: u32,
    y: u32,
    pixels: SubImage<&'a ImageBuffer>,
}

impl<'a, P: Pixel + 'static> UpdateRegion<'a, P> {
    /// Splits an image with offset into update regions. See
    /// [`incremental_update()`] for a detailed explanation.
    /// This works not only for full-width/full-height strips, but
    /// here are vertical (left) and horizontal (right) strips
    /// visualized:
    ///
    /// ```text
    ///     +---+-+
    ///     | 3 |4|
    ///     +---+-+              +---+---------+
    ///     |   | |              | 3 |    4    |
    ///     | 1 |2|              +---+---------+
    ///     |   | |              | 1 |    2    |
    ///     +---+-+              +---+---------+
    ///        |                        |
    ///        V                        V
    /// +-+-------+---+          +---------+---+
    /// | |       |   |          |    2    | 1 |
    /// |2|       | 1 |          +---------+---+
    /// | |       |   |          |             |
    /// +-+       +---+          +---------+---+
    /// |4|       | 3 |          |    4    | 3 |
    /// +-+-------+---+          +---------+---+
    /// ```
    ///
    /// x is right and y is up, so the origin of the image is the lower left
    /// corner of region 1.

    pub fn new_regions(
        xoff: u32,
        yoff: u32,
        size: u32,
        pixels: &'a ImageBuffer,
    ) -> [UpdateRegion<'a, P>; 4] {
        // Check invariant
        debug_assert!(xoff < size && yoff <= size);
        // These variables are named after the regions they apply to. For
        // instance, regions 1 and 3 share the same width.
        let width_1_3 = pixels.width().min(size - xoff);
        let width_2_4 = pixels.width() - width_1_3;
        let height_1_2 = pixels.height().min(size - yoff);
        let height_3_4 = pixels.height() - height_1_2;
        [
            UpdateRegion {
                x: xoff,
                y: yoff,
                pixels: pixels.view(0, 0, width_1_3, height_1_2),
            },
            UpdateRegion {
                x: 0,
                y: yoff,
                pixels: pixels.view(width_1_3, 0, width_2_4, height_1_2),
            },
            UpdateRegion {
                x: xoff,
                y: 0,
                pixels: pixels.view(0, height_1_2, width_1_3, height_3_4),
            },
            UpdateRegion {
                x: 0,
                y: 0,
                pixels: pixels.view(width_1_3, height_1_2, width_2_4, height_3_4),
            },
        ]
    }
}

impl
 GlMovingWindowTexture

where
    P: TextureFormat + 'static,
    P::Subpixel: 'static + std::fmt::Debug,
{
    /// The texture_unit parameter is just a sequence number for textures
    pub fn new(
        program: &GlProgram,
        gl: Rc<opengl::Gl>,
        name: &str,
        size: u32,
        texture_unit: u32,
        pixels: ImageBuffer,
    ) -> Self {
        let mut id = 0;
        let name_c = CString::new(name).unwrap();
        unsafe {
            gl.UseProgram(program.id);
            let loc = gl.GetUniformLocation(program.id, name_c.as_ptr());
            gl.Uniform1i(loc, i32::try_from(texture_unit).unwrap());

            gl.GenTextures(1, &mut id);
            gl.BindTexture(opengl::TEXTURE_2D, id);

            // Enable wraparound addressing
            gl.TexParameteri(
                opengl::TEXTURE_2D,
                opengl::TEXTURE_WRAP_S,
                opengl::REPEAT as i32,
            );
            gl.TexParameteri(
                opengl::TEXTURE_2D,
                opengl::TEXTURE_WRAP_T,
                opengl::REPEAT as i32,
            );

            // Intended for exact pixel fetching, no interpolation needed
            gl.TexParameteri(
                opengl::TEXTURE_2D,
                opengl::TEXTURE_MIN_FILTER,
                opengl::NEAREST as i32,
            );
            gl.TexParameteri(
                opengl::TEXTURE_2D,
                opengl::TEXTURE_MAG_FILTER,
                opengl::NEAREST as i32,
            );
            // For an explanation of the different parameters, see
            // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml
            gl.TexImage2D(
                opengl::TEXTURE_2D,
                0, // level
                P::INTERNALFORMAT,
                size as i32, // width
                size as i32, // height
                0,           // border
                P::FORMAT,
                P::DTYPE,
                pixels.into_raw().as_ptr() as *const c_void,
            );
        }

        let u_texture_offset = GlUniform::new(
            &program,
            &format!("{}_texture_offset", name),
            Vector2::new(0, 0),
        );

        GlMovingWindowTexture {
            id,
            gl,
            size,
            texture_unit,
            u_texture_offset,
            pixel_type: PhantomData,
        }
    }

    /// Let's say the texture window has moved left and up. The new pixels that
    /// are now inside the window are passed as a vertical and a horizontal
    /// strip. Here they are in the texture window:
    /// ```text
    /// +-----+------------+
    /// |#####|############| <- hori_strip
    /// +-----|------------+
    /// |#####|            |
    /// |#####|            |
    /// |#####|            |
    /// +-----+------------+
    ///    ^
    ///    |
    ///   vert_strip
    /// ```
    ///
    /// You can see that they are redundant where they overlap. This is not
    /// handled to keep the code from becoming more complex. Also, either may
    /// be empty, which is the case for purely horizontal/vertical shifts.
    ///
    /// These strips have to be inserted correctly into the OpenGL texture,
    /// which starts not at 0 but at `texture_offset` because of wrapping indexing.
    /// Updating that texture from such a strip can typically not be done in one
    /// step, but requires breaking it into up to four subregions. This is
    /// because OpenGL textures can be read with wrapping indexing, but not
    /// written with wrapping indexing, so we need to do it ourselves.
    /// Let's look at the vertical strip:
    ///
    /// ```text
    /// <- width ->
    /// +---+-+
    /// | 3 |4|
    /// +---+-+
    /// |   | |  vert_strip
    /// | 1 |2|
    /// |   | |
    /// +---+-+
    /// ```
    ///
    /// Wraparound at the right texture edge causes the split into regions 1/3
    /// vs 2/4, and wraparound at the upper texture edge causes the split into
    /// regions 1/2 vs 3/4.
    /// Here's the texture with the vert_strip placed correctly:
    ///
    /// ```text
    /// <- self.size ->
    /// +-+-------+---+
    /// | |       |   |
    /// |2|       | 1 |
    /// | |       |   |
    /// +-+       +---+ <- texture_offset.y
    /// |4|       | 3 |
    /// +-+-------+---+
    ///           ^
    ///           |
    ///           xoff
    /// ```
    ///
    /// `xoff` is not equal to `texture_offset.x` if the texture moved right.
    ///
    /// The way this is handled is by creating regions as if they always need
    /// splitting, and skipping empty regions that result from that.
    pub fn incremental_update(
        &mut self,
        delta_x: i32,
        delta_y: i32,
        vert_strip: ImageBuffer,
        hori_strip: ImageBuffer,
    ) {
        // Calculate the updated texture offset, which is always in [0; self.size)
        let x_after_update =
            (self.u_texture_offset.value.x + delta_x).mod_floor(&i32::try_from(self.size).unwrap());
        let y_after_update =
            (self.u_texture_offset.value.y + delta_y).mod_floor(&i32::try_from(self.size).unwrap());
        let texture_offset_after_update = Vector2::new(x_after_update, y_after_update);

        // The vertical region's x coordinate needs to be the "lower" (but not
        // really, because of wraparound, so don't use min) of the old and new
        // horizontal texture offset. Why? If delta_x > 0 and we use the new
        // offset, we'll overwrite the wrong data. The y coordinate is just the
        // new vertical texture offset however, which may not seem intuitive.
        // You can convince yourself by staring at the illustration in section
        // 2.4 of the page linked above,
        // https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter02.html,
        // remembering that y is up and recalling where the L shape originates.
        // If that doesn't help, draw an image with named pixels and a texture
        // window in it and perform a few updates in different directions,
        // noting where the L-shaped region (aka vert_strip + hori_strip) are
        // placed in the texture.
        let vert_x = if delta_x > 0 {
            self.u_texture_offset.value.x
        } else {
            x_after_update
        };
        let hori_y = if delta_y > 0 {
            self.u_texture_offset.value.y
        } else {
            y_after_update
        };
        let vert_regions = UpdateRegion::new_regions(
            vert_x.try_into().unwrap(),
            y_after_update.try_into().unwrap(),
            self.size,
            &vert_strip,
        );
        let hori_regions = UpdateRegion::new_regions(
            x_after_update.try_into().unwrap(),
            hori_y.try_into().unwrap(),
            self.size,
            &hori_strip,
        );
        let regions = vert_regions.iter().chain(hori_regions.iter());

        // Now we can overwrite the old texture offset
        self.u_texture_offset.value = texture_offset_after_update;

        unsafe {
            self.gl.ActiveTexture(opengl::TEXTURE0 + self.texture_unit);
            self.gl.BindTexture(opengl::TEXTURE_2D, self.id);
            for r in regions {
                let width = i32::try_from(r.pixels.width()).unwrap();
                let height = i32::try_from(r.pixels.height()).unwrap();
                if height * width == 0 {
                    continue;
                }
                let image = r.pixels.to_image();
                // For an explanation of the different parameters, see
                // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexSubImage2D.xhtml
                self.gl.TexSubImage2D(
                    opengl::TEXTURE_2D,
                    0, // level
                    i32::try_from(r.x).unwrap(),
                    i32::try_from(r.y).unwrap(),
                    width,
                    height,
                    P::FORMAT,
                    P::DTYPE,
                    image.into_raw().as_ptr() as *const c_void,
                );
            }
        }
    }

    /// Updates the offset and binds the texture
    pub fn submit(&self) {
        unsafe {
            // The purpose of texture units is to allow us to use more than 1 texture in our shaders.
            self.gl.ActiveTexture(opengl::TEXTURE0 + self.texture_unit);
            // After activating a texture unit, a subsequent BindTexture call will bind that
            // texture to the currently active texture unit.
            self.gl.BindTexture(opengl::TEXTURE_2D, self.id);
        }
        self.u_texture_offset.submit();
    }
}

/// Trait to associate pixel formats with OpenGL constants
pub trait TextureFormat: Pixel {
    const INTERNALFORMAT: GLint;
    const FORMAT: GLuint;
    const DTYPE: GLuint;
}

impl TextureFormat for LumaA<f32> {
    const INTERNALFORMAT: GLint = opengl::RG32F as GLint;
    const FORMAT: GLuint = opengl::RG;
    const DTYPE: GLuint = opengl::FLOAT;
}

impl TextureFormat for Rgba<u8> {
    const INTERNALFORMAT: GLint = opengl::RGBA8 as GLint;
    const FORMAT: GLuint = opengl::RGBA;
    const DTYPE: GLuint = opengl::UNSIGNED_BYTE;
}

#[cfg(test)]
mod tests {
    use super::*;
    use image::GenericImage;

    #[test]
    fn test_regions() {
        let test_src = ImageBuffer::from_fn(16, 16, |x, y| Rgba::<u8>([x as u8, y as u8, 0, 255]));
        let regions = UpdateRegion::new_regions(4, 7, 16, &test_src);

        let mut dest = ImageBuffer::from_pixel(16, 16, Rgba::<u8>([0, 0, 0, 0]));
        for r in &regions {
            dest.copy_from(&r.pixels, r.x as u32, r.y as u32);
        }
        let reference = ImageBuffer::from_fn(16, 16, |x, y| {
            Rgba::<u8>([(x + 16 - 4) as u8 % 16, (y + 16 - 7) as u8 % 16, 0, 255])
        });
        assert!(dest.pixels().eq(reference.pixels()));
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "rustc-serialize")]
use serialize::{Encodable, Encoder, Decodable, Decoder};

use std::hash;
use std::iter::FromIterator;
use std::iter::IntoIterator;
use std::ops::{
    Index,
    IndexMut,
};

use super::{
    Dimension, Ix,
    Elements,
    ElementsMut,
    ArrayBase,
    ArrayView,
    ArrayViewMut,
    Data,
    DataMut,
    DataOwned,
    NdIndex,
};

use numeric_util;

#[cold]
#[inline(never)]
fn array_out_of_bounds() -> ! {
    panic!("ndarray: index out of bounds");
}

// Macro to insert more informative out of bounds message in debug builds
#[cfg(debug_assertions)]
macro_rules! debug_bounds_check {
    ($self_:ident, $index:expr) => {
        if let None = $index.index_checked(&$self_.dim, &$self_.strides) {
            panic!("ndarray: index {:?} is out of bounds for array of shape {:?}",
                   $index, $self_.shape());
        }
    };
}

#[cfg(not(debug_assertions))]
macro_rules! debug_bounds_check {
    ($self_:ident, $index:expr) => { };
}

#[inline(always)]
pub fn debug_bounds_check<S, D, I>(a: &ArrayBase<S, D>, index: &I)
    where D: Dimension,
          I: NdIndex<Dim=D>,
          S: Data,
{
    debug_bounds_check!(a, *index);
}

/// Access the element at **index**.
///
/// **Panics** if index is out of bounds.
impl<S, D, I> Index<I> for ArrayBase<S, D>
    where D: Dimension,
          I: NdIndex<Dim=D>,
          S: Data,
{
    type Output = S::Elem;
    #[inline]
    fn index(&self, index: I) -> &S::Elem {
        debug_bounds_check!(self, index);
        self.get(index).unwrap_or_else(|| array_out_of_bounds())
    }
}

/// Access the element at **index** mutably.
///
/// **Panics** if index is out of bounds.
impl<S, D, I> IndexMut<I> for ArrayBase<S, D>
    where D: Dimension,
          I: NdIndex<Dim=D>,
          S: DataMut,
{
    #[inline]
    fn index_mut(&mut self, index: I) -> &mut S::Elem {
        debug_bounds_check!(self, index);
        self.get_mut(index).unwrap_or_else(|| array_out_of_bounds())
    }
}

/// Return `true` if the array shapes and all elements of `self` and
/// `rhs` are equal. Return `false` otherwise.
impl<S, S2, D> PartialEq<ArrayBase<S2, D>> for ArrayBase<S, D>
    where D: Dimension,
          S: Data,
          S2: Data<Elem = S::Elem>,
          S::Elem: PartialEq
{
    fn eq(&self, rhs: &ArrayBase<S2, D>) -> bool {
        if self.shape() != rhs.shape() {
            return false;
        }
        if let Some(self_s) = self.as_slice() {
            if let Some(rhs_s) = rhs.as_slice() {
                return numeric_util::unrolled_eq(self_s, rhs_s);
            }
        }
        self.iter().zip(rhs.iter()).all(|(a, b)| a == b)
    }
}

impl<S, D> Eq for ArrayBase<S, D>
    where D: Dimension,
          S: Data,
          S::Elem: Eq,
{ }

impl<A, S> FromIterator<A> for ArrayBase<S, Ix>
    where S: DataOwned<Elem=A>
{
    fn from_iter<I>(iterable: I) -> ArrayBase<S, Ix>
        where I: IntoIterator<Item=A>,
    {
        ArrayBase::from_iter(iterable)
    }
}

impl<'a, S, D> IntoIterator for &'a ArrayBase<S, D>
    where D: Dimension,
          S: Data,
{
    type Item = &'a S::Elem;
    type IntoIter = Elements<'a, S::Elem, D>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a, S, D> IntoIterator for &'a mut ArrayBase<S, D>
    where D: Dimension,
          S: DataMut
{
    type Item = &'a mut S::Elem;
    type IntoIter = ElementsMut<'a, S::Elem, D>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter_mut()
    }
}

impl<'a, A, D> IntoIterator for ArrayView<'a, A, D>
    where D: Dimension
{
    type Item = &'a A;
    type IntoIter = Elements<'a, A, D>;

    fn into_iter(self) -> Self::IntoIter {
        self.into_iter_()
    }
}

impl<'a, A, D> IntoIterator for ArrayViewMut<'a, A, D>
    where D: Dimension
{
    type Item = &'a mut A;
    type IntoIter = ElementsMut<'a, A, D>;

    fn into_iter(self) -> Self::IntoIter {
        self.into_iter_()
    }
}

impl<'a, S, D> hash::Hash for ArrayBase<S, D>
    where D: Dimension,
          S: Data,
          S::Elem: hash::Hash
{
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.shape().hash(state);
        if let Some(self_s) = self.as_slice() {
            hash::Hash::hash_slice(self_s, state);
        } else {
            for row in self.inner_iter() {
                if let Some(row_s) = row.as_slice() {
                    hash::Hash::hash_slice(row_s, state);
                } else {
                    for elt in row {
                        elt.hash(state)
                    }
                }
            }
        }
    }
}

// NOTE: ArrayBase keeps an internal raw pointer that always
// points into the storage. This is Sync & Send as long as we
// follow the usual inherited mutability rules, as we do with
// Vec, &[] and &mut []

/// `ArrayBase` is `Sync` when the storage type is.
unsafe impl<S, D> Sync for ArrayBase<S, D>
    where S: Sync + Data, D: Sync
{ }

/// `ArrayBase` is `Send` when the storage type is.
unsafe impl<S, D> Send for ArrayBase<S, D>
    where S: Send + Data, D: Send
{ }

#[cfg(feature = "rustc-serialize")]
// Use version number so we can add a packed format later.
static ARRAY_FORMAT_VERSION: u8 = 1u8;

/// **Requires crate feature `"rustc-serialize"`**
#[cfg(feature = "rustc-serialize")]
impl<A, S, D> Encodable for ArrayBase<S, D>
    where A: Encodable,
          D: Dimension + Encodable,
          S: Data<Elem = A>
{
    fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
        s.emit_struct("Array", 3, |e| {
            try!(e.emit_struct_field("v", 0, |e| ARRAY_FORMAT_VERSION.encode(e)));
            // FIXME: Write self.dim as a slice (self.shape)
            // The problem is decoding it.
            try!(e.emit_struct_field("dim", 1, |e| self.dim.encode(e)));
            try!(e.emit_struct_field("data", 2, |e| {
                let sz = self.dim.size();
                e.emit_seq(sz, |e| {
                    for (i, elt) in self.iter().enumerate() {
                        try!(e.emit_seq_elt(i, |e| elt.encode(e)))
                    }
                    Ok(())
                })
            }));
            Ok(())
        })
    }
}

/// **Requires crate feature `"rustc-serialize"`**
#[cfg(feature = "rustc-serialize")]
impl<A, S, D> Decodable for ArrayBase<S, D>
    where A: Decodable,
          D: Dimension + Decodable,
          S: DataOwned<Elem = A>
{
    fn decode<E: Decoder>(d: &mut E) -> Result<ArrayBase<S, D>, E::Error> {
        d.read_struct("Array", 3, |d| {
            let version: u8 = try!(d.read_struct_field("v", 0, Decodable::decode));
            if version > ARRAY_FORMAT_VERSION {
                return Err(d.error("unknown array version"))
            }
            let dim: D = try!(d.read_struct_field("dim", 1, |d| {
                Decodable::decode(d)
            }));
            let elements = try!(
                d.read_struct_field("data", 2, |d| {
                    d.read_seq(|d, len| {
                        if len != dim.size() {
                            Err(d.error("data and dimension must match in size"))
                        } else {
                            let mut elements = Vec::with_capacity(len);
                            for i in 0..len {
                                elements.push(try!(d.read_seq_elt::<A, _>(i, Decodable::decode)))
                            }
                            Ok(elements)
                        }
                    })
            }));
            unsafe {
                Ok(ArrayBase::from_vec_dim_unchecked(dim, elements))
            }
        })
    }
}
<commit_msg>Impl `From` for types that can be converted to array views<commit_after>#[cfg(feature = "rustc-serialize")]
use serialize::{Encodable, Encoder, Decodable, Decoder};

use std::hash;
use std::iter::FromIterator;
use std::iter::IntoIterator;
use std::ops::{
    Index,
    IndexMut,
};

use super::{
    Dimension, Ix,
    Elements,
    ElementsMut,
    ArrayBase,
    ArrayView,
    ArrayViewMut,
    Data,
    DataMut,
    DataOwned,
    NdIndex,
};

use numeric_util;

#[cold]
#[inline(never)]
fn array_out_of_bounds() -> ! {
    panic!("ndarray: index out of bounds");
}

// Macro to insert more informative out of bounds message in debug builds
#[cfg(debug_assertions)]
macro_rules! debug_bounds_check {
    ($self_:ident, $index:expr) => {
        if let None = $index.index_checked(&$self_.dim, &$self_.strides) {
            panic!("ndarray: index {:?} is out of bounds for array of shape {:?}",
                   $index, $self_.shape());
        }
    };
}

#[cfg(not(debug_assertions))]
macro_rules! debug_bounds_check {
    ($self_:ident, $index:expr) => { };
}

#[inline(always)]
pub fn debug_bounds_check<S, D, I>(a: &ArrayBase<S, D>, index: &I)
    where D: Dimension,
          I: NdIndex<Dim=D>,
          S: Data,
{
    debug_bounds_check!(a, *index);
}

/// Access the element at **index**.
///
/// **Panics** if index is out of bounds.
impl<S, D, I> Index<I> for ArrayBase<S, D>
    where D: Dimension,
          I: NdIndex<Dim=D>,
          S: Data,
{
    type Output = S::Elem;
    #[inline]
    fn index(&self, index: I) -> &S::Elem {
        debug_bounds_check!(self, index);
        self.get(index).unwrap_or_else(|| array_out_of_bounds())
    }
}

/// Access the element at **index** mutably.
///
/// **Panics** if index is out of bounds.
impl<S, D, I> IndexMut<I> for ArrayBase<S, D>
    where D: Dimension,
          I: NdIndex<Dim=D>,
          S: DataMut,
{
    #[inline]
    fn index_mut(&mut self, index: I) -> &mut S::Elem {
        debug_bounds_check!(self, index);
        self.get_mut(index).unwrap_or_else(|| array_out_of_bounds())
    }
}

/// Return `true` if the array shapes and all elements of `self` and
/// `rhs` are equal. Return `false` otherwise.
impl<S, S2, D> PartialEq<ArrayBase<S2, D>> for ArrayBase<S, D>
    where D: Dimension,
          S: Data,
          S2: Data<Elem = S::Elem>,
          S::Elem: PartialEq
{
    fn eq(&self, rhs: &ArrayBase<S2, D>) -> bool {
        if self.shape() != rhs.shape() {
            return false;
        }
        if let Some(self_s) = self.as_slice() {
            if let Some(rhs_s) = rhs.as_slice() {
                return numeric_util::unrolled_eq(self_s, rhs_s);
            }
        }
        self.iter().zip(rhs.iter()).all(|(a, b)| a == b)
    }
}

impl<S, D> Eq for ArrayBase<S, D>
    where D: Dimension,
          S: Data,
          S::Elem: Eq,
{ }

impl<A, S> FromIterator<A> for ArrayBase<S, Ix>
    where S: DataOwned<Elem=A>
{
    fn from_iter<I>(iterable: I) -> ArrayBase<S, Ix>
        where I: IntoIterator<Item=A>,
    {
        ArrayBase::from_iter(iterable)
    }
}

impl<'a, S, D> IntoIterator for &'a ArrayBase<S, D>
    where D: Dimension,
          S: Data,
{
    type Item = &'a S::Elem;
    type IntoIter = Elements<'a, S::Elem, D>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a, S, D> IntoIterator for &'a mut ArrayBase<S, D>
    where D: Dimension,
          S: DataMut
{
    type Item = &'a mut S::Elem;
    type IntoIter = ElementsMut<'a, S::Elem, D>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter_mut()
    }
}

impl<'a, A, D> IntoIterator for ArrayView<'a, A, D>
    where D: Dimension
{
    type Item = &'a A;
    type IntoIter = Elements<'a, A, D>;

    fn into_iter(self) -> Self::IntoIter {
        self.into_iter_()
    }
}

impl<'a, A, D> IntoIterator for ArrayViewMut<'a, A, D>
    where D: Dimension
{
    type Item = &'a mut A;
    type IntoIter = ElementsMut<'a, A, D>;

    fn into_iter(self) -> Self::IntoIter {
        self.into_iter_()
    }
}

impl<'a, S, D> hash::Hash for ArrayBase<S, D>
    where D: Dimension,
          S: Data,
          S::Elem: hash::Hash
{
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.shape().hash(state);
        if let Some(self_s) = self.as_slice() {
            hash::Hash::hash_slice(self_s, state);
        } else {
            for row in self.inner_iter() {
                if let Some(row_s) = row.as_slice() {
                    hash::Hash::hash_slice(row_s, state);
                } else {
                    for elt in row {
                        elt.hash(state)
                    }
                }
            }
        }
    }
}

// NOTE: ArrayBase keeps an internal raw pointer that always
// points into the storage. This is Sync & Send as long as we
// follow the usual inherited mutability rules, as we do with
// Vec, &[] and &mut []

/// `ArrayBase` is `Sync` when the storage type is.
unsafe impl<S, D> Sync for ArrayBase<S, D>
    where S: Sync + Data, D: Sync
{ }

/// `ArrayBase` is `Send` when the storage type is.
unsafe impl<S, D> Send for ArrayBase<S, D>
    where S: Send + Data, D: Send
{ }

#[cfg(feature = "rustc-serialize")]
// Use version number so we can add a packed format later.
static ARRAY_FORMAT_VERSION: u8 = 1u8;

/// **Requires crate feature `"rustc-serialize"`**
#[cfg(feature = "rustc-serialize")]
impl<A, S, D> Encodable for ArrayBase<S, D>
    where A: Encodable,
          D: Dimension + Encodable,
          S: Data<Elem = A>
{
    fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
        s.emit_struct("Array", 3, |e| {
            try!(e.emit_struct_field("v", 0, |e| ARRAY_FORMAT_VERSION.encode(e)));
            // FIXME: Write self.dim as a slice (self.shape)
            // The problem is decoding it.
            try!(e.emit_struct_field("dim", 1, |e| self.dim.encode(e)));
            try!(e.emit_struct_field("data", 2, |e| {
                let sz = self.dim.size();
                e.emit_seq(sz, |e| {
                    for (i, elt) in self.iter().enumerate() {
                        try!(e.emit_seq_elt(i, |e| elt.encode(e)))
                    }
                    Ok(())
                })
            }));
            Ok(())
        })
    }
}

/// **Requires crate feature `"rustc-serialize"`**
#[cfg(feature = "rustc-serialize")]
impl<A, S, D> Decodable for ArrayBase<S, D>
    where A: Decodable,
          D: Dimension + Decodable,
          S: DataOwned<Elem = A>
{
    fn decode<E: Decoder>(d: &mut E) -> Result<ArrayBase<S, D>, E::Error> {
        d.read_struct("Array", 3, |d| {
            let version: u8 = try!(d.read_struct_field("v", 0, Decodable::decode));
            if version > ARRAY_FORMAT_VERSION {
                return Err(d.error("unknown array version"))
            }
            let dim: D = try!(d.read_struct_field("dim", 1, |d| {
                Decodable::decode(d)
            }));
            let elements = try!(
                d.read_struct_field("data", 2, |d| {
                    d.read_seq(|d, len| {
                        if len != dim.size() {
                            Err(d.error("data and dimension must match in size"))
                        } else {
                            let mut elements = Vec::with_capacity(len);
                            for i in 0..len {
                                elements.push(try!(d.read_seq_elt::<A, _>(i, Decodable::decode)))
                            }
                            Ok(elements)
                        }
                    })
            }));
            unsafe {
                Ok(ArrayBase::from_vec_dim_unchecked(dim, elements))
            }
        })
    }
}

impl<'a, A, Slice: ?Sized> From<&'a Slice> for ArrayView<'a, A, Ix>
    where Slice: AsRef<[A]>
{
    fn from(slice: &'a Slice) -> Self {
        ArrayView::from_slice(slice.as_ref())
    }
}

impl<'a, A, S, D> From<&'a ArrayBase<S, D>> for ArrayView<'a, A, D>
    where S: Data<Elem=A>,
          D: Dimension,
{
    fn from(array: &'a ArrayBase<S, D>) -> Self {
        array.view()
    }
}

impl<'a, A, Slice: ?Sized> From<&'a mut Slice> for ArrayViewMut<'a, A, Ix>
    where Slice: AsMut<[A]>
{
    fn from(slice: &'a mut Slice) -> Self {
        ArrayViewMut::from_slice(slice.as_mut())
    }
}

impl<'a, A, S, D> From<&'a mut ArrayBase<S, D>> for ArrayViewMut<'a, A, D>
    where S: DataMut<Elem=A>,
          D: Dimension,
{
    fn from(array: &'a mut ArrayBase<S, D>) -> Self {
        array.view_mut()
    }
}
<|endoftext|>


<commit_before>use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

static REVISION: &'static str = "7979016aff545f7b41cc517031026020b340989d";

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail")
        || path_string.starts_with("tests/rust/src/test/compile-fail")
        || path_string.starts_with("tests/rust/src/test/rustfix")
    {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // Deprecated placement syntax
        "tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
        // Deprecated anonymous parameter syntax in traits
        "tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
        "tests/rust/src/test/ui/issues/issue-13105.rs" |
        "tests/rust/src/test/ui/issues/issue-13775.rs" |
        "tests/rust/src/test/ui/issues/issue-34074.rs" |
        // Deprecated await macro syntax
        "tests/rust/src/test/ui/async-await/await-macro.rs" |
        // 2015-style dyn that libsyntax rejects
        "tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
        // not actually test cases
        "tests/rust/src/test/ui/include-single-expr-helper.rs" |
        "tests/rust/src/test/ui/include-single-expr-helper-1.rs" |
        "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let request = reqwest::get(&url)?;
    let decoder = GzDecoder::new(request);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);
    for mut entry in archive.entries()?.filter_map(|e| e.ok()) {
        if entry.path()?.starts_with(&prefix[..]) {
            let path =
                Path::new("tests/rust").join(entry.path()?.strip_prefix(&prefix[..])?.to_owned());
            entry.unpack(&path)?;
        }
    }
    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<commit_msg>Check for errors in tar entries iterator<commit_after>use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

static REVISION: &'static str = "7979016aff545f7b41cc517031026020b340989d";

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail")
        || path_string.starts_with("tests/rust/src/test/compile-fail")
        || path_string.starts_with("tests/rust/src/test/rustfix")
    {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // Deprecated placement syntax
        "tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
        // Deprecated anonymous parameter syntax in traits
        "tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
        "tests/rust/src/test/ui/issues/issue-13105.rs" |
        "tests/rust/src/test/ui/issues/issue-13775.rs" |
        "tests/rust/src/test/ui/issues/issue-34074.rs" |
        // Deprecated await macro syntax
        "tests/rust/src/test/ui/async-await/await-macro.rs" |
        // 2015-style dyn that libsyntax rejects
        "tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
        // not actually test cases
        "tests/rust/src/test/ui/include-single-expr-helper.rs" |
        "tests/rust/src/test/ui/include-single-expr-helper-1.rs" |
        "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let request = reqwest::get(&url)?;
    let decoder = GzDecoder::new(request);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);
    for entry in archive.entries()? {
        let mut entry = entry?;
        if entry.path()?.starts_with(&prefix[..]) {
            let path =
                Path::new("tests/rust").join(entry.path()?.strip_prefix(&prefix[..])?.to_owned());
            entry.unpack(&path)?;
        }
    }
    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<|endoftext|>