<commit_before>extern crate rustc_serialize;
extern crate csv;
extern crate utilities;
extern crate distance;

use std::collections::HashMap;
use utilities::abs_standard_deviation;
use distance::manhattan_dist;

/******************** Athletes DB ********************/
#[derive(Debug)]
#[derive(RustcDecodable)]
pub struct AthlRecord {
    class: String,
    height: f32,
    weight: f32,
}

#[derive(Debug)]
pub struct AthlDatabase {
    keys: HashMap<String, usize>,
    data: Vec<AthlRecord>,
    asd_data: Vec<(f32, f32)>,
}

impl AthlDatabase {
    pub fn from_file(path: &str) -> AthlDatabase {
        let mut rdr = csv::Reader::from_file(path)
            .unwrap()
            .delimiter(b'\t')
            .has_headers(true);

        let mut keys: HashMap<String, usize> = HashMap::new();
        let mut data: Vec<AthlRecord> = Vec::new();

        let mut indx = 0;
        for record in rdr.decode() {
            let rcrd: (String, AthlRecord) = record.unwrap();
            keys.insert(rcrd.0, indx);
            data.push(rcrd.1);

            indx += 1;
        }

        AthlDatabase {
            keys: keys,
            data: data,
            asd_data: Vec::new()
        }
    }

    pub fn standarize(&mut self) {
        println!("Standarizing DB...");
        for i in 0..2 {
            let mut feat_vec: Vec<f32> = Vec::new();
            for feat in self.data.iter() {
                feat_vec.push(match i {
                                  0 => feat.height,
                                  1 => feat.weight,
                                  _ => {
                    panic!("Out of range, fn covers only two options");
                }
                              });
            }

            let (asd, median) = abs_standard_deviation(&feat_vec);
            println!("\t{}> asd: {}\tmedian: {}", i, asd, median);

            for feat in self.data.iter_mut() {
                match i {
                    0 => {
                        feat.height = (feat.height - median) / asd;
                    }
                    1 => {
                        feat.weight = (feat.weight - median) / asd;
                    }
                    _ => {}
                }
            }

            self.asd_data.push((asd, median));
        }
    }

    fn nearest_neighbors(&self, rcrd: &AthlRecord, func: fn(&Vec<f32>, &Vec<f32>) -> f32) -> Vec<usize> {
        let feats = vec![rcrd.height, rcrd.weight];
        let mut distances: Vec<(f32, usize)> = Vec::new();
        let mut i = 0;
        for record in self.data.iter() {
            distances.push((func(&feats, &vec![record.height, record.weight]), i));
            i += 1;
        }
        distances.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());

        let mut indexes = Vec::new();
        for record in distances.iter() {
            indexes.push(record.1);
        }

        indexes
    }

    pub fn predict(&self, height: f32, weight: f32) -> AthlRecord {
        let mut rcrd = AthlRecord {
            class: String::new(),
            height: height,
            weight: weight,
        };

        for i in 0..2 {
            match i {
                0 => {
                    rcrd.height = (rcrd.height - self.asd_data[i].1) / self.asd_data[i].0;
                }
                1 => {
                    rcrd.weight = (rcrd.weight - self.asd_data[i].1) / self.asd_data[i].0;
                }
                _ => {}
            }
        }

        rcrd.class = self.data[self.nearest_neighbors(&rcrd, manhattan_dist)[0]].class.clone();
        // println!("{:?}", self.data[self.nearest_neighbors(&rcrd, manhattan_dist)[0]]);
        rcrd
    }
}
/*******************************************************/

// def test(training_filename, test_filename):
//     """Test the classifier on a test set of data"""
//     classifier = Classifier(training_filename)
//     f = open(test_filename)
//     lines = f.readlines()
//     f.close()
//     numCorrect = 0.0
//     for line in lines:
//         data = line.strip().split('\t')
//         vector = []
//         classInColumn = -1
//         for i in range(len(classifier.format)):
//               if classifier.format[i] == 'num':
//                   vector.append(float(data[i]))
//               elif classifier.format[i] == 'class':
//                   classInColumn = i
//         theClass= classifier.classify(vector)
//         prefix = '-'
//         if theClass == data[classInColumn]:
//             # it is correct
//             numCorrect += 1
//             prefix = '+'
//         print("%s  %12s  %s" % (prefix, theClass, line))
//     print("%4.2f%% correct" % (numCorrect * 100/ len(lines)))
<commit_msg>init commit for new database type<commit_after>extern crate rustc_serialize;
extern crate csv;
extern crate utilities;
extern crate distance;

use std::collections::HashMap;
use utilities::abs_standard_deviation;
use distance::manhattan_dist;

/******************** Athletes DB ********************/
#[derive(Debug)]
#[derive(RustcDecodable)]
pub struct AthlRecord {
    class: String,
    height: f32,
    weight: f32,
}

#[derive(Debug)]
pub struct AthlDatabase {
    keys: HashMap<String, usize>,
    data: Vec<AthlRecord>,
    asd_data: Vec<(f32, f32)>,
}

impl AthlDatabase {
    pub fn from_file(path: &str) -> AthlDatabase {
        let mut rdr = csv::Reader::from_file(path)
            .unwrap()
            .delimiter(b'\t')
            .has_headers(true);

        let mut keys: HashMap<String, usize> = HashMap::new();
        let mut data: Vec<AthlRecord> = Vec::new();

        let mut indx = 0;
        for record in rdr.decode() {
            let rcrd: (String, AthlRecord) = record.unwrap();
            keys.insert(rcrd.0, indx);
            data.push(rcrd.1);

            indx += 1;
        }

        AthlDatabase {
            keys: keys,
            data: data,
            asd_data: Vec::new()
        }
    }

    pub fn standarize(&mut self) {
        println!("Standarizing DB...");
        for i in 0..2 {
            let mut feat_vec: Vec<f32> = Vec::new();
            for feat in self.data.iter() {
                feat_vec.push(match i {
                                  0 => feat.height,
                                  1 => feat.weight,
                                  _ => {
                    panic!("Out of range, fn covers only two options");
                }
                              });
            }

            let (asd, median) = abs_standard_deviation(&feat_vec);
            println!("\t{}> asd: {}\tmedian: {}", i, asd, median);

            for feat in self.data.iter_mut() {
                match i {
                    0 => {
                        feat.height = (feat.height - median) / asd;
                    }
                    1 => {
                        feat.weight = (feat.weight - median) / asd;
                    }
                    _ => {}
                }
            }

            self.asd_data.push((asd, median));
        }
    }

    fn nearest_neighbors(&self, rcrd: &AthlRecord, func: fn(&Vec<f32>, &Vec<f32>) -> f32) -> Vec<usize> {
        let feats = vec![rcrd.height, rcrd.weight];
        let mut distances: Vec<(f32, usize)> = Vec::new();
        let mut i = 0;
        for record in self.data.iter() {
            distances.push((func(&feats, &vec![record.height, record.weight]), i));
            i += 1;
        }
        distances.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());

        let mut indexes = Vec::new();
        for record in distances.iter() {
            indexes.push(record.1);
        }

        indexes
    }

    pub fn predict(&self, height: f32, weight: f32) -> AthlRecord {
        let mut rcrd = AthlRecord {
            class: String::new(),
            height: height,
            weight: weight,
        };

        for i in 0..2 {
            match i {
                0 => {
                    rcrd.height = (rcrd.height - self.asd_data[i].1) / self.asd_data[i].0;
                }
                1 => {
                    rcrd.weight = (rcrd.weight - self.asd_data[i].1) / self.asd_data[i].0;
                }
                _ => {}
            }
        }

        rcrd.class = self.data[self.nearest_neighbors(&rcrd, manhattan_dist)[0]].class.clone();
        // println!("{:?}", self.data[self.nearest_neighbors(&rcrd, manhattan_dist)[0]]);
        rcrd
    }
}
/*******************************************************/

/******************** Athletes DB ********************/
#[derive(Debug)]
#[derive(RustcDecodable)]
pub struct AthlRecord {
    class: String,
    height: f32,
    weight: f32,
}

#[derive(Debug)]
pub struct AthlDatabase {
    keys: HashMap<String, usize>,
    data: Vec<AthlRecord>,
    asd_data: Vec<(f32, f32)>,
}

impl AthlDatabase {
    pub fn from_file(path: &str) -> AthlDatabase {
        let mut rdr = csv::Reader::from_file(path)
            .unwrap()
            .delimiter(b'\t')
            .has_headers(true);

        let mut keys: HashMap<String, usize> = HashMap::new();
        let mut data: Vec<AthlRecord> = Vec::new();

        let mut indx = 0;
        for record in rdr.decode() {
            let rcrd: (String, AthlRecord) = record.unwrap();
            keys.insert(rcrd.0, indx);
            data.push(rcrd.1);

            indx += 1;
        }

        AthlDatabase {
            keys: keys,
            data: data,
            asd_data: Vec::new()
        }
    }
}
/*******************************************************/

// def test(training_filename, test_filename):
//     """Test the classifier on a test set of data"""
//     classifier = Classifier(training_filename)
//     f = open(test_filename)
//     lines = f.readlines()
//     f.close()
//     numCorrect = 0.0
//     for line in lines:
//         data = line.strip().split('\t')
//         vector = []
//         classInColumn = -1
//         for i in range(len(classifier.format)):
//               if classifier.format[i] == 'num':
//                   vector.append(float(data[i]))
//               elif classifier.format[i] == 'class':
//                   classInColumn = i
//         theClass= classifier.classify(vector)
//         prefix = '-'
//         if theClass == data[classInColumn]:
//             # it is correct
//             numCorrect += 1
//             prefix = '+'
//         print("%s  %12s  %s" % (prefix, theClass, line))
//     print("%4.2f%% correct" % (numCorrect * 100/ len(lines)))
<|endoftext|>


