<commit_before>use byteorder::{LittleEndian, WriteBytesExt};
use std::io::{self, Write};

use crate::color;
use crate::error::{ImageError, ImageResult, ParameterError, ParameterErrorKind};
use crate::image::ImageEncoder;

const BITMAPFILEHEADER_SIZE: u32 = 14;
const BITMAPINFOHEADER_SIZE: u32 = 40;
const BITMAPV4HEADER_SIZE: u32 = 108;

/// The representation of a BMP encoder.
pub struct BmpEncoder<'a, W: 'a> {
    writer: &'a mut W,
}

/// BMP Encoder
///
/// An alias of [`BmpEncoder`].
///
/// TODO: remove
///
/// [`BmpEncoder`]: struct.BmpEncoder.html
#[allow(dead_code)]
#[deprecated(note = "Use `BmpEncoder` instead")]
pub type BMPEncoder<'a, W> = BmpEncoder<'a, W>;

impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
    /// Create a new encoder that writes its output to ```w```.
    pub fn new(w: &'a mut W) -> Self {
        BmpEncoder { writer: w }
    }

    /// Encodes the image ```image```
    /// that has dimensions ```width``` and ```height```
    /// and ```ColorType``` ```c```.
    pub fn encode(
        &mut self,
        image: &[u8],
        width: u32,
        height: u32,
        c: color::ColorType,
    ) -> ImageResult<()> {
        self.encode_with_palette(image, width, height, c, None)
    }

    /// Same as ```encode```, but allow a palette to be passed in
    pub fn encode_with_palette(
        &mut self,
        image: &[u8],
        width: u32,
        height: u32,
        c: color::ColorType,
        palette: Option<&[(u8, u8, u8)]>,
    ) -> ImageResult<()> {
        let bmp_header_size = BITMAPFILEHEADER_SIZE;

        let (dib_header_size, written_pixel_size, palette_color_count) = get_pixel_info(c, palette)?;
        let row_pad_size = (4 - (width * written_pixel_size) % 4) % 4; // each row must be padded to a multiple of 4 bytes
        let image_size = width
            .checked_mul(height)
            .and_then(|v| v.checked_mul(written_pixel_size))
            .and_then(|v| v.checked_add(height * row_pad_size))
            .ok_or_else(|| {
                ImageError::Parameter(ParameterError::from_kind(
                    ParameterErrorKind::DimensionMismatch,
                ))
            })?;
        let palette_size = palette_color_count * 4; // all palette colors are BGRA
        let file_size = bmp_header_size + dib_header_size + palette_size + image_size;

        // write BMP header
        self.writer.write_u8(b'B')?;
        self.writer.write_u8(b'M')?;
        self.writer.write_u32::<LittleEndian>(file_size)?; // file size
        self.writer.write_u16::<LittleEndian>(0)?; // reserved 1
        self.writer.write_u16::<LittleEndian>(0)?; // reserved 2
        self.writer
            .write_u32::<LittleEndian>(bmp_header_size + dib_header_size + palette_size)?; // image data offset

        // write DIB header
        self.writer.write_u32::<LittleEndian>(dib_header_size)?;
        self.writer.write_i32::<LittleEndian>(width as i32)?;
        self.writer.write_i32::<LittleEndian>(height as i32)?;
        self.writer.write_u16::<LittleEndian>(1)?; // color planes
        self.writer
            .write_u16::<LittleEndian>((written_pixel_size * 8) as u16)?; // bits per pixel
        if dib_header_size >= BITMAPV4HEADER_SIZE {
            // Assume BGRA32
            self.writer.write_u32::<LittleEndian>(3)?; // compression method - bitfields
        } else {
            self.writer.write_u32::<LittleEndian>(0)?; // compression method - no compression
        }
        self.writer.write_u32::<LittleEndian>(image_size)?;
        self.writer.write_i32::<LittleEndian>(0)?; // horizontal ppm
        self.writer.write_i32::<LittleEndian>(0)?; // vertical ppm
        self.writer.write_u32::<LittleEndian>(palette_color_count)?;
        self.writer.write_u32::<LittleEndian>(0)?; // all colors are important
        if dib_header_size >= BITMAPV4HEADER_SIZE {
            // Assume BGRA32
            self.writer.write_u32::<LittleEndian>(0xff << 16)?; // red mask
            self.writer.write_u32::<LittleEndian>(0xff << 8)?; // green mask
            self.writer.write_u32::<LittleEndian>(0xff)?; // blue mask
            self.writer.write_u32::<LittleEndian>(0xff << 24)?; // alpha mask
            self.writer.write_u32::<LittleEndian>(0x73524742)?; // colorspace - sRGB

            // endpoints (3x3) and gamma (3)
            for _ in 0..12 {
                self.writer.write_u32::<LittleEndian>(0)?;
            }
        }

        // write image data
        match c {
            color::ColorType::Rgb8 => {
                self.encode_rgb(image, width, height, row_pad_size, 3)?
            }
            color::ColorType::Rgba8 => {
                self.encode_rgba(image, width, height, row_pad_size, 4)?
            }
            color::ColorType::L8 => {
                self.encode_gray(image, width, height, row_pad_size, 1, palette)?
            }
            color::ColorType::La8 => {
                self.encode_gray(image, width, height, row_pad_size, 2, palette)?
            }
            _ => {
                return Err(ImageError::IoError(io::Error::new(
                    io::ErrorKind::InvalidInput,
                    &get_unsupported_error_message(c)[..],
                )))
            }
        }

        Ok(())
    }

    fn encode_rgb(
        &mut self,
        image: &[u8],
        width: u32,
        height: u32,
        row_pad_size: u32,
        bytes_per_pixel: u32,
    ) -> io::Result<()> {
        let width = width as usize;
        let height = height as usize;
        let x_stride = bytes_per_pixel as usize;
        let y_stride = width * x_stride;
        for row in (0..height).rev() {
            // from the bottom up
            let row_start = row * y_stride;
            for px in image[row_start..][..y_stride].chunks_exact(x_stride) {
                let r = px[0];
                let g = px[1];
                let b = px[2];
                // written as BGR
                self.writer.write_all(&[b, g, r])?;
            }
            self.write_row_pad(row_pad_size)?;
        }

        Ok(())
    }

    fn encode_rgba(
        &mut self,
        image: &[u8],
        width: u32,
        height: u32,
        row_pad_size: u32,
        bytes_per_pixel: u32,
    ) -> io::Result<()> {
        let width = width as usize;
        let height = height as usize;
        let x_stride = bytes_per_pixel as usize;
        let y_stride = width * x_stride;
        for row in (0..height).rev() {
            // from the bottom up
            let row_start = row * y_stride;
            for px in image[row_start..][..y_stride].chunks_exact(x_stride) {
                let r = px[0];
                let g = px[1];
                let b = px[2];
                let a = px[3];
                // written as BGRA
                self.writer.write_all(&[b, g, r, a])?;
            }
            self.write_row_pad(row_pad_size)?;
        }

        Ok(())
    }

    fn encode_gray(
        &mut self,
        image: &[u8],
        width: u32,
        height: u32,
        row_pad_size: u32,
        bytes_per_pixel: u32,
        palette: Option<&[(u8, u8, u8)]>,
    ) -> io::Result<()> {
        // write grayscale palette
        if let Some(palette) = palette {
            for (r, g, b) in palette {
                // each color is written as BGRA, where A is always 0
                self.writer.write_all(&[*b, *g, *r, 0])?;
            }
        } else {
            for val in 0u8..=255 {
                // each color is written as BGRA, where A is always 0 and since only grayscale is being written, B = G = R = index
                self.writer.write_all(&[val, val, val, 0])?;
            }
        }

        // write image data
        let x_stride = bytes_per_pixel;
        let y_stride = width * x_stride;
        for row in (0..height).rev() {
            // from the bottom up
            let row_start = row * y_stride;
            for col in 0..width {
                let pixel_start = (row_start + (col * x_stride)) as usize;
                // color value is equal to the palette index
                self.writer.write_u8(image[pixel_start])?;
                // alpha is never written as it's not widely supported
            }

            self.write_row_pad(row_pad_size)?;
        }

        Ok(())
    }

    fn write_row_pad(&mut self, row_pad_size: u32) -> io::Result<()> {
        for _ in 0..row_pad_size {
            self.writer.write_u8(0)?;
        }

        Ok(())
    }
}

impl<'a, W: Write> ImageEncoder for BmpEncoder<'a, W> {
    fn write_image(
        mut self,
        buf: &[u8],
        width: u32,
        height: u32,
        color_type: color::ColorType,
    ) -> ImageResult<()> {
        self.encode(buf, width, height, color_type)
    }
}

fn get_unsupported_error_message(c: color::ColorType) -> String {
    format!(
        "Unsupported color type {:?}.  Supported types: RGB(8), RGBA(8), Gray(8), GrayA(8).",
        c
    )
}

/// Returns a tuple representing: (dib header size, written pixel size, palette color count).
fn get_pixel_info(c: color::ColorType, palette: Option<&[(u8, u8, u8)]>) -> io::Result<(u32, u32, u32)> {
    let sizes = match c {
        color::ColorType::Rgb8 => (BITMAPINFOHEADER_SIZE, 3, 0),
        color::ColorType::Rgba8 => (BITMAPV4HEADER_SIZE, 4, 0),
        color::ColorType::L8 => (BITMAPINFOHEADER_SIZE, 1, palette.map(|p| p.len()).unwrap_or(256) as u32),
        color::ColorType::La8 => (BITMAPINFOHEADER_SIZE, 1, palette.map(|p| p.len()).unwrap_or(256) as u32),
        _ => {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                &get_unsupported_error_message(c)[..],
            ))
        }
    };

    Ok(sizes)
}

#[cfg(test)]
mod tests {
    use super::super::BmpDecoder;
    use super::BmpEncoder;
    use crate::color::ColorType;
    use crate::image::ImageDecoder;
    use std::io::Cursor;

    fn round_trip_image(image: &[u8], width: u32, height: u32, c: ColorType) -> Vec<u8> {
        let mut encoded_data = Vec::new();
        {
            let mut encoder = BmpEncoder::new(&mut encoded_data);
            encoder
                .encode(&image, width, height, c)
                .expect("could not encode image");
        }

        let decoder = BmpDecoder::new(Cursor::new(&encoded_data)).expect("failed to decode");

        let mut buf = vec![0; decoder.total_bytes() as usize];
        decoder.read_image(&mut buf).expect("failed to decode");
        buf
    }

