<commit_before>use serde::de::{Deserialize, Deserializer, Error, MapVisitor, SeqVisitor, Type, Visitor};
use serde::de::impls::IgnoredAny;

// https://tools.ietf.org/html/rfc7946#section-3.1
#[derive(Clone, Debug, PartialEq)]
pub enum Geometry {
    Point(Position),
    MultiPoint(Vec<Position>),
    LineString(LineString),
    MultiLineString(Vec<LineString>),
    Polygon(Polygon),
    MultiPolygon(Vec<Polygon>),
    // GeometryCollection(Vec<Geometry>),
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Position(
    /// Longitude
    pub f64,
    /// Latitude
    pub f64,
    // Twitter API does not provide altitudes
);

pub type LineString = Vec<Position>;
pub type Polygon = Vec<LinearRing>;
pub type LinearRing = LineString;

impl Deserialize for Geometry {
    fn deserialize<D: Deserializer>(d: &mut D) -> Result<Self, D::Error> {
        struct GeometryVisitor;

        impl Visitor for GeometryVisitor {
            type Value = Geometry;

            fn visit_map<V: MapVisitor>(&mut self, mut v: V) -> Result<Geometry, V::Error> {
                enum Coordinates {
                    F64(f64),
                    Dim0(Position), // Point
                    Dim1(Vec<Position>), // MultiPoint, LineString
                    Dim2(Vec<Vec<Position>>), // MultiLineString, Polygon
                    Dim3(Vec<Vec<Vec<Position>>>), // MultiPolygon
                }

                impl Deserialize for Coordinates {
                    fn deserialize<D: Deserializer>(d: &mut D) -> Result<Self, D::Error> {
                        struct CoordinatesVisitor;

                        impl Visitor for CoordinatesVisitor {
                            type Value = Coordinates;

                            fn visit_f64<E>(&mut self, v: f64) -> Result<Coordinates, E> {
                                Ok(Coordinates::F64(v))
                            }

                            fn visit_seq<V: SeqVisitor>(&mut self, mut v: V) -> Result<Coordinates, V::Error> {
                                macro_rules! match_val {
                                    (
                                        $C:ident,
                                        $($V:ident => $R:ident,)*
                                    ) => {
                                        match v.visit()? {
                                            Some($C::F64(v1)) => {
                                                let v2 = match v.visit()? {
                                                    Some(val) => val,
                                                    None => return Err(V::Error::invalid_length(1)),
                                                };
                                                while let Some(_) = v.visit::<IgnoredAny>()? {}
                                                v.end()?;
                                                Ok($C::Dim0(Position(v1, v2)))
                                            },
                                            $(Some($C::$V(val)) => {
                                                let mut ret = Vec::with_capacity(v.size_hint().0 + 1);
                                                ret.push(val);
                                                while let Some(val) = v.visit()? {
                                                    ret.push(val);
                                                }
                                                v.end()?;
                                                Ok($C::$R(ret))
                                            },)*
                                            Some($C::Dim3(_)) => Err(V::Error::invalid_type(Type::Seq)),
                                            None => Ok($C::Dim1(Vec::new())),
                                        }
                                    };
                                }

                                match_val! {
                                    Coordinates,
                                    Dim0 => Dim1,
                                    Dim1 => Dim2,
                                    Dim2 => Dim3,
                                }
                            }
                        }

                        d.deserialize_seq(CoordinatesVisitor)
                    }
                }

                let mut c = None;

                use self::Geometry::*;

                macro_rules! end {
                    () => {{
                        while let Some(_) = v.visit::<IgnoredAny, IgnoredAny>()? {}
                        v.end()?;
                    }};
                }

                while let Some(k) = v.visit_key::<String>()? {
                    match k.as_str() {
                        "type" => {
                            let t = v.visit_value::<String>()?;
                            macro_rules! match_type {
                                ($C:ident, $($($V:ident($typ:expr))|* => $D:ident,)*) => {
                                    match t.as_str() {
                                        $($($typ => match c {
                                            Some($C::$D(val)) => {
                                                end!();
                                                return Ok($V(val));
                                            },
                                            None => {
                                                while let Some(k) = v.visit_key::<String>()? {
                                                    match k.as_str() {
                                                        "coordinates" => {
                                                            end!();
                                                            return Ok($V(v.visit_value()?));
                                                        },
                                                        _ => { v.visit_value::<IgnoredAny>()?; },
                                                    }
                                                }
                                                return Err(V::Error::missing_field("coordinates"));
                                            },
                                            _ => return Err(V::Error::custom("invalid coordinates type")),
                                        },)*)*
                                        s => return Err(V::Error::unknown_variant(&s)),
                                    }
                                };
                            }
                            match_type! {
                                Coordinates,
                                Point("Point") => Dim0,
                                MultiPoint("MultiPoint") | LineString("LineString") => Dim1,
                                MultiLineString("MultiLineString") | Polygon("Polygon") => Dim2,
                                MultiPolygon("MultiPolygon") => Dim3,
                            }
                        },
                        "coordinates" => c = Some(v.visit_value()?),
                        _ => { v.visit_value::<IgnoredAny>()?; },
                    }
                }

                v.missing_field("type")
            }
        }

        d.deserialize_map(GeometryVisitor)
    }
}

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

    #[test]
    fn deserialize() {
        assert_eq!(
            Geometry::Point(Position(-75.14310264, 40.05701649)),
            json::from_str("{\"coordinates\":[-75.14310264,40.05701649],\"type\":\"Point\"}").unwrap()
        );
        assert_eq!(
            Geometry::Polygon(vec![vec![Position(2.2241006,48.8155414), Position(2.4699099,48.8155414),
                Position(2.4699099,48.9021461), Position(2.2241006,48.9021461)]]),
            json::from_str("{\"coordinates\":[
                [[2.2241006,48.8155414],[2.4699099,48.8155414],[2.4699099,48.9021461],[2.2241006,48.9021461]]
                ],\"type\":\"Polygon\"}").unwrap()
        );
    }
}
<commit_msg>Fix issue where Geometry failed in a certain condition<commit_after>use serde::de::{Deserialize, Deserializer, Error, MapVisitor, SeqVisitor, Type, Visitor};
use serde::de::impls::IgnoredAny;

// https://tools.ietf.org/html/rfc7946#section-3.1
#[derive(Clone, Debug, PartialEq)]
pub enum Geometry {
    Point(Position),
    MultiPoint(Vec<Position>),
    LineString(LineString),
    MultiLineString(Vec<LineString>),
    Polygon(Polygon),
    MultiPolygon(Vec<Polygon>),
    // GeometryCollection(Vec<Geometry>),
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Position(
    /// Longitude
    pub f64,
    /// Latitude
    pub f64,
    // Twitter API does not provide altitudes
);

pub type LineString = Vec<Position>;
pub type Polygon = Vec<LinearRing>;
pub type LinearRing = LineString;

impl Deserialize for Geometry {
    fn deserialize<D: Deserializer>(d: &mut D) -> Result<Self, D::Error> {
        struct GeometryVisitor;

        impl Visitor for GeometryVisitor {
            type Value = Geometry;

            fn visit_map<V: MapVisitor>(&mut self, mut v: V) -> Result<Geometry, V::Error> {
                enum Coordinates {
                    F64(f64),
                    Dim0(Position), // Point
                    Dim1(Vec<Position>), // MultiPoint, LineString
                    Dim2(Vec<Vec<Position>>), // MultiLineString, Polygon
                    Dim3(Vec<Vec<Vec<Position>>>), // MultiPolygon
                }

                impl Deserialize for Coordinates {
                    fn deserialize<D: Deserializer>(d: &mut D) -> Result<Self, D::Error> {
                        struct CoordinatesVisitor;

                        impl Visitor for CoordinatesVisitor {
                            type Value = Coordinates;

                            fn visit_f64<E>(&mut self, v: f64) -> Result<Coordinates, E> {
                                Ok(Coordinates::F64(v))
                            }

                            fn visit_i64<E>(&mut self, v: i64) -> Result<Coordinates, E> {
                                Ok(Coordinates::F64(v as _))
                            }

                            fn visit_u64<E>(&mut self, v: u64) -> Result<Coordinates, E> {
                                Ok(Coordinates::F64(v as _))
                            }

                            fn visit_seq<V: SeqVisitor>(&mut self, mut v: V) -> Result<Coordinates, V::Error> {
                                macro_rules! match_val {
                                    (
                                        $C:ident,
                                        $($V:ident => $R:ident,)*
                                    ) => {
                                        match v.visit()? {
                                            Some($C::F64(v1)) => {
                                                let v2 = match v.visit()? {
                                                    Some(val) => val,
                                                    None => return Err(V::Error::invalid_length(1)),
                                                };
                                                while let Some(_) = v.visit::<IgnoredAny>()? {}
                                                v.end()?;
                                                Ok($C::Dim0(Position(v1, v2)))
                                            },
                                            $(Some($C::$V(val)) => {
                                                let mut ret = Vec::with_capacity(v.size_hint().0 + 1);
                                                ret.push(val);
                                                while let Some(val) = v.visit()? {
                                                    ret.push(val);
                                                }
                                                v.end()?;
                                                Ok($C::$R(ret))
                                            },)*
                                            Some($C::Dim3(_)) => Err(V::Error::invalid_type(Type::Seq)),
                                            None => Ok($C::Dim1(Vec::new())),
                                        }
                                    };
                                }

                                match_val! {
                                    Coordinates,
                                    Dim0 => Dim1,
                                    Dim1 => Dim2,
                                    Dim2 => Dim3,
                                }
                            }
                        }

                        d.deserialize_seq(CoordinatesVisitor)
                    }
                }

                let mut c = None;

                use self::Geometry::*;

                macro_rules! end {
                    () => {{
                        while let Some(_) = v.visit::<IgnoredAny, IgnoredAny>()? {}
                        v.end()?;
                    }};
                }

                while let Some(k) = v.visit_key::<String>()? {
                    match k.as_str() {
                        "type" => {
                            let t = v.visit_value::<String>()?;
                            macro_rules! match_type {
                                ($C:ident, $($($V:ident($typ:expr))|* => $D:ident,)*) => {
                                    match t.as_str() {
                                        $($($typ => match c {
                                            Some($C::$D(val)) => {
                                                end!();
                                                return Ok($V(val));
                                            },
                                            None => {
                                                while let Some(k) = v.visit_key::<String>()? {
                                                    match k.as_str() {
                                                        "coordinates" => {
                                                            end!();
                                                            return Ok($V(v.visit_value()?));
                                                        },
                                                        _ => { v.visit_value::<IgnoredAny>()?; },
                                                    }
                                                }
                                                return Err(V::Error::missing_field("coordinates"));
                                            },
                                            _ => return Err(V::Error::custom("invalid coordinates type")),
                                        },)*)*
                                        s => return Err(V::Error::unknown_variant(&s)),
                                    }
                                };
                            }
                            match_type! {
                                Coordinates,
                                Point("Point") => Dim0,
                                MultiPoint("MultiPoint") | LineString("LineString") => Dim1,
                                MultiLineString("MultiLineString") | Polygon("Polygon") => Dim2,
                                MultiPolygon("MultiPolygon") => Dim3,
                            }
                        },
                        "coordinates" => c = Some(v.visit_value()?),
                        _ => { v.visit_value::<IgnoredAny>()?; },
                    }
                }

                v.missing_field("type")
            }
        }

        d.deserialize_map(GeometryVisitor)
    }
}

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