<commit_before>//! # Overview
//!
//! This crate provides native rust implementations of image encoding and decoding as well as some
//! basic image manipulation functions. Additional documentation can currently also be found in the
//! [README.md file which is most easily viewed on
//! github](https://github.com/image-rs/image/blob/master/README.md).
//!
//! There are two core problems for which this library provides solutions: a unified interface for image
//! encodings and simple generic buffers for their content. It's possible to use either feature
//! without the other. The focus is on a small and stable set of common operations that can be
//! supplemented by other specialized crates. The library also prefers safe solutions with few
//! dependencies.
//!
//! # High level API
//!
//! Load images using [`io::Reader`]:
//!
//! ```rust,no_run
//! # use std::io::Cursor;
//! use image::io::Reader as ImageReader;
//! # fn main() -> Result<(), image::ImageError> {
//! # let bytes = vec![0u8];
//!
//! let img = ImageReader::open("myimage.png")?.decode()?;
//! let img2 = ImageReader::new(Cursor::new(bytes)).decode()?;
//! # Ok(())
//! # }
//! ```
//!
//! And save them using [`save`] or [`write_to`] methods:
//!
//! ```rust,no_run
//! # use std::io::Write;
//! # use image::ImageOutputFormat;
//! # use image::DynamicImage;
//! # #[cfg(feature = "png")]
//! # fn main() -> Result<(), image::ImageError> {
//! # let img: DynamicImage = unimplemented!();
//! # let img2: DynamicImage = unimplemented!();
//! img.save("empty.jpg")?;
//!
//! let mut bytes: Vec<u8> = Vec::new();
//! img2.write_to(&mut bytes, image::ImageOutputFormat::Png)?;
//! # Ok(())
//! # }
//! # #[cfg(not(feature = "png"))] fn main() {}
//! ```
//!
//! With default features, the crate includes support for [many common image formats](codecs/index.html#supported-formats).
//!
//! [`save`]: enum.DynamicImage.html#method.save
//! [`write_to`]: enum.DynamicImage.html#method.write_to
//! [`io::Reader`]: io/struct.Reader.html
//!
//! # Image buffers
//!
//! The two main types for storing images:
//! * [`ImageBuffer`] which holds statically typed image contents.
//! * [`DynamicImage`] which is an enum over the supported ImageBuffer formats
//!     and supports conversions between them.
//!
//! As well as a few more specialized options:
//! * [`GenericImage`] trait for a mutable image buffer.
//! * [`GenericImageView`] trait for read only references to a GenericImage.
//! * [`flat`] module containing types for interoperability with generic channel
//!     matrices and foreign interfaces.
//!
//! [`GenericImageView`]: trait.GenericImageView.html
//! [`GenericImage`]: trait.GenericImage.html
//! [`ImageBuffer`]: struct.ImageBuffer.html
//! [`DynamicImage`]: enum.DynamicImage.html
//! [`flat`]: flat/index.html
//!
//! # Low level encoding/decoding API
//!
//! The [`ImageDecoder`] and [`ImageDecoderExt`] traits are implemented for many image file
//! formats. They decode image data by directly on raw byte slices. Given an ImageDecoder, you can
//! produce a DynamicImage via [`DynamicImage::from_decoder`].
//!
//! [`ImageEncoder`] provides the analogous functionality for encoding image data.
//!
//! [`DynamicImage::from_decoder`]: enum.DynamicImage.html#method.from_decoder
//! [`ImageDecoderExt`]: trait.ImageDecoderExt.html
//! [`ImageDecoder`]: trait.ImageDecoder.html
//! [`ImageEncoder`]: trait.ImageEncoder.html
#![warn(missing_docs)]
#![warn(unused_qualifications)]
#![deny(unreachable_pub)]
#![deny(deprecated)]
#![deny(missing_copy_implementations)]
#![cfg_attr(all(test, feature = "benchmarks"), feature(test))]
// it's a bit of a pain otherwise
#![allow(clippy::many_single_char_names)]
// it's a backwards compatibility break
#![allow(clippy::wrong_self_convention, clippy::enum_variant_names)]

#[cfg(all(test, feature = "benchmarks"))]
extern crate test;

#[cfg(test)]
#[macro_use]
extern crate quickcheck;

use std::io::Write;

pub use crate::color::{ColorType, ExtendedColorType};

pub use crate::color::{Luma, LumaA, Rgb, Rgba, Bgr, Bgra};

pub use crate::error::{ImageError, ImageResult};

pub use crate::image::{AnimationDecoder,
                GenericImage,
                GenericImageView,
                ImageDecoder,
                ImageDecoderExt,
                ImageEncoder,
                ImageFormat,
                ImageOutputFormat,
                Progress,
                // Iterators
                Pixels,
                SubImage};

pub use crate::buffer_::{
                 GrayAlphaImage,
                 GrayImage,
                 // Image types
                 ImageBuffer,
                 RgbImage,
                 RgbaImage};

pub use crate::flat::FlatSamples;

// Traits
pub use crate::traits::{EncodableLayout, Primitive, Pixel};

// Opening and loading images
pub use crate::io::free_functions::{guess_format, load};
pub use crate::dynimage::{load_from_memory, load_from_memory_with_format, open,
                   save_buffer, save_buffer_with_format, write_buffer_with_format, image_dimensions};

pub use crate::dynimage::DynamicImage;

pub use crate::animation::{Delay, Frame, Frames};

// More detailed error type
pub mod error;

/// Iterators and other auxiliary structure for the `ImageBuffer` type.
pub mod buffer {
    // Only those not exported at the top-level
    pub use crate::buffer_::{
        ConvertBuffer,
        EnumeratePixels,
        EnumeratePixelsMut,
        EnumerateRows,
        EnumerateRowsMut,
        Pixels,
        PixelsMut,
        Rows,
        RowsMut,
    };
}

// Math utils
pub mod math;

// Image processing functions
pub mod imageops;

// Io bindings
pub mod io;

// Buffer representations for ffi.
pub mod flat;

/// Encoding and decoding for various image file formats.
///
/// # Supported formats
///
/// | Format | Decoding | Encoding |
/// | ------ | -------- | -------- |
/// | PNG    | All supported color types | Same as decoding |
/// | JPEG   | Baseline and progressive | Baseline JPEG |
/// | GIF    | Yes | Yes |
/// | BMP    | Yes | RGB8, RGBA8, Gray8, GrayA8 |
/// | ICO    | Yes | Yes |
/// | TIFF   | Baseline(no fax support) + LZW + PackBits | RGB8, RGBA8, Gray8 |
/// | WebP   | Lossy(Luma channel only) | No |
/// | AVIF   | Only 8-bit | Lossy |
/// | PNM    | PBM, PGM, PPM, standard PAM | Yes |
/// | DDS    | DXT1, DXT3, DXT5 | No |
/// | TGA    | Yes | RGB8, RGBA8, BGR8, BGRA8, Gray8, GrayA8 |
/// | farbfeld | Yes | Yes |
///
/// ## A note on format specific features
///
/// One of the main goals of `image` is stability, in runtime but also for programmers. This
/// ensures that performance as well as safety fixes reach a majority of its user base with little
/// effort. Re-exporting all details of its dependencies would run counter to this goal as it
/// linked _all_ major version bumps between them and `image`. As such, we are wary of exposing too
/// many details, or configuration options, that are not shared between different image formats.
///
/// Nevertheless, the advantage of precise control is hard to ignore. We will thus consider
/// _wrappers_, not direct re-exports, in either of the following cases:
///
/// 1. A standard specifies that configuration _x_ is required for decoders/encoders and there
///    exists an essentially canonical way to control it.
/// 2. At least two different implementations agree on some (sub-)set of features in practice.
/// 3. A technical argument including measurements of the performance, space benefits, or otherwise
///    objectively quantified benefits can be made, and the added interface is unlikely to require
///    breaking changes.
///
/// Features that fulfill two or more criteria are preferred.
///
/// Re-exports of dependencies that reach version `1` will be discussed when it happens.
pub mod codecs {
    #[cfg(any(feature = "avif-encoder", feature = "avif-decoder"))]
    pub mod avif;
    #[cfg(feature = "bmp")]
    pub mod bmp;
    #[cfg(feature = "dds")]
    pub mod dds;
    #[cfg(feature = "dxt")]
    pub mod dxt;
    #[cfg(feature = "farbfeld")]
    pub mod farbfeld;
    #[cfg(feature = "gif")]
    pub mod gif;
    #[cfg(feature = "hdr")]
    pub mod hdr;
    #[cfg(feature = "ico")]
    pub mod ico;
    #[cfg(feature = "jpeg")]
    pub mod jpeg;
    #[cfg(feature = "png")]
    pub mod png;
    #[cfg(feature = "pnm")]
    pub mod pnm;
    #[cfg(feature = "tga")]
    pub mod tga;
    #[cfg(feature = "tiff")]
    pub mod tiff;
    #[cfg(feature = "webp")]
    pub mod webp;
    #[cfg(feature = "openexr")]
    pub mod openexr;
}

