<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

//! Mac OS-specific implementation of cross-process surfaces. This uses `IOSurface`, introduced
//! in Mac OS X 10.6 Snow Leopard.

use core_foundation::base::TCFType;
use core_foundation::boolean::CFBoolean;
use core_foundation::dictionary::CFDictionary;
use core_foundation::number::CFNumber;
use core_foundation::string::CFString;
use serialize::{Decoder, Encodable, Encoder};
use geom::size::Size2D;
use io_surface::{kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow, kIOSurfaceHeight};
use io_surface::{kIOSurfaceIsGlobal, kIOSurfaceWidth, IOSurface, IOSurfaceID};
use io_surface;
use opengles::cgl::{CGLChoosePixelFormat, CGLDescribePixelFormat, CGLPixelFormatAttribute};
use opengles::cgl::{CGLPixelFormatObj, CORE_BOOLEAN_ATTRIBUTES, CORE_INTEGER_ATTRIBUTES};
use opengles::cgl::{kCGLNoError};
use opengles::gl2::GLint;
use collections::HashMap;
use std::local_data;
use std::ptr;

use platform::surface::NativeSurfaceMethods;
use texturegl::Texture;

local_data_key!(io_surface_repository: HashMap<IOSurfaceID,IOSurface>)

/// The Mac native graphics metadata.
#[deriving(Clone)]
pub struct NativeGraphicsMetadata {
    pub pixel_format: CGLPixelFormatObj,
}

impl NativeGraphicsMetadata {
    /// Creates a native graphics metadatum from a CGL pixel format.
    pub fn from_cgl_pixel_format(pixel_format: CGLPixelFormatObj) -> NativeGraphicsMetadata {
        NativeGraphicsMetadata {
            pixel_format: pixel_format,
        }
    }

    pub fn from_descriptor(descriptor: &NativeGraphicsMetadataDescriptor)
                           -> NativeGraphicsMetadata {
        unsafe {
            let mut attributes = ~[];
            for (i, &set) in descriptor.boolean_attributes.iter().enumerate() {
                if set {
                    attributes.push(CORE_BOOLEAN_ATTRIBUTES[i]);
                }
            }
            for (i, &value) in descriptor.integer_attributes.iter().enumerate() {
                attributes.push(CORE_INTEGER_ATTRIBUTES[i]);
                attributes.push(value as CGLPixelFormatAttribute);
            }
            attributes.push(0);
            let mut pixel_format = ptr::null();
            let mut count = 0;
            assert!(CGLChoosePixelFormat(&attributes[0], &mut pixel_format, &mut count) ==
                    kCGLNoError);
            assert!(pixel_format != ptr::null());
            assert!(count > 0);

            NativeGraphicsMetadata {
                pixel_format: pixel_format,
            }
        }
    }
}

/// The Mac native graphics metadata descriptor, which encompasses the values needed to create a
/// pixel format object.
#[deriving(Clone, Decodable, Encodable)]
pub struct NativeGraphicsMetadataDescriptor {
    boolean_attributes: ~[bool],
    integer_attributes: ~[GLint],
}

impl NativeGraphicsMetadataDescriptor {
    pub fn from_metadata(metadata: NativeGraphicsMetadata) -> NativeGraphicsMetadataDescriptor {
        unsafe {
            let mut descriptor = NativeGraphicsMetadataDescriptor {
                boolean_attributes: ~[],
                integer_attributes: ~[],
            };
            for &attribute in CORE_BOOLEAN_ATTRIBUTES.iter() {
                let mut value = 0;
                assert!(CGLDescribePixelFormat(metadata.pixel_format, 0, attribute, &mut value) ==
                        kCGLNoError);
                descriptor.boolean_attributes.push(value != 0);
                println!("{}: bool = {}", attribute, value);
            }
            for &attribute in CORE_INTEGER_ATTRIBUTES.iter() {
                let mut value = 0;
                assert!(CGLDescribePixelFormat(metadata.pixel_format, 0, attribute, &mut value) ==
                        kCGLNoError);
                descriptor.integer_attributes.push(value);
                println!("{}: int = {}", attribute, value);
            }
            descriptor
        }
    }

}

pub struct NativePaintingGraphicsContext {
    metadata: NativeGraphicsMetadata,
}

impl NativePaintingGraphicsContext {
    pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext {
        NativePaintingGraphicsContext {
            metadata: (*metadata).clone(),
        }
    }
}

impl Drop for NativePaintingGraphicsContext {
    fn drop(&mut self) {}
}

pub struct NativeCompositingGraphicsContext {
    contents: (),
}

impl NativeCompositingGraphicsContext {
    pub fn new() -> NativeCompositingGraphicsContext {
        NativeCompositingGraphicsContext {
            contents: (),
        }
    }
}

#[deriving(Decodable, Encodable)]
pub struct NativeSurface {
    io_surface_id: Option<IOSurfaceID>,
    will_leak: bool,
}

impl NativeSurface {
    pub fn from_io_surface(io_surface: IOSurface) -> NativeSurface {
        // Take the surface by ID (so that we can send it cross-process) and consume its reference.
        let id = io_surface.get_id();

        let mut io_surface = Some(io_surface);
        local_data::modify(io_surface_repository, |opt_repository| {
            let mut repository = match opt_repository {
                None => HashMap::new(),
                Some(repository) => repository,
            };
            repository.insert(id, io_surface.take().unwrap());
            Some(repository)
        });

        NativeSurface {
            io_surface_id: Some(id),
            will_leak: true,
        }
    }
}

impl NativeSurfaceMethods for NativeSurface {
    fn new(_: &NativePaintingGraphicsContext, size: Size2D<i32>, stride: i32) -> NativeSurface {
        unsafe {
            let width_key: CFString = TCFType::wrap_under_get_rule(kIOSurfaceWidth);
            let width_value: CFNumber = FromPrimitive::from_i32(size.width).unwrap();

            let height_key: CFString = TCFType::wrap_under_get_rule(kIOSurfaceHeight);
            let height_value: CFNumber = FromPrimitive::from_i32(size.height).unwrap();

            let bytes_per_row_key: CFString = TCFType::wrap_under_get_rule(kIOSurfaceBytesPerRow);
            let bytes_per_row_value: CFNumber = FromPrimitive::from_i32(stride).unwrap();

            let bytes_per_elem_key: CFString =
                TCFType::wrap_under_get_rule(kIOSurfaceBytesPerElement);
            let bytes_per_elem_value: CFNumber = FromPrimitive::from_i32(4).unwrap();

            let is_global_key: CFString = TCFType::wrap_under_get_rule(kIOSurfaceIsGlobal);
            let is_global_value = CFBoolean::true_value();

            let surface = io_surface::new(&CFDictionary::from_CFType_pairs([
                (width_key.as_CFType(), width_value.as_CFType()),
                (height_key.as_CFType(), height_value.as_CFType()),
                (bytes_per_row_key.as_CFType(), bytes_per_row_value.as_CFType()),
                (bytes_per_elem_key.as_CFType(), bytes_per_elem_value.as_CFType()),
                (is_global_key.as_CFType(), is_global_value.as_CFType()),
            ]));

            NativeSurface::from_io_surface(surface)
        }
    }

    fn bind_to_texture(&self,
                       _: &NativeCompositingGraphicsContext,
                       texture: &Texture,
                       size: Size2D<int>) {
        let _bound_texture = texture.bind();
        let io_surface = io_surface::lookup(self.io_surface_id.unwrap());
        io_surface.bind_to_gl_texture(size)
    }

    fn upload(&self, _: &NativePaintingGraphicsContext, data: &[u8]) {
        let io_surface = io_surface::lookup(self.io_surface_id.unwrap());
        io_surface.upload(data)
    }

    fn get_id(&self) -> int {
        match self.io_surface_id {
            None => 0,
            Some(id) => id as int,
        }
    }

    fn destroy(&mut self, _: &NativePaintingGraphicsContext) {
        local_data::get_mut(io_surface_repository, |opt_repository| {
            opt_repository.unwrap().remove(&self.io_surface_id.unwrap())
        });
        self.io_surface_id = None;
        self.mark_wont_leak()
    }