    #[test]
    fn round_trip_single_pixel_rgb() {
        let image = [255u8, 0, 0]; // single red pixel
        let decoded = round_trip_image(&image, 1, 1, ColorType::Rgb8);
        assert_eq!(3, decoded.len());
        assert_eq!(255, decoded[0]);
        assert_eq!(0, decoded[1]);
        assert_eq!(0, decoded[2]);
    }

    #[test]
    fn huge_files_return_error() {
        let mut encoded_data = Vec::new();
        let image = vec![0u8; 3 * 40_000 * 40_000]; // 40_000x40_000 pixels, 3 bytes per pixel, allocated on the heap
        let mut encoder = BmpEncoder::new(&mut encoded_data);
        let result = encoder.encode(&image, 40_000, 40_000, ColorType::Rgb8);
        assert!(result.is_err());
    }

    #[test]
    fn round_trip_single_pixel_rgba() {
        let image = [1, 2, 3, 4];
        let decoded = round_trip_image(&image, 1, 1, ColorType::Rgba8);
        assert_eq!(&decoded[..], &image[..]);
    }

    #[test]
    fn round_trip_3px_rgb() {
        let image = [0u8; 3 * 3 * 3]; // 3x3 pixels, 3 bytes per pixel
        let _decoded = round_trip_image(&image, 3, 3, ColorType::Rgb8);
    }

    #[test]
    fn round_trip_gray() {
        let image = [0u8, 1, 2]; // 3 pixels
        let decoded = round_trip_image(&image, 3, 1, ColorType::L8);
        // should be read back as 3 RGB pixels
        assert_eq!(9, decoded.len());
        assert_eq!(0, decoded[0]);
        assert_eq!(0, decoded[1]);
        assert_eq!(0, decoded[2]);
        assert_eq!(1, decoded[3]);
        assert_eq!(1, decoded[4]);
        assert_eq!(1, decoded[5]);
        assert_eq!(2, decoded[6]);
        assert_eq!(2, decoded[7]);
        assert_eq!(2, decoded[8]);
    }

    #[test]
    fn round_trip_graya() {
        let image = [0u8, 0, 1, 0, 2, 0]; // 3 pixels, each with an alpha channel
        let decoded = round_trip_image(&image, 1, 3, ColorType::La8);
        // should be read back as 3 RGB pixels
        assert_eq!(9, decoded.len());
        assert_eq!(0, decoded[0]);
        assert_eq!(0, decoded[1]);
        assert_eq!(0, decoded[2]);
        assert_eq!(1, decoded[3]);
        assert_eq!(1, decoded[4]);
        assert_eq!(1, decoded[5]);
        assert_eq!(2, decoded[6]);
        assert_eq!(2, decoded[7]);
        assert_eq!(2, decoded[8]);
    }
}
<commit_msg>Update src/codecs/bmp/encoder.rs<commit_after>use byteorder::{LittleEndian, WriteBytesExt};
use std::io::{self, Write};

use crate::color;
use crate::error::{ImageError, ImageResult, ParameterError, ParameterErrorKind};
use crate::image::ImageEncoder;

const BITMAPFILEHEADER_SIZE: u32 = 14;
const BITMAPINFOHEADER_SIZE: u32 = 40;
const BITMAPV4HEADER_SIZE: u32 = 108;

/// The representation of a BMP encoder.
pub struct BmpEncoder<'a, W: 'a> {
    writer: &'a mut W,
}

/// BMP Encoder
///
/// An alias of [`BmpEncoder`].
///
/// TODO: remove
///
/// [`BmpEncoder`]: struct.BmpEncoder.html
#[allow(dead_code)]
#[deprecated(note = "Use `BmpEncoder` instead")]
pub type BMPEncoder<'a, W> = BmpEncoder<'a, W>;

impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
    /// Create a new encoder that writes its output to ```w```.
    pub fn new(w: &'a mut W) -> Self {
        BmpEncoder { writer: w }
    }

    /// Encodes the image ```image```
    /// that has dimensions ```width``` and ```height```
    /// and ```ColorType``` ```c```.
    pub fn encode(
        &mut self,
        image: &[u8],
        width: u32,
        height: u32,
        c: color::ColorType,
    ) -> ImageResult<()> {
        self.encode_with_palette(image, width, height, c, None)
    }

    /// Same as ```encode```, but allow a palette to be passed in
    pub fn encode_with_palette(
        &mut self,
        image: &[u8],
        width: u32,
        height: u32,
        c: color::ColorType,
        palette: Option<&[(u8, u8, u8)]>,
    ) -> ImageResult<()> {
        let bmp_header_size = BITMAPFILEHEADER_SIZE;

        let (dib_header_size, written_pixel_size, palette_color_count) = get_pixel_info(c, palette)?;
        let row_pad_size = (4 - (width * written_pixel_size) % 4) % 4; // each row must be padded to a multiple of 4 bytes
        let image_size = width
            .checked_mul(height)
            .and_then(|v| v.checked_mul(written_pixel_size))
            .and_then(|v| v.checked_add(height * row_pad_size))
            .ok_or_else(|| {
                ImageError::Parameter(ParameterError::from_kind(
                    ParameterErrorKind::DimensionMismatch,
                ))
            })?;
        let palette_size = palette_color_count * 4; // all palette colors are BGRA
        let file_size = bmp_header_size + dib_header_size + palette_size + image_size;

        // write BMP header
        self.writer.write_u8(b'B')?;
        self.writer.write_u8(b'M')?;
        self.writer.write_u32::<LittleEndian>(file_size)?; // file size
        self.writer.write_u16::<LittleEndian>(0)?; // reserved 1
        self.writer.write_u16::<LittleEndian>(0)?; // reserved 2
        self.writer
            .write_u32::<LittleEndian>(bmp_header_size + dib_header_size + palette_size)?; // image data offset

        // write DIB header
        self.writer.write_u32::<LittleEndian>(dib_header_size)?;
        self.writer.write_i32::<LittleEndian>(width as i32)?;
        self.writer.write_i32::<LittleEndian>(height as i32)?;
        self.writer.write_u16::<LittleEndian>(1)?; // color planes
        self.writer
            .write_u16::<LittleEndian>((written_pixel_size * 8) as u16)?; // bits per pixel
        if dib_header_size >= BITMAPV4HEADER_SIZE {
            // Assume BGRA32
            self.writer.write_u32::<LittleEndian>(3)?; // compression method - bitfields
        } else {
            self.writer.write_u32::<LittleEndian>(0)?; // compression method - no compression
        }
        self.writer.write_u32::<LittleEndian>(image_size)?;
        self.writer.write_i32::<LittleEndian>(0)?; // horizontal ppm
        self.writer.write_i32::<LittleEndian>(0)?; // vertical ppm
        self.writer.write_u32::<LittleEndian>(palette_color_count)?;
        self.writer.write_u32::<LittleEndian>(0)?; // all colors are important
        if dib_header_size >= BITMAPV4HEADER_SIZE {
            // Assume BGRA32
            self.writer.write_u32::<LittleEndian>(0xff << 16)?; // red mask
            self.writer.write_u32::<LittleEndian>(0xff << 8)?; // green mask
            self.writer.write_u32::<LittleEndian>(0xff)?; // blue mask
            self.writer.write_u32::<LittleEndian>(0xff << 24)?; // alpha mask
            self.writer.write_u32::<LittleEndian>(0x73524742)?; // colorspace - sRGB

            // endpoints (3x3) and gamma (3)
            for _ in 0..12 {
                self.writer.write_u32::<LittleEndian>(0)?;
            }
        }

        // write image data
        match c {
            color::ColorType::Rgb8 => {
                self.encode_rgb(image, width, height, row_pad_size, 3)?
            }
            color::ColorType::Rgba8 => {
                self.encode_rgba(image, width, height, row_pad_size, 4)?
            }
            color::ColorType::L8 => {
                self.encode_gray(image, width, height, row_pad_size, 1, palette)?
            }
            color::ColorType::La8 => {
                self.encode_gray(image, width, height, row_pad_size, 2, palette)?
            }
            _ => {
                return Err(ImageError::IoError(io::Error::new(
                    io::ErrorKind::InvalidInput,
                    &get_unsupported_error_message(c)[..],
                )))
            }
        }

        Ok(())
    }

    fn encode_rgb(
        &mut self,
        image: &[u8],
        width: u32,
        height: u32,
        row_pad_size: u32,
        bytes_per_pixel: u32,
    ) -> io::Result<()> {
        let width = width as usize;
        let height = height as usize;
        let x_stride = bytes_per_pixel as usize;
        let y_stride = width * x_stride;
        for row in (0..height).rev() {
            // from the bottom up
            let row_start = row * y_stride;
            for px in image[row_start..][..y_stride].chunks_exact(x_stride) {
                let r = px[0];
                let g = px[1];
                let b = px[2];
                // written as BGR
                self.writer.write_all(&[b, g, r])?;
            }
            self.write_row_pad(row_pad_size)?;
        }

        Ok(())
    }

    fn encode_rgba(
        &mut self,
        image: &[u8],
        width: u32,
        height: u32,
        row_pad_size: u32,
        bytes_per_pixel: u32,
    ) -> io::Result<()> {
        let width = width as usize;
        let height = height as usize;
        let x_stride = bytes_per_pixel as usize;
        let y_stride = width * x_stride;
        for row in (0..height).rev() {
            // from the bottom up
            let row_start = row * y_stride;
            for px in image[row_start..][..y_stride].chunks_exact(x_stride) {
                let r = px[0];
                let g = px[1];
                let b = px[2];
                let a = px[3];
                // written as BGRA
                self.writer.write_all(&[b, g, r, a])?;
            }
            self.write_row_pad(row_pad_size)?;
        }

        Ok(())
    }

    fn encode_gray(
        &mut self,
        image: &[u8],
        width: u32,
        height: u32,
        row_pad_size: u32,
        bytes_per_pixel: u32,
        palette: Option<&[(u8, u8, u8)]>,
    ) -> io::Result<()> {
        // write grayscale palette
        if let Some(palette) = palette {
            for &(r, g, b) in palette {
                // each color is written as BGRA, where A is always 0
                self.writer.write_all(&[b, g, r, 0])?;
            }
        } else {
            for val in 0u8..=255 {
                // each color is written as BGRA, where A is always 0 and since only grayscale is being written, B = G = R = index
                self.writer.write_all(&[val, val, val, 0])?;
            }
        }

        // write image data
        let x_stride = bytes_per_pixel;
        let y_stride = width * x_stride;
        for row in (0..height).rev() {
            // from the bottom up
            let row_start = row * y_stride;
            for col in 0..width {
                let pixel_start = (row_start + (col * x_stride)) as usize;
                // color value is equal to the palette index
                self.writer.write_u8(image[pixel_start])?;
                // alpha is never written as it's not widely supported
            }

            self.write_row_pad(row_pad_size)?;
        }

        Ok(())
    }

    fn write_row_pad(&mut self, row_pad_size: u32) -> io::Result<()> {
        for _ in 0..row_pad_size {
            self.writer.write_u8(0)?;
        }

        Ok(())
    }
}