#[cfg(feature = "avif-encoder")]
#[deprecated = "Use codecs::avif instead"]
pub mod avif {
    //! Encoding of AVIF images.
    pub use crate::codecs::avif::AvifEncoder;
}
#[cfg(feature = "bmp")]
#[deprecated = "Use codecs::bmp instead"]
pub mod bmp {
    //! Decoding and Encoding of BMP Images
    #[allow(deprecated)]
    pub use crate::codecs::bmp::{BMPEncoder, BmpDecoder, BmpEncoder};
}
#[cfg(feature = "dds")]
#[deprecated = "Use codecs::dds instead"]
pub mod dds {
    //! Decoding of DDS images
    pub use crate::codecs::dds::DdsDecoder;
}
#[cfg(feature = "dxt")]
#[deprecated = "Use codecs:: instead"]
pub mod dxt {
    //! Decoding of DXT (S3TC) compression
    #[allow(deprecated)]
    pub use crate::codecs::dxt::{
        DXTEncoder, DXTReader, DXTVariant, DxtDecoder, DxtEncoder, DxtReader, DxtVariant,
    };
}
#[cfg(feature = "farbfeld")]
#[deprecated = "Use codecs::farbfeld instead"]
pub mod farbfeld {
    //! Decoding of farbfeld images
    pub use crate::codecs::farbfeld::{FarbfeldDecoder, FarbfeldEncoder, FarbfeldReader};
}
#[cfg(feature = "gif")]
#[deprecated = "Use codecs::gif instead"]
pub mod gif {
    //! Decoding of GIF Images
    #[allow(deprecated)]
    pub use crate::codecs::gif::{Encoder, GifDecoder, GifEncoder, GifReader, Repeat};
}
#[cfg(feature = "hdr")]
#[deprecated = "Use codecs::hdr instead"]
pub mod hdr {
    //! Decoding of Radiance HDR Images
    #[allow(deprecated)]
    pub use crate::codecs::hdr::{
        read_raw_file, rgbe8, to_rgbe8, HDRAdapter, HDREncoder, HDRImageDecoderIterator,
        HDRMetadata, HdrAdapter, HdrDecoder, HdrEncoder, HdrImageDecoderIterator, HdrMetadata,
        HdrReader, RGBE8Pixel, Rgbe8Pixel, SIGNATURE,
    };
}
#[cfg(feature = "ico")]
#[deprecated = "Use codecs::ico instead"]
pub mod ico {
    //! Decoding and Encoding of ICO files
    #[allow(deprecated)]
    pub use crate::codecs::ico::{ICOEncoder, IcoDecoder, IcoEncoder};
}
#[cfg(feature = "jpeg")]
#[deprecated = "Use codecs::jpeg instead"]
pub mod jpeg {
    //! Decoding and Encoding of JPEG Images
    #[allow(deprecated)]
    pub use crate::codecs::jpeg::{
        JPEGEncoder, JpegDecoder, JpegEncoder, PixelDensity, PixelDensityUnit,
    };
}
#[cfg(feature = "png")]
#[deprecated = "Use codecs::png instead"]
pub mod png {
    //! Decoding and Encoding of PNG Images
    #[allow(deprecated)]
    pub use crate::codecs::png::{
        ApngDecoder, CompressionType, FilterType, PNGEncoder, PNGReader, PngDecoder, PngEncoder,
        PngReader,
    };
}
#[cfg(feature = "pnm")]
#[deprecated = "Use codecs::pnm instead"]
pub mod pnm {
    //! Decoding and Encoding of netpbm image formats (pbm, pgm, ppm and pam)
    #[allow(deprecated)]
    pub use crate::codecs::pnm::{
        ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PNMEncoder, PNMHeader,
        PNMSubtype, PixmapHeader, PnmDecoder, PnmEncoder, PnmHeader, PnmSubtype, SampleEncoding,
    };
}
#[cfg(feature = "tga")]
#[deprecated = "Use codecs::tga instead"]
pub mod tga {
    //! Decoding and Encoding of TGA Images
    #[allow(deprecated)]
    pub use crate::codecs::tga::{TgaDecoder, TgaEncoder};
}
#[cfg(feature = "tiff")]
#[deprecated = "Use codecs::tiff instead"]
pub mod tiff {
    //! Decoding and Encoding of TIFF Images
    #[allow(deprecated)]
    pub use crate::codecs::tiff::{TiffDecoder, TiffEncoder, TiffReader};
}
#[cfg(feature = "webp")]
#[deprecated = "Use codecs::webp instead"]
pub mod webp {
    //! Decoding of WebP Images
    #[allow(deprecated)]
    pub use crate::codecs::webp::{vp8, WebPDecoder};
}

mod animation;
#[path = "buffer.rs"]
mod buffer_;
mod color;
mod dynimage;
mod image;
mod traits;
mod utils;

// Can't use the macro-call itself within the `doc` attribute. So force it to eval it as part of
// the macro invocation.
//
// The inspiration for the macro and implementation is from
// <https://github.com/GuillaumeGomez/doc-comment>
//
// MIT License
//
// Copyright (c) 2018 Guillaume Gomez
macro_rules! insert_as_doc {
    { $content:expr } => {
        #[doc = $content] extern { }
    }
}

// Provides the README.md as doc, to ensure the example works!
insert_as_doc!(include_str!("../README.md"));

// Copies data from `src` to `dst`
//
// Panics if the length of `dst` is less than the length of `src`.
#[inline]
fn copy_memory(src: &[u8], mut dst: &mut [u8]) {
    let len_src = src.len();
    assert!(dst.len() >= len_src);
    dst.write_all(src).unwrap();
}
<commit_msg>update supported formats documentation (add exr, use camel case)<commit_after>//! # Overview
//!
//! This crate provides native rust implementations of image encoding and decoding as well as some
//! basic image manipulation functions. Additional documentation can currently also be found in the
//! [README.md file which is most easily viewed on
//! github](https://github.com/image-rs/image/blob/master/README.md).
//!
//! There are two core problems for which this library provides solutions: a unified interface for image
//! encodings and simple generic buffers for their content. It's possible to use either feature
//! without the other. The focus is on a small and stable set of common operations that can be
//! supplemented by other specialized crates. The library also prefers safe solutions with few
//! dependencies.
//!
//! # High level API
//!
//! Load images using [`io::Reader`]:
//!
//! ```rust,no_run
//! # use std::io::Cursor;
//! use image::io::Reader as ImageReader;
//! # fn main() -> Result<(), image::ImageError> {
//! # let bytes = vec![0u8];
//!
//! let img = ImageReader::open("myimage.png")?.decode()?;
//! let img2 = ImageReader::new(Cursor::new(bytes)).decode()?;
//! # Ok(())
//! # }
//! ```
//!
//! And save them using [`save`] or [`write_to`] methods:
//!
//! ```rust,no_run
//! # use std::io::Write;
//! # use image::ImageOutputFormat;
//! # use image::DynamicImage;
//! # #[cfg(feature = "png")]
//! # fn main() -> Result<(), image::ImageError> {
//! # let img: DynamicImage = unimplemented!();
//! # let img2: DynamicImage = unimplemented!();
//! img.save("empty.jpg")?;
//!
//! let mut bytes: Vec<u8> = Vec::new();
//! img2.write_to(&mut bytes, image::ImageOutputFormat::Png)?;
//! # Ok(())
//! # }
//! # #[cfg(not(feature = "png"))] fn main() {}
//! ```
//!
//! With default features, the crate includes support for [many common image formats](codecs/index.html#supported-formats).
//!
//! [`save`]: enum.DynamicImage.html#method.save
//! [`write_to`]: enum.DynamicImage.html#method.write_to
//! [`io::Reader`]: io/struct.Reader.html
//!
//! # Image buffers
//!
//! The two main types for storing images:
//! * [`ImageBuffer`] which holds statically typed image contents.
//! * [`DynamicImage`] which is an enum over the supported ImageBuffer formats
//!     and supports conversions between them.
//!
//! As well as a few more specialized options:
//! * [`GenericImage`] trait for a mutable image buffer.
//! * [`GenericImageView`] trait for read only references to a GenericImage.
//! * [`flat`] module containing types for interoperability with generic channel
//!     matrices and foreign interfaces.
//!
//! [`GenericImageView`]: trait.GenericImageView.html
//! [`GenericImage`]: trait.GenericImage.html
//! [`ImageBuffer`]: struct.ImageBuffer.html
//! [`DynamicImage`]: enum.DynamicImage.html
//! [`flat`]: flat/index.html
//!
//! # Low level encoding/decoding API
//!
//! The [`ImageDecoder`] and [`ImageDecoderExt`] traits are implemented for many image file
//! formats. They decode image data by directly on raw byte slices. Given an ImageDecoder, you can
//! produce a DynamicImage via [`DynamicImage::from_decoder`].
//!
//! [`ImageEncoder`] provides the analogous functionality for encoding image data.
//!
//! [`DynamicImage::from_decoder`]: enum.DynamicImage.html#method.from_decoder
//! [`ImageDecoderExt`]: trait.ImageDecoderExt.html
//! [`ImageDecoder`]: trait.ImageDecoder.html
//! [`ImageEncoder`]: trait.ImageEncoder.html
#![warn(missing_docs)]
#![warn(unused_qualifications)]
#![deny(unreachable_pub)]
#![deny(deprecated)]
#![deny(missing_copy_implementations)]
#![cfg_attr(all(test, feature = "benchmarks"), feature(test))]
// it's a bit of a pain otherwise
#![allow(clippy::many_single_char_names)]
// it's a backwards compatibility break
#![allow(clippy::wrong_self_convention, clippy::enum_variant_names)]

#[cfg(all(test, feature = "benchmarks"))]
extern crate test;

#[cfg(test)]
#[macro_use]
extern crate quickcheck;

use std::io::Write;

pub use crate::color::{ColorType, ExtendedColorType};

pub use crate::color::{Luma, LumaA, Rgb, Rgba, Bgr, Bgra};

pub use crate::error::{ImageError, ImageResult};

pub use crate::image::{AnimationDecoder,
                GenericImage,
                GenericImageView,
                ImageDecoder,
                ImageDecoderExt,
                ImageEncoder,
                ImageFormat,
                ImageOutputFormat,
                Progress,
                // Iterators
                Pixels,
                SubImage};