    #[test]
    fn deserialize() {
        assert_eq!(
            Geometry::Point(Position(-75.14310264, 40.05701649)),
            json::from_str("{\"coordinates\":[-75.14310264,40.05701649],\"type\":\"Point\"}").unwrap()
        );
        assert_eq!(
            Geometry::Polygon(vec![vec![Position(2.2241006,48.8155414), Position(2.4699099,48.8155414),
                Position(2.4699099,48.9021461), Position(2.2241006,48.9021461)]]),
            json::from_str("{\"coordinates\":[
                [[2.2241006,48.8155414],[2.4699099,48.8155414],[2.4699099,48.9021461],[2.2241006,48.9021461]]
                ],\"type\":\"Polygon\"}").unwrap()
        );
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Seek};
use std::path::Path;
use std::u32;

#[cfg(feature = "bmp")]
use crate::codecs::bmp;
#[cfg(feature = "gif")]
use crate::codecs::gif;
#[cfg(feature = "hdr")]
use crate::codecs::hdr;
#[cfg(feature = "ico")]
use crate::codecs::ico;
#[cfg(feature = "jpeg")]
use crate::codecs::jpeg;
#[cfg(feature = "png")]
use crate::codecs::png;
#[cfg(feature = "pnm")]
use crate::codecs::pnm;
#[cfg(feature = "tga")]
use crate::codecs::tga;
#[cfg(feature = "dds")]
use crate::codecs::dds;
#[cfg(feature = "tiff")]
use crate::codecs::tiff;
#[cfg(feature = "webp")]
use crate::codecs::webp;
#[cfg(feature = "farbfeld")]
use crate::codecs::farbfeld;
#[cfg(any(feature = "avif-encoder", feature = "avif-decoder"))]
use crate::codecs::avif;

use crate::{ImageOutputFormat, color};
use crate::image;
use crate::dynimage::DynamicImage;
use crate::error::{ImageError, ImageFormatHint, ImageResult};
use crate::image::ImageFormat;
#[allow(unused_imports)]  // When no features are supported
use crate::image::{ImageDecoder, ImageEncoder};

pub(crate) fn open_impl(path: &Path) -> ImageResult<DynamicImage> {
    let fin = match File::open(path) {
        Ok(f) => f,
        Err(err) => return Err(ImageError::IoError(err)),
    };
    let fin = BufReader::new(fin);

    load(fin, ImageFormat::from_path(path)?)
}

/// Create a new image from a Reader
///
/// Try [`io::Reader`] for more advanced uses.
///
/// [`io::Reader`]: io/struct.Reader.html
#[allow(unused_variables)]
// r is unused if no features are supported.
pub fn load<R: BufRead + Seek>(r: R, format: ImageFormat) -> ImageResult<DynamicImage> {
    #[allow(unreachable_patterns)]
    // Default is unreachable if all features are supported.
    match format {
        #[cfg(feature = "avif-decoder")]
        image::ImageFormat::Avif => DynamicImage::from_decoder(avif::AvifDecoder::new(r)?),
        #[cfg(feature = "png")]
        image::ImageFormat::Png => DynamicImage::from_decoder(png::PngDecoder::new(r)?),
        #[cfg(feature = "gif")]
        image::ImageFormat::Gif => DynamicImage::from_decoder(gif::GifDecoder::new(r)?),
        #[cfg(feature = "jpeg")]
        image::ImageFormat::Jpeg => DynamicImage::from_decoder(jpeg::JpegDecoder::new(r)?),
        #[cfg(feature = "webp")]
        image::ImageFormat::WebP => DynamicImage::from_decoder(webp::WebPDecoder::new(r)?),
        #[cfg(feature = "tiff")]
        image::ImageFormat::Tiff => DynamicImage::from_decoder(tiff::TiffDecoder::new(r)?),
        #[cfg(feature = "tga")]
        image::ImageFormat::Tga => DynamicImage::from_decoder(tga::TgaDecoder::new(r)?),
        #[cfg(feature = "dds")]
        image::ImageFormat::Dds => DynamicImage::from_decoder(dds::DdsDecoder::new(r)?),
        #[cfg(feature = "bmp")]
        image::ImageFormat::Bmp => DynamicImage::from_decoder(bmp::BmpDecoder::new(r)?),
        #[cfg(feature = "ico")]
        image::ImageFormat::Ico => DynamicImage::from_decoder(ico::IcoDecoder::new(r)?),
        #[cfg(feature = "hdr")]
        image::ImageFormat::Hdr => DynamicImage::from_decoder(hdr::HdrAdapter::new(BufReader::new(r))?),
        #[cfg(feature = "pnm")]
        image::ImageFormat::Pnm => DynamicImage::from_decoder(pnm::PnmDecoder::new(BufReader::new(r))?),
        #[cfg(feature = "farbfeld")]
        image::ImageFormat::Farbfeld => DynamicImage::from_decoder(farbfeld::FarbfeldDecoder::new(r)?),
        _ => Err(ImageError::Unsupported(ImageFormatHint::Exact(format).into())),
    }
}

pub(crate) fn image_dimensions_impl(path: &Path) -> ImageResult<(u32, u32)> {
    let format = image::ImageFormat::from_path(path)?;

    let fin = File::open(path)?;
    let fin = BufReader::new(fin);

    image_dimensions_with_format_impl(fin, format)
}

#[allow(unused_variables)]
// fin is unused if no features are supported.
pub(crate) fn image_dimensions_with_format_impl<R: BufRead + Seek>(fin: R, format: ImageFormat)
    -> ImageResult<(u32, u32)>
{
    #[allow(unreachable_patterns,unreachable_code)]
    // Default is unreachable if all features are supported.
    // Code after the match is unreachable if none are.
    Ok(match format {
        #[cfg(feature = "avif-decoder")]
        image::ImageFormat::Avif => avif::AvifDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "jpeg")]
        image::ImageFormat::Jpeg => jpeg::JpegDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "png")]
        image::ImageFormat::Png => png::PngDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "gif")]
        image::ImageFormat::Gif => gif::GifDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "webp")]
        image::ImageFormat::WebP => webp::WebPDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "tiff")]
        image::ImageFormat::Tiff => tiff::TiffDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "tga")]
        image::ImageFormat::Tga => tga::TgaDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "dds")]
        image::ImageFormat::Dds => dds::DdsDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "bmp")]
        image::ImageFormat::Bmp => bmp::BmpDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "ico")]
        image::ImageFormat::Ico => ico::IcoDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "hdr")]
        image::ImageFormat::Hdr => hdr::HdrAdapter::new(fin)?.dimensions(),
        #[cfg(feature = "pnm")]
        image::ImageFormat::Pnm => {
            pnm::PnmDecoder::new(fin)?.dimensions()
        }
        format => return Err(ImageError::Unsupported(ImageFormatHint::Exact(format).into())),
    })
}

#[allow(unused_variables)]
// Most variables when no features are supported
pub(crate) fn save_buffer_impl(
    path: &Path,
    buf: &[u8],
    width: u32,
    height: u32,
    color: color::ColorType,
) -> ImageResult<()> {
    let fout = &mut BufWriter::new(File::create(path)?);
    let format =  ImageFormat::from_path(path)?;
    save_buffer_with_format_impl(path, buf, width, height, color, format)
}

#[allow(unused_variables)]
// Most variables when no features are supported
pub(crate) fn save_buffer_with_format_impl(
    path: &Path,
    buf: &[u8],
    width: u32,
    height: u32,
    color: color::ColorType,
    format: ImageFormat,
) -> ImageResult<()> {
    let fout = &mut BufWriter::new(File::create(path)?);

    match format {
        #[cfg(feature = "gif")]
        image::ImageFormat::Gif => gif::GifEncoder::new(fout).encode(buf, width, height, color),
        #[cfg(feature = "ico")]
        image::ImageFormat::Ico => ico::IcoEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "jpeg")]
        image::ImageFormat::Jpeg => jpeg::JpegEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "png")]
        image::ImageFormat::Png => png::PngEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "pnm")]
        image::ImageFormat::Pnm => {
            let ext = path.extension()
            .and_then(|s| s.to_str())
            .map_or("".to_string(), |s| s.to_ascii_lowercase());
            match &*ext {
                "pbm" => pnm::PnmEncoder::new(fout)
                    .with_subtype(pnm::PNMSubtype::Bitmap(pnm::SampleEncoding::Binary))
                    .write_image(buf, width, height, color),
                "pgm" => pnm::PnmEncoder::new(fout)
                    .with_subtype(pnm::PNMSubtype::Graymap(pnm::SampleEncoding::Binary))
                    .write_image(buf, width, height, color),
                "ppm" => pnm::PnmEncoder::new(fout)
                    .with_subtype(pnm::PNMSubtype::Pixmap(pnm::SampleEncoding::Binary))
                    .write_image(buf, width, height, color),
                "pam" => pnm::PnmEncoder::new(fout).write_image(buf, width, height, color),
                _ => Err(ImageError::Unsupported(ImageFormatHint::Exact(format).into())), // Unsupported Pnm subtype.
            }
        },
        #[cfg(feature = "farbfeld")]
        image::ImageFormat::Farbfeld => farbfeld::FarbfeldEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "avif-encoder")]
        image::ImageFormat::Avif => avif::AvifEncoder::new(fout).write_image(buf, width, height, color),
        // #[cfg(feature = "hdr")]
        // image::ImageFormat::Hdr => hdr::HdrEncoder::new(fout).encode(&[Rgb<f32>], width, height), // usize
        #[cfg(feature = "bmp")]
        image::ImageFormat::Bmp => bmp::BmpEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "tiff")]
        image::ImageFormat::Tiff => tiff::TiffEncoder::new(fout)
            .write_image(buf, width, height, color),
        #[cfg(feature = "tga")]
        image::ImageFormat::Tga => tga::TgaEncoder::new(fout).write_image(buf, width, height, color),
        format => Err(ImageError::Unsupported(ImageFormatHint::Exact(format).into())),
    }
}

#[allow(unused_variables)]
// Most variables when no features are supported
pub(crate) fn write_buffer_impl<W: std::io::Write>(
    fout: &mut W,
    buf: &[u8],
    width: u32,
    height: u32,
    color: color::ColorType,
    format: ImageOutputFormat,
) -> ImageResult<()> {
    match format {
        #[cfg(feature = "png")]
        ImageOutputFormat::Png => png::PngEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "jpeg")]
        ImageOutputFormat::Jpeg(quality) => jpeg::JpegEncoder::new_with_quality(fout, quality)
            .write_image(buf, width, height, color),
        #[cfg(feature = "pnm")]
        ImageOutputFormat::Pnm(subtype) => pnm::PnmEncoder::new(fout)
            .with_subtype(subtype)
            .write_image(buf, width, height, color),
        #[cfg(feature = "gif")]
        ImageOutputFormat::Gif => gif::GifEncoder::new(fout).encode(buf, width, height, color),
        #[cfg(feature = "ico")]
        ImageOutputFormat::Ico => ico::IcoEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "bmp")]
        ImageOutputFormat::Bmp => bmp::BmpEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "farbfeld")]
        ImageOutputFormat::Farbfeld => farbfeld::FarbfeldEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "tga")]
        ImageOutputFormat::Tga => tga::TgaEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "avif")]
        ImageOutputFormat::Avif => avif::AvifEncoder::new(fout).write_image(buf, width, height, color),
        ImageOutputFormat::Unsupported(format) => Err(ImageError::Unsupported(ImageFormatHint::Name(format).into())),
        format => Err(ImageError::Unsupported(ImageFormatHint::Name(format!("{:?}", format)).into()))
    }
}