impl<'a, W: Write> ImageEncoder for BmpEncoder<'a, W> {
    fn write_image(
        mut self,
        buf: &[u8],
        width: u32,
        height: u32,
        color_type: color::ColorType,
    ) -> ImageResult<()> {
        self.encode(buf, width, height, color_type)
    }
}

fn get_unsupported_error_message(c: color::ColorType) -> String {
    format!(
        "Unsupported color type {:?}.  Supported types: RGB(8), RGBA(8), Gray(8), GrayA(8).",
        c
    )
}

/// Returns a tuple representing: (dib header size, written pixel size, palette color count).
fn get_pixel_info(c: color::ColorType, palette: Option<&[(u8, u8, u8)]>) -> io::Result<(u32, u32, u32)> {
    let sizes = match c {
        color::ColorType::Rgb8 => (BITMAPINFOHEADER_SIZE, 3, 0),
        color::ColorType::Rgba8 => (BITMAPV4HEADER_SIZE, 4, 0),
        color::ColorType::L8 => (BITMAPINFOHEADER_SIZE, 1, palette.map(|p| p.len()).unwrap_or(256) as u32),
        color::ColorType::La8 => (BITMAPINFOHEADER_SIZE, 1, palette.map(|p| p.len()).unwrap_or(256) as u32),
        _ => {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                &get_unsupported_error_message(c)[..],
            ))
        }
    };

    Ok(sizes)
}

#[cfg(test)]
mod tests {
    use super::super::BmpDecoder;
    use super::BmpEncoder;
    use crate::color::ColorType;
    use crate::image::ImageDecoder;
    use std::io::Cursor;

    fn round_trip_image(image: &[u8], width: u32, height: u32, c: ColorType) -> Vec<u8> {
        let mut encoded_data = Vec::new();
        {
            let mut encoder = BmpEncoder::new(&mut encoded_data);
            encoder
                .encode(&image, width, height, c)
                .expect("could not encode image");
        }

        let decoder = BmpDecoder::new(Cursor::new(&encoded_data)).expect("failed to decode");

        let mut buf = vec![0; decoder.total_bytes() as usize];
        decoder.read_image(&mut buf).expect("failed to decode");
        buf
    }

    #[test]
    fn round_trip_single_pixel_rgb() {
        let image = [255u8, 0, 0]; // single red pixel
        let decoded = round_trip_image(&image, 1, 1, ColorType::Rgb8);
        assert_eq!(3, decoded.len());
        assert_eq!(255, decoded[0]);
        assert_eq!(0, decoded[1]);
        assert_eq!(0, decoded[2]);
    }

    #[test]
    fn huge_files_return_error() {
        let mut encoded_data = Vec::new();
        let image = vec![0u8; 3 * 40_000 * 40_000]; // 40_000x40_000 pixels, 3 bytes per pixel, allocated on the heap
        let mut encoder = BmpEncoder::new(&mut encoded_data);
        let result = encoder.encode(&image, 40_000, 40_000, ColorType::Rgb8);
        assert!(result.is_err());
    }

    #[test]
    fn round_trip_single_pixel_rgba() {
        let image = [1, 2, 3, 4];
        let decoded = round_trip_image(&image, 1, 1, ColorType::Rgba8);
        assert_eq!(&decoded[..], &image[..]);
    }

    #[test]
    fn round_trip_3px_rgb() {
        let image = [0u8; 3 * 3 * 3]; // 3x3 pixels, 3 bytes per pixel
        let _decoded = round_trip_image(&image, 3, 3, ColorType::Rgb8);
    }

    #[test]
    fn round_trip_gray() {
        let image = [0u8, 1, 2]; // 3 pixels
        let decoded = round_trip_image(&image, 3, 1, ColorType::L8);
        // should be read back as 3 RGB pixels
        assert_eq!(9, decoded.len());
        assert_eq!(0, decoded[0]);
        assert_eq!(0, decoded[1]);
        assert_eq!(0, decoded[2]);
        assert_eq!(1, decoded[3]);
        assert_eq!(1, decoded[4]);
        assert_eq!(1, decoded[5]);
        assert_eq!(2, decoded[6]);
        assert_eq!(2, decoded[7]);
        assert_eq!(2, decoded[8]);
    }

    #[test]
    fn round_trip_graya() {
        let image = [0u8, 0, 1, 0, 2, 0]; // 3 pixels, each with an alpha channel
        let decoded = round_trip_image(&image, 1, 3, ColorType::La8);
        // should be read back as 3 RGB pixels
        assert_eq!(9, decoded.len());
        assert_eq!(0, decoded[0]);
        assert_eq!(0, decoded[1]);
        assert_eq!(0, decoded[2]);
        assert_eq!(1, decoded[3]);
        assert_eq!(1, decoded[4]);
        assert_eq!(1, decoded[5]);
        assert_eq!(2, decoded[6]);
        assert_eq!(2, decoded[7]);
        assert_eq!(2, decoded[8]);
    }
}
<|endoftext|>


<commit_before>use std::fs::{self, DirEntry};
use std::path::Path;

#[test]
fn test_missing_tests() {
    let missing_files = explore_directory(Path::new("./tests"));
    if missing_files.len() > 0 {
        assert!(
            false,
            format!(
                "Didn't see a test file for the following files:\n\n{}\n",
                missing_files
                    .iter()
                    .map(|s| format!("\t{}", s))
                    .collect::<Vec<_>>()
                    .join("\n")
            )
        );
    }
}

/*
Test for missing files.

Since rs files are alphabetically before stderr/stdout, we can sort by the full name
and iter in that order. If we've seen the file stem for the first time and it's not
a rust file, it means the rust file has to be missing.
*/
fn explore_directory(dir: &Path) -> Vec<String> {
    let mut missing_files: Vec<String> = Vec::new();
    let mut current_file = String::new();
    let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect();
    files.sort_by_key(|e| e.path());
    for entry in files.iter() {
        let path = entry.path();
        if path.is_dir() {
            missing_files.extend(explore_directory(&path));
        } else {
            let file_stem = path.file_stem().unwrap().to_str().unwrap().to_string();
            match path.extension() {
                Some(ext) => {
                    match ext.to_str().unwrap() {
                        "rs" => current_file = file_stem.clone(),
                        "stderr" | "stdout" => {
                            if file_stem != current_file {
                                missing_files.push(path.to_str().unwrap().to_string());
                            }
                        },
                        _ => continue,
                    };
                },
                None => {},
            }
        }
    }
    missing_files
}
<commit_msg>Fixing issues pointed out by dogfood tests.<commit_after>use std::fs::{self, DirEntry};
use std::path::Path;

#[test]
fn test_missing_tests() {
    let missing_files = explore_directory(Path::new("./tests"));
    if !missing_files.is_empty() {
        assert!(
            false,
            format!(
                "Didn't see a test file for the following files:\n\n{}\n",
                missing_files
                    .iter()
                    .map(|s| format!("\t{}", s))
                    .collect::<Vec<_>>()
                    .join("\n")
            )
        );
    }
}

/*
Test for missing files.

Since rs files are alphabetically before stderr/stdout, we can sort by the full name
and iter in that order. If we've seen the file stem for the first time and it's not
a rust file, it means the rust file has to be missing.
*/
fn explore_directory(dir: &Path) -> Vec<String> {
    let mut missing_files: Vec<String> = Vec::new();
    let mut current_file = String::new();
    let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect();
    files.sort_by_key(|e| e.path());
    for entry in &files {
        let path = entry.path();
        if path.is_dir() {
            missing_files.extend(explore_directory(&path));
        } else {
            let file_stem = path.file_stem().unwrap().to_str().unwrap().to_string();
            if let Some(ext) = path.extension() {
                match ext.to_str().unwrap() {
                    "rs" => current_file = file_stem.clone(),
                    "stderr" | "stdout" => {
                        if file_stem != current_file {
                            missing_files.push(path.to_str().unwrap().to_string());
                        }
                    },
                    _ => continue,
                };
            }
        }
    }
    missing_files
}
<|endoftext|>


<commit_before>extern crate failure;
#[macro_use]
extern crate failure_derive;
#[macro_use]
extern crate nom;
#[macro_use]
extern crate log;
pub mod errors;
pub mod keywords;
pub mod parser;
pub mod scc;
pub mod types;

use errors::{Error, Result};
use std::path::{Path, PathBuf};
use types::Config;

/// A builder for Config
///
/// # Example buld.rs
///
/// ```rust,no_run
/// extern crate pb_rs;
/// extern crate walkdir;
///
/// use pb_rs::{types::FileDescriptor, ConfigBuilder};
/// use std::path::{Path, PathBuf};
/// use walkdir::WalkDir;
///
/// fn main() {
///     let out_dir = std::env::var("OUT_DIR").unwrap();
///     let out_dir = Path::new(&out_dir).join("protos");
///
///     let in_dir = PathBuf::from(::std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("protos");
///     // Re-run this build.rs if the protos dir changes (i.e. a new file is added)
///     println!("cargo:rerun-if-changed={}", in_dir.to_str().unwrap());
///
///     // Find all *.proto files in the `in_dir` and add them to the list of files
///     let mut protos = Vec::new();
///     let proto_ext = Some(Path::new("proto").as_os_str());
///     for entry in WalkDir::new(&in_dir) {
///         let path = entry.unwrap().into_path();
///         if path.extension() == proto_ext {
///             // Re-run this build.rs if any of the files in the protos dir change
///             println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
///             protos.push(path);
///         }
///     }
///
///     // Delete all old generated files before re-generating new ones
///     if out_dir.exists() {
///         std::fs::remove_dir_all(&out_dir).unwrap();
///     }
///     std::fs::DirBuilder::new().create(&out_dir).unwrap();
///     let config_builder = ConfigBuilder::new(&protos, None, Some(&out_dir), &[in_dir]).unwrap();
///     FileDescriptor::run(&config_builder.build()).unwrap()
/// }
/// ```

#[derive(Debug, Default)]
pub struct ConfigBuilder {
    in_files: Vec<PathBuf>,
    out_file: Option<PathBuf>,
    include_paths: Vec<PathBuf>,
    single_module: bool,
    no_output: bool,
    error_cycle: bool,
    headers: bool,
    dont_use_cow: bool,
    custom_struct_derive: Vec<String>,
}