pub use crate::buffer_::{
                 GrayAlphaImage,
                 GrayImage,
                 // Image types
                 ImageBuffer,
                 RgbImage,
                 RgbaImage};

pub use crate::flat::FlatSamples;

// Traits
pub use crate::traits::{EncodableLayout, Primitive, Pixel};

// Opening and loading images
pub use crate::io::free_functions::{guess_format, load};
pub use crate::dynimage::{load_from_memory, load_from_memory_with_format, open,
                   save_buffer, save_buffer_with_format, write_buffer_with_format, image_dimensions};

pub use crate::dynimage::DynamicImage;

pub use crate::animation::{Delay, Frame, Frames};

// More detailed error type
pub mod error;

/// Iterators and other auxiliary structure for the `ImageBuffer` type.
pub mod buffer {
    // Only those not exported at the top-level
    pub use crate::buffer_::{
        ConvertBuffer,
        EnumeratePixels,
        EnumeratePixelsMut,
        EnumerateRows,
        EnumerateRowsMut,
        Pixels,
        PixelsMut,
        Rows,
        RowsMut,
    };
}

// Math utils
pub mod math;

// Image processing functions
pub mod imageops;

// Io bindings
pub mod io;

// Buffer representations for ffi.
pub mod flat;

/// Encoding and decoding for various image file formats.
///
/// # Supported formats
///
/// | Format | Decoding | Encoding |
/// | ------ | -------- | -------- |
/// | PNG    | All supported color types | Same as decoding |
/// | JPEG   | Baseline and progressive | Baseline JPEG |
/// | GIF    | Yes | Yes |
/// | BMP    | Yes | Rgb8, Rgba8, Gray8, GrayA8 |
/// | ICO    | Yes | Yes |
/// | TIFF   | Baseline(no fax support) + LZW + PackBits | Rgb8, Rgba8, Gray8 |
/// | WebP   | Lossy(Luma channel only) | No |
/// | AVIF   | Only 8-bit | Lossy |
/// | PNM    | PBM, PGM, PPM, standard PAM | Yes |
/// | DDS    | DXT1, DXT3, DXT5 | No |
/// | TGA    | Yes | Rgb8, Rgba8, Bgr8, Bgra8, Gray8, GrayA8 |
/// | OpenEXR  | Rgb32F, Rgba32F (no dwa compression) | Rgb32F, Rgba32F (no dwa compression) |
/// | farbfeld | Yes | Yes |
///
/// ## A note on format specific features
///
/// One of the main goals of `image` is stability, in runtime but also for programmers. This
/// ensures that performance as well as safety fixes reach a majority of its user base with little
/// effort. Re-exporting all details of its dependencies would run counter to this goal as it
/// linked _all_ major version bumps between them and `image`. As such, we are wary of exposing too
/// many details, or configuration options, that are not shared between different image formats.
///
/// Nevertheless, the advantage of precise control is hard to ignore. We will thus consider
/// _wrappers_, not direct re-exports, in either of the following cases:
///
/// 1. A standard specifies that configuration _x_ is required for decoders/encoders and there
///    exists an essentially canonical way to control it.
/// 2. At least two different implementations agree on some (sub-)set of features in practice.
/// 3. A technical argument including measurements of the performance, space benefits, or otherwise
///    objectively quantified benefits can be made, and the added interface is unlikely to require
///    breaking changes.
///
/// Features that fulfill two or more criteria are preferred.
///
/// Re-exports of dependencies that reach version `1` will be discussed when it happens.
pub mod codecs {
    #[cfg(any(feature = "avif-encoder", feature = "avif-decoder"))]
    pub mod avif;
    #[cfg(feature = "bmp")]
    pub mod bmp;
    #[cfg(feature = "dds")]
    pub mod dds;
    #[cfg(feature = "dxt")]
    pub mod dxt;
    #[cfg(feature = "farbfeld")]
    pub mod farbfeld;
    #[cfg(feature = "gif")]
    pub mod gif;
    #[cfg(feature = "hdr")]
    pub mod hdr;
    #[cfg(feature = "ico")]
    pub mod ico;
    #[cfg(feature = "jpeg")]
    pub mod jpeg;
    #[cfg(feature = "png")]
    pub mod png;
    #[cfg(feature = "pnm")]
    pub mod pnm;
    #[cfg(feature = "tga")]
    pub mod tga;
    #[cfg(feature = "tiff")]
    pub mod tiff;
    #[cfg(feature = "webp")]
    pub mod webp;
    #[cfg(feature = "openexr")]
    pub mod openexr;
}

#[cfg(feature = "avif-encoder")]
#[deprecated = "Use codecs::avif instead"]
pub mod avif {
    //! Encoding of AVIF images.
    pub use crate::codecs::avif::AvifEncoder;
}
#[cfg(feature = "bmp")]
#[deprecated = "Use codecs::bmp instead"]
pub mod bmp {
    //! Decoding and Encoding of BMP Images
    #[allow(deprecated)]
    pub use crate::codecs::bmp::{BMPEncoder, BmpDecoder, BmpEncoder};
}
#[cfg(feature = "dds")]
#[deprecated = "Use codecs::dds instead"]
pub mod dds {
    //! Decoding of DDS images
    pub use crate::codecs::dds::DdsDecoder;
}
#[cfg(feature = "dxt")]
#[deprecated = "Use codecs:: instead"]
pub mod dxt {
    //! Decoding of DXT (S3TC) compression
    #[allow(deprecated)]
    pub use crate::codecs::dxt::{
        DXTEncoder, DXTReader, DXTVariant, DxtDecoder, DxtEncoder, DxtReader, DxtVariant,
    };
}
#[cfg(feature = "farbfeld")]
#[deprecated = "Use codecs::farbfeld instead"]
pub mod farbfeld {
    //! Decoding of farbfeld images
    pub use crate::codecs::farbfeld::{FarbfeldDecoder, FarbfeldEncoder, FarbfeldReader};
}
#[cfg(feature = "gif")]
#[deprecated = "Use codecs::gif instead"]
pub mod gif {
    //! Decoding of GIF Images
    #[allow(deprecated)]
    pub use crate::codecs::gif::{Encoder, GifDecoder, GifEncoder, GifReader, Repeat};
}
#[cfg(feature = "hdr")]
#[deprecated = "Use codecs::hdr instead"]
pub mod hdr {
    //! Decoding of Radiance HDR Images
    #[allow(deprecated)]
    pub use crate::codecs::hdr::{
        read_raw_file, rgbe8, to_rgbe8, HDRAdapter, HDREncoder, HDRImageDecoderIterator,
        HDRMetadata, HdrAdapter, HdrDecoder, HdrEncoder, HdrImageDecoderIterator, HdrMetadata,
        HdrReader, RGBE8Pixel, Rgbe8Pixel, SIGNATURE,
    };
}
#[cfg(feature = "ico")]
#[deprecated = "Use codecs::ico instead"]
pub mod ico {
    //! Decoding and Encoding of ICO files
    #[allow(deprecated)]
    pub use crate::codecs::ico::{ICOEncoder, IcoDecoder, IcoEncoder};
}
#[cfg(feature = "jpeg")]
#[deprecated = "Use codecs::jpeg instead"]
pub mod jpeg {
    //! Decoding and Encoding of JPEG Images
    #[allow(deprecated)]
    pub use crate::codecs::jpeg::{
        JPEGEncoder, JpegDecoder, JpegEncoder, PixelDensity, PixelDensityUnit,
    };
}
#[cfg(feature = "png")]
#[deprecated = "Use codecs::png instead"]
pub mod png {
    //! Decoding and Encoding of PNG Images
    #[allow(deprecated)]
    pub use crate::codecs::png::{
        ApngDecoder, CompressionType, FilterType, PNGEncoder, PNGReader, PngDecoder, PngEncoder,
        PngReader,
    };
}
#[cfg(feature = "pnm")]
#[deprecated = "Use codecs::pnm instead"]
pub mod pnm {
    //! Decoding and Encoding of netpbm image formats (pbm, pgm, ppm and pam)
    #[allow(deprecated)]
    pub use crate::codecs::pnm::{
        ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PNMEncoder, PNMHeader,
        PNMSubtype, PixmapHeader, PnmDecoder, PnmEncoder, PnmHeader, PnmSubtype, SampleEncoding,
    };
}
#[cfg(feature = "tga")]
#[deprecated = "Use codecs::tga instead"]
pub mod tga {
    //! Decoding and Encoding of TGA Images
    #[allow(deprecated)]
    pub use crate::codecs::tga::{TgaDecoder, TgaEncoder};
}
#[cfg(feature = "tiff")]
#[deprecated = "Use codecs::tiff instead"]
pub mod tiff {
    //! Decoding and Encoding of TIFF Images
    #[allow(deprecated)]
    pub use crate::codecs::tiff::{TiffDecoder, TiffEncoder, TiffReader};
}
#[cfg(feature = "webp")]
#[deprecated = "Use codecs::webp instead"]
pub mod webp {
    //! Decoding of WebP Images
    #[allow(deprecated)]
    pub use crate::codecs::webp::{vp8, WebPDecoder};
}

mod animation;
#[path = "buffer.rs"]
mod buffer_;
mod color;
mod dynimage;
mod image;
mod traits;
mod utils;

// Can't use the macro-call itself within the `doc` attribute. So force it to eval it as part of
// the macro invocation.
//
// The inspiration for the macro and implementation is from
// <https://github.com/GuillaumeGomez/doc-comment>
//
// MIT License
//
// Copyright (c) 2018 Guillaume Gomez
macro_rules! insert_as_doc {
    { $content:expr } => {
        #[doc = $content] extern { }
    }
}

// Provides the README.md as doc, to ensure the example works!
insert_as_doc!(include_str!("../README.md"));