static MAGIC_BYTES: [(&[u8], ImageFormat); 20] = [
    (b"\x89PNG\r\n\x1a\n", ImageFormat::Png),
    (&[0xff, 0xd8, 0xff], ImageFormat::Jpeg),
    (b"GIF89a", ImageFormat::Gif),
    (b"GIF87a", ImageFormat::Gif),
    (b"RIFF", ImageFormat::WebP), // TODO: better magic byte detection, see https://github.com/image-rs/image/issues/660
    (b"MM\x00*", ImageFormat::Tiff),
    (b"II*\x00", ImageFormat::Tiff),
    (b"DDS ", ImageFormat::Dds),
    (b"BM", ImageFormat::Bmp),
    (&[0, 0, 1, 0], ImageFormat::Ico),
    (b"#?RADIANCE", ImageFormat::Hdr),
    (b"P1", ImageFormat::Pnm),
    (b"P2", ImageFormat::Pnm),
    (b"P3", ImageFormat::Pnm),
    (b"P4", ImageFormat::Pnm),
    (b"P5", ImageFormat::Pnm),
    (b"P6", ImageFormat::Pnm),
    (b"P7", ImageFormat::Pnm),
    (b"farbfeld", ImageFormat::Farbfeld),
    (b"\0\0\0 ftypavif", ImageFormat::Avif),
];

/// Guess image format from memory block
///
/// Makes an educated guess about the image format based on the Magic Bytes at the beginning.
/// TGA is not supported by this function.
/// This is not to be trusted on the validity of the whole memory block
pub fn guess_format(buffer: &[u8]) -> ImageResult<ImageFormat> {
    match guess_format_impl(buffer) {
        Some(format) => Ok(format),
        None => Err(ImageError::Unsupported(ImageFormatHint::Unknown.into())),
    }
}

pub(crate) fn guess_format_impl(buffer: &[u8]) -> Option<ImageFormat> {
    for &(signature, format) in &MAGIC_BYTES {
        if buffer.starts_with(signature) {
            return Some(format);
        }
    }

    None
}
<commit_msg>refactor: use `write_buffer_impl` as the back-end for `save_buffer_with_format_impl`<commit_after>use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Seek};
use std::path::Path;
use std::u32;

#[cfg(feature = "bmp")]
use crate::codecs::bmp;
#[cfg(feature = "gif")]
use crate::codecs::gif;
#[cfg(feature = "hdr")]
use crate::codecs::hdr;
#[cfg(feature = "ico")]
use crate::codecs::ico;
#[cfg(feature = "jpeg")]
use crate::codecs::jpeg;
#[cfg(feature = "png")]
use crate::codecs::png;
#[cfg(feature = "pnm")]
use crate::codecs::pnm;
#[cfg(feature = "tga")]
use crate::codecs::tga;
#[cfg(feature = "dds")]
use crate::codecs::dds;
#[cfg(feature = "tiff")]
use crate::codecs::tiff;
#[cfg(feature = "webp")]
use crate::codecs::webp;
#[cfg(feature = "farbfeld")]
use crate::codecs::farbfeld;
#[cfg(any(feature = "avif-encoder", feature = "avif-decoder"))]
use crate::codecs::avif;

use crate::{ImageOutputFormat, color};
use crate::image;
use crate::dynimage::DynamicImage;
use crate::error::{ImageError, ImageFormatHint, ImageResult};
use crate::image::ImageFormat;
#[allow(unused_imports)]  // When no features are supported
use crate::image::{ImageDecoder, ImageEncoder};

pub(crate) fn open_impl(path: &Path) -> ImageResult<DynamicImage> {
    let fin = match File::open(path) {
        Ok(f) => f,
        Err(err) => return Err(ImageError::IoError(err)),
    };
    let fin = BufReader::new(fin);

    load(fin, ImageFormat::from_path(path)?)
}

/// Create a new image from a Reader
///
/// Try [`io::Reader`] for more advanced uses.
///
/// [`io::Reader`]: io/struct.Reader.html
#[allow(unused_variables)]
// r is unused if no features are supported.
pub fn load<R: BufRead + Seek>(r: R, format: ImageFormat) -> ImageResult<DynamicImage> {
    #[allow(unreachable_patterns)]
    // Default is unreachable if all features are supported.
    match format {
        #[cfg(feature = "avif-decoder")]
        image::ImageFormat::Avif => DynamicImage::from_decoder(avif::AvifDecoder::new(r)?),
        #[cfg(feature = "png")]
        image::ImageFormat::Png => DynamicImage::from_decoder(png::PngDecoder::new(r)?),
        #[cfg(feature = "gif")]
        image::ImageFormat::Gif => DynamicImage::from_decoder(gif::GifDecoder::new(r)?),
        #[cfg(feature = "jpeg")]
        image::ImageFormat::Jpeg => DynamicImage::from_decoder(jpeg::JpegDecoder::new(r)?),
        #[cfg(feature = "webp")]
        image::ImageFormat::WebP => DynamicImage::from_decoder(webp::WebPDecoder::new(r)?),
        #[cfg(feature = "tiff")]
        image::ImageFormat::Tiff => DynamicImage::from_decoder(tiff::TiffDecoder::new(r)?),
        #[cfg(feature = "tga")]
        image::ImageFormat::Tga => DynamicImage::from_decoder(tga::TgaDecoder::new(r)?),
        #[cfg(feature = "dds")]
        image::ImageFormat::Dds => DynamicImage::from_decoder(dds::DdsDecoder::new(r)?),
        #[cfg(feature = "bmp")]
        image::ImageFormat::Bmp => DynamicImage::from_decoder(bmp::BmpDecoder::new(r)?),
        #[cfg(feature = "ico")]
        image::ImageFormat::Ico => DynamicImage::from_decoder(ico::IcoDecoder::new(r)?),
        #[cfg(feature = "hdr")]
        image::ImageFormat::Hdr => DynamicImage::from_decoder(hdr::HdrAdapter::new(BufReader::new(r))?),
        #[cfg(feature = "pnm")]
        image::ImageFormat::Pnm => DynamicImage::from_decoder(pnm::PnmDecoder::new(BufReader::new(r))?),
        #[cfg(feature = "farbfeld")]
        image::ImageFormat::Farbfeld => DynamicImage::from_decoder(farbfeld::FarbfeldDecoder::new(r)?),
        _ => Err(ImageError::Unsupported(ImageFormatHint::Exact(format).into())),
    }
}

pub(crate) fn image_dimensions_impl(path: &Path) -> ImageResult<(u32, u32)> {
    let format = image::ImageFormat::from_path(path)?;

    let fin = File::open(path)?;
    let fin = BufReader::new(fin);

    image_dimensions_with_format_impl(fin, format)
}

#[allow(unused_variables)]
// fin is unused if no features are supported.
pub(crate) fn image_dimensions_with_format_impl<R: BufRead + Seek>(fin: R, format: ImageFormat)
    -> ImageResult<(u32, u32)>
{
    #[allow(unreachable_patterns,unreachable_code)]
    // Default is unreachable if all features are supported.
    // Code after the match is unreachable if none are.
    Ok(match format {
        #[cfg(feature = "avif-decoder")]
        image::ImageFormat::Avif => avif::AvifDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "jpeg")]
        image::ImageFormat::Jpeg => jpeg::JpegDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "png")]
        image::ImageFormat::Png => png::PngDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "gif")]
        image::ImageFormat::Gif => gif::GifDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "webp")]
        image::ImageFormat::WebP => webp::WebPDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "tiff")]
        image::ImageFormat::Tiff => tiff::TiffDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "tga")]
        image::ImageFormat::Tga => tga::TgaDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "dds")]
        image::ImageFormat::Dds => dds::DdsDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "bmp")]
        image::ImageFormat::Bmp => bmp::BmpDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "ico")]
        image::ImageFormat::Ico => ico::IcoDecoder::new(fin)?.dimensions(),
        #[cfg(feature = "hdr")]
        image::ImageFormat::Hdr => hdr::HdrAdapter::new(fin)?.dimensions(),
        #[cfg(feature = "pnm")]
        image::ImageFormat::Pnm => {
            pnm::PnmDecoder::new(fin)?.dimensions()
        }
        format => return Err(ImageError::Unsupported(ImageFormatHint::Exact(format).into())),
    })
}

#[allow(unused_variables)]
// Most variables when no features are supported
pub(crate) fn save_buffer_impl(
    path: &Path,
    buf: &[u8],
    width: u32,
    height: u32,
    color: color::ColorType,
) -> ImageResult<()> {
    let fout = &mut BufWriter::new(File::create(path)?);
    let format =  ImageFormat::from_path(path)?;
    save_buffer_with_format_impl(path, buf, width, height, color, format)
}

#[allow(unused_variables)]
// Most variables when no features are supported
pub(crate) fn save_buffer_with_format_impl(
    path: &Path,
    buf: &[u8],
    width: u32,
    height: u32,
    color: color::ColorType,
    format: ImageFormat,
) -> ImageResult<()> {
    let fout = &mut BufWriter::new(File::create(path)?);

    let format = match format {
        #[cfg(feature = "pnm")]
        image::ImageFormat::Pnm => {
            let ext = path.extension()
            .and_then(|s| s.to_str())
            .map_or("".to_string(), |s| s.to_ascii_lowercase());
            ImageOutputFormat::Pnm(match &*ext {
                "pbm" => pnm::PNMSubtype::Bitmap(pnm::SampleEncoding::Binary),
                "pgm" => pnm::PNMSubtype::Graymap(pnm::SampleEncoding::Binary),
                "ppm" => pnm::PNMSubtype::Pixmap(pnm::SampleEncoding::Binary),
                _ => { return Err(ImageError::Unsupported(ImageFormatHint::Exact(format).into())) }, // Unsupported Pnm subtype.
            })
        },
        // #[cfg(feature = "hdr")]
        // image::ImageFormat::Hdr => hdr::HdrEncoder::new(fout).encode(&[Rgb<f32>], width, height), // usize
        #[cfg(feature = "tiff")]
        image::ImageFormat::Tiff => {
            return tiff::TiffEncoder::new(fout).write_image(buf, width, height, color);
        },
        format => format.into(),
    };

    write_buffer_impl(fout, buf, width, height, color, format)
}

#[allow(unused_variables)]
// Most variables when no features are supported
pub(crate) fn write_buffer_impl<W: std::io::Write>(
    fout: &mut W,
    buf: &[u8],
    width: u32,
    height: u32,
    color: color::ColorType,
    format: ImageOutputFormat,
) -> ImageResult<()> {
    match format {
        #[cfg(feature = "png")]
        ImageOutputFormat::Png => png::PngEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "jpeg")]
        ImageOutputFormat::Jpeg(quality) => jpeg::JpegEncoder::new_with_quality(fout, quality)
            .write_image(buf, width, height, color),
        #[cfg(feature = "pnm")]
        ImageOutputFormat::Pnm(subtype) => pnm::PnmEncoder::new(fout)
            .with_subtype(subtype)
            .write_image(buf, width, height, color),
        #[cfg(feature = "gif")]
        ImageOutputFormat::Gif => gif::GifEncoder::new(fout).encode(buf, width, height, color),
        #[cfg(feature = "ico")]
        ImageOutputFormat::Ico => ico::IcoEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "bmp")]
        ImageOutputFormat::Bmp => bmp::BmpEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "farbfeld")]
        ImageOutputFormat::Farbfeld => farbfeld::FarbfeldEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "tga")]
        ImageOutputFormat::Tga => tga::TgaEncoder::new(fout).write_image(buf, width, height, color),
        #[cfg(feature = "avif-encoder")]
        ImageOutputFormat::Avif => avif::AvifEncoder::new(fout).write_image(buf, width, height, color),
        ImageOutputFormat::Unsupported(format) => Err(ImageError::Unsupported(ImageFormatHint::Name(format).into())),
        format => Err(ImageError::Unsupported(ImageFormatHint::Name(format!("{:?}", format)).into()))
    }
}