impl ConfigBuilder {
    pub fn new<P: AsRef<Path>>(
        in_files: &[P],
        output: Option<&P>,
        output_dir: Option<&P>,
        include_paths: &[P],
    ) -> Result<ConfigBuilder> {
        let in_files = in_files
            .iter()
            .map(|f| f.as_ref().into())
            .collect::<Vec<PathBuf>>();
        let output = output.map(|f| f.as_ref().into());
        let output_dir: Option<PathBuf> = output_dir.map(|f| f.as_ref().into());
        let mut include_paths = include_paths
            .iter()
            .map(|f| f.as_ref().into())
            .collect::<Vec<PathBuf>>();

        if in_files.is_empty() {
            return Err(Error::NoProto);
        }

        for f in &in_files {
            if !f.exists() {
                return Err(Error::InputFile(format!("{}", f.display())));
            }
        }

        let out_file = match (output, output_dir) {
            (Some(_), None) if in_files.len() > 1 => return Err(Error::OutputMultipleInputs),
            (Some(output), None) => Some(output),
            (None, Some(output_dir)) => {
                if !output_dir.is_dir() {
                    return Err(Error::OutputDirectory(format!("{}", output_dir.display())));
                }
                Some(output_dir)
            }
            (Some(_), Some(_)) => return Err(Error::OutputAndOutputDir),
            (None, None) => None,
        };

        let default = PathBuf::from(".");
        if include_paths.is_empty() || !include_paths.contains(&default) {
            include_paths.push(default);
        }

        Ok(ConfigBuilder {
            in_files: in_files,
            out_file: out_file,
            include_paths: include_paths,
            headers: true,
            ..Default::default()
        })
    }

    /// Omit generation of modules for each package when there is only one package
    pub fn single_module(mut self, val: bool) -> Self {
        self.single_module = val;
        self
    }

    /// Show enums and messages in this .proto file, including those imported. No code generated.
    /// `no_output` should probably only be used by the pb-rs cli.
    pub fn no_output(mut self, val: bool) -> Self {
        self.no_output = val;
        self
    }

    /// Error out if recursive messages do not have optional fields
    pub fn error_cycle(mut self, val: bool) -> Self {
        self.error_cycle = val;
        self
    }

    /// Enable module comments and module attributes in generated file (default = true)
    pub fn headers(mut self, val: bool) -> Self {
        self.headers = val;
        self
    }

    /// Add custom values to #[derive(...)] at the beginning of every structure
    pub fn custom_struct_derive(mut self, val: Vec<String>) -> Self {
        self.custom_struct_derive = val;
        self
    }

    /// Use Cow<_,_> for Strings and Bytes
    pub fn dont_use_cow(mut self, val: bool) -> Self {
        self.dont_use_cow = val;
        self
    }

    /// Build Config from this ConfigBuilder
    pub fn build(self) -> Vec<Config> {
        self.in_files
            .iter()
            .map(|in_file| {
                let mut out_file = in_file.with_extension("rs");

                if let Some(ref ofile) = self.out_file {
                    if ofile.is_dir() {
                        out_file = ofile.join(out_file.file_name().unwrap());
                    } else {
                        out_file = ofile.into();
                    }
                }

                Config {
                    in_file: in_file.to_owned(),
                    out_file: out_file,
                    import_search_path: self.include_paths.clone(),
                    single_module: self.single_module,
                    no_output: self.no_output,
                    error_cycle: self.error_cycle,
                    headers: self.headers,
                    dont_use_cow: self.dont_use_cow, //Change this to false to not use cow for v2 and v3 tests
                    custom_struct_derive: self.custom_struct_derive.clone(),
                    custom_rpc_generator: Box::new(|_,_| Ok(())),
                    custom_includes: Vec::new(),
                }
            })
            .collect()
    }
}
<commit_msg>Updated comment.<commit_after>extern crate failure;
#[macro_use]
extern crate failure_derive;
#[macro_use]
extern crate nom;
#[macro_use]
extern crate log;
pub mod errors;
pub mod keywords;
pub mod parser;
pub mod scc;
pub mod types;

use errors::{Error, Result};
use std::path::{Path, PathBuf};
use types::Config;

/// A builder for Config
///
/// # Example buld.rs
///
/// ```rust,no_run
/// extern crate pb_rs;
/// extern crate walkdir;
///
/// use pb_rs::{types::FileDescriptor, ConfigBuilder};
/// use std::path::{Path, PathBuf};
/// use walkdir::WalkDir;
///
/// fn main() {
///     let out_dir = std::env::var("OUT_DIR").unwrap();
///     let out_dir = Path::new(&out_dir).join("protos");
///
///     let in_dir = PathBuf::from(::std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("protos");
///     // Re-run this build.rs if the protos dir changes (i.e. a new file is added)
///     println!("cargo:rerun-if-changed={}", in_dir.to_str().unwrap());
///
///     // Find all *.proto files in the `in_dir` and add them to the list of files
///     let mut protos = Vec::new();
///     let proto_ext = Some(Path::new("proto").as_os_str());
///     for entry in WalkDir::new(&in_dir) {
///         let path = entry.unwrap().into_path();
///         if path.extension() == proto_ext {
///             // Re-run this build.rs if any of the files in the protos dir change
///             println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
///             protos.push(path);
///         }
///     }
///
///     // Delete all old generated files before re-generating new ones
///     if out_dir.exists() {
///         std::fs::remove_dir_all(&out_dir).unwrap();
///     }
///     std::fs::DirBuilder::new().create(&out_dir).unwrap();
///     let config_builder = ConfigBuilder::new(&protos, None, Some(&out_dir), &[in_dir]).unwrap();
///     FileDescriptor::run(&config_builder.build()).unwrap()
/// }
/// ```

#[derive(Debug, Default)]
pub struct ConfigBuilder {
    in_files: Vec<PathBuf>,
    out_file: Option<PathBuf>,
    include_paths: Vec<PathBuf>,
    single_module: bool,
    no_output: bool,
    error_cycle: bool,
    headers: bool,
    dont_use_cow: bool,
    custom_struct_derive: Vec<String>,
}

impl ConfigBuilder {
    pub fn new<P: AsRef<Path>>(
        in_files: &[P],
        output: Option<&P>,
        output_dir: Option<&P>,
        include_paths: &[P],
    ) -> Result<ConfigBuilder> {
        let in_files = in_files
            .iter()
            .map(|f| f.as_ref().into())
            .collect::<Vec<PathBuf>>();
        let output = output.map(|f| f.as_ref().into());
        let output_dir: Option<PathBuf> = output_dir.map(|f| f.as_ref().into());
        let mut include_paths = include_paths
            .iter()
            .map(|f| f.as_ref().into())
            .collect::<Vec<PathBuf>>();

        if in_files.is_empty() {
            return Err(Error::NoProto);
        }

        for f in &in_files {
            if !f.exists() {
                return Err(Error::InputFile(format!("{}", f.display())));
            }
        }

        let out_file = match (output, output_dir) {
            (Some(_), None) if in_files.len() > 1 => return Err(Error::OutputMultipleInputs),
            (Some(output), None) => Some(output),
            (None, Some(output_dir)) => {
                if !output_dir.is_dir() {
                    return Err(Error::OutputDirectory(format!("{}", output_dir.display())));
                }
                Some(output_dir)
            }
            (Some(_), Some(_)) => return Err(Error::OutputAndOutputDir),
            (None, None) => None,
        };

        let default = PathBuf::from(".");
        if include_paths.is_empty() || !include_paths.contains(&default) {
            include_paths.push(default);
        }

        Ok(ConfigBuilder {
            in_files: in_files,
            out_file: out_file,
            include_paths: include_paths,
            headers: true,
            ..Default::default()
        })
    }

    /// Omit generation of modules for each package when there is only one package
    pub fn single_module(mut self, val: bool) -> Self {
        self.single_module = val;
        self
    }

    /// Show enums and messages in this .proto file, including those imported. No code generated.
    /// `no_output` should probably only be used by the pb-rs cli.
    pub fn no_output(mut self, val: bool) -> Self {
        self.no_output = val;
        self
    }

    /// Error out if recursive messages do not have optional fields
    pub fn error_cycle(mut self, val: bool) -> Self {
        self.error_cycle = val;
        self
    }

    /// Enable module comments and module attributes in generated file (default = true)
    pub fn headers(mut self, val: bool) -> Self {
        self.headers = val;
        self
    }

    /// Add custom values to #[derive(...)] at the beginning of every structure
    pub fn custom_struct_derive(mut self, val: Vec<String>) -> Self {
        self.custom_struct_derive = val;
        self
    }

    /// Use Cow<_,_> for Strings and Bytes
    pub fn dont_use_cow(mut self, val: bool) -> Self {
        self.dont_use_cow = val;
        self
    }

    /// Build Config from this ConfigBuilder
    pub fn build(self) -> Vec<Config> {
        self.in_files
            .iter()
            .map(|in_file| {
                let mut out_file = in_file.with_extension("rs");

                if let Some(ref ofile) = self.out_file {
                    if ofile.is_dir() {
                        out_file = ofile.join(out_file.file_name().unwrap());
                    } else {
                        out_file = ofile.into();
                    }
                }

                Config {
                    in_file: in_file.to_owned(),
                    out_file: out_file,
                    import_search_path: self.include_paths.clone(),
                    single_module: self.single_module,
                    no_output: self.no_output,
                    error_cycle: self.error_cycle,
                    headers: self.headers,
                    dont_use_cow: self.dont_use_cow, //Change this to true to not use cow for v2 and v3 tests
                    custom_struct_derive: self.custom_struct_derive.clone(),
                    custom_rpc_generator: Box::new(|_,_| Ok(())),
                    custom_includes: Vec::new(),
                }
            })
            .collect()
    }
}
<|endoftext|>


<commit_before>extern crate protobuf;
extern crate grpc;
extern crate futures;
extern crate futures_cpupool;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate chrono;
extern crate clap;

pub mod empty;
pub mod messages;
pub mod test_grpc;

use chrono::*;
use clap::{App, Arg};

use empty::*;
use messages::{Payload, ResponseParameters, SimpleRequest,
               StreamingInputCallRequest, StreamingOutputCallRequest};
use test_grpc::*;

fn empty_unary(client: TestServiceClient) {
    client.EmptyCall(Empty::new()).expect("failed to get EmptyUnary result");
    println!("{} EmptyUnary done", Local::now().to_rfc3339());
}