// Copies data from `src` to `dst`
//
// Panics if the length of `dst` is less than the length of `src`.
#[inline]
fn copy_memory(src: &[u8], mut dst: &mut [u8]) {
    let len_src = src.len();
    assert!(dst.len() >= len_src);
    dst.write_all(src).unwrap();
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do
//! [Cap'n Proto code generation](https://capnproto.org/otherlang.html#how-to-write-compiler-plugins)
//! within a Cargo build. You still need the `capnp` binary (implemented in C++).
//! (If you use a package manager, try looking for a package called
//! `capnproto`.)
//!
//! In your Cargo.toml:
//!
//! ```ignore
//! [package]
//! build = "build.rs"
//!
//! [build-dependencies]
//! capnpc = "0.12"
//! ```
//!
//! In your build.rs:
//!
//! ```ignore
//! extern crate capnpc;
//!
//! fn main() {
//!     capnpc::CompilerCommand::new()
//!         .src_prefix("schema")
//!         .file("schema/foo.capnp")
//!         .file("schema/bar.capnp")
//!         .run().expect("schema compiler command");
//! }
//! ```
//!
//! This will be equivalent to executing the shell command
//!
//! ```ignore
//!   capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//! ```
//!

extern crate capnp;

/// Code generated from
/// [schema.capnp](https://github.com/capnproto/capnproto/blob/master/c%2B%2B/src/capnp/schema.capnp).
pub mod schema_capnp;

pub mod codegen;
pub mod codegen_types;
mod pointer_constants;

use std::path::{Path, PathBuf};

fn run_command(mut command: ::std::process::Command, path: &PathBuf) -> ::capnp::Result<()> {
    let mut p = command.spawn()?;
    crate::codegen::generate_code(p.stdout.take().unwrap(), path.as_path())?;
    let exit_status = p.wait()?;
    if !exit_status.success() {
        Err(::capnp::Error::failed(format!(
            "Non-success exit status: {}",
            exit_status
        )))
    } else {
        Ok(())
    }
}

/// A builder object for schema compiler commands.
pub struct CompilerCommand {
    files: Vec<PathBuf>,
    src_prefixes: Vec<PathBuf>,
    import_paths: Vec<PathBuf>,
    no_standard_import: bool,
    output_path: Option<PathBuf>,
}

impl CompilerCommand {
    /// Creates a new, empty command.
    pub fn new() -> CompilerCommand {
        CompilerCommand {
            files: Vec::new(),
            src_prefixes: Vec::new(),
            import_paths: Vec::new(),
            no_standard_import: false,
            output_path: None,
        }
    }

    /// Adds a file to be compiled.
    pub fn file<P>(&mut self, path: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.files.push(path.as_ref().to_path_buf());
        self
    }

    /// Adds a --src-prefix flag. For all files specified for compilation that start
    /// with `prefix`, removes the prefix when computing output filenames.
    pub fn src_prefix<P>(&mut self, prefix: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.src_prefixes.push(prefix.as_ref().to_path_buf());
        self
    }

    /// Adds an --import_path flag. Adds `dir` to the list of directories searched
    /// for absolute imports.
    pub fn import_path<P>(&mut self, dir: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.import_paths.push(dir.as_ref().to_path_buf());
        self
    }

    /// Adds the --no-standard-import flag, indicating that the default import paths of
    /// /usr/include and /usr/local/include should not bet included.
    pub fn no_standard_import(&mut self) -> &mut CompilerCommand {
        self.no_standard_import = true;
        self
    }

    ///Sets the output directory of generated code. Default is OUT_DIR
    pub fn output_path<P>(&mut self, path: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.output_path = Some(path.as_ref().to_path_buf());
        self
    }

    /// Runs the command, assuming a 'capnp' executable is accessible from current working directory (e.g. locally or in PATH environment variable).
    /// Returns an error if `OUT_DIR` or a custom output directory was not set or if `capnp compile` fails.
    pub fn run(&mut self) -> ::capnp::Result<()> {
        self.run_with("capnp")
    }

    /// Runs the command, using a custom capnp `executable` path (not a directory).
    /// Returns an error if `OUT_DIR` or a custom output directory was not set or if `<executable> compile` fails.
    pub fn run_with<P>(&mut self, executable: P) -> ::capnp::Result<()>
    where
        P: AsRef<Path>
    {
        let mut command = ::std::process::Command::new(executable.as_ref());
        command.arg("compile").arg("-o").arg("-");

        if self.no_standard_import {
            command.arg("--no-standard-import");
        }

        for import_path in &self.import_paths {
            command.arg(&format!("--import-path={}", import_path.display()));
        }

        for src_prefix in &self.src_prefixes {
            command.arg(&format!("--src-prefix={}", src_prefix.display()));
        }

        for file in &self.files {
            command.arg(&format!("{}", file.display()));
        }

        let output_path = if let Some(output_path) = &self.output_path {
            output_path.clone()
        } else {
            // Try `OUT_DIR` by default
            PathBuf::from(::std::env::var("OUT_DIR").map_err(|error| {
                ::capnp::Error::failed(format!(
                    "Could not access `OUT_DIR` environment variable: {}. \
                     You might need to set it up or instead create you own output \
                     structure using `CompilerCommand::output_path`",
                    error
                ))
            })?)
        };

        command.stdout(::std::process::Stdio::piped());
        command.stderr(::std::process::Stdio::inherit());

        run_command(command, &output_path).map_err(|error| {
            ::capnp::Error::failed(format!(
                "Error while trying to execute `capnp compile`: {}.  \
                 Please verify that version 0.5.2 or higher of the capnp executable \
                 is installed on your system. See https://capnproto.org/install.html",
                error
            ))
        })
    }
}

#[test]
fn compiler_command_new_no_out_dir() {
    let error = CompilerCommand::new().run().unwrap_err().description;
    assert!(error.starts_with("Could not access `OUT_DIR` environment variable"));
}

#[test]
fn compiler_command_with_output_path_no_out_dir() {
    let error = CompilerCommand::new().output_path("foo").run().unwrap_err().description;
    assert!(error.starts_with("Error while trying to execute `capnp compile`"));
}
<commit_msg>use 'capnp_executable()' fluent method instead of 'run_with()'<commit_after>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do
//! [Cap'n Proto code generation](https://capnproto.org/otherlang.html#how-to-write-compiler-plugins)
//! within a Cargo build. You still need the `capnp` binary (implemented in C++).
//! (If you use a package manager, try looking for a package called
//! `capnproto`.)
//!
//! In your Cargo.toml:
//!
//! ```ignore
//! [package]
//! build = "build.rs"
//!
//! [build-dependencies]
//! capnpc = "0.12"
//! ```
//!
//! In your build.rs:
//!
//! ```ignore
//! extern crate capnpc;
//!
//! fn main() {
//!     capnpc::CompilerCommand::new()
//!         .src_prefix("schema")
//!         .file("schema/foo.capnp")
//!         .file("schema/bar.capnp")
//!         .run().expect("schema compiler command");
//! }
//! ```
//!
//! This will be equivalent to executing the shell command
//!
//! ```ignore
//!   capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//! ```
//!

extern crate capnp;

/// Code generated from
/// [schema.capnp](https://github.com/capnproto/capnproto/blob/master/c%2B%2B/src/capnp/schema.capnp).
pub mod schema_capnp;

pub mod codegen;
pub mod codegen_types;
mod pointer_constants;

use std::path::{Path, PathBuf};

fn run_command(mut command: ::std::process::Command, path: &PathBuf) -> ::capnp::Result<()> {
    let mut p = command.spawn()?;
    crate::codegen::generate_code(p.stdout.take().unwrap(), path.as_path())?;
    let exit_status = p.wait()?;
    if !exit_status.success() {
        Err(::capnp::Error::failed(format!(
            "Non-success exit status: {}",
            exit_status
        )))
    } else {
        Ok(())
    }
}

/// A builder object for schema compiler commands.
pub struct CompilerCommand {
    files: Vec<PathBuf>,
    src_prefixes: Vec<PathBuf>,
    import_paths: Vec<PathBuf>,
    no_standard_import: bool,
    executable_path: Option<PathBuf>,
    output_path: Option<PathBuf>,
}

impl CompilerCommand {
    /// Creates a new, empty command.
    pub fn new() -> CompilerCommand {
        CompilerCommand {
            files: Vec::new(),
            src_prefixes: Vec::new(),
            import_paths: Vec::new(),
            no_standard_import: false,
            executable_path: None,
            output_path: None,
        }
    }

    /// Adds a file to be compiled.
    pub fn file<P>(&mut self, path: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.files.push(path.as_ref().to_path_buf());
        self
    }

    /// Adds a --src-prefix flag. For all files specified for compilation that start
    /// with `prefix`, removes the prefix when computing output filenames.
    pub fn src_prefix<P>(&mut self, prefix: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.src_prefixes.push(prefix.as_ref().to_path_buf());
        self
    }

    /// Adds an --import_path flag. Adds `dir` to the list of directories searched
    /// for absolute imports.
    pub fn import_path<P>(&mut self, dir: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.import_paths.push(dir.as_ref().to_path_buf());
        self
    }

    /// Adds the --no-standard-import flag, indicating that the default import paths of
    /// /usr/include and /usr/local/include should not bet included.
    pub fn no_standard_import(&mut self) -> &mut CompilerCommand {
        assert!(!self.no_standard_import, "no_standard_import() must only be called once");

        self.no_standard_import = true;
        self
    }

    /// Sets the output directory of generated code. Default is OUT_DIR
    pub fn output_path<P>(&mut self, path: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        assert!(self.executable_path.is_none(), "output_path() must only be called once");

        self.output_path = Some(path.as_ref().to_path_buf());
        self
    }

    /// Specify the executable which is used for the 'capnp' tool. When this method is not called, the command looks for a name 'capnp'
    /// on the system (e.g. in working directory or in PATH environment variable).
    pub fn capnp_executable<P>(&mut self, path: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>
    {
        assert!(self.executable_path.is_none(), "capnp_executable() must only be called once");

        self.executable_path = Some(path.as_ref().to_path_buf());
        self
    }

    /// Runs the command.
    /// Returns an error if `OUT_DIR` or a custom output directory was not set, or if `capnp compile` fails.
    pub fn run(&mut self) -> ::capnp::Result<()> {
        let mut command = if let Some(executable) = &self.executable_path {
            ::std::process::Command::new(executable)
        } else {
            ::std::process::Command::new("capnp")
        };

        command.arg("compile").arg("-o").arg("-");

        if self.no_standard_import {
            command.arg("--no-standard-import");
        }

        for import_path in &self.import_paths {
            command.arg(&format!("--import-path={}", import_path.display()));
        }

        for src_prefix in &self.src_prefixes {
            command.arg(&format!("--src-prefix={}", src_prefix.display()));
        }

        for file in &self.files {
            command.arg(&format!("{}", file.display()));
        }

        let output_path = if let Some(output_path) = &self.output_path {
            output_path.clone()
        } else {
            // Try `OUT_DIR` by default
            PathBuf::from(::std::env::var("OUT_DIR").map_err(|error| {
                ::capnp::Error::failed(format!(
                    "Could not access `OUT_DIR` environment variable: {}. \
                     You might need to set it up or instead create you own output \
                     structure using `CompilerCommand::output_path`",
                    error
                ))
            })?)
        };

        command.stdout(::std::process::Stdio::piped());
        command.stderr(::std::process::Stdio::inherit());

        run_command(command, &output_path).map_err(|error| {
            ::capnp::Error::failed(format!(
                "Error while trying to execute `capnp compile`: {}.  \
                 Please verify that version 0.5.2 or higher of the capnp executable \
                 is installed on your system. See https://capnproto.org/install.html",
                error
            ))
        })
    }
}

#[test]
fn compiler_command_new_no_out_dir() {
    let error = CompilerCommand::new().run().unwrap_err().description;
    assert!(error.starts_with("Could not access `OUT_DIR` environment variable"));
}

#[test]
fn compiler_command_with_output_path_no_out_dir() {
    let error = CompilerCommand::new().output_path("foo").run().unwrap_err().description;
    assert!(error.starts_with("Error while trying to execute `capnp compile`"));
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do [Cap'n Proto code generation]
//! (https://capnproto.org/otherlang.html#how-to-write-compiler-plugins) within
//! a Cargo build. You still need the `capnp` binary (implemented in C++).
//! (If you use a package manager, try looking for a package called
//! `capnproto`.)
//!
//! In your Cargo.toml:
//!
//! ```ignore
//! [package]
//! build = "build.rs"
//!
//! [build-dependencies]
//! capnpc = "0.10"
//! ```
//!
//! In your build.rs:
//!
//! ```ignore
//! extern crate capnpc;
//!
//! fn main() {
//!     capnpc::CompilerCommand::new()
//!         .src_prefix("schema")
//!         .file("schema/foo.capnp")
//!         .file("schema/bar.capnp")
//!         .run().expect("schema compiler command");
//! }
//! ```
//!
//! This will be equivalent to executing the shell command
//!
//! ```ignore
//!   capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//! ```
//!

extern crate capnp;

/// Code generated from [schema.capnp]
/// (https://github.com/capnproto/capnproto/blob/master/c%2B%2B/src/capnp/schema.capnp).
pub mod schema_capnp;

pub mod codegen;
pub mod codegen_types;
mod pointer_constants;

use std::path::{Path, PathBuf};

#[derive(Copy, Clone)]
pub enum RustEdition {
    Rust2015,
    Rust2018,
}

fn run_command(mut command: ::std::process::Command, path: &PathBuf) -> ::capnp::Result<()> {
    let mut p = command.spawn()?;
    crate::codegen::generate_code(p.stdout.take().unwrap(), path.as_path())?;
    let exit_status = p.wait()?;
    if !exit_status.success() {
        Err(::capnp::Error::failed(format!(
            "Non-success exit status: {}",
            exit_status
        )))
    } else {
        Ok(())
    }
}

/// A builder object for schema compiler commands.
pub struct CompilerCommand {
    files: Vec<PathBuf>,
    src_prefixes: Vec<PathBuf>,
    import_paths: Vec<PathBuf>,
    no_standard_import: bool,
    output_path: Option<PathBuf>,
}

impl CompilerCommand {
    /// Creates a new, empty command.
    pub fn new() -> CompilerCommand {
        CompilerCommand {
            files: Vec::new(),
            src_prefixes: Vec::new(),
            import_paths: Vec::new(),
            no_standard_import: false,
            output_path: None,
        }
    }

    /// Adds a file to be compiled.
    pub fn file<'a, P>(&'a mut self, path: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.files.push(path.as_ref().to_path_buf());
        self
    }

    /// Adds a --src-prefix flag. For all files specified for compilation that start
    /// with `prefix`, removes the prefix when computing output filenames.
    pub fn src_prefix<'a, P>(&'a mut self, prefix: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.src_prefixes.push(prefix.as_ref().to_path_buf());
        self
    }

    /// Adds an --import_path flag. Adds `dir` to the list of directories searched
    /// for absolute imports.
    pub fn import_path<'a, P>(&'a mut self, dir: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.import_paths.push(dir.as_ref().to_path_buf());
        self
    }

    /// Adds the --no-standard-import flag, indicating that the default import paths of
    /// /usr/include and /usr/local/include should not bet included.
    pub fn no_standard_import<'a>(&'a mut self) -> &'a mut CompilerCommand {
        self.no_standard_import = true;
        self
    }

    /// Sets the Rust edition of the generated code.
    #[deprecated(since = "0.10.0", note = "no longer need to specify rust edition")]
    pub fn edition(&mut self, _rust_edition: RustEdition) -> &mut Self {
        self
    }

    ///Sets the output directory of generated code. Default is OUT_DIR
    pub fn output_path<'a, P>(&'a mut self, path: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.output_path = Some(path.as_ref().to_path_buf());
        self
    }

    /// Runs the command. Returns an error if `OUT_DIR` or a custom output directory was not set
    /// or if `capnp compile` fails.
    pub fn run(&mut self) -> ::capnp::Result<()> {
        let mut command = ::std::process::Command::new("capnp");
        command.arg("compile").arg("-o").arg("-");

        if self.no_standard_import {
            command.arg("--no-standard-import");
        }

        for import_path in &self.import_paths {
            command.arg(&format!("--import-path={}", import_path.display()));
        }

        for src_prefix in &self.src_prefixes {
            command.arg(&format!("--src-prefix={}", src_prefix.display()));
        }

        for file in &self.files {
            command.arg(&format!("{}", file.display()));
        }

        let output_path = if let Some(output_path) = &self.output_path {
            output_path.clone()
        } else {
            // Try `OUT_DIR` by default
            PathBuf::from(::std::env::var("OUT_DIR").map_err(|error| {
                ::capnp::Error::failed(format!(
                    "Could not access `OUT_DIR` environment variable: {}. \
                     You might need to set it up or instead create you own output \
                     structure using `CompilerCommand::output_path`",
                    error
                ))
            })?)
        };

        command.stdout(::std::process::Stdio::piped());
        command.stderr(::std::process::Stdio::inherit());

        run_command(command, &output_path).map_err(|error| {
            ::capnp::Error::failed(format!(
                "Error while trying to execute `capnp compile`: {}.  \
                 Please verify that version 0.5.2 or higher of the capnp executable \
                 is installed on your system. See https://capnproto.org/install.html",
                error
            ))
        })
    }
}