static MAGIC_BYTES: [(&[u8], ImageFormat); 20] = [
    (b"\x89PNG\r\n\x1a\n", ImageFormat::Png),
    (&[0xff, 0xd8, 0xff], ImageFormat::Jpeg),
    (b"GIF89a", ImageFormat::Gif),
    (b"GIF87a", ImageFormat::Gif),
    (b"RIFF", ImageFormat::WebP), // TODO: better magic byte detection, see https://github.com/image-rs/image/issues/660
    (b"MM\x00*", ImageFormat::Tiff),
    (b"II*\x00", ImageFormat::Tiff),
    (b"DDS ", ImageFormat::Dds),
    (b"BM", ImageFormat::Bmp),
    (&[0, 0, 1, 0], ImageFormat::Ico),
    (b"#?RADIANCE", ImageFormat::Hdr),
    (b"P1", ImageFormat::Pnm),
    (b"P2", ImageFormat::Pnm),
    (b"P3", ImageFormat::Pnm),
    (b"P4", ImageFormat::Pnm),
    (b"P5", ImageFormat::Pnm),
    (b"P6", ImageFormat::Pnm),
    (b"P7", ImageFormat::Pnm),
    (b"farbfeld", ImageFormat::Farbfeld),
    (b"\0\0\0 ftypavif", ImageFormat::Avif),
];

/// Guess image format from memory block
///
/// Makes an educated guess about the image format based on the Magic Bytes at the beginning.
/// TGA is not supported by this function.
/// This is not to be trusted on the validity of the whole memory block
pub fn guess_format(buffer: &[u8]) -> ImageResult<ImageFormat> {
    match guess_format_impl(buffer) {
        Some(format) => Ok(format),
        None => Err(ImageError::Unsupported(ImageFormatHint::Unknown.into())),
    }
}

pub(crate) fn guess_format_impl(buffer: &[u8]) -> Option<ImageFormat> {
    for &(signature, format) in &MAGIC_BYTES {
        if buffer.starts_with(signature) {
            return Some(format);
        }
    }

    None
}
<|endoftext|>


<commit_before>#![cfg(test)]

// These tests are primarily targeting "abusive" producers that will
// try to drive the "collect consumer" incorrectly. These should
// result in panics.

use iter::internal::*;
use super::Collect;

/// Promises to produce 2 items, but then produces 3.  Does not do any
/// splits at all.
#[test]
#[should_panic(expected = "too many values")]
fn produce_too_many_items() {
    let mut v = vec![];
    let mut collect = Collect::new(&mut v, 2);
    let consumer = collect.as_consumer();
    let mut folder = consumer.into_folder();
    folder = folder.consume(22);
    folder = folder.consume(23);
    folder.consume(24);
}
<commit_msg>add test that drives the collect-consumer, producing too less values<commit_after>#![cfg(test)]

// These tests are primarily targeting "abusive" producers that will
// try to drive the "collect consumer" incorrectly. These should
// result in panics.

use iter::internal::*;
use super::Collect;

/// Promises to produce 2 items, but then produces 3.  Does not do any
/// splits at all.
#[test]
#[should_panic(expected = "too many values")]
fn produce_too_many_items() {
    let mut v = vec![];
    let mut collect = Collect::new(&mut v, 2);
    let consumer = collect.as_consumer();
    let mut folder = consumer.into_folder();
    folder = folder.consume(22);
    folder = folder.consume(23);
    folder.consume(24);
}

/// Produces less items than promised. Does not do any
/// splits at all.
#[test]
#[should_panic(expected = "too few values")]
fn produce_too_few_items() {
    let mut vec = vec![];
    let mut collect = Collect::new(&mut vec, 5);
    let consumer =  collect.as_consumer();
    let mut folder = consumer.into_folder();
    folder = folder.consume(22);
    folder = folder.consume(23);
    folder.complete();
}
<|endoftext|>


<commit_before>// helper for transmutation, shown below.
type RustClosure = (int,int);
struct Handler<T, U:Copy> {
    handle: RustClosure,
    prev: Option<@Handler<T, U>>,
}

struct Condition<T, U:Copy> {
    key: task::local_data::LocalDataKey<Handler<T,U>>
}

impl<T, U: Copy>  Condition<T,U> {

    fn trap(&self, h: &self/fn(&T) ->U) -> Trap/&self<T,U> {
        unsafe {
            let p : *RustClosure = ::cast::transmute(&h);
            let prev = task::local_data::local_data_get(self.key);
            let h = @Handler{handle: *p, prev: prev};
            move Trap { cond: self, handler: h }
        }
    }

    fn raise(t:&T) -> U {
        unsafe {
            match task::local_data::local_data_pop(self.key) {
                None => {
                    debug!("Condition.raise: found no handler");
                    fail
                }

                Some(handler) => {
                    debug!("Condition.raise: found handler");
                    match handler.prev {
                        None => (),
                        Some(hp) =>
                        task::local_data::local_data_set(self.key, hp)
                    }
                    let handle : &fn(&T) -> U =
                        ::cast::transmute(handler.handle);
                    let u = handle(t);
                    task::local_data::local_data_set(self.key,
                                                     handler);
                    move u
                }
            }
        }
    }
}

struct Trap<T, U:Copy> {
    cond: &Condition<T,U>,
    handler: @Handler<T, U>
}

impl<T, U: Copy> Trap<T,U> {
    fn in<V: Copy>(&self, inner: &self/fn() -> V) -> V {
        unsafe {
            let _g = Guard { cond: self.cond };
            debug!("Trap: pushing handler to TLS");
            task::local_data::local_data_set(self.cond.key, self.handler);
            inner()
        }
    }
}

struct Guard<T, U:Copy> {
    cond: &Condition<T,U>,
    drop {
        unsafe {
            debug!("Guard: popping handler from TLS");
            let curr = task::local_data::local_data_pop(self.cond.key);
            match curr {
                None => (),
                Some(h) =>
                match h.prev {
                    None => (),
                    Some(hp) => {
                        task::local_data::local_data_set(self.cond.key, hp)
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod test {

    fn sadness_key(_x: @Handler<int,int>) { }
    fn trouble(i: int) {
        // Condition should work as a const, just limitations in consts.
        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };
        debug!("trouble: raising conition");
        let j = sadness_condition.raise(&i);
        debug!("trouble: handler recovered with %d", j);
    }

    fn nested_trap_test_inner() {
        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };

        let mut inner_trapped = false;

        do sadness_condition.trap(|_j| {
            debug!("nested_trap_test_inner: in handler");
            inner_trapped = true;
            0
        }).in {
            debug!("nested_trap_test_inner: in protected block");
            trouble(1);
        }

        assert inner_trapped;
    }

    #[test]
    fn nested_trap_test_outer() {

        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };

        let mut outer_trapped = false;

        do sadness_condition.trap(|_j| {
            debug!("nested_trap_test_outer: in handler");
            outer_trapped = true; 0
        }).in {
            debug!("nested_guard_test_outer: in protected block");
            nested_trap_test_inner();
            trouble(1);
        }

        assert outer_trapped;
    }

    fn nested_reraise_trap_test_inner() {
        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };

        let mut inner_trapped = false;

        do sadness_condition.trap(|_j| {
            debug!("nested_reraise_trap_test_inner: in handler");
            inner_trapped = true;
            let i = 10;
            debug!("nested_reraise_trap_test_inner: handler re-raising");
            sadness_condition.raise(&i)
        }).in {
            debug!("nested_reraise_trap_test_inner: in protected block");
            trouble(1);
        }

        assert inner_trapped;
    }

    #[test]
    fn nested_reraise_trap_test_outer() {

        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };

        let mut outer_trapped = false;

        do sadness_condition.trap(|_j| {
            debug!("nested_reraise_trap_test_outer: in handler");
            outer_trapped = true; 0
        }).in {
            debug!("nested_reraise_trap_test_outer: in protected block");
            nested_reraise_trap_test_inner();
        }

        assert outer_trapped;
    }

}<commit_msg>core: add condition.raise_default.<commit_after>// helper for transmutation, shown below.
type RustClosure = (int,int);
struct Handler<T, U:Copy> {
    handle: RustClosure,
    prev: Option<@Handler<T, U>>,
}

struct Condition<T, U:Copy> {
    key: task::local_data::LocalDataKey<Handler<T,U>>
}

impl<T, U: Copy>  Condition<T,U> {

    fn trap(&self, h: &self/fn(&T) ->U) -> Trap/&self<T,U> {
        unsafe {
            let p : *RustClosure = ::cast::transmute(&h);
            let prev = task::local_data::local_data_get(self.key);
            let h = @Handler{handle: *p, prev: prev};
            move Trap { cond: self, handler: h }
        }
    }

    fn raise(t:&T) -> U  {
        do self.raise_default(t) {
            fail ~"Unhandled condition";
        }
    }