// TODO: file a bug on this failure.
fn large_unary(client: TestServiceClient) {
    let mut payload = Payload::new();
    payload.set_body(vec![0; 271828]);
    let mut request = SimpleRequest::new();
    request.set_payload(payload);
    request.set_response_size(314159);
    let response = client.UnaryCall(request).expect("expected full frame");
    assert!(response.get_payload().body.len() == 314159);
    println!("{} LargeUnary done", Local::now().to_rfc3339());
}

fn client_streaming(client: TestServiceClient) {
    let mut requests = Vec::new();
    for size in [27182, 8, 1828, 45904].iter() {
        let mut request = StreamingInputCallRequest::new();
        let mut payload = Payload::new();
        payload.set_body(vec![0; size.to_owned()]);
        request.set_payload(payload);
        requests.push(Ok(request));
    }

    let response = client.StreamingInputCall(Box::new(requests.into_iter()))
        .expect("expected response");
    assert!(response.aggregated_payload_size == 74922);
    println!("{} ClientStreaming done", Local::now().to_rfc3339());
}

// TODO: test fails with an assertion error, we never see a response from the client.
// fails with 'expected a response: Other("partial frame")'
fn server_streaming(client: TestServiceClient) {
    let mut req = StreamingOutputCallRequest::new();
    let mut params = Vec::new();
    for &size in [31415, 9, 2653, 58979].iter() {
        let mut rp = ResponseParameters::new();
        rp.set_size(size as i32);
        params.push(rp);
    }
    req.set_response_parameters(::protobuf::RepeatedField::from_vec(params));

    let response_stream = client.StreamingOutputCall(req);

    let mut response_sizes = Vec::new();

    {
        // this scope is to satisfy the borrow checker.
        let bar = response_stream.map(|response| {
            response_sizes.push(response.expect("expected a response").get_payload().body.len());
        });
        assert!(bar.count() == 4);
    }

    assert!(response_sizes.len() == 4);
    assert!(response_sizes[0] == 31415);
    assert!(response_sizes[1] == 9);
    assert!(response_sizes[2] == 2653);
    assert!(response_sizes[3] == 58979);
    println!("{} ServerStreaming done", Local::now().to_rfc3339());
}

// TODO: this test needs to interleave requests with responses and check along the way.
// Need to find a way to model that with the blocking API.
fn ping_pong(client: TestServiceClient) {
    let mut requests = Vec::new();
    for &size_body_len in [(31415, 27182), (9, 8), (2653, 1828), (58979, 45904)].iter() {
        let mut req = StreamingOutputCallRequest::new();
        let mut params = ResponseParameters::new();
        params.set_size(size_body_len.0);
        req.set_response_parameters(::protobuf::RepeatedField::from_vec(vec![params]));
        let mut payload = Payload::new();
        payload.set_body(vec![0;size_body_len.1]);
        req.set_payload(payload);
        requests.push(Ok(req));
    }
    let response = client.FullDuplexCall(Box::new(requests.into_iter()));
    let mut response_sizes = Vec::new();
    {
        // this scope is to satisfy the borrow checker.
        let bar = response.map(|result| {
            response_sizes.push(result.unwrap().get_payload().body.len());
        });
        assert!(bar.count() == 4);
    }

    println!("response_sizes.len is {}", response_sizes.len());
    assert!(response_sizes.len() == 4);
    assert!(response_sizes[0] == 31415);
    assert!(response_sizes[1] == 9);
    assert!(response_sizes[2] == 2653);
    assert!(response_sizes[3] == 58979);
    println!("{} PingPong done", Local::now().to_rfc3339());
}

fn empty_stream(client: TestServiceClient) {
    let response = client.FullDuplexCall(Box::new(Vec::new().into_iter()));
    assert!(response.count() == 0);
    println!("{} EmptyStream done", Local::now().to_rfc3339());
}

// The flags we use are defined in the gRPC Interopability doc
// https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md
fn main() {
    drop(env_logger::init().unwrap());

    let options = App::new("gRPC interopability client")
        .version("0.1")
        .author("Steve Jenson <stevej@buoyant.io>")
        .about("Interoperability Test Client for grpc-rust")
        .arg(Arg::with_name("server_host")
            .long("server_host")
            .help("The server host to connect to. For example, \"localhost\" or \"127.0.0.1\"")
            .takes_value(true))
        .arg(Arg::with_name("server_host_override")
            .long("server_host_override")
            .help("The server host to claim to be connecting to, for use in TLS and HTTP/2 \
                   :authority header. If unspecified, the value of --server_host will be used")
            .takes_value(true))
        .arg(Arg::with_name("server_port")
            .long("server_port")
            .help("The server port to connect to. For example, \"8080\"")
            .takes_value(true))
        .arg(Arg::with_name("test_case")
            .long("test_case")
            .help("The name of the test case to execute. For example, \"empty_unary\"")
            .takes_value(true))
        .arg(Arg::with_name("use_tls") // boolean
            .long("use_tls")
            .help("Whether to use a plaintext or encrypted connection")
            .takes_value(true))
        .arg(Arg::with_name("use_test_ca")
            .long("use_test_ca")
            .help("Whether to replace platform root CAs with ca.pem as the CA root")
            .takes_value(true))
        .arg(Arg::with_name("default_service_account")
            .long("default_service_account")
            .help("Email of the GCE default service account.")
            .takes_value(true))
        .arg(Arg::with_name("oauth_scope")
            .long("oauth_scope")
            .help("OAuth scope. For example, \"https://www.googleapis.com/auth/xapi.zoo\"")
            .takes_value(true))
        .arg(Arg::with_name("service_account_key_file")
            .long("service_account_key_file")
            .help("The path to the service account JSON key file generated from GCE developer \
                   console.")
            .takes_value(true))
        .get_matches();

    let hostname = options.value_of("server_host").unwrap_or("localhost");
    let serverport = options.value_of("server_port").unwrap_or("60011").parse::<u16>().unwrap();

    let client = TestServiceClient::new(hostname, serverport, false, Default::default())
        .expect("init");

    let testcase = options.value_of("test_case").unwrap_or("");
    match testcase.as_ref() {
        "empty_unary" => empty_unary(client),
        "cacheable_unary" => println!("cacheable_unary not done yet"),
        "large_unary" => large_unary(client),
        "client_compressed_unary" => println!("client_compressed_unary not done yet"),
        "server_compressed_unary" => println!("server_compressed_unary not done yet"),
        "client_streaming" => client_streaming(client),
        "client_compressed_streaming" => println!("client_compressed_streaming not done yet"),
        "server_streaming" => server_streaming(client),
        "server_compressed_streaming" => println!("server_compressed_streaming not done yet"),
        "ping_pong" => ping_pong(client),
        "empty_stream" => empty_stream(client),
        "compute_engine_creds" => println!("compute_engine_creds not done yet"),
        "jwt_token_creds" => println!("jwt_token_creds not done yet"),
        "oauth2_auth_token" => println!("oauth2_auth_token not done yet"),
        "per_rpc_creds" => println!("per_rpc_creds not done yet"),
        "custom_metadata" => println!("custom_metadata not done yet"),
        "status_code_and_message" => println!("status_code_and_message not done yet"),
        "unimplemented_method" => println!("unimplemented_method not done yet"),
        "unimplemented_service" => println!("unimplemented_service not done yet"),
        "cancel_after_begin" => println!("cancel_after_begin not done yet"),
        "cancel_after_first_response" => println!("cancel_after_first_response not done yet"),
        "timeout_on_sleeping_server" => println!("timeout_on_sleeping_server not done yet"),
        _ => println!("no test_case specified"),
    }
}<commit_msg>Add missing trailing newline<commit_after>extern crate protobuf;
extern crate grpc;
extern crate futures;
extern crate futures_cpupool;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate chrono;
extern crate clap;

pub mod empty;
pub mod messages;
pub mod test_grpc;

use chrono::*;
use clap::{App, Arg};

use empty::*;
use messages::{Payload, ResponseParameters, SimpleRequest,
               StreamingInputCallRequest, StreamingOutputCallRequest};
use test_grpc::*;

fn empty_unary(client: TestServiceClient) {
    client.EmptyCall(Empty::new()).expect("failed to get EmptyUnary result");
    println!("{} EmptyUnary done", Local::now().to_rfc3339());
}

// TODO: file a bug on this failure.
fn large_unary(client: TestServiceClient) {
    let mut payload = Payload::new();
    payload.set_body(vec![0; 271828]);
    let mut request = SimpleRequest::new();
    request.set_payload(payload);
    request.set_response_size(314159);
    let response = client.UnaryCall(request).expect("expected full frame");
    assert!(response.get_payload().body.len() == 314159);
    println!("{} LargeUnary done", Local::now().to_rfc3339());
}

fn client_streaming(client: TestServiceClient) {
    let mut requests = Vec::new();
    for size in [27182, 8, 1828, 45904].iter() {
        let mut request = StreamingInputCallRequest::new();
        let mut payload = Payload::new();
        payload.set_body(vec![0; size.to_owned()]);
        request.set_payload(payload);
        requests.push(Ok(request));
    }

    let response = client.StreamingInputCall(Box::new(requests.into_iter()))
        .expect("expected response");
    assert!(response.aggregated_payload_size == 74922);
    println!("{} ClientStreaming done", Local::now().to_rfc3339());
}

// TODO: test fails with an assertion error, we never see a response from the client.
// fails with 'expected a response: Other("partial frame")'
fn server_streaming(client: TestServiceClient) {
    let mut req = StreamingOutputCallRequest::new();
    let mut params = Vec::new();
    for &size in [31415, 9, 2653, 58979].iter() {
        let mut rp = ResponseParameters::new();
        rp.set_size(size as i32);
        params.push(rp);
    }
    req.set_response_parameters(::protobuf::RepeatedField::from_vec(params));

    let response_stream = client.StreamingOutputCall(req);

    let mut response_sizes = Vec::new();

    {
        // this scope is to satisfy the borrow checker.
        let bar = response_stream.map(|response| {
            response_sizes.push(response.expect("expected a response").get_payload().body.len());
        });
        assert!(bar.count() == 4);
    }

    assert!(response_sizes.len() == 4);
    assert!(response_sizes[0] == 31415);
    assert!(response_sizes[1] == 9);
    assert!(response_sizes[2] == 2653);
    assert!(response_sizes[3] == 58979);
    println!("{} ServerStreaming done", Local::now().to_rfc3339());
}