#[test]
fn compiler_command_new_no_out_dir() {
    let error = CompilerCommand::new().run().unwrap_err().description;
    assert!(error.starts_with("Could not access `OUT_DIR` environment variable"));
}

#[test]
fn compiler_command_with_output_path_no_out_dir() {
    let error = CompilerCommand::new().output_path("foo").run().unwrap_err().description;
    assert!(error.starts_with("Error while trying to execute `capnp compile`"));
}
<commit_msg>remove deprecated CompilerCommand::edition() method<commit_after>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do [Cap'n Proto code generation]
//! (https://capnproto.org/otherlang.html#how-to-write-compiler-plugins) within
//! a Cargo build. You still need the `capnp` binary (implemented in C++).
//! (If you use a package manager, try looking for a package called
//! `capnproto`.)
//!
//! In your Cargo.toml:
//!
//! ```ignore
//! [package]
//! build = "build.rs"
//!
//! [build-dependencies]
//! capnpc = "0.10"
//! ```
//!
//! In your build.rs:
//!
//! ```ignore
//! extern crate capnpc;
//!
//! fn main() {
//!     capnpc::CompilerCommand::new()
//!         .src_prefix("schema")
//!         .file("schema/foo.capnp")
//!         .file("schema/bar.capnp")
//!         .run().expect("schema compiler command");
//! }
//! ```
//!
//! This will be equivalent to executing the shell command
//!
//! ```ignore
//!   capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//! ```
//!

extern crate capnp;

/// Code generated from [schema.capnp]
/// (https://github.com/capnproto/capnproto/blob/master/c%2B%2B/src/capnp/schema.capnp).
pub mod schema_capnp;

pub mod codegen;
pub mod codegen_types;
mod pointer_constants;

use std::path::{Path, PathBuf};

#[derive(Copy, Clone)]
pub enum RustEdition {
    Rust2015,
    Rust2018,
}

fn run_command(mut command: ::std::process::Command, path: &PathBuf) -> ::capnp::Result<()> {
    let mut p = command.spawn()?;
    crate::codegen::generate_code(p.stdout.take().unwrap(), path.as_path())?;
    let exit_status = p.wait()?;
    if !exit_status.success() {
        Err(::capnp::Error::failed(format!(
            "Non-success exit status: {}",
            exit_status
        )))
    } else {
        Ok(())
    }
}

/// A builder object for schema compiler commands.
pub struct CompilerCommand {
    files: Vec<PathBuf>,
    src_prefixes: Vec<PathBuf>,
    import_paths: Vec<PathBuf>,
    no_standard_import: bool,
    output_path: Option<PathBuf>,
}

impl CompilerCommand {
    /// Creates a new, empty command.
    pub fn new() -> CompilerCommand {
        CompilerCommand {
            files: Vec::new(),
            src_prefixes: Vec::new(),
            import_paths: Vec::new(),
            no_standard_import: false,
            output_path: None,
        }
    }

    /// Adds a file to be compiled.
    pub fn file<'a, P>(&'a mut self, path: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.files.push(path.as_ref().to_path_buf());
        self
    }

    /// Adds a --src-prefix flag. For all files specified for compilation that start
    /// with `prefix`, removes the prefix when computing output filenames.
    pub fn src_prefix<'a, P>(&'a mut self, prefix: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.src_prefixes.push(prefix.as_ref().to_path_buf());
        self
    }

    /// Adds an --import_path flag. Adds `dir` to the list of directories searched
    /// for absolute imports.
    pub fn import_path<'a, P>(&'a mut self, dir: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.import_paths.push(dir.as_ref().to_path_buf());
        self
    }

    /// Adds the --no-standard-import flag, indicating that the default import paths of
    /// /usr/include and /usr/local/include should not bet included.
    pub fn no_standard_import<'a>(&'a mut self) -> &'a mut CompilerCommand {
        self.no_standard_import = true;
        self
    }

    ///Sets the output directory of generated code. Default is OUT_DIR
    pub fn output_path<'a, P>(&'a mut self, path: P) -> &'a mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.output_path = Some(path.as_ref().to_path_buf());
        self
    }

    /// Runs the command. Returns an error if `OUT_DIR` or a custom output directory was not set
    /// or if `capnp compile` fails.
    pub fn run(&mut self) -> ::capnp::Result<()> {
        let mut command = ::std::process::Command::new("capnp");
        command.arg("compile").arg("-o").arg("-");

        if self.no_standard_import {
            command.arg("--no-standard-import");
        }

        for import_path in &self.import_paths {
            command.arg(&format!("--import-path={}", import_path.display()));
        }

        for src_prefix in &self.src_prefixes {
            command.arg(&format!("--src-prefix={}", src_prefix.display()));
        }

        for file in &self.files {
            command.arg(&format!("{}", file.display()));
        }

        let output_path = if let Some(output_path) = &self.output_path {
            output_path.clone()
        } else {
            // Try `OUT_DIR` by default
            PathBuf::from(::std::env::var("OUT_DIR").map_err(|error| {
                ::capnp::Error::failed(format!(
                    "Could not access `OUT_DIR` environment variable: {}. \
                     You might need to set it up or instead create you own output \
                     structure using `CompilerCommand::output_path`",
                    error
                ))
            })?)
        };

        command.stdout(::std::process::Stdio::piped());
        command.stderr(::std::process::Stdio::inherit());

        run_command(command, &output_path).map_err(|error| {
            ::capnp::Error::failed(format!(
                "Error while trying to execute `capnp compile`: {}.  \
                 Please verify that version 0.5.2 or higher of the capnp executable \
                 is installed on your system. See https://capnproto.org/install.html",
                error
            ))
        })
    }
}