    fn raise_default(t:&T, default: fn() -> U) -> U {
        unsafe {
            match task::local_data::local_data_pop(self.key) {
                None => {
                    debug!("Condition.raise: found no handler");
                    default()
                }

                Some(handler) => {
                    debug!("Condition.raise: found handler");
                    match handler.prev {
                        None => (),
                        Some(hp) =>
                        task::local_data::local_data_set(self.key, hp)
                    }
                    let handle : &fn(&T) -> U =
                        ::cast::transmute(handler.handle);
                    let u = handle(t);
                    task::local_data::local_data_set(self.key,
                                                     handler);
                    move u
                }
            }
        }
    }
}

struct Trap<T, U:Copy> {
    cond: &Condition<T,U>,
    handler: @Handler<T, U>
}

impl<T, U: Copy> Trap<T,U> {
    fn in<V: Copy>(&self, inner: &self/fn() -> V) -> V {
        unsafe {
            let _g = Guard { cond: self.cond };
            debug!("Trap: pushing handler to TLS");
            task::local_data::local_data_set(self.cond.key, self.handler);
            inner()
        }
    }
}

struct Guard<T, U:Copy> {
    cond: &Condition<T,U>,
    drop {
        unsafe {
            debug!("Guard: popping handler from TLS");
            let curr = task::local_data::local_data_pop(self.cond.key);
            match curr {
                None => (),
                Some(h) =>
                match h.prev {
                    None => (),
                    Some(hp) => {
                        task::local_data::local_data_set(self.cond.key, hp)
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod test {

    fn sadness_key(_x: @Handler<int,int>) { }
    fn trouble(i: int) {
        // Condition should work as a const, just limitations in consts.
        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };
        debug!("trouble: raising conition");
        let j = sadness_condition.raise(&i);
        debug!("trouble: handler recovered with %d", j);
    }

    fn nested_trap_test_inner() {
        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };

        let mut inner_trapped = false;

        do sadness_condition.trap(|_j| {
            debug!("nested_trap_test_inner: in handler");
            inner_trapped = true;
            0
        }).in {
            debug!("nested_trap_test_inner: in protected block");
            trouble(1);
        }

        assert inner_trapped;
    }

    #[test]
    fn nested_trap_test_outer() {

        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };

        let mut outer_trapped = false;

        do sadness_condition.trap(|_j| {
            debug!("nested_trap_test_outer: in handler");
            outer_trapped = true; 0
        }).in {
            debug!("nested_guard_test_outer: in protected block");
            nested_trap_test_inner();
            trouble(1);
        }

        assert outer_trapped;
    }

    fn nested_reraise_trap_test_inner() {
        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };

        let mut inner_trapped = false;

        do sadness_condition.trap(|_j| {
            debug!("nested_reraise_trap_test_inner: in handler");
            inner_trapped = true;
            let i = 10;
            debug!("nested_reraise_trap_test_inner: handler re-raising");
            sadness_condition.raise(&i)
        }).in {
            debug!("nested_reraise_trap_test_inner: in protected block");
            trouble(1);
        }

        assert inner_trapped;
    }

    #[test]
    fn nested_reraise_trap_test_outer() {

        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };

        let mut outer_trapped = false;

        do sadness_condition.trap(|_j| {
            debug!("nested_reraise_trap_test_outer: in handler");
            outer_trapped = true; 0
        }).in {
            debug!("nested_reraise_trap_test_outer: in protected block");
            nested_reraise_trap_test_inner();
        }

        assert outer_trapped;
    }

    #[test]
    fn test_default() {
        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };

        let mut trapped = false;

        do sadness_condition.trap(|j| {
            debug!("test_default: in handler");
            sadness_condition.raise_default(j, || {trapped=true; 5})
        }).in {
            debug!("test_default: in protected block");
            trouble(1);
        }

        assert trapped;
    }

}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The first version of the prelude of the standard library.

#![stable(feature = "rust1", since = "1.0.0")]

// Reexported core operators
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use marker::{Copy, Send, Sized, Sync};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use ops::{Drop, Fn, FnMut, FnOnce};

// Reexported functions
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use mem::drop;

// Reexported types and traits

#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use boxed::Box;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use char::CharExt;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use clone::Clone;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use iter::DoubleEndedIterator;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use iter::ExactSizeIterator;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use iter::{Iterator, IteratorExt, Extend};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use option::Option::{self, Some, None};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use ptr::{PtrExt, MutPtrExt};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use result::Result::{self, Ok, Err};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use slice::AsSlice;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use slice::{SliceExt, SliceConcatExt};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use str::{Str, StrExt};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use string::{String, ToString};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use vec::Vec;

// NB: remove when path reform lands
#[doc(no_inline)] pub use old_path::{Path, GenericPath};
// NB: remove when I/O reform lands
#[doc(no_inline)] pub use old_io::{Buffer, Writer, Reader, Seek, BufferPrelude};
// NB: remove when range syntax lands
#[doc(no_inline)] pub use iter::range;
<commit_msg>std::prelude: code consistency nits<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The first version of the prelude of the standard library.

#![stable(feature = "rust1", since = "1.0.0")]

// Reexported core operators
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use marker::{Copy, Send, Sized, Sync};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use ops::{Drop, Fn, FnMut, FnOnce};

// Reexported functions
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use mem::drop;

// Reexported types and traits
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use boxed::Box;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use char::CharExt;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use clone::Clone;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use iter::DoubleEndedIterator;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use iter::ExactSizeIterator;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use iter::{Iterator, IteratorExt, Extend};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use option::Option::{self, Some, None};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use ptr::{PtrExt, MutPtrExt};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use result::Result::{self, Ok, Err};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use slice::{SliceExt, SliceConcatExt, AsSlice};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use str::{Str, StrExt};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use string::{String, ToString};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)] pub use vec::Vec;

// NB: remove when path reform lands
#[doc(no_inline)] pub use old_path::{Path, GenericPath};
// NB: remove when I/O reform lands
#[doc(no_inline)] pub use old_io::{Buffer, Writer, Reader, Seek, BufferPrelude};
// NB: remove when range syntax lands
#[doc(no_inline)] pub use iter::range;
<|endoftext|>


<commit_before>#![allow(unused_variables)]
use autograd::{Function, FuncIntf, FuncDelegate, FIWrap};
use tensor::{TensorKindList, OptTensorKindList, TensorKind, NumLimits};

#[builder(pattern="owned")]
#[derive(Builder, Clone)]
pub struct DropoutArgs {
    #[builder(default="0.5")]
    pub p: f64,
    #[builder(default="false")]
    pub training: bool,
    #[builder(default="false")]
    pub inplace: bool,
}

impl Default for DropoutArgs {
    fn default() -> Self {
        DropoutArgsBuilder::default().build().unwrap()
    }
}

impl_func_args!(Dropout1d, DropoutArgs);
impl_func_args!(Dropout2d, DropoutArgs);

trait Noise: FuncIntf {
    fn make_noise(&self, input: &TensorKind) -> TensorKind;
}

trait Dropout: Noise + FuncIntf {
    fn dropout_forward(&mut self,
                       input: &mut TensorKindList,
                       args: &DropoutArgs)
                       -> TensorKindList {
        let mut output = if args.inplace {
            self.mark_dirty(input);
            input[0].clone()
        } else {
            input[0].copy()
        };
        if args.p > 0. && args.training {
            let noise = self.make_noise(&input[0])
                .bernoulli_(1. - args.p)
                .div_(1. - args.p)
                .expand_as(&input[0]);
            output.mult_(&noise);
            vec![noise, output]
        } else {
            vec![output]
        }
    }
    fn dropout_backward(&mut self,
                        grad_output_: &mut OptTensorKindList,
                        args: &DropoutArgs)
                        -> OptTensorKindList {
        match grad_output_[0] {
            None => return vec![None],
            Some(ref mut grad_output) => {
                if args.p > 0. && args.training {
                    let noise = &self.saved_tensors()[0];
                    vec![Some(grad_output.mult_(noise).clone())]
                } else {
                    vec![Some(grad_output.clone())]
                }
            }
        }
    }
}

impl Dropout for Dropout1d {}
impl Dropout for Dropout2d {}
impl Noise for Dropout1d {
    fn make_noise(&self, input: &TensorKind) -> TensorKind {
        input.new(()).resize_as_(input)
    }
}
impl Noise for Dropout2d {
    fn make_noise(&self, input: &TensorKind) -> TensorKind {
        let mut v = vec![input.size()[0], input.size()[1]];
        for _ in 0..input.dim() - 2 {
            v.push(1)
        }
        input.new(v)
    }
}
impl FuncIntf for Dropout1d {
    fn forward(&mut self, input: &mut TensorKindList) -> TensorKindList {
        let args = self.args.clone();
        let mut result = self.dropout_forward(input, &args);
        if self.args.p > 0. && args.training {
            self.saved_tensors.push(result.remove(0))
        }
        result
    }
    fn backward(&mut self, grad_output: &mut OptTensorKindList) -> OptTensorKindList {
        let args = self.args.clone();
        self.dropout_backward(grad_output, &args)
    }
}
impl FuncIntf for Dropout2d {
    fn forward(&mut self, input: &mut TensorKindList) -> TensorKindList {
        let args = self.args.clone();
        let mut result = self.dropout_forward(input, &args);
        if self.args.p > 0. && args.training {
            self.saved_tensors.push(result.remove(0))
        }
        result
    }
    fn backward(&mut self, grad_output: &mut OptTensorKindList) -> OptTensorKindList {
        let args = self.args.clone();
        self.dropout_backward(grad_output, &args)
    }
}
<commit_msg>pass in noise directly to backward<commit_after>#![allow(unused_variables)]
use autograd::{Function, FuncIntf, FuncDelegate, FIWrap};
use tensor::{TensorKindList, OptTensorKindList, TensorKind, NumLimits};

#[builder(pattern="owned")]
#[derive(Builder, Clone)]
pub struct DropoutArgs {
    #[builder(default="0.5")]
    pub p: f64,
    #[builder(default="false")]
    pub training: bool,
    #[builder(default="false")]
    pub inplace: bool,
}

impl Default for DropoutArgs {
    fn default() -> Self {
        DropoutArgsBuilder::default().build().unwrap()
    }
}

impl_func_args!(Dropout1d, DropoutArgs);
impl_func_args!(Dropout2d, DropoutArgs);

trait Noise: FuncIntf {
    fn make_noise(&self, input: &TensorKind) -> TensorKind;
}

trait Dropout: Noise + FuncIntf {
    fn dropout_forward(&mut self,
                       input: &mut TensorKindList,
                       args: &DropoutArgs)
                       -> TensorKindList {
        let mut output = if args.inplace {
            self.mark_dirty(input);
            input[0].clone()
        } else {
            input[0].copy()
        };
        if args.p > 0. && args.training {
            let noise = self.make_noise(&input[0])
                .bernoulli_(1. - args.p)
                .div_(1. - args.p)
                .expand_as(&input[0]);
            output.mult_(&noise);
            vec![noise, output]
        } else {
            vec![output]
        }
    }
    fn dropout_backward(&mut self,
                        grad_output_: &mut OptTensorKindList,
                        args: &DropoutArgs,
                        noise: TensorKind)
                        -> OptTensorKindList {
        match grad_output_[0] {
            None => return vec![None],
            Some(ref mut grad_output) => {
                if args.p > 0. && args.training {
                    vec![Some(grad_output.mult_(&noise).clone())]
                } else {
                    vec![Some(grad_output.clone())]
                }
            }
        }
    }
}

impl Dropout for Dropout1d {}
impl Dropout for Dropout2d {}
impl Noise for Dropout1d {
    fn make_noise(&self, input: &TensorKind) -> TensorKind {
        input.new(()).resize_as_(input)
    }
}
impl Noise for Dropout2d {
    fn make_noise(&self, input: &TensorKind) -> TensorKind {
        let mut v = vec![input.size()[0], input.size()[1]];
        for _ in 0..input.dim() - 2 {
            v.push(1)
        }
        input.new(v)
    }
}
impl FuncIntf for Dropout1d {
    fn forward(&mut self, input: &mut TensorKindList) -> TensorKindList {
        let args = self.args.clone();
        let mut result = self.dropout_forward(input, &args);
        if self.args.p > 0. && args.training {
            self.saved_tensors.push(result.remove(0))
        }
        result
    }
    fn backward(&mut self, grad_output: &mut OptTensorKindList) -> OptTensorKindList {
        let args = self.args.clone();
        println!("dropout1d backward");
        let noise = self.saved_tensors.remove(0);
        self.dropout_backward(grad_output, &args, noise)
    }
}
impl FuncIntf for Dropout2d {
    fn forward(&mut self, input: &mut TensorKindList) -> TensorKindList {
        let args = self.args.clone();
        let mut result = self.dropout_forward(input, &args);
        if self.args.p > 0. && args.training {
            self.saved_tensors.push(result.remove(0))
        }
        result
    }
    fn backward(&mut self, grad_output: &mut OptTensorKindList) -> OptTensorKindList {
        let args = self.args.clone();
        println!("dropout2d backward");
        let noise = self.saved_tensors.remove(0);
        self.dropout_backward(grad_output, &args, noise)
    }
}
<|endoftext|>


<commit_before>
use super::events::*;