// TODO: this test needs to interleave requests with responses and check along the way.
// Need to find a way to model that with the blocking API.
fn ping_pong(client: TestServiceClient) {
    let mut requests = Vec::new();
    for &size_body_len in [(31415, 27182), (9, 8), (2653, 1828), (58979, 45904)].iter() {
        let mut req = StreamingOutputCallRequest::new();
        let mut params = ResponseParameters::new();
        params.set_size(size_body_len.0);
        req.set_response_parameters(::protobuf::RepeatedField::from_vec(vec![params]));
        let mut payload = Payload::new();
        payload.set_body(vec![0;size_body_len.1]);
        req.set_payload(payload);
        requests.push(Ok(req));
    }
    let response = client.FullDuplexCall(Box::new(requests.into_iter()));
    let mut response_sizes = Vec::new();
    {
        // this scope is to satisfy the borrow checker.
        let bar = response.map(|result| {
            response_sizes.push(result.unwrap().get_payload().body.len());
        });
        assert!(bar.count() == 4);
    }

    println!("response_sizes.len is {}", response_sizes.len());
    assert!(response_sizes.len() == 4);
    assert!(response_sizes[0] == 31415);
    assert!(response_sizes[1] == 9);
    assert!(response_sizes[2] == 2653);
    assert!(response_sizes[3] == 58979);
    println!("{} PingPong done", Local::now().to_rfc3339());
}

fn empty_stream(client: TestServiceClient) {
    let response = client.FullDuplexCall(Box::new(Vec::new().into_iter()));
    assert!(response.count() == 0);
    println!("{} EmptyStream done", Local::now().to_rfc3339());
}

// The flags we use are defined in the gRPC Interopability doc
// https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md
fn main() {
    drop(env_logger::init().unwrap());

    let options = App::new("gRPC interopability client")
        .version("0.1")
        .author("Steve Jenson <stevej@buoyant.io>")
        .about("Interoperability Test Client for grpc-rust")
        .arg(Arg::with_name("server_host")
            .long("server_host")
            .help("The server host to connect to. For example, \"localhost\" or \"127.0.0.1\"")
            .takes_value(true))
        .arg(Arg::with_name("server_host_override")
            .long("server_host_override")
            .help("The server host to claim to be connecting to, for use in TLS and HTTP/2 \
                   :authority header. If unspecified, the value of --server_host will be used")
            .takes_value(true))
        .arg(Arg::with_name("server_port")
            .long("server_port")
            .help("The server port to connect to. For example, \"8080\"")
            .takes_value(true))
        .arg(Arg::with_name("test_case")
            .long("test_case")
            .help("The name of the test case to execute. For example, \"empty_unary\"")
            .takes_value(true))
        .arg(Arg::with_name("use_tls") // boolean
            .long("use_tls")
            .help("Whether to use a plaintext or encrypted connection")
            .takes_value(true))
        .arg(Arg::with_name("use_test_ca")
            .long("use_test_ca")
            .help("Whether to replace platform root CAs with ca.pem as the CA root")
            .takes_value(true))
        .arg(Arg::with_name("default_service_account")
            .long("default_service_account")
            .help("Email of the GCE default service account.")
            .takes_value(true))
        .arg(Arg::with_name("oauth_scope")
            .long("oauth_scope")
            .help("OAuth scope. For example, \"https://www.googleapis.com/auth/xapi.zoo\"")
            .takes_value(true))
        .arg(Arg::with_name("service_account_key_file")
            .long("service_account_key_file")
            .help("The path to the service account JSON key file generated from GCE developer \
                   console.")
            .takes_value(true))
        .get_matches();

    let hostname = options.value_of("server_host").unwrap_or("localhost");
    let serverport = options.value_of("server_port").unwrap_or("60011").parse::<u16>().unwrap();

    let client = TestServiceClient::new(hostname, serverport, false, Default::default())
        .expect("init");

    let testcase = options.value_of("test_case").unwrap_or("");
    match testcase.as_ref() {
        "empty_unary" => empty_unary(client),
        "cacheable_unary" => println!("cacheable_unary not done yet"),
        "large_unary" => large_unary(client),
        "client_compressed_unary" => println!("client_compressed_unary not done yet"),
        "server_compressed_unary" => println!("server_compressed_unary not done yet"),
        "client_streaming" => client_streaming(client),
        "client_compressed_streaming" => println!("client_compressed_streaming not done yet"),
        "server_streaming" => server_streaming(client),
        "server_compressed_streaming" => println!("server_compressed_streaming not done yet"),
        "ping_pong" => ping_pong(client),
        "empty_stream" => empty_stream(client),
        "compute_engine_creds" => println!("compute_engine_creds not done yet"),
        "jwt_token_creds" => println!("jwt_token_creds not done yet"),
        "oauth2_auth_token" => println!("oauth2_auth_token not done yet"),
        "per_rpc_creds" => println!("per_rpc_creds not done yet"),
        "custom_metadata" => println!("custom_metadata not done yet"),
        "status_code_and_message" => println!("status_code_and_message not done yet"),
        "unimplemented_method" => println!("unimplemented_method not done yet"),
        "unimplemented_service" => println!("unimplemented_service not done yet"),
        "cancel_after_begin" => println!("cancel_after_begin not done yet"),
        "cancel_after_first_response" => println!("cancel_after_first_response not done yet"),
        "timeout_on_sleeping_server" => println!("timeout_on_sleeping_server not done yet"),
        _ => println!("no test_case specified"),
    }
}
<|endoftext|>


<commit_before>use super::{general::doc_hidden, property_body};
use crate::{
    analysis::{
        child_properties::ChildProperty,
        rust_type::{parameter_rust_type, rust_type},
    },
    chunk::Chunk,
    env::Env,
    library,
    traits::IntoString,
    writer::{primitives::tabs, ToCode},
};
use std::io::{Result, Write};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    prop: &ChildProperty,
    in_trait: bool,
    only_declaration: bool,
    indent: usize,
) -> Result<()> {
    generate_func(w, env, prop, in_trait, only_declaration, indent, true)?;
    generate_func(w, env, prop, in_trait, only_declaration, indent, false)?;

    Ok(())
}

fn generate_func(
    w: &mut dyn Write,
    env: &Env,
    prop: &ChildProperty,
    in_trait: bool,
    only_declaration: bool,
    indent: usize,
    is_get: bool,
) -> Result<()> {
    let pub_prefix = if in_trait { "" } else { "pub " };
    let decl_suffix = if only_declaration { ";" } else { " {" };
    let type_string = rust_type(env, prop.typ);
    let comment_prefix = if type_string.is_err() { "//" } else { "" };

    writeln!(w)?;

    doc_hidden(w, prop.doc_hidden, comment_prefix, indent)?;
    // FIXME handle doc alias
    let decl = declaration(env, prop, is_get);
    writeln!(
        w,
        "{}{}{}{}{}",
        tabs(indent),
        comment_prefix,
        pub_prefix,
        decl,
        decl_suffix
    )?;

    if !only_declaration {
        let body = body(env, prop, in_trait, is_get).to_code(env);
        for s in body {
            writeln!(w, "{}{}{}", tabs(indent), comment_prefix, s)?;
        }
    }

    Ok(())
}

fn declaration(env: &Env, prop: &ChildProperty, is_get: bool) -> String {
    let func_name = if is_get {
        format!("{}_{}", prop.child_name, prop.getter_name)
    } else {
        format!("set_{}_{}", prop.child_name, prop.prop_name)
    };
    let mut bounds = if let Some(typ) = prop.child_type {
        let child_type = rust_type(env, typ).into_string();
        format!("T: IsA<{}>", child_type)
    } else {
        "T: IsA<Widget>".to_string()
    };
    if !is_get && !prop.bounds.is_empty() {
        bounds = format!("{}, {}", prop.bounds, bounds);
    }
    let return_str = if is_get {
        let dir = library::ParameterDirection::Return;
        let ret_type = parameter_rust_type(
            env,
            prop.typ,
            dir,
            prop.nullable,
            prop.get_out_ref_mode,
            library::ParameterScope::None,
        )
        .into_string();
        format!(" -> {}", ret_type)
    } else {
        "".to_string()
    };
    format!(
        "fn {}<{}>(&self, item: &T{}){}",
        func_name,
        bounds,
        if is_get {
            "".to_owned()
        } else {
            format!(", {}", prop.set_params)
        },
        return_str
    )
}

fn body(env: &Env, prop: &ChildProperty, in_trait: bool, is_get: bool) -> Chunk {
    let mut builder = property_body::Builder::new_for_child_property(env);
    builder
        .name(&prop.name)
        .in_trait(in_trait)
        .var_name(&prop.prop_name)
        .is_get(is_get)
        .is_ref(prop.set_in_ref_mode.is_ref())
        .is_nullable(*prop.nullable);

    if let Ok(type_) = rust_type(env, prop.typ) {
        builder.type_(&type_);
    } else {
        builder.type_("/*Unknown type*/");
    }

    builder.generate()
}
<commit_msg>codegen: add child prop doc-aliases<commit_after>use super::{
    general::{doc_alias, doc_hidden},
    property_body,
};
use crate::{
    analysis::{
        child_properties::ChildProperty,
        rust_type::{parameter_rust_type, rust_type},
    },
    chunk::Chunk,
    env::Env,
    library,
    traits::IntoString,
    writer::{primitives::tabs, ToCode},
};
use std::io::{Result, Write};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    prop: &ChildProperty,
    in_trait: bool,
    only_declaration: bool,
    indent: usize,
) -> Result<()> {
    generate_func(w, env, prop, in_trait, only_declaration, indent, true)?;
    generate_func(w, env, prop, in_trait, only_declaration, indent, false)?;

    Ok(())
}

fn generate_func(
    w: &mut dyn Write,
    env: &Env,
    prop: &ChildProperty,
    in_trait: bool,
    only_declaration: bool,
    indent: usize,
    is_get: bool,
) -> Result<()> {
    let pub_prefix = if in_trait { "" } else { "pub " };
    let decl_suffix = if only_declaration { ";" } else { " {" };
    let type_string = rust_type(env, prop.typ);
    let comment_prefix = if type_string.is_err() { "//" } else { "" };

    writeln!(w)?;

    doc_hidden(w, prop.doc_hidden, comment_prefix, indent)?;
    let decl = declaration(env, prop, is_get);
    if !in_trait || only_declaration {
        let add_doc_alias = if is_get {
            prop.name != prop.getter_name && prop.name != prop.prop_name
        } else {
            prop.name != prop.prop_name
        };
        if add_doc_alias {
            doc_alias(
                w,
                &format!("{}.{}", &prop.child_name, &prop.name),
                comment_prefix,
                indent,
            )?;
        }
    }
    writeln!(
        w,
        "{}{}{}{}{}",
        tabs(indent),
        comment_prefix,
        pub_prefix,
        decl,
        decl_suffix
    )?;

    if !only_declaration {
        let body = body(env, prop, in_trait, is_get).to_code(env);
        for s in body {
            writeln!(w, "{}{}{}", tabs(indent), comment_prefix, s)?;
        }
    }

    Ok(())
}