    fn mark_will_leak(&mut self) {
        self.will_leak = true
    }

    fn mark_wont_leak(&mut self) {
        self.will_leak = false
    }
}

<commit_msg>Rust upgrade 20140510<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

//! Mac OS-specific implementation of cross-process surfaces. This uses `IOSurface`, introduced
//! in Mac OS X 10.6 Snow Leopard.

use core_foundation::base::TCFType;
use core_foundation::boolean::CFBoolean;
use core_foundation::dictionary::CFDictionary;
use core_foundation::number::CFNumber;
use core_foundation::string::CFString;
use serialize::{Decoder, Encodable, Encoder};
use geom::size::Size2D;
use io_surface::{kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow, kIOSurfaceHeight};
use io_surface::{kIOSurfaceIsGlobal, kIOSurfaceWidth, IOSurface, IOSurfaceID};
use io_surface;
use opengles::cgl::{CGLChoosePixelFormat, CGLDescribePixelFormat, CGLPixelFormatAttribute};
use opengles::cgl::{CGLPixelFormatObj, CORE_BOOLEAN_ATTRIBUTES, CORE_INTEGER_ATTRIBUTES};
use opengles::cgl::{kCGLNoError};
use opengles::gl2::GLint;
use collections::HashMap;
use std::ptr;
use std::vec::Vec;

use platform::surface::NativeSurfaceMethods;
use texturegl::Texture;

local_data_key!(io_surface_repository: HashMap<IOSurfaceID,IOSurface>)

/// The Mac native graphics metadata.
#[deriving(Clone)]
pub struct NativeGraphicsMetadata {
    pub pixel_format: CGLPixelFormatObj,
}

impl NativeGraphicsMetadata {
    /// Creates a native graphics metadatum from a CGL pixel format.
    pub fn from_cgl_pixel_format(pixel_format: CGLPixelFormatObj) -> NativeGraphicsMetadata {
        NativeGraphicsMetadata {
            pixel_format: pixel_format,
        }
    }

    pub fn from_descriptor(descriptor: &NativeGraphicsMetadataDescriptor)
                           -> NativeGraphicsMetadata {
        unsafe {
            let mut attributes = Vec::new();
            for (i, &set) in descriptor.boolean_attributes.iter().enumerate() {
                if set {
                    attributes.push(CORE_BOOLEAN_ATTRIBUTES[i]);
                }
            }
            for (i, &value) in descriptor.integer_attributes.iter().enumerate() {
                attributes.push(CORE_INTEGER_ATTRIBUTES[i]);
                attributes.push(value as CGLPixelFormatAttribute);
            }
            attributes.push(0);
            let mut pixel_format = ptr::null();
            let mut count = 0;
            assert!(CGLChoosePixelFormat(attributes.as_ptr(), &mut pixel_format, &mut count) ==
                    kCGLNoError);
            assert!(pixel_format != ptr::null());
            assert!(count > 0);

            NativeGraphicsMetadata {
                pixel_format: pixel_format,
            }
        }
    }
}

/// The Mac native graphics metadata descriptor, which encompasses the values needed to create a
/// pixel format object.
#[deriving(Clone, Decodable, Encodable)]
pub struct NativeGraphicsMetadataDescriptor {
    boolean_attributes: Vec<bool>,
    integer_attributes: Vec<GLint>,
}

impl NativeGraphicsMetadataDescriptor {
    pub fn from_metadata(metadata: NativeGraphicsMetadata) -> NativeGraphicsMetadataDescriptor {
        unsafe {
            let mut descriptor = NativeGraphicsMetadataDescriptor {
                boolean_attributes: Vec::new(),
                integer_attributes: Vec::new(),
            };
            for &attribute in CORE_BOOLEAN_ATTRIBUTES.iter() {
                let mut value = 0;
                assert!(CGLDescribePixelFormat(metadata.pixel_format, 0, attribute, &mut value) ==
                        kCGLNoError);
                descriptor.boolean_attributes.push(value != 0);
                println!("{}: bool = {}", attribute, value);
            }
            for &attribute in CORE_INTEGER_ATTRIBUTES.iter() {
                let mut value = 0;
                assert!(CGLDescribePixelFormat(metadata.pixel_format, 0, attribute, &mut value) ==
                        kCGLNoError);
                descriptor.integer_attributes.push(value);
                println!("{}: int = {}", attribute, value);
            }
            descriptor
        }
    }

}

pub struct NativePaintingGraphicsContext {
    metadata: NativeGraphicsMetadata,
}

impl NativePaintingGraphicsContext {
    pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext {
        NativePaintingGraphicsContext {
            metadata: (*metadata).clone(),
        }
    }
}

impl Drop for NativePaintingGraphicsContext {
    fn drop(&mut self) {}
}

pub struct NativeCompositingGraphicsContext {
    contents: (),
}

impl NativeCompositingGraphicsContext {
    pub fn new() -> NativeCompositingGraphicsContext {
        NativeCompositingGraphicsContext {
            contents: (),
        }
    }
}

#[deriving(Decodable, Encodable)]
pub struct NativeSurface {
    io_surface_id: Option<IOSurfaceID>,
    will_leak: bool,
}

impl NativeSurface {
    pub fn from_io_surface(io_surface: IOSurface) -> NativeSurface {
        // Take the surface by ID (so that we can send it cross-process) and consume its reference.
        let id = io_surface.get_id();

        let mut io_surface = Some(io_surface);

        let opt_repository = io_surface_repository.replace(None);
        let mut repository = match opt_repository {
            None => HashMap::new(),
            Some(repository) => repository,
        };
        repository.insert(id, io_surface.take().unwrap());
        io_surface_repository.replace(Some(repository));

        NativeSurface {
            io_surface_id: Some(id),
            will_leak: true,
        }
    }
}

impl NativeSurfaceMethods for NativeSurface {
    fn new(_: &NativePaintingGraphicsContext, size: Size2D<i32>, stride: i32) -> NativeSurface {
        unsafe {
            let width_key: CFString = TCFType::wrap_under_get_rule(kIOSurfaceWidth);
            let width_value: CFNumber = FromPrimitive::from_i32(size.width).unwrap();

            let height_key: CFString = TCFType::wrap_under_get_rule(kIOSurfaceHeight);
            let height_value: CFNumber = FromPrimitive::from_i32(size.height).unwrap();

            let bytes_per_row_key: CFString = TCFType::wrap_under_get_rule(kIOSurfaceBytesPerRow);
            let bytes_per_row_value: CFNumber = FromPrimitive::from_i32(stride).unwrap();

            let bytes_per_elem_key: CFString =
                TCFType::wrap_under_get_rule(kIOSurfaceBytesPerElement);
            let bytes_per_elem_value: CFNumber = FromPrimitive::from_i32(4).unwrap();

            let is_global_key: CFString = TCFType::wrap_under_get_rule(kIOSurfaceIsGlobal);
            let is_global_value = CFBoolean::true_value();

            let surface = io_surface::new(&CFDictionary::from_CFType_pairs([
                (width_key.as_CFType(), width_value.as_CFType()),
                (height_key.as_CFType(), height_value.as_CFType()),
                (bytes_per_row_key.as_CFType(), bytes_per_row_value.as_CFType()),
                (bytes_per_elem_key.as_CFType(), bytes_per_elem_value.as_CFType()),
                (is_global_key.as_CFType(), is_global_value.as_CFType()),
            ]));

            NativeSurface::from_io_surface(surface)
        }
    }

    fn bind_to_texture(&self,
                       _: &NativeCompositingGraphicsContext,
                       texture: &Texture,
                       size: Size2D<int>) {
        let _bound_texture = texture.bind();
        let io_surface = io_surface::lookup(self.io_surface_id.unwrap());
        io_surface.bind_to_gl_texture(size)
    }

    fn upload(&self, _: &NativePaintingGraphicsContext, data: &[u8]) {
        let io_surface = io_surface::lookup(self.io_surface_id.unwrap());
        io_surface.upload(data)
    }

    fn get_id(&self) -> int {
        match self.io_surface_id {
            None => 0,
            Some(id) => id as int,
        }
    }