use super::server::RaftServerState;
use super::server::{RaftStateTransition, NextState, Continue};
use super::server::{RaftNextState, RaftLeader, RaftCandidate};

// Rust doesn't support arbitrary methods being defined in another
// file... except with traits.
//
// I don't know how this copes with small private helper functions.
// Hopefully you won't need to declare them in the trait before you
// can define them in the impl Follower for RaftServerState.

pub trait Follower {
    fn follower_setup(&mut self) -> RaftStateTransition;
    fn follower_teardown(&mut self);

    fn follower_append_entries_req(&mut self, req: AppendEntriesReq, chan: Sender<AppendEntriesRes>) -> RaftStateTransition;
    fn follower_append_entries_res(&mut self, res: AppendEntriesRes) -> RaftStateTransition;

    fn follower_vote_req(&mut self, req: VoteReq, chan: Sender<VoteRes>) -> RaftStateTransition;
    fn follower_vote_res(&mut self, res: VoteRes) -> RaftStateTransition;
}

// TODO: Real Implementations
impl Follower for RaftServerState {
    fn follower_setup(&mut self) -> RaftStateTransition {
        Continue
    }

    fn follower_teardown(&mut self) {
    }

    fn follower_append_entries_req(&mut self, req: AppendEntriesReq, chan: Sender<AppendEntriesRes>) -> RaftStateTransition {
        if req.commit_idx > self.last_applied {
            self.last_applied += 1;
            // TODO:
            // self.to_app_sm.send(log(lastApplied))
        }

        Continue
    }

    fn follower_append_entries_res(&mut self, res: AppendEntriesRes) -> RaftStateTransition {
        Continue
    }

    fn follower_vote_req(&mut self, req: VoteReq, chan: Sender<VoteRes>) -> RaftStateTransition {
        Continue
    }

    fn follower_vote_res(&mut self, res: VoteRes) -> RaftStateTransition  {
        Continue
    }
}
<commit_msg>some really basic follower logic<commit_after>use uuid::{Uuid, UuidVersion, Version4Random};

use super::events::*;
use super::server::RaftServerState;
use super::server::{RaftStateTransition, NextState, Continue};
use super::server::{RaftNextState, RaftLeader, RaftCandidate};

// Rust doesn't support arbitrary methods being defined in another
// file... except with traits.
//
// I don't know how this copes with small private helper functions.
// Hopefully you won't need to declare them in the trait before you
// can define them in the impl Follower for RaftServerState.

pub trait Follower {
    fn follower_setup(&mut self) -> RaftStateTransition;
    fn follower_teardown(&mut self);

    fn follower_append_entries_req(&mut self, req: AppendEntriesReq, chan: Sender<AppendEntriesRes>) -> RaftStateTransition;
    fn follower_append_entries_res(&mut self, res: AppendEntriesRes) -> RaftStateTransition;

    fn follower_vote_req(&mut self, req: VoteReq, chan: Sender<VoteRes>) -> RaftStateTransition;
    fn follower_vote_res(&mut self, res: VoteRes) -> RaftStateTransition;
}

// TODO: Real Implementations
impl Follower for RaftServerState {
    fn follower_setup(&mut self) -> RaftStateTransition {
        Continue
    }

    fn follower_teardown(&mut self) {
    }

    fn follower_append_entries_req(&mut self, req: AppendEntriesReq, chan: Sender<AppendEntriesRes>) -> RaftStateTransition {
        if req.commit_idx > self.last_applied {
            self.last_applied += 1;
            // TODO:
            // self.to_app_sm.send(log(lastApplied))
        }
        if req.term > self.current_term {
            // TODO: maybe state transition to follower (do setup/teardown again)?
            // Raft paper:
            //     If RPC request or response contains term T > currentTerm:
            //     set currentTerm = T, convert to follower
        }
        else if req.term < self.current_term {
            chan.send(AppendEntriesRes {
                success: false,
                term: self.current_term,
                uuid: Uuid::new(Version4Random).unwrap(),
            });
        }
        // TODO: (pseudo-haskell for being concise ...)
        // if len $ filter (self.log[previousLogIdx].term ==) (map (.term) req.entries) then reply false

        Continue
    }

    fn follower_append_entries_res(&mut self, res: AppendEntriesRes) -> RaftStateTransition {
        Continue
    }

    fn follower_vote_req(&mut self, req: VoteReq, chan: Sender<VoteRes>) -> RaftStateTransition {
        Continue
    }

    fn follower_vote_res(&mut self, res: VoteRes) -> RaftStateTransition  {
        Continue
    }
}
<|endoftext|>


<commit_before>use memory::Memory;
use std;

/// Like `/dev/null`.
///
/// The `NullMemory` is always 2^32 bytes large (osci’s memory size),
/// reads `0` everywhere and discards all writes.
///
/// # Examples
/// ```
/// use osciemu::memory::{Memory, NullMemory};
///
/// let mut m = NullMemory::new();
/// assert_eq!(m.get(0), 0);
/// m.set(0, 1);
/// assert_eq!(m.get(0), 0);
/// ```
pub struct NullMemory;

impl NullMemory {
    pub fn new() -> NullMemory {
        NullMemory
    }
}

impl Memory for NullMemory {
    #[inline]
    fn get(&self, _: usize) -> u32 {
        0
    }

    #[inline]
    fn set(&mut self, _: usize, _: u32) {}

    #[inline]
    fn size(&self) -> usize {
        std::u32::MAX as usize
    }
}

#[cfg(test)]
mod tests {
    use memory::Memory;

    #[test]
    fn read() {
        let m = super::NullMemory::new();
        assert_eq!(m.get(0), 0);
        assert_eq!(m.get(123), 0);
        assert_eq!(m.get(u32::max_value() as usize), 0);
    }

    #[test]
    fn write() {
        let mut m = super::NullMemory::new();
        assert_eq!(m.get(0), 0);
        m.set(0, 4);
        assert_eq!(m.get(0), 0);
    }
}
<commit_msg>refactor(nullmemory): Update for new memory design<commit_after>use memory::Memory;
use std;

/// Like `/dev/null`.
///
/// The `NullMemory` is always 2^31 bytes large (osci’s memory size),
/// reads `0` everywhere and discards all writes.
///
/// # Examples
/// ```
/// use osciemu::memory::{Memory, NullMemory};
///
/// let mut m = NullMemory::new();
/// assert_eq!(m.get(0), 0);
/// m.set(0, 1);
/// assert_eq!(m.get(0), 0);
/// ```
pub struct NullMemory;

impl NullMemory {
    pub fn new() -> NullMemory {
        NullMemory
    }
}

impl Memory for NullMemory {
    #[inline]
    fn get(&self, _: usize) -> u32 {
        0
    }

    #[inline]
    fn set(&mut self, _: usize, _: u32) {}

    #[inline]
    fn size(&self) -> usize {
        2<<31
    }
}

#[cfg(test)]
mod tests {
    use memory::Memory;

    #[test]
    fn read() {
        let m = super::NullMemory::new();
        assert_eq!(m.get(0), 0);
        assert_eq!(m.get(123), 0);
    }