#[test]
fn compiler_command_new_no_out_dir() {
    let error = CompilerCommand::new().run().unwrap_err().description;
    assert!(error.starts_with("Could not access `OUT_DIR` environment variable"));
}

#[test]
fn compiler_command_with_output_path_no_out_dir() {
    let error = CompilerCommand::new().output_path("foo").run().unwrap_err().description;
    assert!(error.starts_with("Error while trying to execute `capnp compile`"));
}
<|endoftext|>


<commit_before>#![crate_name = "objc"]
#![crate_type = "lib"]

#![feature(unsafe_destructor)]
#![allow(unstable)]

extern crate libc;

#[cfg(test)]
extern crate objc_test_utils;

pub use id::{Id, IdVector, IntoIdVector, Owned, Ownership, Shared, ShareId};
pub use declare::{ClassDecl, MethodDecl};
pub use encode::{encode, Encode, Encoding};
pub use message::{to_obj_ptr, Message, ToMessage};
pub use weak::WeakId;

#[macro_use]
mod macros;

pub mod runtime;
mod id;
pub mod block;
mod declare;
mod encode;
mod message;
mod weak;
<commit_msg>Added unboxed_closures feature for the latest rust.<commit_after>#![crate_name = "objc"]
#![crate_type = "lib"]

#![feature(unboxed_closures, unsafe_destructor)]
#![allow(unstable)]

extern crate libc;

#[cfg(test)]
extern crate objc_test_utils;

pub use id::{Id, IdVector, IntoIdVector, Owned, Ownership, Shared, ShareId};
pub use declare::{ClassDecl, MethodDecl};
pub use encode::{encode, Encode, Encoding};
pub use message::{to_obj_ptr, Message, ToMessage};
pub use weak::WeakId;

#[macro_use]
mod macros;

pub mod runtime;
mod id;
pub mod block;
mod declare;
mod encode;
mod message;
mod weak;
<|endoftext|>


<commit_before>#![cfg(feature = "logs")]
#![deny(warnings)]
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate rusoto_core;
extern crate rusoto_credential;
extern crate rusoto_logs;

use rusoto_core::{HttpClient, Region, RusotoError};
use rusoto_core::encoding::ContentEncoding;
use rusoto_credential::DefaultCredentialsProvider;
use rusoto_logs::{
    CloudWatchLogs, CloudWatchLogsClient, CreateLogGroupError, CreateLogGroupRequest,
    CreateLogStreamError, CreateLogStreamRequest, DeleteLogGroupRequest, DescribeLogStreamsRequest,
    GetLogEventsRequest, InputLogEvent, PutLogEventsRequest, GetLogEventsResponse,
};
use std::fs;
use std::time::SystemTime;
use std::{thread, time};

fn rusoto_logs_test_executor(client: CloudWatchLogsClient, log_group: &str, log_stream: &str) {
    let _ = env_logger::try_init();

    // First, create the log group
    let mut create_log_group_req: CreateLogGroupRequest = Default::default();
    create_log_group_req.log_group_name = log_group.to_string();
    client
        .create_log_group(create_log_group_req)
        .sync()
        .unwrap_or_else(|e| {
            match e {
                RusotoError::Service(CreateLogGroupError::ResourceAlreadyExists(err)) => {
                    warn!("CreateLogGroupError::ResourceAlreadyExists: {}", err);
                    // It's fine, continue
                }
                err => {
                    panic!("Failed to create log group: {}", err);
                }
            }
        });

    // Create the log stream for that log group
    let create_log_stream_req = CreateLogStreamRequest {
        log_group_name: log_group.to_string(),
        log_stream_name: log_stream.to_string(),
    };
    client
        .create_log_stream(create_log_stream_req)
        .sync()
        .unwrap_or_else(|e| {
            match e {
                RusotoError::Service(CreateLogStreamError::ResourceAlreadyExists(err)) => {
                    warn!("CreateLogStreamError::ResourceAlreadyExists: {}", err);
                    // It's fine, continue
                }
                err => {
                    panic!("Failed to create log group: {}", err);
                }
            }
        });

    // Describe log stream to fetch sequence token
    let mut desc_streams_req: DescribeLogStreamsRequest = Default::default();
    desc_streams_req.log_group_name = log_group.to_owned();
    desc_streams_req.log_stream_name_prefix = Some(log_stream.to_owned());
    let streams_resp = client.describe_log_streams(desc_streams_req).sync();
    let log_streams = streams_resp.unwrap().log_streams.unwrap();
    let stream = &log_streams
        .iter()
        .find(|s| s.log_stream_name == Some(log_stream.to_string()))
        .unwrap();
    let upload_sequence_token = stream.upload_sequence_token.clone();

    // Prepare event data with a huge log message
    let data = fs::read_to_string("tests/sample-data/sagan.log").expect("Unable to read file");
    let now = SystemTime::now()
        .duration_since(SystemTime::UNIX_EPOCH)
        .unwrap()
        .as_millis() as i64;
    let input_event = InputLogEvent {
        message: data,
        timestamp: now,
    };
    let mut input_events = Vec::<InputLogEvent>::new();
    input_events.push(input_event.clone());

    // Now put the log event
    let put_log_req = PutLogEventsRequest {
        log_events: input_events.clone(),
        log_group_name: log_group.to_owned(),
        log_stream_name: log_stream.to_owned(),
        sequence_token: upload_sequence_token,
    };
    client
        .put_log_events(put_log_req.clone())
        .sync()
        .unwrap_or_else(|e| panic!("Failed on put log events: {:?}", e));

    // Get log events back to verify if it successfully reached
    let mut get_log_req: GetLogEventsRequest = Default::default();
    get_log_req.log_group_name = log_group.to_owned();
    get_log_req.log_stream_name = log_stream.to_owned();
    // Restrict timestamp to fetch only our event
    get_log_req.start_time = Some(input_event.timestamp - 1);
    get_log_req.end_time = Some(input_event.timestamp + 1);

    // It takes time for Cloudwatch to organize events. Retry until it's ready.
    let retry_count = 5;
    let mut i = 0;
    let get_log_resp: Option<GetLogEventsResponse> = loop {
        if i == retry_count {
            break None;
        }
        info!("Trying to get log events: {} out of {} times", i, retry_count);
        let get_log_resp = client
            .get_log_events(get_log_req.clone())
            .sync()
            .unwrap_or_else(|e| panic!("Failed on get log events: {}", e));
        if (get_log_resp.events).as_ref().unwrap().len() != 0_usize {
            break Some(get_log_resp);
        } else {
            i = i + 1;
            // sleep for one second before calling again
            thread::sleep(time::Duration::from_secs(1));
        }
    };

    if get_log_resp.is_none() {
        panic!("Failed to get log events for {} times", retry_count);
    }

    // Assert that our event is there
    let output_event = &get_log_resp.unwrap().events.unwrap()[0];
    assert_eq!(output_event.message.as_ref().unwrap(), &input_events[0].message);
    assert_eq!(output_event.timestamp.unwrap(), input_events[0].timestamp);

    // Delete log group. This will clear all resources so we would not leak anything.
    let del_log_group_req = DeleteLogGroupRequest {
        log_group_name: log_group.to_owned(),
    };
    client.delete_log_group(del_log_group_req).sync().unwrap_or_else(|e| {
        panic!("Failed to delete log group:/n{}", e)
    });
}