    fn destroy(&mut self, _: &NativePaintingGraphicsContext) {
        // There is no mutable borrow of items in local data.
        let opt_repository = io_surface_repository.replace(None);
        let mut repo = opt_repository.unwrap();
        repo.remove(&self.io_surface_id.unwrap());
        io_surface_repository.replace(Some(repo));
        self.io_surface_id = None;
        self.mark_wont_leak()
    }

    fn mark_will_leak(&mut self) {
        self.will_leak = true
    }

    fn mark_wont_leak(&mut self) {
        self.will_leak = false
    }
}

<|endoftext|>


<commit_before>//! AWS Regions and helper functions.
//!
//! Mostly used for translating the Region enum to a string AWS accepts.
//!
//! For example: `UsEast1` to "us-east-1"

use std;
use std::error::Error;
use std::str::FromStr;
use std::fmt::{self, Display, Error as FmtError, Formatter};
use credential::ProfileProvider;
use serde::{de, Serialize, Serializer, Deserialize, Deserializer};
use serde::ser::SerializeTuple;

/// An AWS region.
///
/// # Default
///
/// `Region` implements the `Default` trait. Calling `Region::default()` will attempt to read the
/// `AWS_DEFAULT_REGION` or `AWS_REGION` environment variable. If it is malformed, it will fall back to `Region::UsEast1`.
/// If it is not present it will fallback on the value associated with the current profile in `~/.aws/config` or the file
/// specified by the `AWS_CONFIG_FILE` environment variable. If that is malformed of absent it will fall back on `Region::UsEast1`
///
/// # AWS-compatible services
///
/// `Region::Custom` can be used to connect to AWS-compatible services such as DynamoDB Local or Ceph.
///
/// ```
///     # use rusoto_core::Region;
///     Region::Custom {
///         name: "eu-east-3".to_owned(),
///         endpoint: "http://localhost:8000".to_owned(),
///     };
/// ```
///
/// # Caveats
///
/// `CnNorth1` is currently untested due to Rusoto maintainers not having access to AWS China.
#[derive(Clone, Debug, PartialEq)]
pub enum Region {
    /// Region that covers the North-Eastern part of Asia Pacific
    ApNortheast1,

    /// Region that covers the North-Eastern part of Asia Pacific
    ApNortheast2,

    /// Region that covers the Southern part of Asia Pacific
    ApSouth1,

    /// Region that covers the South-Eastern part of Asia Pacific
    ApSoutheast1,

    /// Region that covers the South-Eastern part of Asia Pacific
    ApSoutheast2,

    /// Region that covers Canada
    CaCentral1,

    /// Region that covers Central Europe
    EuCentral1,

    /// Region that covers Western Europe
    EuWest1,

    /// Region that covers Western Europe
    EuWest2,

    /// Region that covers Western Europe
    EuWest3,

    /// Region that covers South America
    SaEast1,

    /// Region that covers the Eastern part of the United States
    UsEast1,

    /// Region that covers the Eastern part of the United States
    UsEast2,

    /// Region that covers the Western part of the United States
    UsWest1,

    /// Region that covers the Western part of the United States
    UsWest2,

    /// Region that covers the Western part of the United States for the US Government
    UsGovWest1,

    /// Region that covers China
    CnNorth1,

    /// Region that covers North-Western  part of China
    CnNorthwest1,

    /// Specifies a custom region, such as a local Ceph target
    Custom {
        /// Name of the endpoint (e.g. `"eu-east-2"`).
        name: String,

        /// Endpoint to be used. For instance, `"https://s3.my-provider.net"` or just
        /// `"s3.my-provider.net"` (default scheme is https).
        endpoint: String,
    },
}

impl Region {
    /// Name of the region
    ///
    /// ```
    ///     # use rusoto_core::Region;
    ///     assert_eq!(Region::CaCentral1.name(), "ca-central-1");
    ///     assert_eq!(
    ///         Region::Custom { name: "eu-east-3".to_owned(), endpoint: "s3.net".to_owned() }.name(),
    ///         "eu-east-3"
    ///     );
    /// ```
    pub fn name(&self) -> &str {
        match *self {
            Region::ApNortheast1 => "ap-northeast-1",
            Region::ApNortheast2 => "ap-northeast-2",
            Region::ApSouth1 => "ap-south-1",
            Region::ApSoutheast1 => "ap-southeast-1",
            Region::ApSoutheast2 => "ap-southeast-2",
            Region::CaCentral1 => "ca-central-1",
            Region::EuCentral1 => "eu-central-1",
            Region::EuWest1 => "eu-west-1",
            Region::EuWest2 => "eu-west-2",
            Region::EuWest3 => "eu-west-3",
            Region::SaEast1 => "sa-east-1",
            Region::UsEast1 => "us-east-1",
            Region::UsEast2 => "us-east-2",
            Region::UsWest1 => "us-west-1",
            Region::UsWest2 => "us-west-2",
            Region::UsGovWest1 => "us-gov-west-1",
            Region::CnNorth1 => "cn-north-1",
            Region::CnNorthwest1 => "cn-northwest-1",
            Region::Custom { ref name, .. } => name,
        }
    }
}

/// An error produced when attempting to convert a `str` into a `Region` fails.
#[derive(Debug,PartialEq)]
pub struct ParseRegionError {
    message: String,
}

// Manually created for lack of a way to flatten the `Region::Custom` variant
// Related: https://github.com/serde-rs/serde/issues/119
impl Serialize for Region {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where S: Serializer
    {
        let mut seq = serializer.serialize_tuple(2)?;
        if let Region::Custom { ref endpoint, ref name } = *self {
            seq.serialize_element(&name)?;
            seq.serialize_element(&Some(&endpoint))?;
        } else {
            seq.serialize_element(self.name())?;
            seq.serialize_element(&None as &Option<&str>)?;
        }
        seq.end()
    }
}

struct RegionVisitor;

impl<'de> de::Visitor<'de> for RegionVisitor {
    type Value = Region;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("sequence of (name, Some(endpoint))")
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
        where
            A: de::SeqAccess<'de>,
    {
        let name: String = seq.next_element()?
            .ok_or_else(|| de::Error::custom("region is missing name"))?;
        let endpoint: Option<String> = seq.next_element()?
            .ok_or_else(|| de::Error::custom("region is missing endpoint"))?;
        match (name, endpoint) {
            (name, Some(endpoint)) => Ok(Region::Custom { name, endpoint }),
            (name, None) => name.parse().map_err(de::Error::custom),
        }
    }
}

// Manually created for lack of a way to flatten the `Region::Custom` variant
// Related: https://github.com/serde-rs/serde/issues/119
impl<'de> Deserialize<'de> for Region {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        deserializer.deserialize_tuple(2, RegionVisitor)
    }
}

impl FromStr for Region {
    type Err = ParseRegionError;

    fn from_str(s: &str) -> Result<Region, ParseRegionError> {
        let v : &str = &s.to_lowercase();
        match v {
            "ap-northeast-1" | "apnortheast1" => Ok(Region::ApNortheast1),
            "ap-northeast-2" | "apnortheast2" => Ok(Region::ApNortheast2),
            "ap-south-1" | "apsouth1" => Ok(Region::ApSouth1),
            "ap-southeast-1" | "apsoutheast1" => Ok(Region::ApSoutheast1),
            "ap-southeast-2" | "apsoutheast2" => Ok(Region::ApSoutheast2),
            "ca-central-1" | "cacentral1" => Ok(Region::CaCentral1),
            "eu-central-1" | "eucentral1" => Ok(Region::EuCentral1),
            "eu-west-1" | "euwest1" => Ok(Region::EuWest1),
            "eu-west-2" | "euwest2" => Ok(Region::EuWest2),
            "eu-west-3" | "euwest3" => Ok(Region::EuWest3),
            "sa-east-1" | "saeast1" => Ok(Region::SaEast1),
            "us-east-1" | "useast1" => Ok(Region::UsEast1),
            "us-east-2" | "useast2" => Ok(Region::UsEast2),
            "us-west-1" | "uswest1" => Ok(Region::UsWest1),
            "us-west-2" | "uswest2" => Ok(Region::UsWest2),
            "us-gov-west-1" | "usgovwest1" => Ok(Region::UsGovWest1),
            "cn-north-1" | "cnnorth1" => Ok(Region::CnNorth1),
            "cn-northwest-1" | "cnnorthwest1" => Ok(Region::CnNorthwest1),
            s => Err(ParseRegionError::new(s)),
        }
    }
}