fn declaration(env: &Env, prop: &ChildProperty, is_get: bool) -> String {
    let func_name = if is_get {
        format!("{}_{}", prop.child_name, prop.getter_name)
    } else {
        format!("set_{}_{}", prop.child_name, prop.prop_name)
    };
    let mut bounds = if let Some(typ) = prop.child_type {
        let child_type = rust_type(env, typ).into_string();
        format!("T: IsA<{}>", child_type)
    } else {
        "T: IsA<Widget>".to_string()
    };
    if !is_get && !prop.bounds.is_empty() {
        bounds = format!("{}, {}", prop.bounds, bounds);
    }
    let return_str = if is_get {
        let dir = library::ParameterDirection::Return;
        let ret_type = parameter_rust_type(
            env,
            prop.typ,
            dir,
            prop.nullable,
            prop.get_out_ref_mode,
            library::ParameterScope::None,
        )
        .into_string();
        format!(" -> {}", ret_type)
    } else {
        "".to_string()
    };
    format!(
        "fn {}<{}>(&self, item: &T{}){}",
        func_name,
        bounds,
        if is_get {
            "".to_owned()
        } else {
            format!(", {}", prop.set_params)
        },
        return_str
    )
}

fn body(env: &Env, prop: &ChildProperty, in_trait: bool, is_get: bool) -> Chunk {
    let mut builder = property_body::Builder::new_for_child_property(env);
    builder
        .name(&prop.name)
        .in_trait(in_trait)
        .var_name(&prop.prop_name)
        .is_get(is_get)
        .is_ref(prop.set_in_ref_mode.is_ref())
        .is_nullable(*prop.nullable);

    if let Ok(type_) = rust_type(env, prop.typ) {
        builder.type_(&type_);
    } else {
        builder.type_("/*Unknown type*/");
    }

    builder.generate()
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use super::{Drawable, BoundingBox, MeasureMode};
use ::platform::Context;
use ::paint::{Canvas, Point, Rect};
use std::cmp::Ordering;
use std::slice::{Iter, IterMut};

pub struct AbsoluteLayout<'a> {
    children: Vec<Child<'a>>,
    bounding_box: BoundingBox,

    baseline: Option<f32>,
    axis: Option<f32>,
}

pub struct Child<'a> {
    drawable: Box<Drawable+'a>,
    params: AbsoluteLayoutParams
}

pub struct AbsoluteLayoutParams {
    position: Point
}

impl AbsoluteLayoutParams {
    pub fn new(point: Point) -> AbsoluteLayoutParams {
        AbsoluteLayoutParams { position: point }
    }
}

impl<'a> Drawable for AbsoluteLayout<'a> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        for child in &self.children {
            child.drawable.draw(canvas, &(pen_pos+&child.params.position))
        }
    }

    fn calculate(&mut self, _: &Context, _: f32, _: &MeasureMode, _: f32,
                 _: &MeasureMode) {
        let end_x_calc = |child: &Child|
            child.drawable.bounding_box().width() + child.params.position.x();

        let width = self.children.iter().max_by(|c1, c2| {
            end_x_calc(*c1).partial_cmp(&end_x_calc(*c2)).unwrap_or(Ordering::Less)
        }).and_then(|c| {
            Some(end_x_calc(c))
        }).unwrap_or(0f32);

        let end_y_calc = |child: &Child|
            child.drawable.bounding_box().height() + child.params.position.y();

        let height = self.children.iter().max_by(|c1, c2| {
            end_y_calc(*c1).partial_cmp(&end_y_calc(*c2)).unwrap_or(Ordering::Less)
        }).and_then(|c| {
            Some(end_y_calc(c))
        }).unwrap_or(0f32);

        self.bounding_box = BoundingBox {
            rect: Rect::new(width, height),
            baseline: self.baseline.unwrap_or(height),
            axis: self.axis.unwrap_or(height/2f32),
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl<'a> AbsoluteLayout<'a> {
    pub fn new() -> AbsoluteLayout<'a> {
        AbsoluteLayout {
            children: Vec::new(),
            bounding_box: BoundingBox::default(),
            baseline: None,
            axis: None,
        }
    }

    pub fn add_child(&mut self, child: Box<Drawable + 'a>, params: AbsoluteLayoutParams) {
        self.children.push(Child { drawable: child, params });
    }

    pub fn remove_child_at(&mut self, index: usize) {
        self.children.remove(index);
    }

    pub fn clear(&mut self) {
        self.children.clear();
    }

    pub fn set_baseline(&mut self, baseline: Option<f32>) {
        self.baseline = baseline;
    }

    pub fn set_axis(&mut self, axis: Option<f32>) {
        self.axis = axis;
    }

    pub fn set_child_params(&mut self, index: usize, params: AbsoluteLayoutParams) {
        if let Some(val) = self.children.get_mut(index) {
            val.params = params;
        }
    }

    pub fn iter(&self) -> Iter<Child<'a>> {
        self.children.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<Child<'a>> {
        self.children.iter_mut()
    }
}<commit_msg>Fix absolute layout not calculating child bounds<commit_after>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use super::{Drawable, BoundingBox, MeasureMode};
use ::platform::Context;
use ::paint::{Canvas, Point, Rect};
use std::cmp::Ordering;
use std::slice::{Iter, IterMut};

pub struct AbsoluteLayout<'a> {
    children: Vec<Child<'a>>,
    bounding_box: BoundingBox,

    baseline: Option<f32>,
    axis: Option<f32>,
}

pub struct Child<'a> {
    drawable: Box<Drawable+'a>,
    params: AbsoluteLayoutParams
}

pub struct AbsoluteLayoutParams {
    position: Point
}

impl AbsoluteLayoutParams {
    pub fn new(point: Point) -> AbsoluteLayoutParams {
        AbsoluteLayoutParams { position: point }
    }
}

impl<'a> Drawable for AbsoluteLayout<'a> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        for child in &self.children {
            child.drawable.draw(canvas, &(pen_pos+&child.params.position))
        }
    }

    fn calculate(&mut self, context: &Context, _: f32, _: &MeasureMode, _: f32,
                 _: &MeasureMode) {
        for child in self.children.iter_mut() {
            child.drawable.calculate(context, -1., &MeasureMode::Wrap, -1.,
                                     &MeasureMode::Wrap);
        }

        let end_x_calc = |child: &Child|
            child.drawable.bounding_box().width() + child.params.position.x();

        let width = self.children.iter().max_by(|c1, c2| {
            end_x_calc(*c1).partial_cmp(&end_x_calc(*c2)).unwrap_or(Ordering::Less)
        }).and_then(|c| {
            Some(end_x_calc(c))
        }).unwrap_or(0f32);

        let end_y_calc = |child: &Child|
            child.drawable.bounding_box().height() + child.params.position.y();

        let height = self.children.iter().max_by(|c1, c2| {
            end_y_calc(*c1).partial_cmp(&end_y_calc(*c2)).unwrap_or(Ordering::Less)
        }).and_then(|c| {
            Some(end_y_calc(c))
        }).unwrap_or(0f32);

        self.bounding_box = BoundingBox {
            rect: Rect::new(width, height),
            baseline: self.baseline.unwrap_or(height),
            axis: self.axis.unwrap_or(height/2f32),
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl<'a> AbsoluteLayout<'a> {
    pub fn new() -> AbsoluteLayout<'a> {
        AbsoluteLayout {
            children: Vec::new(),
            bounding_box: BoundingBox::default(),
            baseline: None,
            axis: None,
        }
    }

    pub fn add_child(&mut self, child: Box<Drawable + 'a>, params: AbsoluteLayoutParams) {
        self.children.push(Child { drawable: child, params });
    }

    pub fn remove_child_at(&mut self, index: usize) {
        self.children.remove(index);
    }

    pub fn clear(&mut self) {
        self.children.clear();
    }

    pub fn set_baseline(&mut self, baseline: Option<f32>) {
        self.baseline = baseline;
    }

    pub fn set_axis(&mut self, axis: Option<f32>) {
        self.axis = axis;
    }

    pub fn set_child_params(&mut self, index: usize, params: AbsoluteLayoutParams) {
        if let Some(val) = self.children.get_mut(index) {
            val.params = params;
        }
    }

    pub fn iter(&self) -> Iter<Child<'a>> {
        self.children.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<Child<'a>> {
        self.children.iter_mut()
    }
}<|endoftext|>


<commit_before>/// Maximum order of the fixed predictors permitted by the format.
pub const MAX_FIXED_ORDER: usize = 4;

/// Maximum LPC order permitted by the format.
pub const MAX_LPC_ORDER: usize   = 32;

/// A single channel of audio data.
pub struct SubFrame {
  /// Data containing one of the four different types of subframes.
  pub data: Data,
  /// Number of wasted bits within each sample.
  pub wasted_bits: u32,
}

/// General enum that holds all the different subframe data types.
#[derive(Debug, PartialEq, Eq)]
pub enum Data {
  /// A single value that represents a constant subframe.
  Constant(i32),
  /// An uncompressed suframe.
  Verbatim(Vec<i32>),
  /// Fixed linear prediction subframe.
  Fixed(Fixed),
  /// FIR linear prediction subframe.
  LPC(LPC),
}

/// Fixed linear prediction subframe.
#[derive(Debug, PartialEq, Eq)]
pub struct Fixed {
  /// Residual coding method.
  pub entropy_coding_method: EntropyCodingMethod,
  /// Polynomial order.
  pub order: u8,
  /// Samples used to warm up, or prime, the predictor.
  pub warmup: [i32; MAX_FIXED_ORDER],
  /// Remaining samples after the warm up samples.
  pub residual: Vec<i32>,
}

/// Finite Impulse Response (FIR) linear prediction subframe.
#[derive(Debug, PartialEq, Eq)]
pub struct LPC {
  /// Residual coding method.
  pub entropy_coding_method: EntropyCodingMethod,
  /// FIR order.
  pub order: u8,
  /// Quantized FIR filter coefficient precision in bits.
  pub qlp_coeff_precision: u8,
  /// Quantized linear predictor coefficient shift needed in bits.
  pub quantization_level: i8,
  /// FIR filter coefficients.
  pub qlp_coefficients: [i32; MAX_LPC_ORDER],
  /// Samples used to warm up, or prime, the predictor.
  pub warmup: [i32; MAX_LPC_ORDER],
  /// Remaining samples after the warm up samples.
  pub residual: Vec<i32>,
}