#[test]
fn should_put_log_events() {
    let http_client = HttpClient::new().expect("failed to create request dispatcher");
    let creds_provider = DefaultCredentialsProvider::new()
        .expect("failed to create default credentials provider");
    let client = CloudWatchLogsClient::new_with(
        http_client,
        creds_provider,
        Region::UsWest2,
    );
    rusoto_logs_test_executor(client, "should_put_log_events", "should_put_log_events");
}

#[cfg(feature = "encoding")]
#[test]
fn should_put_log_events_with_gzip_encoding() {
    let http_client = HttpClient::new().expect("failed to create request dispatcher");
    let creds_provider = DefaultCredentialsProvider::new()
        .expect("failed to create default credentials provider");
    let mut client = CloudWatchLogsClient::new_with(
        http_client,
        creds_provider,
        Region::UsWest2,
    );
    client.set_http_content_encoding(ContentEncoding::Gzip(Some(1024), rusoto_core::flate2::Compression::default()));
    rusoto_logs_test_executor(client, "should_put_log_events_with_encoding", "should_put_log_events_with_encoding");
}
<commit_msg>Run cargo fmt on integration tests<commit_after>#![cfg(feature = "logs")]
#![deny(warnings)]
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate rusoto_core;
extern crate rusoto_credential;
extern crate rusoto_logs;

use rusoto_core::encoding::ContentEncoding;
use rusoto_core::{HttpClient, Region, RusotoError};
use rusoto_credential::DefaultCredentialsProvider;
use rusoto_logs::{
    CloudWatchLogs, CloudWatchLogsClient, CreateLogGroupError, CreateLogGroupRequest,
    CreateLogStreamError, CreateLogStreamRequest, DeleteLogGroupRequest, DescribeLogStreamsRequest,
    GetLogEventsRequest, GetLogEventsResponse, InputLogEvent, PutLogEventsRequest,
};
use std::fs;
use std::time::SystemTime;
use std::{thread, time};

fn rusoto_logs_test_executor(client: CloudWatchLogsClient, log_group: &str, log_stream: &str) {
    let _ = env_logger::try_init();

    // First, create the log group
    let mut create_log_group_req: CreateLogGroupRequest = Default::default();
    create_log_group_req.log_group_name = log_group.to_string();
    client
        .create_log_group(create_log_group_req)
        .sync()
        .unwrap_or_else(|e| {
            match e {
                RusotoError::Service(CreateLogGroupError::ResourceAlreadyExists(err)) => {
                    warn!("CreateLogGroupError::ResourceAlreadyExists: {}", err);
                    // It's fine, continue
                }
                err => {
                    panic!("Failed to create log group: {}", err);
                }
            }
        });

    // Create the log stream for that log group
    let create_log_stream_req = CreateLogStreamRequest {
        log_group_name: log_group.to_string(),
        log_stream_name: log_stream.to_string(),
    };
    client
        .create_log_stream(create_log_stream_req)
        .sync()
        .unwrap_or_else(|e| {
            match e {
                RusotoError::Service(CreateLogStreamError::ResourceAlreadyExists(err)) => {
                    warn!("CreateLogStreamError::ResourceAlreadyExists: {}", err);
                    // It's fine, continue
                }
                err => {
                    panic!("Failed to create log group: {}", err);
                }
            }
        });

    // Describe log stream to fetch sequence token
    let mut desc_streams_req: DescribeLogStreamsRequest = Default::default();
    desc_streams_req.log_group_name = log_group.to_owned();
    desc_streams_req.log_stream_name_prefix = Some(log_stream.to_owned());
    let streams_resp = client.describe_log_streams(desc_streams_req).sync();
    let log_streams = streams_resp.unwrap().log_streams.unwrap();
    let stream = &log_streams
        .iter()
        .find(|s| s.log_stream_name == Some(log_stream.to_string()))
        .unwrap();
    let upload_sequence_token = stream.upload_sequence_token.clone();

    // Prepare event data with a huge log message
    let data = fs::read_to_string("tests/sample-data/sagan.log").expect("Unable to read file");
    let now = SystemTime::now()
        .duration_since(SystemTime::UNIX_EPOCH)
        .unwrap()
        .as_millis() as i64;
    let input_event = InputLogEvent {
        message: data,
        timestamp: now,
    };
    let mut input_events = Vec::<InputLogEvent>::new();
    input_events.push(input_event.clone());

    // Now put the log event
    let put_log_req = PutLogEventsRequest {
        log_events: input_events.clone(),
        log_group_name: log_group.to_owned(),
        log_stream_name: log_stream.to_owned(),
        sequence_token: upload_sequence_token,
    };
    client
        .put_log_events(put_log_req.clone())
        .sync()
        .unwrap_or_else(|e| panic!("Failed on put log events: {:?}", e));

    // Get log events back to verify if it successfully reached
    let mut get_log_req: GetLogEventsRequest = Default::default();
    get_log_req.log_group_name = log_group.to_owned();
    get_log_req.log_stream_name = log_stream.to_owned();
    // Restrict timestamp to fetch only our event
    get_log_req.start_time = Some(input_event.timestamp - 1);
    get_log_req.end_time = Some(input_event.timestamp + 1);

    // It takes time for Cloudwatch to organize events. Retry until it's ready.
    let retry_count = 5;
    let mut i = 0;
    let get_log_resp: Option<GetLogEventsResponse> = loop {
        if i == retry_count {
            break None;
        }
        info!(
            "Trying to get log events: {} out of {} times",
            i, retry_count
        );
        let get_log_resp = client
            .get_log_events(get_log_req.clone())
            .sync()
            .unwrap_or_else(|e| panic!("Failed on get log events: {}", e));
        if (get_log_resp.events).as_ref().unwrap().len() != 0_usize {
            break Some(get_log_resp);
        } else {
            i = i + 1;
            // sleep for one second before calling again
            thread::sleep(time::Duration::from_secs(1));
        }
    };

    if get_log_resp.is_none() {
        panic!("Failed to get log events for {} times", retry_count);
    }

    // Assert that our event is there
    let output_event = &get_log_resp.unwrap().events.unwrap()[0];
    assert_eq!(
        output_event.message.as_ref().unwrap(),
        &input_events[0].message
    );
    assert_eq!(output_event.timestamp.unwrap(), input_events[0].timestamp);

    // Delete log group. This will clear all resources so we would not leak anything.
    let del_log_group_req = DeleteLogGroupRequest {
        log_group_name: log_group.to_owned(),
    };
    client
        .delete_log_group(del_log_group_req)
        .sync()
        .unwrap_or_else(|e| panic!("Failed to delete log group:/n{}", e));
}

#[test]
fn should_put_log_events() {
    let http_client = HttpClient::new().expect("failed to create request dispatcher");
    let creds_provider =
        DefaultCredentialsProvider::new().expect("failed to create default credentials provider");
    let client = CloudWatchLogsClient::new_with(http_client, creds_provider, Region::UsWest2);
    rusoto_logs_test_executor(client, "should_put_log_events", "should_put_log_events");
}

#[cfg(feature = "encoding")]
#[test]
fn should_put_log_events_with_gzip_encoding() {
    let http_client = HttpClient::new().expect("failed to create request dispatcher");
    let creds_provider =
        DefaultCredentialsProvider::new().expect("failed to create default credentials provider");
    let mut client = CloudWatchLogsClient::new_with(http_client, creds_provider, Region::UsWest2);
    client.set_http_content_encoding(ContentEncoding::Gzip(
        Some(1024),
        rusoto_core::flate2::Compression::default(),
    ));
    rusoto_logs_test_executor(
        client,
        "should_put_log_events_with_encoding",
        "should_put_log_events_with_encoding",
    );
}

fn should_put_log_events_with_gzip_encoding_via_shared_client() {
    let http_client = HttpClient::new().expect("failed to create request dispatcher");
    let creds_provider =
        DefaultCredentialsProvider::new().expect("failed to create default credentials provider");
    let mut client = CloudWatchLogsClient::new_with(http_client, creds_provider, Region::UsWest2);
    client.set_http_content_encoding(ContentEncoding::Gzip(
        Some(1024),
        rusoto_core::flate2::Compression::default(),
    ));
    let mut client = rusoto_core::Shared
    rusoto_logs_test_executor(
        client,
        "should_put_log_events_with_gzip_encoding_via_shared_client",
        "should_put_log_events_with_gzip_encoding_via_shared_client",
    );
}
<|endoftext|>