    #[test]
    fn write() {
        let mut m = super::NullMemory::new();
        assert_eq!(m.get(0), 0);
        m.set(0, 4);
        assert_eq!(m.get(0), 0);
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
use juliaset::PixelSize;

use juliaset::draw;
use juliaset::ParamSet;
use std::env;

/// Parses command line arguments and returns their values
///
/// # Arguments
///
/// * `args` Command line arguments that includes the name-of-executable
fn parse_args(args: &[String]) -> ParamSet {
    let mut opts = getopts::Options::new();
    opts.optopt(
        "x",
        "x_offset",
        "An x offset that is added in iterations",
        "X offset",
    )
    .optopt(
        "y",
        "y_offset",
        "A y offset that is added in iterations",
        "Y offset",
    )
    .optopt("m", "max_iter", "maximum # of iterations", "Max iterations")
    .optopt("s", "size", "# of pixels in the output image", "Pixel size")
    .optopt("c", "csv", "set output CSV filename", "CSV filename")
    .optopt("o", "image", "set output PNG filename", "PNG filename");
    let matches = opts.parse(&args[1..]).unwrap();

    let x_offset = match matches.opt_str("x") {
        Some(value) => value.parse().unwrap(),
        None => 0.375,
    };

    let y_offset = match matches.opt_str("y") {
        Some(value) => value.parse().unwrap(),
        None => 0.375,
    };

    let max_iter = match matches.opt_str("m") {
        Some(value) => value.parse().unwrap(),
        None => 100,
    };

    let n_pixels = match matches.opt_str("s") {
        Some(value) => value.parse().unwrap(),
        None => 256,
    };

    let csv_filename = matches.opt_str("c");
    let filename = matches
        .opt_str("o")
        .unwrap_or_else(|| "rust_juliaset.png".to_string());
    let image_filename = Some(filename);

    ParamSet::new(
        x_offset,
        y_offset,
        max_iter,
        n_pixels,
        &csv_filename,
        &image_filename,
    )
}

#[test]
fn test_default_arguments() {
    let args: Vec<String> = vec!["command"].iter().map(|&s| s.into()).collect();
    let actual = parse_args(&args);
    let n_pixels: PixelSize = 256;
    let csv_filename = None;
    let image_filename = Some("rust_juliaset.png".to_string());
    let expected = ParamSet::new(0.375, 0.375, 100, n_pixels, &csv_filename, &image_filename);
    assert_eq!(actual, expected);
}

#[test]
fn test_long_arguments() {
    let args: Vec<String> = vec![
        "command",
        "--x_offset",
        "0.25",
        "--y_offset",
        "0.5",
        "--max_iter",
        "16",
        "--size",
        "31",
        "--csv",
        "_test.csv",
        "--image",
        "_test.png",
    ]
    .iter()
    .map(|&s| s.into())
    .collect();
    let actual = parse_args(&args);
    let n_pixels: PixelSize = 31;
    let csv_filename = Some("_test.csv".to_string());
    let image_filename = Some("_test.png".to_string());
    let expected = ParamSet::new(0.25, 0.5, 16, n_pixels, &csv_filename, &image_filename);
    assert_eq!(actual, expected);
}

#[test]
fn test_short_arguments() {
    let args: Vec<String> = vec![
        "command",
        "-x",
        "0.5",
        "-y",
        "0.25",
        "-m",
        "31",
        "-s",
        "16",
        "-c",
        "_short.csv",
        "-o",
        "_short.png",
    ]
    .iter()
    .map(|&s| s.into())
    .collect();
    let actual = parse_args(&args);
    let n_pixels: PixelSize = 16;
    let csv_filename = Some("_short.csv".to_string());
    let image_filename = Some("_short.png".to_string());
    let expected = ParamSet::new(0.5, 0.25, 31, n_pixels, &csv_filename, &image_filename);
    assert_eq!(actual, expected);
}

// Takes the first command line argument as a pixel size if available
fn main() {
    let args: Vec<String> = env::args().collect();
    let params = parse_args(&args);
    draw(&params);
}
<commit_msg>Check command line arguments<commit_after>#[cfg(test)]
use juliaset::PixelSize;

use juliaset::draw;
use juliaset::ParamSet;
use std::env;

/// Parses command line arguments and returns their values
///
/// # Arguments
///
/// * `args` Command line arguments that includes the name-of-executable
fn parse_args(args: &[String]) -> ParamSet {
    let mut opts = getopts::Options::new();
    opts.optopt(
        "x",
        "x_offset",
        "An x offset that is added in iterations",
        "X offset",
    )
    .optopt(
        "y",
        "y_offset",
        "A y offset that is added in iterations",
        "Y offset",
    )
    .optopt("m", "max_iter", "maximum # of iterations", "Max iterations")
    .optopt("s", "size", "# of pixels in the output image", "Pixel size")
    .optopt("c", "csv", "set output CSV filename", "CSV filename")
    .optopt("o", "image", "set output PNG filename", "PNG filename");
    let matches = opts.parse(&args[1..]).unwrap();

    let x_offset = match matches.opt_str("x") {
        Some(value) => value.parse().unwrap(),
        None => 0.375,
    };

    let y_offset = match matches.opt_str("y") {
        Some(value) => value.parse().unwrap(),
        None => 0.375,
    };

    let max_iter = match matches.opt_str("m") {
        Some(value) => value.parse().unwrap(),
        None => 100,
    };
    assert!(max_iter > 0);

    let n_pixels = match matches.opt_str("s") {
        Some(value) => value.parse().unwrap(),
        None => 256,
    };
    assert!(n_pixels > 1);

    let csv_filename = matches.opt_str("c");
    let filename = matches
        .opt_str("o")
        .unwrap_or_else(|| "rust_juliaset.png".to_string());
    let image_filename = Some(filename);

    ParamSet::new(
        x_offset,
        y_offset,
        max_iter,
        n_pixels,
        &csv_filename,
        &image_filename,
    )
}

#[test]
fn test_default_arguments() {
    let args: Vec<String> = vec!["command"].iter().map(|&s| s.into()).collect();
    let actual = parse_args(&args);
    let n_pixels: PixelSize = 256;
    let csv_filename = None;
    let image_filename = Some("rust_juliaset.png".to_string());
    let expected = ParamSet::new(0.375, 0.375, 100, n_pixels, &csv_filename, &image_filename);
    assert_eq!(actual, expected);
}

#[test]
fn test_long_arguments() {
    let args: Vec<String> = vec![
        "command",
        "--x_offset",
        "0.25",
        "--y_offset",
        "0.5",
        "--max_iter",
        "16",
        "--size",
        "31",
        "--csv",
        "_test.csv",
        "--image",
        "_test.png",
    ]
    .iter()
    .map(|&s| s.into())
    .collect();
    let actual = parse_args(&args);
    let n_pixels: PixelSize = 31;
    let csv_filename = Some("_test.csv".to_string());
    let image_filename = Some("_test.png".to_string());
    let expected = ParamSet::new(0.25, 0.5, 16, n_pixels, &csv_filename, &image_filename);
    assert_eq!(actual, expected);
}

#[test]
fn test_short_arguments() {
    let args: Vec<String> = vec![
        "command",
        "-x",
        "0.5",
        "-y",
        "0.25",
        "-m",
        "31",
        "-s",
        "16",
        "-c",
        "_short.csv",
        "-o",
        "_short.png",
    ]
    .iter()
    .map(|&s| s.into())
    .collect();
    let actual = parse_args(&args);
    let n_pixels: PixelSize = 16;
    let csv_filename = Some("_short.csv".to_string());
    let image_filename = Some("_short.png".to_string());
    let expected = ParamSet::new(0.5, 0.25, 31, n_pixels, &csv_filename, &image_filename);
    assert_eq!(actual, expected);
}

#[test]
#[should_panic]
fn test_invalid_x_offset() {
    let args: Vec<String> = vec!["command", "--x_offset", "a.b",].iter().map(|&s| s.into()).collect();
    parse_args(&args);
}

#[test]
#[should_panic]
fn test_invalid_y_offset() {
    let args: Vec<String> = vec!["command", "--y_offset", "a.b",].iter().map(|&s| s.into()).collect();
    parse_args(&args);
}

#[test]
#[should_panic]
fn test_invalid_max_iter_not_a_number() {
    let args: Vec<String> = vec!["command", "--max_iter", "a",].iter().map(|&s| s.into()).collect();
    parse_args(&args);
}

#[test]
#[should_panic]
fn test_invalid_max_iter_negative() {
    let args: Vec<String> = vec!["command", "--max_iter", "-1",].iter().map(|&s| s.into()).collect();
    parse_args(&args);
}

#[test]
#[should_panic]
fn test_invalid_max_iter_min() {
    let args: Vec<String> = vec!["command", "--max_iter", "0",].iter().map(|&s| s.into()).collect();
    parse_args(&args);
}

#[test]
#[should_panic]
fn test_invalid_size_not_a_number() {
    let args: Vec<String> = vec!["command", "--size", "a",].iter().map(|&s| s.into()).collect();
    parse_args(&args);
}

#[test]
#[should_panic]
fn test_invalid_size_negative() {
    let args: Vec<String> = vec!["command", "--size", "-1",].iter().map(|&s| s.into()).collect();
    parse_args(&args);
}

#[test]
#[should_panic]
fn test_invalid_size_zero() {
    let args: Vec<String> = vec!["command", "--size", "0",].iter().map(|&s| s.into()).collect();
    parse_args(&args);
}

#[test]
#[should_panic]
fn test_invalid_size_min() {
    let args: Vec<String> = vec!["command", "--size", "1",].iter().map(|&s| s.into()).collect();
    parse_args(&args);
}

// Takes the first command line argument as a pixel size if available
fn main() {
    let args: Vec<String> = env::args().collect();
    let params = parse_args(&args);
    draw(&params);
}
<|endoftext|>


<commit_before>use actix_web::{self, AsyncResponder, FromRequest, HttpMessage, HttpRequest, HttpResponse, Query};
use futures::{Future, IntoFuture};
use serde::de::DeserializeOwned;
use serde::Serialize;

use error;
use service::{ServiceApiBackend, ServiceApiContext, ServiceApiContextMut};
use NamedFn;

pub type RawHandler = Fn(HttpRequest<ServiceApiContextMut>)
    -> Box<Future<Item = HttpResponse, Error = actix_web::Error>>;

pub struct RequestHandler {
    pub name: &'static str,
    pub method: actix_web::http::Method,
    pub inner: Box<RawHandler>,
}

impl<Q, I, F> From<NamedFn<ServiceApiContext, Q, I, Result<I, error::Error>, F>> for RequestHandler
where
    F: for<'r> Fn(&'r ServiceApiContext, Q) -> Result<I, error::Error> + 'static,
    Q: DeserializeOwned + 'static,
    I: Serialize + 'static,
{
    fn from(f: NamedFn<ServiceApiContext, Q, I, Result<I, error::Error>, F>) -> Self {
        let handler = f.inner.f;
        let index = move |request: HttpRequest<ServiceApiContextMut>|
         -> Box<Future<Item=HttpResponse, Error=actix_web::Error>> {
            let to_response = |request: HttpRequest<ServiceApiContextMut>|
             -> Result<HttpResponse, actix_web::Error> {
                let context = request.state();
                let query: Query<Q> = Query::from_request(&request, &())?;
                let value = handler(context, query.into_inner())?;
                Ok(HttpResponse::Ok().json(value))
            };

            Box::new(to_response(request).into_future())
        };

        RequestHandler {
            name: f.name,
            method: actix_web::http::Method::GET,
            inner: Box::new(index) as Box<RawHandler>,
        }
    }
}

impl<Q, I, F> From<NamedFn<ServiceApiContextMut, Q, I, Result<I, error::Error>, F>>
    for RequestHandler
where
    F: for<'r> Fn(&'r ServiceApiContextMut, Q) -> Result<I, error::Error> + 'static + Clone,
    Q: DeserializeOwned + 'static,
    I: Serialize + 'static,
{
    fn from(f: NamedFn<ServiceApiContextMut, Q, I, Result<I, error::Error>, F>) -> Self {
        let handler = f.inner.f;
        let index = move |request: HttpRequest<ServiceApiContextMut>|
         -> Box<Future<Item=HttpResponse, Error=actix_web::Error>> {
            let handler = handler.clone();
            let context = request.state().clone();
            request.json().from_err().and_then(move |query: Q| {
                let value = handler(&context, query)?;
                Ok(HttpResponse::Ok().json(value))
            }).responder()
        };

        RequestHandler {
            name: f.name,
            method: actix_web::http::Method::POST,
            inner: Box::new(index) as Box<RawHandler>,
        }
    }
}

#[derive(Default)]
pub struct BackendBuilder {
    handlers: Vec<RequestHandler>,
}

impl ServiceApiBackend for BackendBuilder {
    type Handler = RequestHandler;

    fn raw_handler(&mut self, handler: Self::Handler) -> &mut Self {
        self.handlers.push(handler);
        self
    }
}

impl BackendBuilder {
    pub fn new() -> BackendBuilder {
        BackendBuilder::default()
    }

    pub fn finish(self) -> Vec<RequestHandler> {
        self.handlers
    }
}
<commit_msg>Use combinators in closures<commit_after>use actix_web::{self, AsyncResponder, FromRequest, HttpMessage, HttpRequest, HttpResponse, Query};
use futures::{Future, IntoFuture};
use serde::de::DeserializeOwned;
use serde::Serialize;

use error;
use service::{ServiceApiBackend, ServiceApiContext, ServiceApiContextMut};
use NamedFn;

pub type RawHandler = Fn(HttpRequest<ServiceApiContextMut>)
    -> Box<Future<Item = HttpResponse, Error = actix_web::Error>>;

pub struct RequestHandler {
    pub name: &'static str,
    pub method: actix_web::http::Method,
    pub inner: Box<RawHandler>,
}

impl<Q, I, F> From<NamedFn<ServiceApiContext, Q, I, Result<I, error::Error>, F>> for RequestHandler
where
    F: for<'r> Fn(&'r ServiceApiContext, Q) -> Result<I, error::Error> + 'static,
    Q: DeserializeOwned + 'static,
    I: Serialize + 'static,
{
    fn from(f: NamedFn<ServiceApiContext, Q, I, Result<I, error::Error>, F>) -> Self {
        let handler = f.inner.f;
        let index = move |request: HttpRequest<ServiceApiContextMut>|
         -> Box<Future<Item=HttpResponse, Error=actix_web::Error>> {
            let context = request.state();
            let future = Query::from_request(&request, &())
                .map(|query: Query<Q>| query.into_inner())
                .and_then(|query| handler(context, query).map_err(From::from))
                .and_then(|value| Ok(HttpResponse::Ok().json(value)))
                .into_future();
            Box::new(future)
        };

        RequestHandler {
            name: f.name,
            method: actix_web::http::Method::GET,
            inner: Box::new(index) as Box<RawHandler>,
        }
    }
}

impl<Q, I, F> From<NamedFn<ServiceApiContextMut, Q, I, Result<I, error::Error>, F>>
    for RequestHandler
where
    F: for<'r> Fn(&'r ServiceApiContextMut, Q) -> Result<I, error::Error> + 'static + Clone,
    Q: DeserializeOwned + 'static,
    I: Serialize + 'static,
{
    fn from(f: NamedFn<ServiceApiContextMut, Q, I, Result<I, error::Error>, F>) -> Self {
        let handler = f.inner.f;
        let index = move |request: HttpRequest<ServiceApiContextMut>|
         -> Box<Future<Item=HttpResponse, Error=actix_web::Error>> {
            let handler = handler.clone();
            let context = request.state().clone();
            request
                .json()
                .from_err()
                .and_then(move |query: Q| {
                    handler(&context, query)
                        .map(|value| HttpResponse::Ok().json(value))
                        .map_err(From::from)
                })
                .responder()
        };

        RequestHandler {
            name: f.name,
            method: actix_web::http::Method::POST,
            inner: Box::new(index) as Box<RawHandler>,
        }
    }
}