/// Header for the entropy coding method.
#[derive(Debug, PartialEq, Eq)]
pub struct EntropyCodingMethod {
  pub method_type: CodingMethod,
  pub data: PartitionedRice,
}

/// The available entropy coding methods.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CodingMethod {
  PartitionedRice,
  PartitionedRice2,
}

/// Header for a Rice partitioned residual.
#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRice {
  pub order: u32,
  pub contents: PartitionedRiceContents,
}

/// Contents of a Rice partitioned residual.
#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRiceContents {
  pub parameters: Vec<u32>,
  pub raw_bits: Vec<u32>,
  pub capacity_by_order: u32,
}

impl PartitionedRiceContents {
  pub fn new(capacity_by_order: u32) -> PartitionedRiceContents {
    let capacity       = 2_usize.pow(capacity_by_order);
    let mut parameters = Vec::with_capacity(capacity);
    let mut raw_bits   = Vec::with_capacity(capacity);

    unsafe {
      parameters.set_len(capacity);
      raw_bits.set_len(capacity);
    }

    PartitionedRiceContents {
      parameters: parameters,
      raw_bits: raw_bits,
      capacity_by_order: capacity_by_order,
    }
  }
}
<commit_msg>Remove `capacity_by_order` field<commit_after>/// Maximum order of the fixed predictors permitted by the format.
pub const MAX_FIXED_ORDER: usize = 4;

/// Maximum LPC order permitted by the format.
pub const MAX_LPC_ORDER: usize   = 32;

/// A single channel of audio data.
pub struct SubFrame {
  /// Data containing one of the four different types of subframes.
  pub data: Data,
  /// Number of wasted bits within each sample.
  pub wasted_bits: u32,
}

/// General enum that holds all the different subframe data types.
#[derive(Debug, PartialEq, Eq)]
pub enum Data {
  /// A single value that represents a constant subframe.
  Constant(i32),
  /// An uncompressed suframe.
  Verbatim(Vec<i32>),
  /// Fixed linear prediction subframe.
  Fixed(Fixed),
  /// FIR linear prediction subframe.
  LPC(LPC),
}

/// Fixed linear prediction subframe.
#[derive(Debug, PartialEq, Eq)]
pub struct Fixed {
  /// Residual coding method.
  pub entropy_coding_method: EntropyCodingMethod,
  /// Polynomial order.
  pub order: u8,
  /// Samples used to warm up, or prime, the predictor.
  pub warmup: [i32; MAX_FIXED_ORDER],
  /// Remaining samples after the warm up samples.
  pub residual: Vec<i32>,
}

/// Finite Impulse Response (FIR) linear prediction subframe.
#[derive(Debug, PartialEq, Eq)]
pub struct LPC {
  /// Residual coding method.
  pub entropy_coding_method: EntropyCodingMethod,
  /// FIR order.
  pub order: u8,
  /// Quantized FIR filter coefficient precision in bits.
  pub qlp_coeff_precision: u8,
  /// Quantized linear predictor coefficient shift needed in bits.
  pub quantization_level: i8,
  /// FIR filter coefficients.
  pub qlp_coefficients: [i32; MAX_LPC_ORDER],
  /// Samples used to warm up, or prime, the predictor.
  pub warmup: [i32; MAX_LPC_ORDER],
  /// Remaining samples after the warm up samples.
  pub residual: Vec<i32>,
}

/// Header for the entropy coding method.
#[derive(Debug, PartialEq, Eq)]
pub struct EntropyCodingMethod {
  pub method_type: CodingMethod,
  pub data: PartitionedRice,
}

/// The available entropy coding methods.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CodingMethod {
  PartitionedRice,
  PartitionedRice2,
}

/// Header for a Rice partitioned residual.
#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRice {
  pub order: u32,
  pub contents: PartitionedRiceContents,
}

/// Contents of a Rice partitioned residual.
#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRiceContents {
  pub parameters: Vec<u32>,
  pub raw_bits: Vec<u32>,
}

impl PartitionedRiceContents {
  pub fn new(capacity: usize) -> PartitionedRiceContents {
    let mut parameters = Vec::with_capacity(capacity);
    let mut raw_bits   = Vec::with_capacity(capacity);

    unsafe {
      parameters.set_len(capacity);
      raw_bits.set_len(capacity);
    }

    PartitionedRiceContents {
      parameters: parameters,
      raw_bits: raw_bits,
    }
  }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use eutil::slice_to_str;
use libc::{c_int};
use std::collections::TreeMap;
use std::mem;
use std::string::String;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_multimap_t,cef_string_t};

fn string_multimap_to_treemap(smm: *mut cef_string_multimap_t) -> *mut TreeMap<String, Vec<*mut cef_string_t>> {
    smm as *mut TreeMap<String, Vec<*mut cef_string_t>>
}

//cef_string_multimap

#[no_mangle]
pub extern "C" fn cef_string_multimap_alloc() -> *mut cef_string_multimap_t {
    unsafe {
         let smm: Box<TreeMap<String, Vec<*mut cef_string_t>>> = box TreeMap::new();
         mem::transmute(smm)
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_size(smm: *mut cef_string_multimap_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let mut c: c_int = 0;
        let v = string_multimap_to_treemap(smm);
        for (_, val) in (*v).iter() {
            c = c + (*val).len() as c_int;
        }
        c
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_find_count(smm: *mut cef_string_multimap_t, key: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    s.len() as c_int
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_append(smm: *mut cef_string_multimap_t, key: *const cef_string_t, value: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            let s = String::from_str(result);
            let csv = cef_string_userfree_utf8_alloc();
            cef_string_utf8_set((*value).str as *const u8, (*value).length, csv, 1);
            match (*v).find_mut(&s) {
                Some(vc) => {
                    (*vc).push(csv);
                    1
                }
                None => {
                    let vc = vec!(csv);
                    (*v).insert(s, vc);
                    1
                }
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_enumerate(smm: *mut cef_string_multimap_t, key: *const cef_string_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    if (*s).len() <= index as uint {
                        return 0;
                    }
                    let cs = (*s)[index as uint];
                    cef_string_utf8_set((*cs).str as *const u8, (*cs).length, value, 1)
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_key(smm: *mut cef_string_multimap_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        let mut rem = index as uint;

        for (key, val) in (*v).iter() {
            if rem < (*val).len() {
                return cef_string_utf8_set((*key).as_bytes().as_ptr(), (*key).len() as u64, value, 1);
            } else {
                rem = rem - (*val).len();
            }
        }
    }
    0
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_value(smm: *mut cef_string_multimap_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        let mut rem = index as uint;

        for (_, val) in (*v).values().enumerate() {
            if rem < (*val).len() {
                let cs = (*val)[rem as uint];
                return cef_string_utf8_set((*cs).str as *const u8, (*cs).length, value, 1);
            } else {
                rem = rem - (*val).len();
            }
        }
    }
    0
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_clear(smm: *mut cef_string_multimap_t) {
    unsafe {
        if smm.is_null() { return; }
        let v = string_multimap_to_treemap(smm);
        if (*v).len() == 0 { return; }
        for (_, val) in (*v).iter_mut() {
            while (*val).len() != 0 {
                let cs = (*val).pop();
                cef_string_userfree_utf8_free(cs.unwrap());
            }
        }
        (*v).clear();
    }
}
<commit_msg>embedding: cef_string_multimap_free()<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use eutil::slice_to_str;
use libc::{c_int};
use std::collections::TreeMap;
use std::mem;
use std::string::String;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_multimap_t,cef_string_t};

fn string_multimap_to_treemap(smm: *mut cef_string_multimap_t) -> *mut TreeMap<String, Vec<*mut cef_string_t>> {
    smm as *mut TreeMap<String, Vec<*mut cef_string_t>>
}

//cef_string_multimap

#[no_mangle]
pub extern "C" fn cef_string_multimap_alloc() -> *mut cef_string_multimap_t {
    unsafe {
         let smm: Box<TreeMap<String, Vec<*mut cef_string_t>>> = box TreeMap::new();
         mem::transmute(smm)
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_size(smm: *mut cef_string_multimap_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let mut c: c_int = 0;
        let v = string_multimap_to_treemap(smm);
        for (_, val) in (*v).iter() {
            c = c + (*val).len() as c_int;
        }
        c
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_find_count(smm: *mut cef_string_multimap_t, key: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    s.len() as c_int
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_append(smm: *mut cef_string_multimap_t, key: *const cef_string_t, value: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            let s = String::from_str(result);
            let csv = cef_string_userfree_utf8_alloc();
            cef_string_utf8_set((*value).str as *const u8, (*value).length, csv, 1);
            match (*v).find_mut(&s) {
                Some(vc) => {
                    (*vc).push(csv);
                    1
                }
                None => {
                    let vc = vec!(csv);
                    (*v).insert(s, vc);
                    1
                }
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_enumerate(smm: *mut cef_string_multimap_t, key: *const cef_string_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    if (*s).len() <= index as uint {
                        return 0;
                    }
                    let cs = (*s)[index as uint];
                    cef_string_utf8_set((*cs).str as *const u8, (*cs).length, value, 1)
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_key(smm: *mut cef_string_multimap_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        let mut rem = index as uint;

        for (key, val) in (*v).iter() {
            if rem < (*val).len() {
                return cef_string_utf8_set((*key).as_bytes().as_ptr(), (*key).len() as u64, value, 1);
            } else {
                rem = rem - (*val).len();
            }
        }
    }
    0
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_value(smm: *mut cef_string_multimap_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        let mut rem = index as uint;

        for (_, val) in (*v).values().enumerate() {
            if rem < (*val).len() {
                let cs = (*val)[rem as uint];
                return cef_string_utf8_set((*cs).str as *const u8, (*cs).length, value, 1);
            } else {
                rem = rem - (*val).len();
            }
        }
    }
    0
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_clear(smm: *mut cef_string_multimap_t) {
    unsafe {
        if smm.is_null() { return; }
        let v = string_multimap_to_treemap(smm);
        if (*v).len() == 0 { return; }
        for (_, val) in (*v).iter_mut() {
            while (*val).len() != 0 {
                let cs = (*val).pop();
                cef_string_userfree_utf8_free(cs.unwrap());
            }
        }
        (*v).clear();
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_free(smm: *mut cef_string_multimap_t) {
    unsafe {
        if smm.is_null() { return; }
        let v: Box<TreeMap<String, Vec<*mut cef_string_t>>> = mem::transmute(smm);
        cef_string_multimap_clear(smm);
        drop(v);
    }
}
<|endoftext|>