impl ParseRegionError {
    /// Parses a region given as a string literal into a type `Region'
    pub fn new(input: &str) -> Self {
        ParseRegionError { message: format!("Not a valid AWS region: {}", input) }
    }
}

impl Error for ParseRegionError {
    fn description(&self) -> &str {
        &self.message
    }
}

impl Display for ParseRegionError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{}", self.message)
    }
}

impl Default for Region {
    fn default() -> Region {
        match std::env::var("AWS_DEFAULT_REGION").or_else(|| std::env::var("AWS_REGION")) {
            Ok(ref v) =>
                Region::from_str(v).unwrap_or(Region::UsEast1),
            Err(_) => {
                match ProfileProvider::region() {
                    Some(region) => Region::from_str(region).unwrap_or(Region::UsEast1),
                    _ => Region::UsEast1,
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate serde_test;
    use self::serde_test::{Token, assert_tokens};
    use super::*;

    #[test]
    fn from_str() {
        assert_eq!("foo"
                       .parse::<Region>()
                       .err()
                       .expect("Parsing foo as a Region was not an error")
                       .to_string(),
                   "Not a valid AWS region: foo".to_owned());
        assert_eq!("ap-northeast-1".parse(), Ok(Region::ApNortheast1));
        assert_eq!("ap-northeast-2".parse(), Ok(Region::ApNortheast2));
        assert_eq!("ap-south-1".parse(), Ok(Region::ApSouth1));
        assert_eq!("ap-southeast-1".parse(), Ok(Region::ApSoutheast1));
        assert_eq!("ap-southeast-2".parse(), Ok(Region::ApSoutheast2));
        assert_eq!("ca-central-1".parse(), Ok(Region::CaCentral1));
        assert_eq!("eu-central-1".parse(), Ok(Region::EuCentral1));
        assert_eq!("eu-west-1".parse(), Ok(Region::EuWest1));
        assert_eq!("eu-west-2".parse(), Ok(Region::EuWest2));
        assert_eq!("eu-west-3".parse(), Ok(Region::EuWest3));
        assert_eq!("sa-east-1".parse(), Ok(Region::SaEast1));
        assert_eq!("us-east-1".parse(), Ok(Region::UsEast1));
        assert_eq!("us-east-2".parse(), Ok(Region::UsEast2));
        assert_eq!("us-west-1".parse(), Ok(Region::UsWest1));
        assert_eq!("us-west-2".parse(), Ok(Region::UsWest2));
        assert_eq!("us-gov-west-1".parse(), Ok(Region::UsGovWest1));
        assert_eq!("cn-north-1".parse(), Ok(Region::CnNorth1));
        assert_eq!("cn-northwest-1".parse(), Ok(Region::CnNorthwest1));
    }

    #[test]
    fn region_serialize_deserialize() {
        assert_tokens(&Region::ApNortheast1, &tokens_for_region("ap-northeast-1"));
        assert_tokens(&Region::ApNortheast2, &tokens_for_region("ap-northeast-2"));
        assert_tokens(&Region::ApSouth1, &tokens_for_region("ap-south-1"));
        assert_tokens(&Region::ApSoutheast1, &tokens_for_region("ap-southeast-1"));
        assert_tokens(&Region::ApSoutheast2, &tokens_for_region("ap-southeast-2"));
        assert_tokens(&Region::CaCentral1, &tokens_for_region("ca-central-1"));
        assert_tokens(&Region::EuCentral1, &tokens_for_region("eu-central-1"));
        assert_tokens(&Region::EuWest1, &tokens_for_region("eu-west-1"));
        assert_tokens(&Region::EuWest2, &tokens_for_region("eu-west-2"));
        assert_tokens(&Region::EuWest3, &tokens_for_region("eu-west-3"));
        assert_tokens(&Region::SaEast1, &tokens_for_region("sa-east-1"));
        assert_tokens(&Region::UsEast1, &tokens_for_region("us-east-1"));
        assert_tokens(&Region::UsEast2, &tokens_for_region("us-east-2"));
        assert_tokens(&Region::UsWest1, &tokens_for_region("us-west-1"));
        assert_tokens(&Region::UsWest2, &tokens_for_region("us-west-2"));
        assert_tokens(&Region::UsGovWest1, &tokens_for_region("us-gov-west-1"));
        assert_tokens(&Region::CnNorth1, &tokens_for_region("cn-north-1"));
        assert_tokens(&Region::CnNorthwest1, &tokens_for_region("cn-northwest-1"))
    }

    fn tokens_for_region(name: &'static str) -> [Token; 4] {
        [
            Token::Tuple { len: 2 },
            Token::String(name),
            Token::None,
            Token::TupleEnd,
        ]
    }

    #[test]
    fn region_serialize_deserialize_custom() {
        let custom_region = Region::Custom {
            endpoint: "http://localhost:8000".to_owned(),
            name: "eu-east-1".to_owned(),
        };
        assert_tokens(
            &custom_region,
            &[
                Token::Tuple { len: 2 },
                Token::String("eu-east-1"),
                Token::Some,
                Token::String("http://localhost:8000"),
                Token::TupleEnd,
            ],
        );
    }
}
<commit_msg>core compile errors<commit_after>//! AWS Regions and helper functions.
//!
//! Mostly used for translating the Region enum to a string AWS accepts.
//!
//! For example: `UsEast1` to "us-east-1"

use std;
use std::error::Error;
use std::str::FromStr;
use std::fmt::{self, Display, Error as FmtError, Formatter};
use credential::ProfileProvider;
use serde::{de, Serialize, Serializer, Deserialize, Deserializer};
use serde::ser::SerializeTuple;

/// An AWS region.
///
/// # Default
///
/// `Region` implements the `Default` trait. Calling `Region::default()` will attempt to read the
/// `AWS_DEFAULT_REGION` or `AWS_REGION` environment variable. If it is malformed, it will fall back to `Region::UsEast1`.
/// If it is not present it will fallback on the value associated with the current profile in `~/.aws/config` or the file
/// specified by the `AWS_CONFIG_FILE` environment variable. If that is malformed of absent it will fall back on `Region::UsEast1`
///
/// # AWS-compatible services
///
/// `Region::Custom` can be used to connect to AWS-compatible services such as DynamoDB Local or Ceph.
///
/// ```
///     # use rusoto_core::Region;
///     Region::Custom {
///         name: "eu-east-3".to_owned(),
///         endpoint: "http://localhost:8000".to_owned(),
///     };
/// ```
///
/// # Caveats
///
/// `CnNorth1` is currently untested due to Rusoto maintainers not having access to AWS China.
#[derive(Clone, Debug, PartialEq)]
pub enum Region {
    /// Region that covers the North-Eastern part of Asia Pacific
    ApNortheast1,

    /// Region that covers the North-Eastern part of Asia Pacific
    ApNortheast2,

    /// Region that covers the Southern part of Asia Pacific
    ApSouth1,

    /// Region that covers the South-Eastern part of Asia Pacific
    ApSoutheast1,

    /// Region that covers the South-Eastern part of Asia Pacific
    ApSoutheast2,

    /// Region that covers Canada
    CaCentral1,

    /// Region that covers Central Europe
    EuCentral1,

    /// Region that covers Western Europe
    EuWest1,

    /// Region that covers Western Europe
    EuWest2,

    /// Region that covers Western Europe
    EuWest3,

    /// Region that covers South America
    SaEast1,

    /// Region that covers the Eastern part of the United States
    UsEast1,

    /// Region that covers the Eastern part of the United States
    UsEast2,

    /// Region that covers the Western part of the United States
    UsWest1,

    /// Region that covers the Western part of the United States
    UsWest2,

    /// Region that covers the Western part of the United States for the US Government
    UsGovWest1,

    /// Region that covers China
    CnNorth1,

    /// Region that covers North-Western  part of China
    CnNorthwest1,

    /// Specifies a custom region, such as a local Ceph target
    Custom {
        /// Name of the endpoint (e.g. `"eu-east-2"`).
        name: String,

        /// Endpoint to be used. For instance, `"https://s3.my-provider.net"` or just
        /// `"s3.my-provider.net"` (default scheme is https).
        endpoint: String,
    },
}

impl Region {
    /// Name of the region
    ///
    /// ```
    ///     # use rusoto_core::Region;
    ///     assert_eq!(Region::CaCentral1.name(), "ca-central-1");
    ///     assert_eq!(
    ///         Region::Custom { name: "eu-east-3".to_owned(), endpoint: "s3.net".to_owned() }.name(),
    ///         "eu-east-3"
    ///     );
    /// ```
    pub fn name(&self) -> &str {
        match *self {
            Region::ApNortheast1 => "ap-northeast-1",
            Region::ApNortheast2 => "ap-northeast-2",
            Region::ApSouth1 => "ap-south-1",
            Region::ApSoutheast1 => "ap-southeast-1",
            Region::ApSoutheast2 => "ap-southeast-2",
            Region::CaCentral1 => "ca-central-1",
            Region::EuCentral1 => "eu-central-1",
            Region::EuWest1 => "eu-west-1",
            Region::EuWest2 => "eu-west-2",
            Region::EuWest3 => "eu-west-3",
            Region::SaEast1 => "sa-east-1",
            Region::UsEast1 => "us-east-1",
            Region::UsEast2 => "us-east-2",
            Region::UsWest1 => "us-west-1",
            Region::UsWest2 => "us-west-2",
            Region::UsGovWest1 => "us-gov-west-1",
            Region::CnNorth1 => "cn-north-1",
            Region::CnNorthwest1 => "cn-northwest-1",
            Region::Custom { ref name, .. } => name,
        }
    }
}

/// An error produced when attempting to convert a `str` into a `Region` fails.
#[derive(Debug,PartialEq)]
pub struct ParseRegionError {
    message: String,
}

// Manually created for lack of a way to flatten the `Region::Custom` variant
// Related: https://github.com/serde-rs/serde/issues/119
impl Serialize for Region {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where S: Serializer
    {
        let mut seq = serializer.serialize_tuple(2)?;
        if let Region::Custom { ref endpoint, ref name } = *self {
            seq.serialize_element(&name)?;
            seq.serialize_element(&Some(&endpoint))?;
        } else {
            seq.serialize_element(self.name())?;
            seq.serialize_element(&None as &Option<&str>)?;
        }
        seq.end()
    }
}

struct RegionVisitor;

impl<'de> de::Visitor<'de> for RegionVisitor {
    type Value = Region;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("sequence of (name, Some(endpoint))")
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
        where
            A: de::SeqAccess<'de>,
    {
        let name: String = seq.next_element()?
            .ok_or_else(|| de::Error::custom("region is missing name"))?;
        let endpoint: Option<String> = seq.next_element()?
            .ok_or_else(|| de::Error::custom("region is missing endpoint"))?;
        match (name, endpoint) {
            (name, Some(endpoint)) => Ok(Region::Custom { name, endpoint }),
            (name, None) => name.parse().map_err(de::Error::custom),
        }
    }
}

// Manually created for lack of a way to flatten the `Region::Custom` variant
// Related: https://github.com/serde-rs/serde/issues/119
impl<'de> Deserialize<'de> for Region {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        deserializer.deserialize_tuple(2, RegionVisitor)
    }
}

impl FromStr for Region {
    type Err = ParseRegionError;

    fn from_str(s: &str) -> Result<Region, ParseRegionError> {
        let v : &str = &s.to_lowercase();
        match v {
            "ap-northeast-1" | "apnortheast1" => Ok(Region::ApNortheast1),
            "ap-northeast-2" | "apnortheast2" => Ok(Region::ApNortheast2),
            "ap-south-1" | "apsouth1" => Ok(Region::ApSouth1),
            "ap-southeast-1" | "apsoutheast1" => Ok(Region::ApSoutheast1),
            "ap-southeast-2" | "apsoutheast2" => Ok(Region::ApSoutheast2),
            "ca-central-1" | "cacentral1" => Ok(Region::CaCentral1),
            "eu-central-1" | "eucentral1" => Ok(Region::EuCentral1),
            "eu-west-1" | "euwest1" => Ok(Region::EuWest1),
            "eu-west-2" | "euwest2" => Ok(Region::EuWest2),
            "eu-west-3" | "euwest3" => Ok(Region::EuWest3),
            "sa-east-1" | "saeast1" => Ok(Region::SaEast1),
            "us-east-1" | "useast1" => Ok(Region::UsEast1),
            "us-east-2" | "useast2" => Ok(Region::UsEast2),
            "us-west-1" | "uswest1" => Ok(Region::UsWest1),
            "us-west-2" | "uswest2" => Ok(Region::UsWest2),
            "us-gov-west-1" | "usgovwest1" => Ok(Region::UsGovWest1),
            "cn-north-1" | "cnnorth1" => Ok(Region::CnNorth1),
            "cn-northwest-1" | "cnnorthwest1" => Ok(Region::CnNorthwest1),
            s => Err(ParseRegionError::new(s)),
        }
    }
}

impl ParseRegionError {
    /// Parses a region given as a string literal into a type `Region'
    pub fn new(input: &str) -> Self {
        ParseRegionError { message: format!("Not a valid AWS region: {}", input) }
    }
}

impl Error for ParseRegionError {
    fn description(&self) -> &str {
        &self.message
    }
}

impl Display for ParseRegionError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{}", self.message)
    }
}

impl Default for Region {
    fn default() -> Region {
        match std::env::var("AWS_DEFAULT_REGION").or_else(|_| std::env::var("AWS_REGION")) {
            Ok(ref v) =>
                Region::from_str(v).unwrap_or(Region::UsEast1),
            Err(_) => {
                match ProfileProvider::region() {
                    Ok(Some(region)) => Region::from_str(&region).unwrap_or(Region::UsEast1),
                    _ => Region::UsEast1,
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate serde_test;
    use self::serde_test::{Token, assert_tokens};
    use super::*;

    #[test]
    fn from_str() {
        assert_eq!("foo"
                       .parse::<Region>()
                       .err()
                       .expect("Parsing foo as a Region was not an error")
                       .to_string(),
                   "Not a valid AWS region: foo".to_owned());
        assert_eq!("ap-northeast-1".parse(), Ok(Region::ApNortheast1));
        assert_eq!("ap-northeast-2".parse(), Ok(Region::ApNortheast2));
        assert_eq!("ap-south-1".parse(), Ok(Region::ApSouth1));
        assert_eq!("ap-southeast-1".parse(), Ok(Region::ApSoutheast1));
        assert_eq!("ap-southeast-2".parse(), Ok(Region::ApSoutheast2));
        assert_eq!("ca-central-1".parse(), Ok(Region::CaCentral1));
        assert_eq!("eu-central-1".parse(), Ok(Region::EuCentral1));
        assert_eq!("eu-west-1".parse(), Ok(Region::EuWest1));
        assert_eq!("eu-west-2".parse(), Ok(Region::EuWest2));
        assert_eq!("eu-west-3".parse(), Ok(Region::EuWest3));
        assert_eq!("sa-east-1".parse(), Ok(Region::SaEast1));
        assert_eq!("us-east-1".parse(), Ok(Region::UsEast1));
        assert_eq!("us-east-2".parse(), Ok(Region::UsEast2));
        assert_eq!("us-west-1".parse(), Ok(Region::UsWest1));
        assert_eq!("us-west-2".parse(), Ok(Region::UsWest2));
        assert_eq!("us-gov-west-1".parse(), Ok(Region::UsGovWest1));
        assert_eq!("cn-north-1".parse(), Ok(Region::CnNorth1));
        assert_eq!("cn-northwest-1".parse(), Ok(Region::CnNorthwest1));
    }

    #[test]
    fn region_serialize_deserialize() {
        assert_tokens(&Region::ApNortheast1, &tokens_for_region("ap-northeast-1"));
        assert_tokens(&Region::ApNortheast2, &tokens_for_region("ap-northeast-2"));
        assert_tokens(&Region::ApSouth1, &tokens_for_region("ap-south-1"));
        assert_tokens(&Region::ApSoutheast1, &tokens_for_region("ap-southeast-1"));
        assert_tokens(&Region::ApSoutheast2, &tokens_for_region("ap-southeast-2"));
        assert_tokens(&Region::CaCentral1, &tokens_for_region("ca-central-1"));
        assert_tokens(&Region::EuCentral1, &tokens_for_region("eu-central-1"));
        assert_tokens(&Region::EuWest1, &tokens_for_region("eu-west-1"));
        assert_tokens(&Region::EuWest2, &tokens_for_region("eu-west-2"));
        assert_tokens(&Region::EuWest3, &tokens_for_region("eu-west-3"));
        assert_tokens(&Region::SaEast1, &tokens_for_region("sa-east-1"));
        assert_tokens(&Region::UsEast1, &tokens_for_region("us-east-1"));
        assert_tokens(&Region::UsEast2, &tokens_for_region("us-east-2"));
        assert_tokens(&Region::UsWest1, &tokens_for_region("us-west-1"));
        assert_tokens(&Region::UsWest2, &tokens_for_region("us-west-2"));
        assert_tokens(&Region::UsGovWest1, &tokens_for_region("us-gov-west-1"));
        assert_tokens(&Region::CnNorth1, &tokens_for_region("cn-north-1"));
        assert_tokens(&Region::CnNorthwest1, &tokens_for_region("cn-northwest-1"))
    }

    fn tokens_for_region(name: &'static str) -> [Token; 4] {
        [
            Token::Tuple { len: 2 },
            Token::String(name),
            Token::None,
            Token::TupleEnd,
        ]
    }

    #[test]
    fn region_serialize_deserialize_custom() {
        let custom_region = Region::Custom {
            endpoint: "http://localhost:8000".to_owned(),
            name: "eu-east-1".to_owned(),
        };
        assert_tokens(
            &custom_region,
            &[
                Token::Tuple { len: 2 },
                Token::String("eu-east-1"),
                Token::Some,
                Token::String("http://localhost:8000"),
                Token::TupleEnd,
            ],
        );
    }
}
<|endoftext|>


<commit_before>extern crate glob;
extern crate prost_build;

fn main() {
    use glob::glob;

    prost_build::compile_protos(&["../common_protos/scaii.proto"], &["../common_protos"]).unwrap();

    // Make our protobuf file a reason to recompile
    // (See http://doc.crates.io/build-script.html for more info
    // on outputs)
    for entry in glob("../common_protos/*.rs").expect("Could not parse glob pattern") {
        if let Ok(path) = entry {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }

    // Unfortunately, rerun-if-changed overrides Cargo's default handling, which
    // is to rerun if any of our files change, so we have to re-add all our source
    // files
    println!("cargo:rerun-if-changed=Cargo.toml");
    println!("cargo:rerun-if-changed=build.rs");

    for entry in glob("src/*.rs").expect("Could not parse glob pattern") {
        if let Ok(path) = entry {
            println!("cargo:rerun-if-changed={}", path.display())
        }
    }
}
<commit_msg>Fix proto recompile bug<commit_after>extern crate glob;
extern crate prost_build;

fn main() {
    use glob::glob;

    prost_build::compile_protos(&["../common_protos/scaii.proto"], &["../common_protos"]).unwrap();

    // Make our protobuf file a reason to recompile
    // (See http://doc.crates.io/build-script.html for more info
    // on outputs)
    for entry in glob("../common_protos/*.proto").expect("Could not parse glob pattern") {
        if let Ok(path) = entry {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }

    // Unfortunately, rerun-if-changed overrides Cargo's default handling, which
    // is to rerun if any of our files change, so we have to re-add all our source
    // files
    println!("cargo:rerun-if-changed=Cargo.toml");
    println!("cargo:rerun-if-changed=build.rs");

    for entry in glob("src/*.rs").expect("Could not parse glob pattern") {
        if let Ok(path) = entry {
            println!("cargo:rerun-if-changed={}", path.display())
        }
    }
}
<|endoftext|>


<commit_before>//! Module containing various utility functions.

mod content_encoding;

use base64;
use std::f64;
use std::cmp;
use iron::Url;
use std::fs::File;
use std::path::Path;
use std::borrow::Cow;
use url::percent_encoding;
use std::collections::HashMap;
use time::{self, Duration, Tm};
use std::io::{BufReader, BufRead};
use mime_guess::get_mime_type_str;

pub use self::content_encoding::*;

/// The generic HTML page to use as response to errors.
pub static ERROR_HTML: &'static str = include_str!("../../assets/error.html");

/// The HTML page to use as template for a requested directory's listing.
pub static DIRECTORY_LISTING_HTML: &'static str = include_str!("../../assets/directory_listing.html");

lazy_static! {
    /// Collection of data to be injected into generated responses.
    pub static ref ASSETS: HashMap<&'static str, Cow<'static, str>> = {
        let mut ass = HashMap::with_capacity(8);
        ass.insert("favicon",
            Cow::Owned(format!("data:{};base64,{}", get_mime_type_str("ico").unwrap(), base64::encode(include_bytes!("../../assets/favicon.ico")))));
        ass.insert("dir_icon",
            Cow::Owned(format!("data:{};base64,{}",
                               get_mime_type_str("gif").unwrap(),
                               base64::encode(include_bytes!("../../assets/icons/directory_icon.gif")))));
        ass.insert("file_icon",
            Cow::Owned(format!("data:{};base64,{}",
                               get_mime_type_str("gif").unwrap(),
                               base64::encode(include_bytes!("../../assets/icons/file_icon.gif")))));
        ass.insert("file_binary_icon",
            Cow::Owned(format!("data:{};base64,{}",
                               get_mime_type_str("gif").unwrap(),
                               base64::encode(include_bytes!("../../assets/icons/file_binary_icon.gif")))));
        ass.insert("file_image_icon",
            Cow::Owned(format!("data:{};base64,{}",
                               get_mime_type_str("gif").unwrap(),
                               base64::encode(include_bytes!("../../assets/icons/file_image_icon.gif")))));
        ass.insert("file_text_icon",
            Cow::Owned(format!("data:{};base64,{}",
                               get_mime_type_str("gif").unwrap(),
                               base64::encode(include_bytes!("../../assets/icons/file_text_icon.gif")))));
        ass.insert("back_arrow_icon",
            Cow::Owned(format!("data:{};base64,{}",
                               get_mime_type_str("gif").unwrap(),
                               base64::encode(include_bytes!("../../assets/icons/back_arrow_icon.gif")))));
        ass.insert("drag_drop", Cow::Borrowed(include_str!("../../assets/drag_drop.js")));
        ass
    };
}

/// The port to start scanning from if no ports were given.
pub static PORT_SCAN_LOWEST: u16 = 8000;

/// The port to end scanning at if no ports were given.
pub static PORT_SCAN_HIGHEST: u16 = 9999;

/// The app name and version to use with User-Agent or Server response header.
pub static USER_AGENT: &'static str = concat!("http/", env!("CARGO_PKG_VERSION"));

/// Index file extensions to look for if `-i` was not specified.
pub static INDEX_EXTENSIONS: &'static [&'static str] = &["html", "htm", "shtml"];

/// Uppercase the first character of the supplied string.
///
/// Based on http://stackoverflow.com/a/38406885/2851815
///
/// # Examples
///
/// ```
/// # use https::util::uppercase_first;
/// assert_eq!(uppercase_first("abolish"), "Abolish".to_string());
/// ```
pub fn uppercase_first(s: &str) -> String {
    let mut c = s.chars();
    match c.next() {
        None => String::new(),
        Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
    }
}

/// Check if the specified file is to be considered "binary".
///
/// Basically checks is a file is UTF-8.
///
/// # Examples
///
/// ```
/// # use https::util::file_binary;
/// # #[cfg(target_os = "windows")]
/// # assert!(file_binary("target/debug/http.exe"));
/// # #[cfg(not(target_os = "windows"))]
/// assert!(file_binary("target/debug/http"));
/// assert!(!file_binary("Cargo.toml"));
/// ```
pub fn file_binary<P: AsRef<Path>>(path: P) -> bool {
    File::open(path).and_then(|f| BufReader::new(f).read_line(&mut String::new())).is_err()
}

/// Fill out an HTML template.
///
/// All fields must be addressed even if formatted to be empty.
///
/// # Examples
///
/// ```
/// # use https::util::{html_response, NOT_IMPLEMENTED_HTML};
/// println!(html_response(NOT_IMPLEMENTED_HTML, &["<p>Abolish the burgeoisie!</p>"]));
/// ```
pub fn html_response<S: AsRef<str>>(data: &str, format_strings: &[S]) -> String {
    ASSETS.iter().fold(format_strings.iter().enumerate().fold(data.to_string(), |d, (i, s)| d.replace(&format!("{{{}}}", i), s.as_ref())),
                       |d, (k, v)| d.replace(&format!("{{{}}}", k), v))
}

/// Return the path part of the URL.
///
/// # Example
///
/// ```
/// # extern crate iron;
/// # extern crate https;
/// # use iron::Url;
/// # use https::util::url_path;
/// let url = Url::parse("127.0.0.1:8000/capitalism/русский/");
/// assert_eq!(url_path(&url), "capitalism/русский/");
/// ```
pub fn url_path(url: &Url) -> String {
    let path = url.path();
    if path == [""] {
        "/".to_string()
    } else {
        path.into_iter().fold("".to_string(),
                              |cur, pp| format!("{}/{}", cur, percent_decode(pp).unwrap_or(Cow::Borrowed("<incorrect UTF8>"))))[1..]
            .to_string()
    }
}

/// Decode a percent-encoded string (like a part of a URL).
///
/// # Example
///
/// ```
/// # use https::util::percent_decode;
/// # use std::borrow::Cow;
/// assert_eq!(percent_decode("%D0%B0%D1%81%D0%B4%D1%84%20fdsa"), Some(Cow::Owned("асдф fdsa".to_string())));
/// assert_eq!(percent_decode("%D0%D1%81%D0%B4%D1%84%20fdsa"), None);
/// ```
pub fn percent_decode(s: &str) -> Option<Cow<str>> {
    percent_encoding::percent_decode(s.as_bytes()).decode_utf8().ok()
}

/// Get the timestamp of the file's last modification as a `time::Tm`.
pub fn file_time_modified(f: &Path) -> Tm {
    match f.metadata().unwrap().modified().unwrap().elapsed() {
        Ok(dur) => time::now() - Duration::from_std(dur).unwrap(),
        Err(ste) => time::now() + Duration::from_std(ste.duration()).unwrap(),
    }
}

/// Check, whether, in any place of the path, a file is treated like a directory.
///
/// A file is treated like a directory when it is treated as if it had a subpath, e.g., given:
///
/// ```sh
/// tree .
/// | dir0
/// | dir1
///   | file01
/// ```
///
/// This function would return true for `./dir1/file01/file010`, `./dir1/file01/dir010/file0100`, etc., but not
/// for `./dir0/file00`, `./dir0/dir00/file000`, `./dir1/file02/`, `./dir1/dir010/file0100`.
pub fn detect_file_as_dir(mut p: &Path) -> bool {
    while let Some(pnt) = p.parent() {
        if pnt.is_file() {
            return true;
        }

        p = pnt;
    }

    false
}

/// Check if a path refers to a symlink in a way that also works on Windows.
pub fn is_symlink<P: AsRef<Path>>(p: P) -> bool {
    p.as_ref().read_link().is_ok()
}

/// Construct string representing a human-readable size.
///
/// Stolen, adapted and inlined from [fielsize.js](http://filesizejs.com).
pub fn human_readable_size(s: u64) -> String {
    if s == 0 {
        "0 B".to_string()
    } else {
        let num = s as f64;
        let exp = cmp::min(cmp::max((num.log(f64::consts::E) / 1024f64.log(f64::consts::E)) as i32, 0), 8);

        let val = num / 2f64.powi(exp * 10);

        if exp > 0 {
                (val * 10f64).round() / 10f64
            } else {
                val.round()
            }
            .to_string() + " " + ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"][cmp::max(exp, 0) as usize]
    }
}
<commit_msg>Cache ln results<commit_after>//! Module containing various utility functions.

mod content_encoding;

use base64;
use std::f64;
use std::cmp;
use iron::Url;
use std::fs::File;
use std::path::Path;
use std::borrow::Cow;
use url::percent_encoding;
use std::collections::HashMap;
use time::{self, Duration, Tm};
use std::io::{BufReader, BufRead};
use mime_guess::get_mime_type_str;

pub use self::content_encoding::*;

/// The generic HTML page to use as response to errors.
pub static ERROR_HTML: &'static str = include_str!("../../assets/error.html");

/// The HTML page to use as template for a requested directory's listing.
pub static DIRECTORY_LISTING_HTML: &'static str = include_str!("../../assets/directory_listing.html");

lazy_static! {
    /// Collection of data to be injected into generated responses.
    pub static ref ASSETS: HashMap<&'static str, Cow<'static, str>> = {
        let mut ass = HashMap::with_capacity(8);
        ass.insert("favicon",
            Cow::Owned(format!("data:{};base64,{}", get_mime_type_str("ico").unwrap(), base64::encode(include_bytes!("../../assets/favicon.ico")))));
        ass.insert("dir_icon",
            Cow::Owned(format!("data:{};base64,{}",
                               get_mime_type_str("gif").unwrap(),
                               base64::encode(include_bytes!("../../assets/icons/directory_icon.gif")))));
        ass.insert("file_icon",
            Cow::Owned(format!("data:{};base64,{}",
                               get_mime_type_str("gif").unwrap(),
                               base64::encode(include_bytes!("../../assets/icons/file_icon.gif")))));
        ass.insert("file_binary_icon",
            Cow::Owned(format!("data:{};base64,{}",
                               get_mime_type_str("gif").unwrap(),
                               base64::encode(include_bytes!("../../assets/icons/file_binary_icon.gif")))));
        ass.insert("file_image_icon",
            Cow::Owned(format!("data:{};base64,{}",
                               get_mime_type_str("gif").unwrap(),
                               base64::encode(include_bytes!("../../assets/icons/file_image_icon.gif")))));
        ass.insert("file_text_icon",
            Cow::Owned(format!("data:{};base64,{}",
                               get_mime_type_str("gif").unwrap(),
                               base64::encode(include_bytes!("../../assets/icons/file_text_icon.gif")))));
        ass.insert("back_arrow_icon",
            Cow::Owned(format!("data:{};base64,{}",
                               get_mime_type_str("gif").unwrap(),
                               base64::encode(include_bytes!("../../assets/icons/back_arrow_icon.gif")))));
        ass.insert("drag_drop", Cow::Borrowed(include_str!("../../assets/drag_drop.js")));
        ass
    };
}

/// The port to start scanning from if no ports were given.
pub static PORT_SCAN_LOWEST: u16 = 8000;

/// The port to end scanning at if no ports were given.
pub static PORT_SCAN_HIGHEST: u16 = 9999;

/// The app name and version to use with User-Agent or Server response header.
pub static USER_AGENT: &'static str = concat!("http/", env!("CARGO_PKG_VERSION"));

/// Index file extensions to look for if `-i` was not specified.
pub static INDEX_EXTENSIONS: &'static [&'static str] = &["html", "htm", "shtml"];

/// Uppercase the first character of the supplied string.
///
/// Based on http://stackoverflow.com/a/38406885/2851815
///
/// # Examples
///
/// ```
/// # use https::util::uppercase_first;
/// assert_eq!(uppercase_first("abolish"), "Abolish".to_string());
/// ```
pub fn uppercase_first(s: &str) -> String {
    let mut c = s.chars();
    match c.next() {
        None => String::new(),
        Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
    }
}

/// Check if the specified file is to be considered "binary".
///
/// Basically checks is a file is UTF-8.
///
/// # Examples
///
/// ```
/// # use https::util::file_binary;
/// # #[cfg(target_os = "windows")]
/// # assert!(file_binary("target/debug/http.exe"));
/// # #[cfg(not(target_os = "windows"))]
/// assert!(file_binary("target/debug/http"));
/// assert!(!file_binary("Cargo.toml"));
/// ```
pub fn file_binary<P: AsRef<Path>>(path: P) -> bool {
    File::open(path).and_then(|f| BufReader::new(f).read_line(&mut String::new())).is_err()
}

/// Fill out an HTML template.
///
/// All fields must be addressed even if formatted to be empty.
///
/// # Examples
///
/// ```
/// # use https::util::{html_response, NOT_IMPLEMENTED_HTML};
/// println!(html_response(NOT_IMPLEMENTED_HTML, &["<p>Abolish the burgeoisie!</p>"]));
/// ```
pub fn html_response<S: AsRef<str>>(data: &str, format_strings: &[S]) -> String {
    ASSETS.iter().fold(format_strings.iter().enumerate().fold(data.to_string(), |d, (i, s)| d.replace(&format!("{{{}}}", i), s.as_ref())),
                       |d, (k, v)| d.replace(&format!("{{{}}}", k), v))
}

/// Return the path part of the URL.
///
/// # Example
///
/// ```
/// # extern crate iron;
/// # extern crate https;
/// # use iron::Url;
/// # use https::util::url_path;
/// let url = Url::parse("127.0.0.1:8000/capitalism/русский/");
/// assert_eq!(url_path(&url), "capitalism/русский/");
/// ```
pub fn url_path(url: &Url) -> String {
    let path = url.path();
    if path == [""] {
        "/".to_string()
    } else {
        path.into_iter().fold("".to_string(),
                              |cur, pp| format!("{}/{}", cur, percent_decode(pp).unwrap_or(Cow::Borrowed("<incorrect UTF8>"))))[1..]
            .to_string()
    }
}

/// Decode a percent-encoded string (like a part of a URL).
///
/// # Example
///
/// ```
/// # use https::util::percent_decode;
/// # use std::borrow::Cow;
/// assert_eq!(percent_decode("%D0%B0%D1%81%D0%B4%D1%84%20fdsa"), Some(Cow::Owned("асдф fdsa".to_string())));
/// assert_eq!(percent_decode("%D0%D1%81%D0%B4%D1%84%20fdsa"), None);
/// ```
pub fn percent_decode(s: &str) -> Option<Cow<str>> {
    percent_encoding::percent_decode(s.as_bytes()).decode_utf8().ok()
}

/// Get the timestamp of the file's last modification as a `time::Tm`.
pub fn file_time_modified(f: &Path) -> Tm {
    match f.metadata().unwrap().modified().unwrap().elapsed() {
        Ok(dur) => time::now() - Duration::from_std(dur).unwrap(),
        Err(ste) => time::now() + Duration::from_std(ste.duration()).unwrap(),
    }
}

/// Check, whether, in any place of the path, a file is treated like a directory.
///
/// A file is treated like a directory when it is treated as if it had a subpath, e.g., given:
///
/// ```sh
/// tree .
/// | dir0
/// | dir1
///   | file01
/// ```
///
/// This function would return true for `./dir1/file01/file010`, `./dir1/file01/dir010/file0100`, etc., but not
/// for `./dir0/file00`, `./dir0/dir00/file000`, `./dir1/file02/`, `./dir1/dir010/file0100`.
pub fn detect_file_as_dir(mut p: &Path) -> bool {
    while let Some(pnt) = p.parent() {
        if pnt.is_file() {
            return true;
        }

        p = pnt;
    }

    false
}

/// Check if a path refers to a symlink in a way that also works on Windows.
pub fn is_symlink<P: AsRef<Path>>(p: P) -> bool {
    p.as_ref().read_link().is_ok()
}

/// Construct string representing a human-readable size.
///
/// Stolen, adapted and inlined from [fielsize.js](http://filesizejs.com).
pub fn human_readable_size(s: u64) -> String {
    lazy_static! {
        static ref LN_KIB: f64 = 1024f64.log(f64::consts::E);
    }

    if s == 0 {
        "0 B".to_string()
    } else {
        let num = s as f64;
        let exp = cmp::min(cmp::max((num.log(f64::consts::E) / *LN_KIB) as i32, 0), 8);

        let val = num / 2f64.powi(exp * 10);

        if exp > 0 {
                (val * 10f64).round() / 10f64
            } else {
                val.round()
            }
            .to_string() + " " + ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"][cmp::max(exp, 0) as usize]
    }
}
<|endoftext|>


<commit_before>extern crate rustbox;

use model::commit::Commit;
use std::error::Error;
use std::default::Default;
use self::rustbox::{Color, RustBox, Key};

pub struct Screen {
    rustbox: RustBox,
    commits: Vec<Commit>,
    query: String
}

impl Screen {
    pub fn new(commits: Vec<Commit>) -> Screen {
        let rustbox = match RustBox::init(Default::default()) {
            Result::Ok(v) => v,
            Result::Err(e) => panic!("{}", e),
        };

        Screen {
            rustbox: rustbox,
            commits: commits,
            query: String::new()
        }
    }

    pub fn draw(&mut self) {
        self.rustbox.clear();
        self.draw_query();
        self.draw_commits();
        self.rustbox.present();

        loop {
            self.rustbox.clear();

            match self.rustbox.poll_event(false) {
                Ok(rustbox::Event::KeyEvent(key)) => {
                    match key {
                        Some(Key::Char(c)) => {
                            self.query.push(c);
                        },
                        Some(Key::Backspace) => {
                            self.query.pop();

                        },
                        Some(Key::Esc) => {
                            break;
                        },
                        _ => {
                        }
                    }
                },
                Err(e) => panic!("{}", e.description()),
                _ => { }
            }

            self.draw_query();
            self.draw_commits();
            self.rustbox.present();
        }
    }

    fn draw_query(&self) {
        let message = format!("QUERY> {}", &self.query);
        self.rustbox.print(0, 0, rustbox::RB_NORMAL, Color::Green, Color::Black, &message);
    }

    fn draw_commits(&self) {
        let mut count = 0;
        self.commits.iter().filter(|commit| {
                commit.message.contains(&self.query)
            }).inspect(|commit| {
                self.rustbox.print(0, count + 1, rustbox::RB_NORMAL, Color::Green, Color::Black, &commit.message);
                count += 1;
            }).collect::<Vec<&Commit>>();
    }
}
<commit_msg>Trap Ctrl('c')<commit_after>extern crate rustbox;

use model::commit::Commit;
use std::error::Error;
use std::default::Default;
use self::rustbox::{Color, RustBox, Key};

pub struct Screen {
    rustbox: RustBox,
    commits: Vec<Commit>,
    query: String
}

impl Screen {
    pub fn new(commits: Vec<Commit>) -> Screen {
        let rustbox = match RustBox::init(Default::default()) {
            Result::Ok(v) => v,
            Result::Err(e) => panic!("{}", e),
        };

        Screen {
            rustbox: rustbox,
            commits: commits,
            query: String::new()
        }
    }

    pub fn draw(&mut self) {
        self.rustbox.clear();
        self.draw_query();
        self.draw_commits();
        self.rustbox.present();

        loop {
            self.rustbox.clear();

            match self.rustbox.poll_event(false) {
                Ok(rustbox::Event::KeyEvent(key)) => {
                    match key {
                        Some(Key::Char(c)) => {
                            self.query.push(c);
                        },
                        Some(Key::Backspace) => {
                            self.query.pop();
                        },
                        Some(Key::Esc) | Some(Key::Ctrl('c')) => {
                            break;
                        },
                        _ => {
                        }
                    }
                },
                Err(e) => panic!("{}", e.description()),
                _ => { }
            }

            self.draw_query();
            self.draw_commits();
            self.rustbox.present();
        }
    }

    fn draw_query(&self) {
        let message = format!("QUERY> {}", &self.query);
        self.rustbox.print(0, 0, rustbox::RB_NORMAL, Color::Green, Color::Black, &message);
    }

    fn draw_commits(&self) {
        let mut count = 0;
        self.commits.iter().filter(|commit| {
                commit.message.contains(&self.query)
            }).inspect(|commit| {
                self.rustbox.print(0, count + 1, rustbox::RB_NORMAL, Color::Green, Color::Black, &commit.message);
                count += 1;
            }).collect::<Vec<&Commit>>();
    }
}
<|endoftext|>