#[derive(Default)]
pub struct BackendBuilder {
    handlers: Vec<RequestHandler>,
}

impl ServiceApiBackend for BackendBuilder {
    type Handler = RequestHandler;

    fn raw_handler(&mut self, handler: Self::Handler) -> &mut Self {
        self.handlers.push(handler);
        self
    }
}

impl BackendBuilder {
    pub fn new() -> BackendBuilder {
        BackendBuilder::default()
    }

    pub fn finish(self) -> Vec<RequestHandler> {
        self.handlers
    }
}
<|endoftext|>


<commit_before>use std::{io, process};
use std::str::FromStr;
use argparse::{ArgumentParser, List, Store, StoreTrue};

use pprint::{self, Config as PpConfig, Mode as PpMode};

#[derive(Copy, Clone, Debug)]
enum CommandType {
    Solve,
}

impl CommandType {
    fn setup_parser<'parser>(&'parser mut self,
                             ap: &mut ArgumentParser<'parser>,
                             args: &'parser mut Vec<String>) {
        let _ = ap.refer(self)
                  .required()
                  .add_argument("command", Store, "command to run (solve)");
        let _ = ap.refer(args)
                  .add_argument("arguments", List, "arguments for command");
        ap.stop_on_first_argument(true);
    }
}

impl Default for CommandType {
    fn default() -> CommandType {
        CommandType::Solve
    }
}

impl FromStr for CommandType {
    type Err = ();

    fn from_str(src: &str) -> Result<CommandType, ()> {
        match src {
            "solve" => Ok(CommandType::Solve),
            _ => Err(()),
        }
    }
}

#[derive(Clone, Debug)]
struct SolveArgs {
    derive_all: bool,
    output_mode: OutputModeArg,
    width: Size,
    height: Size,
    input_files: Vec<String>,
}

impl SolveArgs {
    fn setup_parser<'parser>(&'parser mut self, ap: &mut ArgumentParser<'parser>) {
        let _ = ap.refer(&mut self.derive_all)
                  .add_option(&["--all"], StoreTrue, "derive all solutions (if any).");
        let _ = ap.refer(&mut self.output_mode)
                  .add_option(&["--output-mode"],
                              Store,
                              "specify output mode (auto, pretty-color, pretty-ascii, raw, none) \
                               [default: auto]");
        let _ = ap.refer(&mut self.width)
                  .add_option(&["--width"], Store, "specify cell width [default: 2]");
        let _ = ap.refer(&mut self.height)
                  .add_option(&["--height"], Store, "specify cell width [default: 1]");
        let _ = ap.refer(&mut self.input_files)
                  .add_argument("input_files", List, "puzzle files to solve.");
    }

    fn output_mode(&self) -> OutputMode {
        let ppmode = match self.output_mode {
            OutputModeArg::Auto => {
                if pprint::is_pprintable() {
                    PpMode::Color
                } else {
                    PpMode::Ascii
                }
            }
            OutputModeArg::PrettyColor => PpMode::Color,
            OutputModeArg::PrettyAscii => PpMode::Ascii,
            OutputModeArg::Raw => return OutputMode::Raw,
            OutputModeArg::None => return OutputMode::None,
        };
        OutputMode::Pretty(PpConfig {
            mode: ppmode,
            cell_width: self.width.0,
            cell_height: self.height.0,
        })
    }
}

impl Default for SolveArgs {
    fn default() -> SolveArgs {
        SolveArgs {
            derive_all: false,
            output_mode: OutputModeArg::Auto,
            width: Size(2),
            height: Size(1),
            input_files: vec![],
        }
    }
}

impl Into<SolveConfig> for SolveArgs {
    fn into(self) -> SolveConfig {
        SolveConfig {
            derive_all: self.derive_all,
            output_mode: self.output_mode(),
            input_files: self.input_files,
        }
    }
}

#[derive(Copy, Clone, Debug)]
struct Size(usize);
impl FromStr for Size {
    type Err = ();

    fn from_str(src: &str) -> Result<Size, ()> {
        let val = usize::from_str(src);
        if let Ok(v) = val {
            if v != 0 {
                return Ok(Size(v));
            }
        }
        Err(())

    }
}

#[derive(Copy, Clone, Debug)]
enum OutputModeArg {
    Auto,
    PrettyColor,
    PrettyAscii,
    Raw,
    None,
}

impl FromStr for OutputModeArg {
    type Err = ();

    fn from_str(src: &str) -> Result<OutputModeArg, ()> {
        match src {
            "auto" => Ok(OutputModeArg::Auto),
            "pretty-color" => Ok(OutputModeArg::PrettyColor),
            "pretty-ascii" => Ok(OutputModeArg::PrettyAscii),
            "raw" => Ok(OutputModeArg::Raw),
            "none" => Ok(OutputModeArg::None),
            _ => Err(()),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Config {
    Solve(SolveConfig),
}

#[derive(Clone, Debug)]
pub struct SolveConfig {
    pub derive_all: bool,
    pub output_mode: OutputMode,
    pub input_files: Vec<String>,
}

#[derive(Copy, Clone, Debug)]
pub enum OutputMode {
    Pretty(PpConfig),
    Raw,
    None,
}

impl Config {
    pub fn parse() -> Config {
        let mut command = CommandType::default();
        let mut args = vec![];
        {
            let mut ap = ArgumentParser::new();
            command.setup_parser(&mut ap, &mut args);
            ap.parse_args_or_exit();
        }

        args.insert(0, format!("{:?}", command));

        match command {
            CommandType::Solve => {
                let mut sub_args = SolveArgs::default();
                {
                    let mut ap = ArgumentParser::new();
                    sub_args.setup_parser(&mut ap);
                    if let Err(x) = ap.parse(args, &mut io::stdout(), &mut io::stderr()) {
                        process::exit(x);
                    }
                }
                Config::Solve(sub_args.into())
            }
        }
    }
}
<commit_msg>Add description<commit_after>use std::{io, process};
use std::str::FromStr;
use argparse::{ArgumentParser, List, Store, StoreTrue};

use pprint::{self, Config as PpConfig, Mode as PpMode};

#[derive(Copy, Clone, Debug)]
enum CommandType {
    Solve,
}

impl CommandType {
    fn setup_parser<'parser>(&'parser mut self,
                             ap: &mut ArgumentParser<'parser>,
                             args: &'parser mut Vec<String>) {
        ap.set_description("Slither link solver - Command line interface");
        let _ = ap.refer(self)
                  .required()
                  .add_argument("command", Store, "command to run (solve)");
        let _ = ap.refer(args)
                  .add_argument("arguments", List, "arguments for command");
        ap.stop_on_first_argument(true);
    }
}

impl Default for CommandType {
    fn default() -> CommandType {
        CommandType::Solve
    }
}

impl FromStr for CommandType {
    type Err = ();

    fn from_str(src: &str) -> Result<CommandType, ()> {
        match src {
            "solve" => Ok(CommandType::Solve),
            _ => Err(()),
        }
    }
}

#[derive(Clone, Debug)]
struct SolveArgs {
    derive_all: bool,
    output_mode: OutputModeArg,
    width: Size,
    height: Size,
    input_files: Vec<String>,
}

impl SolveArgs {
    fn setup_parser<'parser>(&'parser mut self, ap: &mut ArgumentParser<'parser>) {
        ap.set_description("Solve the given problem(s)");
        let _ = ap.refer(&mut self.derive_all)
                  .add_option(&["--all"], StoreTrue, "derive all solutions (if any).");
        let _ = ap.refer(&mut self.output_mode)
                  .add_option(&["--output-mode"],
                              Store,
                              "specify output mode (auto, pretty-color, pretty-ascii, raw, none) \
                               [default: auto]");
        let _ = ap.refer(&mut self.width)
                  .add_option(&["--width"], Store, "specify cell width [default: 2]");
        let _ = ap.refer(&mut self.height)
                  .add_option(&["--height"], Store, "specify cell width [default: 1]");
        let _ = ap.refer(&mut self.input_files)
                  .add_argument("input_files", List, "puzzle files to solve.");
    }

    fn output_mode(&self) -> OutputMode {
        let ppmode = match self.output_mode {
            OutputModeArg::Auto => {
                if pprint::is_pprintable() {
                    PpMode::Color
                } else {
                    PpMode::Ascii
                }
            }
            OutputModeArg::PrettyColor => PpMode::Color,
            OutputModeArg::PrettyAscii => PpMode::Ascii,
            OutputModeArg::Raw => return OutputMode::Raw,
            OutputModeArg::None => return OutputMode::None,
        };
        OutputMode::Pretty(PpConfig {
            mode: ppmode,
            cell_width: self.width.0,
            cell_height: self.height.0,
        })
    }
}

impl Default for SolveArgs {
    fn default() -> SolveArgs {
        SolveArgs {
            derive_all: false,
            output_mode: OutputModeArg::Auto,
            width: Size(2),
            height: Size(1),
            input_files: vec![],
        }
    }
}

impl Into<SolveConfig> for SolveArgs {
    fn into(self) -> SolveConfig {
        SolveConfig {
            derive_all: self.derive_all,
            output_mode: self.output_mode(),
            input_files: self.input_files,
        }
    }
}

#[derive(Copy, Clone, Debug)]
struct Size(usize);
impl FromStr for Size {
    type Err = ();

    fn from_str(src: &str) -> Result<Size, ()> {
        let val = usize::from_str(src);
        if let Ok(v) = val {
            if v != 0 {
                return Ok(Size(v));
            }
        }
        Err(())

    }
}

#[derive(Copy, Clone, Debug)]
enum OutputModeArg {
    Auto,
    PrettyColor,
    PrettyAscii,
    Raw,
    None,
}

impl FromStr for OutputModeArg {
    type Err = ();

    fn from_str(src: &str) -> Result<OutputModeArg, ()> {
        match src {
            "auto" => Ok(OutputModeArg::Auto),
            "pretty-color" => Ok(OutputModeArg::PrettyColor),
            "pretty-ascii" => Ok(OutputModeArg::PrettyAscii),
            "raw" => Ok(OutputModeArg::Raw),
            "none" => Ok(OutputModeArg::None),
            _ => Err(()),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Config {
    Solve(SolveConfig),
}

#[derive(Clone, Debug)]
pub struct SolveConfig {
    pub derive_all: bool,
    pub output_mode: OutputMode,
    pub input_files: Vec<String>,
}

#[derive(Copy, Clone, Debug)]
pub enum OutputMode {
    Pretty(PpConfig),
    Raw,
    None,
}

impl Config {
    pub fn parse() -> Config {
        let mut command = CommandType::default();
        let mut args = vec![];
        {
            let mut ap = ArgumentParser::new();
            command.setup_parser(&mut ap, &mut args);
            ap.parse_args_or_exit();
        }

        args.insert(0, format!("{:?}", command));

        match command {
            CommandType::Solve => {
                let mut sub_args = SolveArgs::default();
                {
                    let mut ap = ArgumentParser::new();
                    sub_args.setup_parser(&mut ap);
                    if let Err(x) = ap.parse(args, &mut io::stdout(), &mut io::stderr()) {
                        process::exit(x);
                    }
                }
                Config::Solve(sub_args.into())
            }
        }
    }
}
<|endoftext|>