<commit_before>extern crate iron;
extern crate unicase;
#[macro_use]
extern crate hyper;

use unicase::UniCase;
use iron::prelude::*;
use iron::method::Method;
use iron::method::Method::*;
use iron::status;
//use iron::headers::Origin as OriginHeader;
use iron::headers::{AccessControlRequestMethod, AccessControlRequestHeaders,
                    AccessControlAllowOrigin, AccessControlAllowHeaders, AccessControlMaxAge,
                    AccessControlAllowMethods, AccessControlAllowCredentials,
                    AccessControlExposeHeaders};
use iron::middleware::{AroundMiddleware, Handler};
use std::collections::HashSet;
use std::iter::FromIterator;
pub use origin::Origin;

mod origin;

// Use custom Origin header to allow for null Origin, which the standard
// iron header does not allow
header! { (OriginHeader, "Origin") => [String] }

/// Specifies which Origins are allowed to access this resource
#[derive(Clone)]
pub enum AllowedOrigins {
    /// Any Origin is allowed.
    Any {
        /// Allowing a null origin is a separate setting, since it's
        /// risky to trust sources with a null Origin, see
        /// https://tools.ietf.org/id/draft-abarth-origin-03.html#rfc.section.6
        /// https://w3c.github.io/webappsec-cors-for-developers/
        allow_null: bool,
    },
    /// Allow a specific set of origins. Remember that allowing
    /// for a null header is risky.
    Specific(HashSet<Origin>),
}

impl AllowedOrigins {
    fn allow(&self,
             origin_string: &str,
             prefer_wildcard: bool,
             allow_credentials: bool)
             -> Option<String> {
        {
            if allow_credentials {
                // Allow credentials does not permit using wildcard
                Some(origin_string.to_owned())
            } else {
                // Use wildcard if preferred
                Some(if prefer_wildcard {
                         "*".to_owned()
                     } else {
                         origin_string.to_owned()
                     })
            }
        }
    }
    /// Returns the value of AccessControlAllowOrigin
    /// given the specified Origin header in the request. The allow_credentials
    /// flag is supplied since AccessControlAllowOrigin * is forbidden when credentials
    /// are allowed.
    ///
    /// We're not using the iron Origin header to construct an Origin directly, since
    /// we are dependent on url.port_or_known_default() to get the default port. This
    /// method is only available after parsing the Origin header to an URL.
    fn allowed_for(&self,
                   origin_string: &str,
                   allow_credentials: bool,
                   prefer_wildcard: bool)
                   -> Option<String> {
        match Origin::parse_allow_null(origin_string) {
            Err(_) => None,
            Ok(origin) => {
                match *self {
                    AllowedOrigins::Any { allow_null } => {
                        // Any origin is allowed, but this does not include Null,
                        // special check for that
                        if origin == Origin::Null && !allow_null {
                            None
                        } else {
                            self.allow(origin_string, prefer_wildcard, allow_credentials)
                        }
                    }
                    AllowedOrigins::Specific(ref allowed) => {
                        if allowed.contains(&origin) {
                            self.allow(origin_string, prefer_wildcard, allow_credentials)
                        } else {
                            None
                        }
                    }
                }
            }
        }

    }
}

/// An iron middleware which implements CORS
///
/// Note: Not using `Vec<Header>` to represent
/// headers since the iron `Header`
/// type is representing a `Key=Value` pair and not just the key.
/// In other words, the Header type represents an instance of
/// a HTTP header. What we need here is something representing the
/// type of header. Since the Header trait defines a a method
/// `fn header_name() -> &'static str`, we conclude that Iron uses
/// strings to represent this.
#[derive(Clone)]
pub struct CorsMiddleware {
    /// The origins which are allowed to access this resource
    pub allowed_origins: AllowedOrigins,
    /// The methods allowed to perform on this resource
    pub allowed_methods: Vec<Method>,
    /// The headers allowed to send to this resource
    pub allowed_headers: Vec<UniCase<String>>,
    /// The headers allowed to read from the response from this resource
    pub exposed_headers: Vec<UniCase<String>>,
    /// Whether to allow clients to send cookies to this resource or not
    pub allow_credentials: bool,
    /// Defines the max cache lifetime for operations allowed on this
    /// resource
    pub max_age_seconds: u32,
    /// If set, wildcard ('*') will be used as value
    /// for AccessControlAllowOrigin if possible. If not set,
    /// echoing the incoming Origin will be preferred.
    /// If credentials are allowed, echoing will always be used.
    pub prefer_wildcard: bool,
}

/// Returns all standard HTTP verbs
pub fn all_std_methods() -> Vec<Method> {
    vec![Options, Get, Post, Put, Delete, Head, Trace, Connect, Patch]
}

/// Returns HTTP Headers commonly set by clients
pub fn common_req_headers() -> Vec<unicase::UniCase<String>> {
    vec![UniCase("Authorization".to_owned()),
         // To allow application/json
         UniCase("Content-Type".to_owned()),
         // Set by some js libs
         UniCase("X-Requested-With".to_owned())]
}

impl CorsMiddleware {
    /// New middleware with sensible permissive settings.
    /// Allows any origin.
    /// Allows all standard HTTP methods.
    /// Allows common request headers (as defined by `common_req_headers()`.
    /// Does not expose any headers.
    /// Does not allow credentials.
    /// Sets MaxAge to 60 minutes.
    pub fn permissive() -> CorsMiddleware {
        CorsMiddleware {
            allowed_origins: AllowedOrigins::Any { allow_null: false },
            allowed_methods: all_std_methods(),
            allowed_headers: common_req_headers(),
            exposed_headers: vec![],
            allow_credentials: false,
            max_age_seconds: 60 * 60,
            prefer_wildcard: false,
        }
    }

    /// Handle a potential CORS request. Detects if this is a
    /// preflight or normal method, adding CORS headers as appropriate
    fn handle(&self, req: &mut Request, handler: &Handler) -> IronResult<Response> {
        // http://stackoverflow.com/questions/14015118/
        // what-is-the-expected-response-to-an-invalid-cors-request
        // http://stackoverflow.com/questions/32331737/
        // how-can-i-identify-a-cors-preflight-request
        if req.method == Options && req.headers.get::<AccessControlRequestMethod>().is_some() {
            self.handle_preflight(req, handler)
        } else {
            self.handle_normal(req, handler)
        }
    }

    /// Handle a preflight request
    fn handle_preflight(&self, req: &mut Request, _: &Handler) -> IronResult<Response> {
        // Successful preflight status code is NoContent
        let mut res = Response::with(status::NoContent);

        // - Preflight request
        // - 1.If the Origin header is not present terminate this set of steps. The request is
        // - outside the scope of this specification.
        let maybe_origin = req.headers.get::<OriginHeader>();
        if maybe_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       "Preflight request without Origin header"));
            return Ok(resp);
        }
        let origin = maybe_origin.unwrap();
        //
        // - 2.If the value of the Origin header is not a case-sensitive match for any of the
        // - values in list of origins do not set any additional headers and terminate this
        // - set of steps.
        //
        // - Note: Always matching is acceptable since the list of origins can be unbounded.
        //
        // - Note: The Origin header can only contain a single origin as the user agent
        //       will not follow redirects.
        //
        let origin_str = origin.to_string();
        let allowed_origin =
            self.allowed_origins.allowed_for(&origin_str,
                                             self.allow_credentials,
                                             self.prefer_wildcard);
        if allowed_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       format!("Preflight request requesting \
                                       disallowed origin '{}'",
                                               origin_str)));
            return Ok(resp);
        }
        //
        // - 3. Let method be the value as result of parsing the Access-Control-Request-Method
        // - header.
        //
        // - If there is no Access-Control-Request-Method header or if parsing failed, do not
        // - set any additional headers and terminate this set of steps. The request is
        // - outside the scope of this specification.

        // We can assume that this header exists, since we already checked that before
        // classifying the request as preflight
        let requested_method = req.headers.get::<AccessControlRequestMethod>().unwrap();

        //
        // - 4. Let header field-names be the values as result of parsing the
        // - Access-Control-Request-Headers headers.
        //
        // - If there are no Access-Control-Request-Headers headers let header field-names be
        // - the empty list.
        //
        // - If parsing failed do not set any additional headers and terminate this set of
        // - steps. The request is outside the scope of this specification.
        //
        let empty_vec: Vec<UniCase<String>> = vec![];
        let maybe_requested_headers = req.headers.get::<AccessControlRequestHeaders>();
        let requested_headers: &Vec<UniCase<String>> = if maybe_requested_headers.is_some() {
            &maybe_requested_headers.unwrap().0
        } else {
            &empty_vec
        };
        // - 5.If method is not a case-sensitive match for any of the values in list of
        // -   methods do not set any additional headers and terminate this set of steps.
        //
        // - Always matching is acceptable since the list of methods can be unbounded.
        //
        if !self.allowed_methods.contains(requested_method) {
            return Ok(Response::with((status::BadRequest,
                                      format!("Preflight request requesting disallowed method {}",
                                              requested_method))));
        }
        // - 6. If any of the header field-names is not a ASCII case-insensitive match for any
        // - of the values in list of headers do not set any additional headers and terminate
        // - this set of steps.
        let requested_headers_set: HashSet<UniCase<String>> =
            HashSet::from_iter(requested_headers.iter().cloned());
        let allowed_headers_set: HashSet<UniCase<String>> =
            HashSet::from_iter(self.allowed_headers.iter().cloned());
        let disallowed_headers: HashSet<UniCase<String>> =
            requested_headers_set.difference(&allowed_headers_set).cloned().collect();
        if !disallowed_headers.is_empty() {
            let a = disallowed_headers.iter()
                .map(|uh| uh.to_string())
                .collect::<Vec<_>>()
                .join(",");
            let msg = format!("Preflight request requesting disallowed header(s) {}", a);
            return Ok(Response::with((status::BadRequest, msg)));

        }
        //
        // - Always matching is acceptable since the list of headers can be unbounded.
        //
        // - 7. If the resource supports credentials add a single Access-Control-Allow-Origin
        // - header, with the value of the Origin header as value, and add a single
        // - Access-Control-Allow-Credentials header with the case-sensitive string "true" as
        // - value.
        //
        // - Otherwise, add a single Access-Control-Allow-Origin header, with either the
        // - value of the Origin header or the string "*" as value.
        //
        // - The string "*" cannot be used for a resource that supports credentials.
        //
        if self.allow_credentials {
            res.headers.set(AccessControlAllowCredentials);
        }
        res.headers.set(AccessControlAllowOrigin::Value(allowed_origin.unwrap()));
        // - 8. Optionally add a single Access-Control-Max-Age header with as value the amount
        // - of seconds the user agent is allowed to cache the result of the request.
        res.headers.set(AccessControlMaxAge(self.max_age_seconds));
        //
        // - 9. If method is a simple method this step may be skipped.
        //
        // - Add one or more Access-Control-Allow-Methods headers consisting of (a subset of)
        // - the list of methods.
        //
        // - If a method is a simple method it does not need to be listed, but this is not
        // - prohibited.
        //
        // - Since the list of methods can be unbounded, simply returning the method
        // - indicated by Access-Control-Request-Method (if supported) can be enough.
        //
        res.headers.set(AccessControlAllowMethods(self.allowed_methods.clone()));
        // - 10.If each of the header field-names is a simple header and none is Content-Type,
        // - this step may be skipped.
        //
        // - Add one or more Access-Control-Allow-Headers headers consisting of (a subset of)
        // - the list of headers.
        //
        // - If a header field name is a simple header and is not Content-Type, it is not
        // - required to be listed. Content-Type is to be listed as only a subset of its
        // - values makes it qualify as simple header.
        //
        // - Since the list of headers can be unbounded, simply returning supported headers
        // - from Access-Control-Allow-Headers can be enough.
        res.headers.set(AccessControlAllowHeaders(self.allowed_headers.clone()));
        Ok(res)
    }

    /// Handle a normal (i.e non-preflight) CORS request
    fn handle_normal(&self, req: &mut Request, handler: &Handler) -> IronResult<Response> {
        // Normal request
        // - 1.If the Origin header is not present terminate this set of steps. The request is
        // - outside the scope of this specification.
        let have_origin;
        {
            let maybe_origin = req.headers.get::<OriginHeader>();
            have_origin = maybe_origin.is_some();
        }
        if !have_origin {
            // No origin, treat as normal request.
            // We could return error here if we wanted according to
            // https://tools.ietf.org/id/draft-abarth-origin-03.html#rfc.section.6
            return handler.handle(req);
        }
        //
        // - 2.If the value of the Origin header is not a case-sensitive match for any of the
        // - values in list of origins, do not set any additional headers and terminate this
        // - set of steps.
        //
        // - Note: Always matching is acceptable since the list of origins can be unbounded.
        //
        let origin = req.headers
            .get::<OriginHeader>()
            .unwrap()
            .clone();
        let origin_str = origin.to_string();
        let allowed_origin =
            self.allowed_origins.allowed_for(&origin_str,
                                             self.allow_credentials,
                                             self.prefer_wildcard);
        if allowed_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       format!("Normal request requesting \
                                       disallowed origin '{}'",
                                               origin_str)));
            return Ok(resp);
        }
        let result = handler.handle(req);
        match result {
            Ok(mut res) => {
                //
                // - 3. If the resource supports credentials add a single
                // - Access-Control-Allow-Origin
                // - header, with the value of the Origin header as value, and add a single
                // - Access-Control-Allow-Credentials header with the case-sensitive string
                // - "true" as value.
                //
                // - Otherwise, add a single Access-Control-Allow-Origin header, with either the
                // - value of the Origin header or the string "*" as value.
                //
                // - Note: The string "*" cannot be used for a resource that supports credentials.
                if self.allow_credentials {
                    res.headers.set(AccessControlAllowCredentials);
                }
                res.headers.set(AccessControlAllowOrigin::Value(allowed_origin.unwrap()));
                //
                // - 4. If the list of exposed headers is not empty add one or more
                // - Access-Control-Expose-Headers headers, with as values the header field names
                // - given in the list of exposed headers.
                res.headers.set(AccessControlExposeHeaders(self.exposed_headers.clone()));
                Ok(res)
            }
            _ => result,
        }

    }

    /// Util function for wrapping the supplied handler with this CorsMiddleware.
    /// Works by constructing a chain with only this middleware linked.
    pub fn decorate<T: Handler>(self, handler: T) -> Chain {
        let mut chain = Chain::new(handler);
        chain.link_around(self);
        chain
    }
}

impl AroundMiddleware for CorsMiddleware {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        Box::new(move |req: &mut Request| self.handle(req, &handler))
    }
}
<commit_msg>reexport UniCase<commit_after>extern crate iron;
extern crate unicase;
#[macro_use]
extern crate hyper;

pub use unicase::UniCase;
use iron::prelude::*;
use iron::method::Method;
use iron::method::Method::*;
use iron::status;
//use iron::headers::Origin as OriginHeader;
use iron::headers::{AccessControlRequestMethod, AccessControlRequestHeaders,
                    AccessControlAllowOrigin, AccessControlAllowHeaders, AccessControlMaxAge,
                    AccessControlAllowMethods, AccessControlAllowCredentials,
                    AccessControlExposeHeaders};
use iron::middleware::{AroundMiddleware, Handler};
use std::collections::HashSet;
use std::iter::FromIterator;
pub use origin::Origin;

mod origin;

// Use custom Origin header to allow for null Origin, which the standard
// iron header does not allow
header! { (OriginHeader, "Origin") => [String] }

/// Specifies which Origins are allowed to access this resource
#[derive(Clone)]
pub enum AllowedOrigins {
    /// Any Origin is allowed.
    Any {
        /// Allowing a null origin is a separate setting, since it's
        /// risky to trust sources with a null Origin, see
        /// https://tools.ietf.org/id/draft-abarth-origin-03.html#rfc.section.6
        /// https://w3c.github.io/webappsec-cors-for-developers/
        allow_null: bool,
    },
    /// Allow a specific set of origins. Remember that allowing
    /// for a null header is risky.
    Specific(HashSet<Origin>),
}

impl AllowedOrigins {
    fn allow(&self,
             origin_string: &str,
             prefer_wildcard: bool,
             allow_credentials: bool)
             -> Option<String> {
        {
            if allow_credentials {
                // Allow credentials does not permit using wildcard
                Some(origin_string.to_owned())
            } else {
                // Use wildcard if preferred
                Some(if prefer_wildcard {
                         "*".to_owned()
                     } else {
                         origin_string.to_owned()
                     })
            }
        }
    }
    /// Returns the value of AccessControlAllowOrigin
    /// given the specified Origin header in the request. The allow_credentials
    /// flag is supplied since AccessControlAllowOrigin * is forbidden when credentials
    /// are allowed.
    ///
    /// We're not using the iron Origin header to construct an Origin directly, since
    /// we are dependent on url.port_or_known_default() to get the default port. This
    /// method is only available after parsing the Origin header to an URL.
    fn allowed_for(&self,
                   origin_string: &str,
                   allow_credentials: bool,
                   prefer_wildcard: bool)
                   -> Option<String> {
        match Origin::parse_allow_null(origin_string) {
            Err(_) => None,
            Ok(origin) => {
                match *self {
                    AllowedOrigins::Any { allow_null } => {
                        // Any origin is allowed, but this does not include Null,
                        // special check for that
                        if origin == Origin::Null && !allow_null {
                            None
                        } else {
                            self.allow(origin_string, prefer_wildcard, allow_credentials)
                        }
                    }
                    AllowedOrigins::Specific(ref allowed) => {
                        if allowed.contains(&origin) {
                            self.allow(origin_string, prefer_wildcard, allow_credentials)
                        } else {
                            None
                        }
                    }
                }
            }
        }

    }
}

/// An iron middleware which implements CORS
///
/// Note: Not using `Vec<Header>` to represent
/// headers since the iron `Header`
/// type is representing a `Key=Value` pair and not just the key.
/// In other words, the Header type represents an instance of
/// a HTTP header. What we need here is something representing the
/// type of header. Since the Header trait defines a a method
/// `fn header_name() -> &'static str`, we conclude that Iron uses
/// strings to represent this.
#[derive(Clone)]
pub struct CorsMiddleware {
    /// The origins which are allowed to access this resource
    pub allowed_origins: AllowedOrigins,
    /// The methods allowed to perform on this resource
    pub allowed_methods: Vec<Method>,
    /// The headers allowed to send to this resource
    pub allowed_headers: Vec<UniCase<String>>,
    /// The headers allowed to read from the response from this resource
    pub exposed_headers: Vec<UniCase<String>>,
    /// Whether to allow clients to send cookies to this resource or not
    pub allow_credentials: bool,
    /// Defines the max cache lifetime for operations allowed on this
    /// resource
    pub max_age_seconds: u32,
    /// If set, wildcard ('*') will be used as value
    /// for AccessControlAllowOrigin if possible. If not set,
    /// echoing the incoming Origin will be preferred.
    /// If credentials are allowed, echoing will always be used.
    pub prefer_wildcard: bool,
}

/// Returns all standard HTTP verbs
pub fn all_std_methods() -> Vec<Method> {
    vec![Options, Get, Post, Put, Delete, Head, Trace, Connect, Patch]
}

/// Returns HTTP Headers commonly set by clients
pub fn common_req_headers() -> Vec<unicase::UniCase<String>> {
    vec![UniCase("Authorization".to_owned()),
         UniCase("Content-Type".to_owned()),
         UniCase("X-Requested-With".to_owned())]
}

impl CorsMiddleware {
    /// New middleware with sensible permissive settings.
    /// Allows any origin.
    /// Allows all standard HTTP methods.
    /// Allows common request headers (as defined by `common_req_headers()`.
    /// Does not expose any headers.
    /// Does not allow credentials.
    /// Sets MaxAge to 60 minutes.
    pub fn permissive() -> CorsMiddleware {
        CorsMiddleware {
            allowed_origins: AllowedOrigins::Any { allow_null: false },
            allowed_methods: all_std_methods(),
            allowed_headers: common_req_headers(),
            exposed_headers: vec![],
            allow_credentials: false,
            max_age_seconds: 60 * 60,
            prefer_wildcard: false,
        }
    }

    /// Handle a potential CORS request. Detects if this is a
    /// preflight or normal method, adding CORS headers as appropriate
    fn handle(&self, req: &mut Request, handler: &Handler) -> IronResult<Response> {
        // http://stackoverflow.com/questions/14015118/
        // what-is-the-expected-response-to-an-invalid-cors-request
        // http://stackoverflow.com/questions/32331737/
        // how-can-i-identify-a-cors-preflight-request
        if req.method == Options && req.headers.get::<AccessControlRequestMethod>().is_some() {
            self.handle_preflight(req, handler)
        } else {
            self.handle_normal(req, handler)
        }
    }

    /// Handle a preflight request
    fn handle_preflight(&self, req: &mut Request, _: &Handler) -> IronResult<Response> {
        // Successful preflight status code is NoContent
        let mut res = Response::with(status::NoContent);

        // - Preflight request
        // - 1.If the Origin header is not present terminate this set of steps. The request is
        // - outside the scope of this specification.
        let maybe_origin = req.headers.get::<OriginHeader>();
        if maybe_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       "Preflight request without Origin header"));
            return Ok(resp);
        }
        let origin = maybe_origin.unwrap();
        //
        // - 2.If the value of the Origin header is not a case-sensitive match for any of the
        // - values in list of origins do not set any additional headers and terminate this
        // - set of steps.
        //
        // - Note: Always matching is acceptable since the list of origins can be unbounded.
        //
        // - Note: The Origin header can only contain a single origin as the user agent
        //       will not follow redirects.
        //
        let origin_str = origin.to_string();
        let allowed_origin =
            self.allowed_origins.allowed_for(&origin_str,
                                             self.allow_credentials,
                                             self.prefer_wildcard);
        if allowed_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       format!("Preflight request requesting \
                                       disallowed origin '{}'",
                                               origin_str)));
            return Ok(resp);
        }
        //
        // - 3. Let method be the value as result of parsing the Access-Control-Request-Method
        // - header.
        //
        // - If there is no Access-Control-Request-Method header or if parsing failed, do not
        // - set any additional headers and terminate this set of steps. The request is
        // - outside the scope of this specification.

        // We can assume that this header exists, since we already checked that before
        // classifying the request as preflight
        let requested_method = req.headers.get::<AccessControlRequestMethod>().unwrap();

        //
        // - 4. Let header field-names be the values as result of parsing the
        // - Access-Control-Request-Headers headers.
        //
        // - If there are no Access-Control-Request-Headers headers let header field-names be
        // - the empty list.
        //
        // - If parsing failed do not set any additional headers and terminate this set of
        // - steps. The request is outside the scope of this specification.
        //
        let empty_vec: Vec<UniCase<String>> = vec![];
        let maybe_requested_headers = req.headers.get::<AccessControlRequestHeaders>();
        let requested_headers: &Vec<UniCase<String>> = if maybe_requested_headers.is_some() {
            &maybe_requested_headers.unwrap().0
        } else {
            &empty_vec
        };
        // - 5.If method is not a case-sensitive match for any of the values in list of
        // -   methods do not set any additional headers and terminate this set of steps.
        //
        // - Always matching is acceptable since the list of methods can be unbounded.
        //
        if !self.allowed_methods.contains(requested_method) {
            return Ok(Response::with((status::BadRequest,
                                      format!("Preflight request requesting disallowed method {}",
                                              requested_method))));
        }
        // - 6. If any of the header field-names is not a ASCII case-insensitive match for any
        // - of the values in list of headers do not set any additional headers and terminate
        // - this set of steps.
        let requested_headers_set: HashSet<UniCase<String>> =
            HashSet::from_iter(requested_headers.iter().cloned());
        let allowed_headers_set: HashSet<UniCase<String>> =
            HashSet::from_iter(self.allowed_headers.iter().cloned());
        let disallowed_headers: HashSet<UniCase<String>> =
            requested_headers_set.difference(&allowed_headers_set).cloned().collect();
        if !disallowed_headers.is_empty() {
            let a = disallowed_headers.iter()
                .map(|uh| uh.to_string())
                .collect::<Vec<_>>()
                .join(",");
            let msg = format!("Preflight request requesting disallowed header(s) {}", a);
            return Ok(Response::with((status::BadRequest, msg)));

        }
        //
        // - Always matching is acceptable since the list of headers can be unbounded.
        //
        // - 7. If the resource supports credentials add a single Access-Control-Allow-Origin
        // - header, with the value of the Origin header as value, and add a single
        // - Access-Control-Allow-Credentials header with the case-sensitive string "true" as
        // - value.
        //
        // - Otherwise, add a single Access-Control-Allow-Origin header, with either the
        // - value of the Origin header or the string "*" as value.
        //
        // - The string "*" cannot be used for a resource that supports credentials.
        //
        if self.allow_credentials {
            res.headers.set(AccessControlAllowCredentials);
        }
        res.headers.set(AccessControlAllowOrigin::Value(allowed_origin.unwrap()));
        // - 8. Optionally add a single Access-Control-Max-Age header with as value the amount
        // - of seconds the user agent is allowed to cache the result of the request.
        res.headers.set(AccessControlMaxAge(self.max_age_seconds));
        //
        // - 9. If method is a simple method this step may be skipped.
        //
        // - Add one or more Access-Control-Allow-Methods headers consisting of (a subset of)
        // - the list of methods.
        //
        // - If a method is a simple method it does not need to be listed, but this is not
        // - prohibited.
        //
        // - Since the list of methods can be unbounded, simply returning the method
        // - indicated by Access-Control-Request-Method (if supported) can be enough.
        //
        res.headers.set(AccessControlAllowMethods(self.allowed_methods.clone()));
        // - 10.If each of the header field-names is a simple header and none is Content-Type,
        // - this step may be skipped.
        //
        // - Add one or more Access-Control-Allow-Headers headers consisting of (a subset of)
        // - the list of headers.
        //
        // - If a header field name is a simple header and is not Content-Type, it is not
        // - required to be listed. Content-Type is to be listed as only a subset of its
        // - values makes it qualify as simple header.
        //
        // - Since the list of headers can be unbounded, simply returning supported headers
        // - from Access-Control-Allow-Headers can be enough.
        res.headers.set(AccessControlAllowHeaders(self.allowed_headers.clone()));
        Ok(res)
    }

    /// Handle a normal (i.e non-preflight) CORS request
    fn handle_normal(&self, req: &mut Request, handler: &Handler) -> IronResult<Response> {
        // Normal request
        // - 1.If the Origin header is not present terminate this set of steps. The request is
        // - outside the scope of this specification.
        let have_origin;
        {
            let maybe_origin = req.headers.get::<OriginHeader>();
            have_origin = maybe_origin.is_some();
        }
        if !have_origin {
            // No origin, treat as normal request.
            // We could return error here if we wanted according to
            // https://tools.ietf.org/id/draft-abarth-origin-03.html#rfc.section.6
            return handler.handle(req);
        }
        //
        // - 2.If the value of the Origin header is not a case-sensitive match for any of the
        // - values in list of origins, do not set any additional headers and terminate this
        // - set of steps.
        //
        // - Note: Always matching is acceptable since the list of origins can be unbounded.
        //
        let origin = req.headers
            .get::<OriginHeader>()
            .unwrap()
            .clone();
        let origin_str = origin.to_string();
        let allowed_origin =
            self.allowed_origins.allowed_for(&origin_str,
                                             self.allow_credentials,
                                             self.prefer_wildcard);
        if allowed_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       format!("Normal request requesting \
                                       disallowed origin '{}'",
                                               origin_str)));
            return Ok(resp);
        }
        let result = handler.handle(req);
        match result {
            Ok(mut res) => {
                //
                // - 3. If the resource supports credentials add a single
                // - Access-Control-Allow-Origin
                // - header, with the value of the Origin header as value, and add a single
                // - Access-Control-Allow-Credentials header with the case-sensitive string
                // - "true" as value.
                //
                // - Otherwise, add a single Access-Control-Allow-Origin header, with either the
                // - value of the Origin header or the string "*" as value.
                //
                // - Note: The string "*" cannot be used for a resource that supports credentials.
                if self.allow_credentials {
                    res.headers.set(AccessControlAllowCredentials);
                }
                res.headers.set(AccessControlAllowOrigin::Value(allowed_origin.unwrap()));
                //
                // - 4. If the list of exposed headers is not empty add one or more
                // - Access-Control-Expose-Headers headers, with as values the header field names
                // - given in the list of exposed headers.
                res.headers.set(AccessControlExposeHeaders(self.exposed_headers.clone()));
                Ok(res)
            }
            _ => result,
        }

    }

    /// Util function for wrapping the supplied handler with this CorsMiddleware.
    /// Works by constructing a chain with only this middleware linked.
    pub fn decorate<T: Handler>(self, handler: T) -> Chain {
        let mut chain = Chain::new(handler);
        chain.link_around(self);
        chain
    }
}

impl AroundMiddleware for CorsMiddleware {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        Box::new(move |req: &mut Request| self.handle(req, &handler))
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Add elf module<commit_after><|endoftext|>


<commit_before>#![feature(test)]
// This is silly...
#![allow(unused_features)]

#[macro_use]
extern crate log;
extern crate crc;
extern crate memmap;
extern crate byteorder;
extern crate env_logger;

#[cfg(test)]
extern crate test;
#[cfg(test)]
extern crate rand;

mod segment;
mod index;
#[cfg(test)]
mod testutil;

use std::path::{Path, PathBuf};
use std::fs;
use std::io;
use segment::*;
use index::*;

/// Offset of an appended log segment.
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Debug)]
pub struct Offset(u64);

#[derive(Debug)]
pub enum AppendError {
    IoError(io::Error),
    NewIndexAppendError,
    NewSegmentAppendError,
}

impl From<io::Error> for AppendError {
    fn from(e: io::Error) -> AppendError {
        AppendError::IoError(e)
    }
}

/// Commit log options allow customization of the commit
/// log behavior.
#[derive(Clone, Debug)]
pub struct LogOptions {
    log_dir: PathBuf,
    log_max_bytes: usize,
    index_max_bytes: usize,
}

impl LogOptions {
    pub fn new<P>(log_dir: P) -> LogOptions
        where P: AsRef<Path>
    {
        LogOptions {
            log_dir: log_dir.as_ref().to_owned(),
            log_max_bytes: 100 * 1024 * 1024,
            index_max_bytes: 800_000,
        }
    }

    /// Bounds the size of a log segment to a number of bytes.
    #[inline]
    pub fn max_bytes_log(&mut self, bytes: usize) -> &mut LogOptions {
        self.log_max_bytes = bytes;
        self
    }

    /// Bounds the size of an individual memory-mapped index file.
    #[inline]
    pub fn max_log_items(&mut self, items: usize) -> &mut LogOptions {
        self.index_max_bytes = items * INDEX_ENTRY_BYTES;
        self
    }
}

/// The commit log is an append-only data structure that can be used in a variety
/// of use-cases, such as tracking sequences of events, logging transactions in a
/// local database, or replicated state machines.
///
/// This implementation of the commit log data structure uses log segments
/// that roll over at pre-defined maximum size boundaries. The messages appended
/// to the log have a unique, monotonically incrasing offset that can be used as
/// a pointer to a log entry.
///
/// The index of the commit log logically stores the offset to a position in the
/// log segment corresponding. The index and segments are separated, in that a
/// segment file does not necessarily correspond to one particular segment file,
/// it could contain file pointers to many index files. In addition, index files
/// are memory-mapped for efficient read and write access.
pub struct CommitLog {
    active_segment: Segment,
    active_index: Index,
    options: LogOptions,
}

impl CommitLog {
    pub fn new(opts: LogOptions) -> io::Result<CommitLog> {
        // TODO: figure out what's already been written to
        fs::create_dir_all(&opts.log_dir).unwrap_or(());

        info!("Opening log at path {:?}", &opts.log_dir.to_str());
        let seg = try!(Segment::new(&opts.log_dir, 0u64, opts.log_max_bytes));
        let ind = try!(Index::new(&opts.log_dir, 0u64, opts.index_max_bytes));

        Ok(CommitLog {
            active_segment: seg,
            active_index: ind,
            options: opts,
        })
    }

    /// Appends a log entry to the commit log. The offset of the appended entry
    /// is the result of the comutation.
    pub fn append(&mut self, payload: &[u8]) -> Result<Offset, AppendError> {
        // first write to the current segment
        let meta = try!(self.active_segment
            .append(payload)
            .or_else(|e| {
                match e {
                    // if the log is full, gracefully close the current segment
                    // and create new one starting from the new offset
                    SegmentAppendError::LogFull => {
                        try!(self.active_segment.flush_sync());
                        let next_offset = self.active_segment.next_offset();
                        info!("Closing active segment at offset {}", next_offset);
                        self.active_segment = try!(Segment::new(&self.options.log_dir,
                                                                next_offset,
                                                                self.options.log_max_bytes));

                        // try again, giving up if we have to
                        self.active_segment
                            .append(payload)
                            .map_err(|_| AppendError::NewIndexAppendError)
                    }
                    SegmentAppendError::IoError(e) => Err(AppendError::IoError(e)),
                }
            }));

        // write to the index
        try!(self.active_index
            .append(meta.offset(), meta.file_pos())
            .or_else(|e| {
                match e {
                    // if the index is full, close the current index and open a new index
                    IndexWriteError::IndexFull => {
                        try!(self.active_index.set_readonly());
                        self.active_index = try!(Index::new(&self.options.log_dir,
                                                            meta.offset(),
                                                            self.options.index_max_bytes));

                        // if the new index cannot append, we're out of luck
                        self.active_index
                            .append(meta.offset(), meta.file_pos())
                            .map_err(|_| AppendError::NewIndexAppendError)
                    }
                    IndexWriteError::OffsetLessThanBase => unreachable!(),
                }
            }));

        Ok(Offset(meta.offset()))
    }

    pub fn flush(&mut self) -> io::Result<()> {
        try!(self.active_segment.flush_sync());
        self.active_index.flush_sync()
    }
}

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

    #[test]
    pub fn append() {
        let dir = TestDir::new();
        let mut log = CommitLog::new(LogOptions::new(&dir)).unwrap();
        assert_eq!(log.append(b"123456").unwrap(), Offset(0));
        assert_eq!(log.append(b"abcdefg").unwrap(), Offset(1));
        assert_eq!(log.append(b"foobarbaz").unwrap(), Offset(2));
        assert_eq!(log.append(b"bing").unwrap(), Offset(3));
        log.flush().unwrap();
    }
}
<commit_msg>Tests<commit_after>#![feature(test)]
// This is silly...
#![allow(unused_features)]

#[macro_use]
extern crate log;
extern crate crc;
extern crate memmap;
extern crate byteorder;
extern crate env_logger;

#[cfg(test)]
extern crate test;
#[cfg(test)]
extern crate rand;

mod segment;
mod index;
#[cfg(test)]
mod testutil;

use std::path::{Path, PathBuf};
use std::fs;
use std::io;
use segment::*;
use index::*;

/// Offset of an appended log segment.
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Debug)]
pub struct Offset(u64);

#[derive(Debug)]
pub enum AppendError {
    IoError(io::Error),
    NewIndexAppendError,
    NewSegmentAppendError,
}

impl From<io::Error> for AppendError {
    fn from(e: io::Error) -> AppendError {
        AppendError::IoError(e)
    }
}

/// Commit log options allow customization of the commit
/// log behavior.
#[derive(Clone, Debug)]
pub struct LogOptions {
    log_dir: PathBuf,
    log_max_bytes: usize,
    index_max_bytes: usize,
}

impl LogOptions {
    pub fn new<P>(log_dir: P) -> LogOptions
        where P: AsRef<Path>
    {
        LogOptions {
            log_dir: log_dir.as_ref().to_owned(),
            log_max_bytes: 100 * 1024 * 1024,
            index_max_bytes: 800_000,
        }
    }

    /// Bounds the size of a log segment to a number of bytes.
    #[inline]
    pub fn max_bytes_log(&mut self, bytes: usize) -> &mut LogOptions {
        self.log_max_bytes = bytes;
        self
    }

    /// Bounds the size of an individual memory-mapped index file.
    #[inline]
    pub fn max_index_items(&mut self, items: usize) -> &mut LogOptions {
        self.index_max_bytes = items * INDEX_ENTRY_BYTES;
        self
    }
}

/// The commit log is an append-only data structure that can be used in a variety
/// of use-cases, such as tracking sequences of events, logging transactions in a
/// local database, or replicated state machines.
///
/// This implementation of the commit log data structure uses log segments
/// that roll over at pre-defined maximum size boundaries. The messages appended
/// to the log have a unique, monotonically incrasing offset that can be used as
/// a pointer to a log entry.
///
/// The index of the commit log logically stores the offset to a position in the
/// log segment corresponding. The index and segments are separated, in that a
/// segment file does not necessarily correspond to one particular segment file,
/// it could contain file pointers to many index files. In addition, index files
/// are memory-mapped for efficient read and write access.
pub struct CommitLog {
    active_segment: Segment,
    active_index: Index,
    options: LogOptions,
}

impl CommitLog {
    pub fn new(opts: LogOptions) -> io::Result<CommitLog> {
        // TODO: figure out what's already been written to
        fs::create_dir_all(&opts.log_dir).unwrap_or(());

        info!("Opening log at path {:?}", &opts.log_dir.to_str());
        let seg = try!(Segment::new(&opts.log_dir, 0u64, opts.log_max_bytes));
        let ind = try!(Index::new(&opts.log_dir, 0u64, opts.index_max_bytes));

        Ok(CommitLog {
            active_segment: seg,
            active_index: ind,
            options: opts,
        })
    }

    /// Appends a log entry to the commit log. The offset of the appended entry
    /// is the result of the comutation.
    pub fn append(&mut self, payload: &[u8]) -> Result<Offset, AppendError> {
        // first write to the current segment
        let meta = try!(self.active_segment
            .append(payload)
            .or_else(|e| {
                match e {
                    // if the log is full, gracefully close the current segment
                    // and create new one starting from the new offset
                    SegmentAppendError::LogFull => {
                        try!(self.active_segment.flush_sync());
                        let next_offset = self.active_segment.next_offset();
                        info!("Closing active segment at offset {}", next_offset);
                        self.active_segment = try!(Segment::new(&self.options.log_dir,
                                                                next_offset,
                                                                self.options.log_max_bytes));

                        // try again, giving up if we have to
                        self.active_segment
                            .append(payload)
                            .map_err(|_| AppendError::NewIndexAppendError)
                    }
                    SegmentAppendError::IoError(e) => Err(AppendError::IoError(e)),
                }
            }));

        // write to the index
        try!(self.active_index
            .append(meta.offset(), meta.file_pos())
            .or_else(|e| {
                match e {
                    // if the index is full, close the current index and open a new index
                    IndexWriteError::IndexFull => {
                        try!(self.active_index.set_readonly());
                        self.active_index = try!(Index::new(&self.options.log_dir,
                                                            meta.offset(),
                                                            self.options.index_max_bytes));

                        // if the new index cannot append, we're out of luck
                        self.active_index
                            .append(meta.offset(), meta.file_pos())
                            .map_err(|_| AppendError::NewIndexAppendError)
                    }
                    IndexWriteError::OffsetLessThanBase => unreachable!(),
                }
            }));

        Ok(Offset(meta.offset()))
    }

    pub fn flush(&mut self) -> io::Result<()> {
        try!(self.active_segment.flush_sync());
        self.active_index.flush_sync()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::testutil::*;
    use std::fs;
    use std::collections::HashSet;

    #[test]
    pub fn append() {
        let dir = TestDir::new();
        let mut log = CommitLog::new(LogOptions::new(&dir)).unwrap();
        assert_eq!(log.append(b"123456").unwrap(), Offset(0));
        assert_eq!(log.append(b"abcdefg").unwrap(), Offset(1));
        assert_eq!(log.append(b"foobarbaz").unwrap(), Offset(2));
        assert_eq!(log.append(b"bing").unwrap(), Offset(3));
        log.flush().unwrap();
    }

    #[test]
    pub fn append_new_segment() {
        let dir = TestDir::new();
        let mut opts = LogOptions::new(&dir);
        opts.max_bytes_log(52);

        {
            let mut log = CommitLog::new(opts).unwrap();
            // first 2 entries fit (both 26 bytes with encoding)
            log.append(b"0123456789").unwrap();
            log.append(b"0123456789").unwrap();

            // this one should roll the log
            log.append(b"0123456789").unwrap();
            log.flush().unwrap();
        }

        let files = fs::read_dir(&dir).unwrap()
            .map(|e| e.unwrap().path().file_name().unwrap().to_str().unwrap().to_string())
            .collect::<HashSet<String>>();

        let expected = ["00000000000000000000.index", "00000000000000000000.log", "00000000000000000002.log"]
            .iter()
            .cloned()
            .map(|s| s.to_string())
            .collect::<HashSet<String>>();

        assert_eq!(files.intersection(&expected).count(), 3);
    }

    #[test]
    pub fn append_new_index() {
        let dir = TestDir::new();
        let mut opts = LogOptions::new(&dir);
        opts.max_index_items(2);

        {
            let mut log = CommitLog::new(opts).unwrap();
            // first 2 entries fit
            log.append(b"0123456789").unwrap();
            log.append(b"0123456789").unwrap();

            // this one should roll the index, but not the segment
            log.append(b"0123456789").unwrap();
            log.flush().unwrap();
        }

        let files = fs::read_dir(&dir).unwrap()
            .map(|e| e.unwrap().path().file_name().unwrap().to_str().unwrap().to_string())
            .collect::<HashSet<String>>();

        let expected = ["00000000000000000000.index", "00000000000000000000.log", "00000000000000000002.index"]
            .iter()
            .cloned()
            .map(|s| s.to_string())
            .collect::<HashSet<String>>();

        assert_eq!(files.intersection(&expected).count(), 3);
    }
}
<|endoftext|>


<commit_before>mod callbacks;
mod channel;
mod parsers;
mod types;
mod utils;

// Re-export public interfaces.
pub use channel::Channel;
pub use parsers::{
    parse_a_result,
    parse_aaaa_result,
};
pub use types::{
    AresError,
    AResult,
    AAAAResult,
    INVALID_FD,
};
pub use utils::str_error;
<commit_msg>Add a single line of documentation<commit_after>//! A safe wrapper for the [`c-ares`](http://c-ares.haxx.se/) library.
mod callbacks;
mod channel;
mod parsers;
mod types;
mod utils;

// Re-export public interfaces.
pub use channel::Channel;
pub use parsers::{
    parse_a_result,
    parse_aaaa_result,
};
pub use types::{
    AresError,
    AResult,
    AAAAResult,
    INVALID_FD,
};
pub use utils::str_error;
<|endoftext|>


<commit_before>//! The Liquid templating language for Rust
//!
//! __http://liquidmarkup.org/__
//!
//! ```toml
//! [dependencies]
//! liquid = "0.9"
//! ```
//!
//! ## Example
//! ```rust
//! use liquid::{Renderable, Context, Value};
//!
//! let template = liquid::parse("Liquid! {{num | minus: 2}}", Default::default()).unwrap();
//!
//! let mut context = Context::new();
//! context.set_val("num", Value::Num(4f32));
//!
//! let output = template.render(&mut context);
//! assert_eq!(output.unwrap(), Some("Liquid! 2".to_string()));
//! ```
#![crate_name = "liquid"]
#![doc(html_root_url = "https://cobalt-org.github.io/liquid-rust/")]

// Deny warnings, except in dev mode
#![deny(warnings)]
// #![deny(missing_docs)]
#![cfg_attr(feature="dev", warn(warnings))]

// Allow zero pointers for lazy_static. Otherwise clippy will complain.
#![allow(unknown_lints)]
#![allow(zero_ptr)]

extern crate regex;
extern crate chrono;
extern crate unicode_segmentation;
extern crate itertools;
extern crate url;

#[macro_use]
extern crate lazy_static;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

use std::collections::HashMap;
use lexer::Element;
use tags::{assign_tag, cycle_tag, include_tag, break_tag, continue_tag, comment_block, raw_block,
           for_block, if_block, unless_block, capture_block, case_block};
use std::default::Default;
use std::fs::File;
use std::io::prelude::Read;
use std::path::{PathBuf, Path};
use error::Result;

pub use value::Value;
pub use value::Object;
pub use value::Array;
pub use context::Context;
pub use template::Template;
pub use error::Error;
pub use filters::FilterError;
pub use token::Token;

pub mod lexer;
pub mod parser;

mod token;
mod error;
mod template;
mod output;
mod text;
mod tags;
mod filters;
mod value;
mod variable;
mod context;
mod path;

/// A trait for creating custom tags. This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a tag and returns
/// a new [Renderable](trait.Renderable.html) based on its parameters. The received parameters
/// specify the name of the tag, the argument [Tokens](lexer/enum.Token.html) passed to
/// the tag and the global [`LiquidOptions`](struct.LiquidOptions.html).
///
/// ## Minimal Example
/// ```
/// # use liquid::{Renderable, LiquidOptions, Context, Error, FnTagParser};
///
/// struct HelloWorld;
///
/// impl Renderable for HelloWorld {
///     fn render(&self, _context: &mut Context) -> Result<Option<String>, Error>{
///         Ok(Some("Hello World!".to_owned()))
///     }
/// }
///
/// let mut options : LiquidOptions = Default::default();
/// options.tags.insert(
///     "hello_world".to_owned(),
///     Box::new(FnTagParser::new(|_tag_name, _arguments, _options| {
///         Ok(Box::new(HelloWorld))
///     })),
/// );
///
/// let template = liquid::parse("{{hello_world}}", options).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Hello World!".to_owned()));
/// ```
pub trait ParseTag: Send + Sync + ParseTagClone {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             options: &LiquidOptions)
             -> Result<Box<Renderable>>;
}

pub trait ParseTagClone {
    fn clone_box(&self) -> Box<ParseTag>;
}

impl<T> ParseTagClone for T
    where T: 'static + ParseTag + Clone
{
    fn clone_box(&self) -> Box<ParseTag> {
        Box::new(self.clone())
    }
}

impl Clone for Box<ParseTag> {
    fn clone(&self) -> Box<ParseTag> {
        self.clone_box()
    }
}

pub type FnParseTag = fn(&str, &[Token], &LiquidOptions) -> Result<Box<Renderable>>;

#[derive(Clone)]
pub struct FnTagParser {
    pub parser: FnParseTag,
}

impl FnTagParser {
    pub fn new(parser: FnParseTag) -> Self {
        Self { parser }
    }
}

impl ParseTag for FnTagParser {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             options: &LiquidOptions)
             -> Result<Box<Renderable>> {
        (self.parser)(tag_name, arguments, options)
    }
}

/// A trait for creating custom custom block-size tags (`{% if something %}{% endif %}`).
/// This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a block and returns
/// a new `Renderable` based on its parameters. The received parameters specify the name
/// of the block, the argument [Tokens](lexer/enum.Token.html) passed to
/// the block, a Vec of all [Elements](lexer/enum.Element.html) inside the block and
/// the global [`LiquidOptions`](struct.LiquidOptions.html).
pub trait ParseBlock: Send + Sync + ParseBlockClone {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             tokens: &[Element],
             options: &LiquidOptions)
             -> Result<Box<Renderable>>;
}

pub trait ParseBlockClone {
    fn clone_box(&self) -> Box<ParseBlock>;
}

impl<T> ParseBlockClone for T
    where T: 'static + ParseBlock + Clone
{
    fn clone_box(&self) -> Box<ParseBlock> {
        Box::new(self.clone())
    }
}

impl Clone for Box<ParseBlock> {
    fn clone(&self) -> Box<ParseBlock> {
        self.clone_box()
    }
}

pub type FnParseBlock = fn(&str, &[Token], &[Element], &LiquidOptions) -> Result<Box<Renderable>>;

#[derive(Clone)]
pub struct FnBlockParser {
    pub parser: FnParseBlock,
}

impl FnBlockParser {
    pub fn new(parser: FnParseBlock) -> Self {
        Self { parser }
    }
}

impl ParseBlock for FnBlockParser {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             tokens: &[Element],
             options: &LiquidOptions)
             -> Result<Box<Renderable>> {
        (self.parser)(tag_name, arguments, tokens, options)
    }
}

/// Any object (tag/block) that can be rendered by liquid must implement this trait.
pub trait Renderable: Send + Sync {
    /// Renders the Renderable instance given a Liquid context.
    /// The Result that is returned signals if there was an error rendering,
    /// the Option<String> that is wrapped by the Result will be None if
    /// the render has run successfully but there is no content to render.
    fn render(&self, context: &mut Context) -> Result<Option<String>>;
}

pub trait TemplateRepository {
    fn read_template(&self, path: &str) -> Result<String>;
}

/// `TemplateRepository` to load files relative to the root
pub struct LocalTemplateRepository {
    root: PathBuf,
}

impl LocalTemplateRepository {
    pub fn new(root: PathBuf) -> LocalTemplateRepository {
        LocalTemplateRepository { root: root }
    }
}

impl TemplateRepository for LocalTemplateRepository {
    fn read_template(&self, relative_path: &str) -> Result<String> {
        let path = self.root.clone().join(relative_path);

        if !path.exists() {
            return Err(Error::from(&*format!("{:?} does not exist", path)));
        }
        let mut file = try!(File::open(path));

        let mut content = String::new();
        file.read_to_string(&mut content)?;
        Ok(content)
    }
}

/// Options that `liquid::parse` takes
pub struct LiquidOptions {
    /// Holds all custom block-size tags
    pub blocks: HashMap<String, Box<ParseBlock>>,
    /// Holds all custom tags
    pub tags: HashMap<String, Box<ParseTag>>,
    /// The path to which paths in include tags should be relative to
    pub template_repository: Box<TemplateRepository>,
}

impl Default for LiquidOptions {
    fn default() -> LiquidOptions {
        LiquidOptions {
            blocks: Default::default(),
            tags: Default::default(),
            template_repository: Box::new(LocalTemplateRepository { root: PathBuf::new() }),
        }
    }
}

impl LiquidOptions {
    /// Creates a LiquidOptions instance, pre-seeded with all known
    /// tags and blocks.
    pub fn with_known_blocks() -> LiquidOptions {
        let mut options = LiquidOptions::default();
        options.register_known_blocks();
        options
    }

    /// Registers all known tags and blocks in an existing options
    /// struct
    pub fn register_known_blocks(&mut self) {
        self.register_tag("assign", Box::new(FnTagParser::new(assign_tag)));
        self.register_tag("break", Box::new(FnTagParser::new(break_tag)));
        self.register_tag("continue", Box::new(FnTagParser::new(continue_tag)));
        self.register_tag("cycle", Box::new(FnTagParser::new(cycle_tag)));
        self.register_tag("include", Box::new(FnTagParser::new(include_tag)));

        self.register_block("raw", Box::new(FnBlockParser::new(raw_block)));
        self.register_block("if", Box::new(FnBlockParser::new(if_block)));
        self.register_block("unless", Box::new(FnBlockParser::new(unless_block)));
        self.register_block("for", Box::new(FnBlockParser::new(for_block)));
        self.register_block("comment", Box::new(FnBlockParser::new(comment_block)));
        self.register_block("capture", Box::new(FnBlockParser::new(capture_block)));
        self.register_block("case", Box::new(FnBlockParser::new(case_block)));
    }

    /// Inserts a new custom block into the options object
    pub fn register_block(&mut self, name: &str, block: Box<ParseBlock>) {
        self.blocks.insert(name.to_owned(), block);
    }

    /// Inserts a new custom tag into the options object
    pub fn register_tag(&mut self, name: &str, tag: Box<ParseTag>) {
        self.tags.insert(name.to_owned(), tag);
    }
}

/// Parses a liquid template, returning a Template object.
/// # Examples
///
/// ## Minimal Template
///
/// ```
/// use liquid::{Renderable, LiquidOptions, Context};
///
/// let template = liquid::parse("Liquid!", LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid!".to_owned()));
/// ```
///
pub fn parse(text: &str, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    options.register_known_blocks();

    let tokens = try!(lexer::tokenize(text));
    parser::parse(&tokens, &options).map(Template::new)
}

/// Parse a liquid template from a file, returning a `Result<Template, Error>`.
/// # Examples
///
/// ## Minimal Template
///
/// `template.txt`:
///
/// ```text
/// "Liquid {{data}}"
/// ```
///
/// Your rust code:
///
/// ```rust,no_run
/// use liquid::{Renderable, LiquidOptions, Context, Value};
///
/// let template = liquid::parse_file("path/to/template.txt",
///                                   LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// data.set_val("data", Value::Num(4f32));
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid 4\n".to_string()));
/// ```
///
pub fn parse_file<P: AsRef<Path>>(fp: P, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    options.register_known_blocks();

    let mut f = try!(File::open(fp));
    let mut buf = String::new();
    try!(f.read_to_string(&mut buf));

    let tokens = try!(lexer::tokenize(&buf));
    parser::parse(&tokens, &options).map(Template::new)
}
<commit_msg>feat: make TemplateRepository cloneable<commit_after>//! The Liquid templating language for Rust
//!
//! __http://liquidmarkup.org/__
//!
//! ```toml
//! [dependencies]
//! liquid = "0.9"
//! ```
//!
//! ## Example
//! ```rust
//! use liquid::{Renderable, Context, Value};
//!
//! let template = liquid::parse("Liquid! {{num | minus: 2}}", Default::default()).unwrap();
//!
//! let mut context = Context::new();
//! context.set_val("num", Value::Num(4f32));
//!
//! let output = template.render(&mut context);
//! assert_eq!(output.unwrap(), Some("Liquid! 2".to_string()));
//! ```
#![crate_name = "liquid"]
#![doc(html_root_url = "https://cobalt-org.github.io/liquid-rust/")]

// Deny warnings, except in dev mode
#![deny(warnings)]
// #![deny(missing_docs)]
#![cfg_attr(feature="dev", warn(warnings))]

// Allow zero pointers for lazy_static. Otherwise clippy will complain.
#![allow(unknown_lints)]
#![allow(zero_ptr)]

extern crate regex;
extern crate chrono;
extern crate unicode_segmentation;
extern crate itertools;
extern crate url;

#[macro_use]
extern crate lazy_static;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

use std::collections::HashMap;
use lexer::Element;
use tags::{assign_tag, cycle_tag, include_tag, break_tag, continue_tag, comment_block, raw_block,
           for_block, if_block, unless_block, capture_block, case_block};
use std::default::Default;
use std::fs::File;
use std::io::prelude::Read;
use std::path::{PathBuf, Path};
use error::Result;

pub use value::Value;
pub use value::Object;
pub use value::Array;
pub use context::Context;
pub use template::Template;
pub use error::Error;
pub use filters::FilterError;
pub use token::Token;

pub mod lexer;
pub mod parser;

mod token;
mod error;
mod template;
mod output;
mod text;
mod tags;
mod filters;
mod value;
mod variable;
mod context;
mod path;

/// A trait for creating custom tags. This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a tag and returns
/// a new [Renderable](trait.Renderable.html) based on its parameters. The received parameters
/// specify the name of the tag, the argument [Tokens](lexer/enum.Token.html) passed to
/// the tag and the global [`LiquidOptions`](struct.LiquidOptions.html).
///
/// ## Minimal Example
/// ```
/// # use liquid::{Renderable, LiquidOptions, Context, Error, FnTagParser};
///
/// struct HelloWorld;
///
/// impl Renderable for HelloWorld {
///     fn render(&self, _context: &mut Context) -> Result<Option<String>, Error>{
///         Ok(Some("Hello World!".to_owned()))
///     }
/// }
///
/// let mut options : LiquidOptions = Default::default();
/// options.tags.insert(
///     "hello_world".to_owned(),
///     Box::new(FnTagParser::new(|_tag_name, _arguments, _options| {
///         Ok(Box::new(HelloWorld))
///     })),
/// );
///
/// let template = liquid::parse("{{hello_world}}", options).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Hello World!".to_owned()));
/// ```
pub trait ParseTag: Send + Sync + ParseTagClone {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             options: &LiquidOptions)
             -> Result<Box<Renderable>>;
}

pub trait ParseTagClone {
    fn clone_box(&self) -> Box<ParseTag>;
}

impl<T> ParseTagClone for T
    where T: 'static + ParseTag + Clone
{
    fn clone_box(&self) -> Box<ParseTag> {
        Box::new(self.clone())
    }
}

impl Clone for Box<ParseTag> {
    fn clone(&self) -> Box<ParseTag> {
        self.clone_box()
    }
}

pub type FnParseTag = fn(&str, &[Token], &LiquidOptions) -> Result<Box<Renderable>>;

#[derive(Clone)]
pub struct FnTagParser {
    pub parser: FnParseTag,
}

impl FnTagParser {
    pub fn new(parser: FnParseTag) -> Self {
        Self { parser }
    }
}

impl ParseTag for FnTagParser {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             options: &LiquidOptions)
             -> Result<Box<Renderable>> {
        (self.parser)(tag_name, arguments, options)
    }
}

/// A trait for creating custom custom block-size tags (`{% if something %}{% endif %}`).
/// This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a block and returns
/// a new `Renderable` based on its parameters. The received parameters specify the name
/// of the block, the argument [Tokens](lexer/enum.Token.html) passed to
/// the block, a Vec of all [Elements](lexer/enum.Element.html) inside the block and
/// the global [`LiquidOptions`](struct.LiquidOptions.html).
pub trait ParseBlock: Send + Sync + ParseBlockClone {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             tokens: &[Element],
             options: &LiquidOptions)
             -> Result<Box<Renderable>>;
}

pub trait ParseBlockClone {
    fn clone_box(&self) -> Box<ParseBlock>;
}

impl<T> ParseBlockClone for T
    where T: 'static + ParseBlock + Clone
{
    fn clone_box(&self) -> Box<ParseBlock> {
        Box::new(self.clone())
    }
}

impl Clone for Box<ParseBlock> {
    fn clone(&self) -> Box<ParseBlock> {
        self.clone_box()
    }
}

pub type FnParseBlock = fn(&str, &[Token], &[Element], &LiquidOptions) -> Result<Box<Renderable>>;

#[derive(Clone)]
pub struct FnBlockParser {
    pub parser: FnParseBlock,
}

impl FnBlockParser {
    pub fn new(parser: FnParseBlock) -> Self {
        Self { parser }
    }
}

impl ParseBlock for FnBlockParser {
    fn parse(&self,
             tag_name: &str,
             arguments: &[Token],
             tokens: &[Element],
             options: &LiquidOptions)
             -> Result<Box<Renderable>> {
        (self.parser)(tag_name, arguments, tokens, options)
    }
}

/// Any object (tag/block) that can be rendered by liquid must implement this trait.
pub trait Renderable: Send + Sync {
    /// Renders the Renderable instance given a Liquid context.
    /// The Result that is returned signals if there was an error rendering,
    /// the Option<String> that is wrapped by the Result will be None if
    /// the render has run successfully but there is no content to render.
    fn render(&self, context: &mut Context) -> Result<Option<String>>;
}

pub trait TemplateRepository: Send + Sync + TemplateRepositoryClone {
    fn read_template(&self, path: &str) -> Result<String>;
}

pub trait TemplateRepositoryClone {
    fn clone_box(&self) -> Box<TemplateRepository>;
}

impl<T> TemplateRepositoryClone for T
    where T: 'static + TemplateRepository + Clone
{
    fn clone_box(&self) -> Box<TemplateRepository> {
        Box::new(self.clone())
    }
}

impl Clone for Box<TemplateRepository> {
    fn clone(&self) -> Box<TemplateRepository> {
        self.clone_box()
    }
}

/// `TemplateRepository` to load files relative to the root
#[derive(Clone)]
pub struct LocalTemplateRepository {
    root: PathBuf,
}

impl LocalTemplateRepository {
    pub fn new(root: PathBuf) -> LocalTemplateRepository {
        LocalTemplateRepository { root: root }
    }
}

impl TemplateRepository for LocalTemplateRepository {
    fn read_template(&self, relative_path: &str) -> Result<String> {
        let path = self.root.clone().join(relative_path);

        if !path.exists() {
            return Err(Error::from(&*format!("{:?} does not exist", path)));
        }
        let mut file = try!(File::open(path));

        let mut content = String::new();
        file.read_to_string(&mut content)?;
        Ok(content)
    }
}

/// Options that `liquid::parse` takes
pub struct LiquidOptions {
    /// Holds all custom block-size tags
    pub blocks: HashMap<String, Box<ParseBlock>>,
    /// Holds all custom tags
    pub tags: HashMap<String, Box<ParseTag>>,
    /// The path to which paths in include tags should be relative to
    pub template_repository: Box<TemplateRepository>,
}

impl Default for LiquidOptions {
    fn default() -> LiquidOptions {
        LiquidOptions {
            blocks: Default::default(),
            tags: Default::default(),
            template_repository: Box::new(LocalTemplateRepository { root: PathBuf::new() }),
        }
    }
}

impl LiquidOptions {
    /// Creates a LiquidOptions instance, pre-seeded with all known
    /// tags and blocks.
    pub fn with_known_blocks() -> LiquidOptions {
        let mut options = LiquidOptions::default();
        options.register_known_blocks();
        options
    }

    /// Registers all known tags and blocks in an existing options
    /// struct
    pub fn register_known_blocks(&mut self) {
        self.register_tag("assign", Box::new(FnTagParser::new(assign_tag)));
        self.register_tag("break", Box::new(FnTagParser::new(break_tag)));
        self.register_tag("continue", Box::new(FnTagParser::new(continue_tag)));
        self.register_tag("cycle", Box::new(FnTagParser::new(cycle_tag)));
        self.register_tag("include", Box::new(FnTagParser::new(include_tag)));

        self.register_block("raw", Box::new(FnBlockParser::new(raw_block)));
        self.register_block("if", Box::new(FnBlockParser::new(if_block)));
        self.register_block("unless", Box::new(FnBlockParser::new(unless_block)));
        self.register_block("for", Box::new(FnBlockParser::new(for_block)));
        self.register_block("comment", Box::new(FnBlockParser::new(comment_block)));
        self.register_block("capture", Box::new(FnBlockParser::new(capture_block)));
        self.register_block("case", Box::new(FnBlockParser::new(case_block)));
    }

    /// Inserts a new custom block into the options object
    pub fn register_block(&mut self, name: &str, block: Box<ParseBlock>) {
        self.blocks.insert(name.to_owned(), block);
    }

    /// Inserts a new custom tag into the options object
    pub fn register_tag(&mut self, name: &str, tag: Box<ParseTag>) {
        self.tags.insert(name.to_owned(), tag);
    }
}

/// Parses a liquid template, returning a Template object.
/// # Examples
///
/// ## Minimal Template
///
/// ```
/// use liquid::{Renderable, LiquidOptions, Context};
///
/// let template = liquid::parse("Liquid!", LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid!".to_owned()));
/// ```
///
pub fn parse(text: &str, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    options.register_known_blocks();

    let tokens = try!(lexer::tokenize(text));
    parser::parse(&tokens, &options).map(Template::new)
}

/// Parse a liquid template from a file, returning a `Result<Template, Error>`.
/// # Examples
///
/// ## Minimal Template
///
/// `template.txt`:
///
/// ```text
/// "Liquid {{data}}"
/// ```
///
/// Your rust code:
///
/// ```rust,no_run
/// use liquid::{Renderable, LiquidOptions, Context, Value};
///
/// let template = liquid::parse_file("path/to/template.txt",
///                                   LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// data.set_val("data", Value::Num(4f32));
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid 4\n".to_string()));
/// ```
///
pub fn parse_file<P: AsRef<Path>>(fp: P, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    options.register_known_blocks();

    let mut f = try!(File::open(fp));
    let mut buf = String::new();
    try!(f.read_to_string(&mut buf));

    let tokens = try!(lexer::tokenize(&buf));
    parser::parse(&tokens, &options).map(Template::new)
}
<|endoftext|>


<commit_before>pub fn add_one(data: &mut [f32])
{
	for i in 0..10
	{
		data[i] = data[i] + 1.0;
	}
}

#[test]
fn add_one_test()
{
	let mut result = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
	add_one(&mut result);
	assert_eq!(result, [2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0]);
}<commit_msg>Fix: Hardcoded array bounds<commit_after>pub fn add_one(data: &mut [f64])
{
	for i in 0..data.len()
	{
		data[i] = data[i] + 1.0;
	}
}

#[test]
fn add_one_test()
{
	let mut result = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
	add_one(&mut result);
	assert_eq!(result, [2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0]);
}

#[test]
fn add_one_test_odd_number_of_elements()
{
	let mut result = [1.0, 2.0, 3.0];
	add_one(&mut result);
	assert_eq!(result, [2.0, 3.0, 4.0]);
}<|endoftext|>


<commit_before>#![recursion_limit = "256"]

use types::Model;
use wasm_bindgen::prelude::*;
use yew::prelude::*;

mod initial;
mod types;
mod view;

#[wasm_bindgen(start)]
pub fn main() {
    // web_logger::init();
    // wasm_logger::init(wasm_logger::Config::default().module_prefix("some::module"));
    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));

    log::info!("starting");
    // See https://github.com/rustwasm/console_error_panic_hook/issues/8.
    // std::panic::set_hook(Box::new(console_error_panic_hook::hook));
    yew::start_app::<Model>();
}
<commit_msg>start app<commit_after>#![recursion_limit = "256"]

use types::Model;
use wasm_bindgen::prelude::*;
use yew::prelude::*;

mod initial;
mod types;
mod view;

#[wasm_bindgen(start)]
pub fn main() {
    // web_logger::init();
    // wasm_logger::init(wasm_logger::Config::default().module_prefix("some::module"));
    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));

    log::info!("starting");
    // See https://github.com/rustwasm/console_error_panic_hook/issues/8.
    // std::panic::set_hook(Box::new(console_error_panic_hook::hook));
    // App::<Model>::new().mount_to_body();
    yew::start_app::<Model>();
}
<|endoftext|>


<commit_before>#![feature(specialization)]
#![feature(type_ascription)]
#![feature(concat_idents)]

extern crate rutorch;
#[macro_use]
extern crate modparse_derive;
#[macro_use]
extern crate derive_builder;

extern crate num;
extern crate rand;
extern crate itertools;

// only needed for torchvision
extern crate curl;
extern crate flate2;
extern crate memmap;

// serialization support
#[macro_use]
extern crate serde_derive;
extern crate rmp;
extern crate rmp_serde as rmps;
extern crate serde;

#[macro_use]
pub mod macros;

pub mod nn;
pub mod autograd;
pub mod optim;
pub mod utils;
pub mod tensor;
pub mod storage;
pub mod torch;
use std::rc::Rc;
use std::cell::RefCell;

// Mutable reference counted T
pub type RcMut<T> = Rc<RefCell<T>>;
// Nullable mutable reference counted T
pub type OptRcMut<T> = Option<RcMut<T>>;
pub type Ix = usize;
/// Array index type (signed)
pub type Ixs = isize;

#[allow(non_snake_case)]
pub fn RcMutNew<T>(arg: T) -> RcMut<T> {
    Rc::new(RefCell::new(arg))
}

#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {}
}
<commit_msg>appease rust<commit_after>#![feature(specialization)]
#![feature(type_ascription)]
#![feature(concat_idents)]
#![feature(const_fn)]

extern crate rutorch;
#[macro_use]
extern crate modparse_derive;
#[macro_use]
extern crate derive_builder;

extern crate num;
extern crate rand;
extern crate itertools;

// only needed for torchvision
extern crate curl;
extern crate flate2;
extern crate memmap;

// serialization support
#[macro_use]
extern crate serde_derive;
extern crate rmp;
extern crate rmp_serde as rmps;
extern crate serde;

#[macro_use]
pub mod macros;

pub mod nn;
pub mod autograd;
pub mod optim;
pub mod utils;
pub mod tensor;
pub mod storage;
pub mod torch;
use std::rc::Rc;
use std::cell::RefCell;

// Mutable reference counted T
pub type RcMut<T> = Rc<RefCell<T>>;
// Nullable mutable reference counted T
pub type OptRcMut<T> = Option<RcMut<T>>;
pub type Ix = usize;
/// Array index type (signed)
pub type Ixs = isize;

#[allow(non_snake_case)]
pub fn RcMutNew<T>(arg: T) -> RcMut<T> {
    Rc::new(RefCell::new(arg))
}

#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>#![feature(if_let)]

use std::os;
use std::io::Command;
use std::io::process::InheritFd;
use std::default::Default;

/// Extra configuration to pass to gcc.
pub struct Config {
    /// Directories where gcc will look for header files.
    pub include_directories: Vec<Path>,
    /// Additional definitions (`-DKEY` or `-DKEY=VALUE`).
    pub definitions: Vec<(String, Option<String>)>,
    /// Additional object files to link into the final archive
    pub objects: Vec<Path>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            include_directories: Vec::new(),
            definitions: Vec::new(),
            objects: Vec::new(),
        }
    }
}

/// Compile a library from the given set of input C files.
///
/// This will simply compile all files into object files and then assemble them
/// into the output. This will read the standard environment variables to detect
/// cross compilations and such.
///
/// # Example
///
/// ```no_run
/// use std::default::Default;
/// gcc::compile_library("libfoo.a", &Default::default(), &[
///     "foo.c",
///     "bar.c",
/// ]);
/// ```
pub fn compile_library(output: &str, config: &Config, files: &[&str]) {
    assert!(output.starts_with("lib"));
    assert!(output.ends_with(".a"));

    let target = os::getenv("TARGET").unwrap();
    let opt_level = os::getenv("OPT_LEVEL").unwrap();

    let mut cmd = Command::new(gcc());
    cmd.arg(format!("-O{}", opt_level));
    cmd.arg("-c");
    cmd.arg("-ffunction-sections").arg("-fdata-sections");
    cmd.args(cflags().as_slice());

    if target.as_slice().contains("-ios") {
        cmd.args(ios_flags(target.as_slice()).as_slice());
    } else {
        if target.as_slice().contains("i686") {
            cmd.arg("-m32");
        } else if target.as_slice().contains("x86_64") {
            cmd.arg("-m64");
        }

        if !target.as_slice().contains("i686") {
            cmd.arg("-fPIC");
        }
    }

    for directory in config.include_directories.iter() {
        cmd.arg("-I").arg(directory);
    }

    for &(ref key, ref value) in config.definitions.iter() {
        if let &Some(ref value) = value {
            cmd.arg(format!("-D{}={}", key, value));
        } else {
            cmd.arg(format!("-D{}", key));
        }
    }

    let src = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    let dst = Path::new(os::getenv("OUT_DIR").unwrap());
    let mut objects = Vec::new();
    for file in files.iter() {
        let obj = dst.join(*file).with_extension("o");
        std::io::fs::mkdir_recursive(&obj.dir_path(), std::io::USER_RWX).unwrap();
        run(cmd.clone().arg(src.join(*file)).arg("-o").arg(&obj));
        objects.push(obj);
    }

    run(Command::new(ar()).arg("crus")
                          .arg(dst.join(output))
                          .args(objects.as_slice())
                          .args(config.objects.as_slice()));
    println!("cargo:rustc-flags=-L {} -l {}:static",
             dst.display(), output.slice(3, output.len() - 2));
}

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    assert!(cmd.stdout(InheritFd(1))
               .stderr(InheritFd(2))
               .status()
               .unwrap()
               .success());

}

fn gcc() -> String {
    os::getenv("CC").unwrap_or(if cfg!(windows) {
        "gcc".to_string()
    } else {
        "cc".to_string()
    })
}

fn ar() -> String {
    os::getenv("AR").unwrap_or("ar".to_string())
}

fn cflags() -> Vec<String> {
    os::getenv("CFLAGS").unwrap_or(String::new())
       .as_slice().words().map(|s| s.to_string())
       .collect()
}

fn ios_flags(target: &str) -> Vec<String> {
    let mut is_device_arch = false;
    let mut res = Vec::new();

    if target.starts_with("arm-") {
        res.push("-arch");
        res.push("armv7");
        is_device_arch = true;
    } else if target.starts_with("arm64-") {
        res.push("-arch");
        res.push("arm64");
        is_device_arch = true;
    } else if target.starts_with("i386-") {
        res.push("-m32");
    } else if target.starts_with("x86_64-") {
        res.push("-m64");
    }

    let sdk = if is_device_arch {"iphoneos"} else {"iphonesimulator"};

    println!("Detecting iOS SDK path for {}", sdk);
    let sdk_path = Command::new("xcrun")
        .arg("--show-sdk-path")
        .arg("--sdk")
        .arg(sdk)
        .stderr(InheritFd(2))
        .output()
        .unwrap()
        .output;

    let sdk_path = String::from_utf8(sdk_path).unwrap();

    res.push("-isysroot");
    res.push(sdk_path.as_slice().trim());

    res.iter().map(|s| s.to_string()).collect::<Vec<_>>()
}
<commit_msg>Backport 'Set default gcc/ar for android cross compiling."<commit_after>#![feature(if_let)]

use std::os;
use std::io::Command;
use std::io::process::InheritFd;
use std::default::Default;

/// Extra configuration to pass to gcc.
pub struct Config {
    /// Directories where gcc will look for header files.
    pub include_directories: Vec<Path>,
    /// Additional definitions (`-DKEY` or `-DKEY=VALUE`).
    pub definitions: Vec<(String, Option<String>)>,
    /// Additional object files to link into the final archive
    pub objects: Vec<Path>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            include_directories: Vec::new(),
            definitions: Vec::new(),
            objects: Vec::new(),
        }
    }
}

/// Compile a library from the given set of input C files.
///
/// This will simply compile all files into object files and then assemble them
/// into the output. This will read the standard environment variables to detect
/// cross compilations and such.
///
/// # Example
///
/// ```no_run
/// use std::default::Default;
/// gcc::compile_library("libfoo.a", &Default::default(), &[
///     "foo.c",
///     "bar.c",
/// ]);
/// ```
pub fn compile_library(output: &str, config: &Config, files: &[&str]) {
    assert!(output.starts_with("lib"));
    assert!(output.ends_with(".a"));

    let target = os::getenv("TARGET").unwrap();
    let opt_level = os::getenv("OPT_LEVEL").unwrap();

    let mut cmd = Command::new(gcc(target.as_slice()));
    cmd.arg(format!("-O{}", opt_level));
    cmd.arg("-c");
    cmd.arg("-ffunction-sections").arg("-fdata-sections");
    cmd.args(cflags().as_slice());

    if target.as_slice().contains("-ios") {
        cmd.args(ios_flags(target.as_slice()).as_slice());
    } else {
        if target.as_slice().contains("i686") {
            cmd.arg("-m32");
        } else if target.as_slice().contains("x86_64") {
            cmd.arg("-m64");
        }

        if !target.as_slice().contains("i686") {
            cmd.arg("-fPIC");
        }
    }

    for directory in config.include_directories.iter() {
        cmd.arg("-I").arg(directory);
    }

    for &(ref key, ref value) in config.definitions.iter() {
        if let &Some(ref value) = value {
            cmd.arg(format!("-D{}={}", key, value));
        } else {
            cmd.arg(format!("-D{}", key));
        }
    }

    let src = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    let dst = Path::new(os::getenv("OUT_DIR").unwrap());
    let mut objects = Vec::new();
    for file in files.iter() {
        let obj = dst.join(*file).with_extension("o");
        std::io::fs::mkdir_recursive(&obj.dir_path(), std::io::USER_RWX).unwrap();
        run(cmd.clone().arg(src.join(*file)).arg("-o").arg(&obj));
        objects.push(obj);
    }

    run(Command::new(ar(target.as_slice())).arg("crus")
                                           .arg(dst.join(output))
                                           .args(objects.as_slice())
                                           .args(config.objects.as_slice()));
    println!("cargo:rustc-flags=-L {} -l {}:static",
             dst.display(), output.slice(3, output.len() - 2));
}

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    assert!(cmd.stdout(InheritFd(1))
               .stderr(InheritFd(2))
               .status()
               .unwrap()
               .success());

}

fn gcc(target: &str) -> String {
    let is_android = target.find_str("android").is_some();

    os::getenv("CC").unwrap_or(if cfg!(windows) {
        "gcc".to_string()
    } else if is_android {
        format!("{}-gcc", target)
    } else {
        "cc".to_string()
    })
}

fn ar(target: &str) -> String {
    let is_android = target.find_str("android").is_some();

    os::getenv("AR").unwrap_or(if is_android {
        format!("{}-ar", target)
    } else {
        "ar".to_string()
    })
}

fn cflags() -> Vec<String> {
    os::getenv("CFLAGS").unwrap_or(String::new())
       .as_slice().words().map(|s| s.to_string())
       .collect()
}

fn ios_flags(target: &str) -> Vec<String> {
    let mut is_device_arch = false;
    let mut res = Vec::new();

    if target.starts_with("arm-") {
        res.push("-arch");
        res.push("armv7");
        is_device_arch = true;
    } else if target.starts_with("arm64-") {
        res.push("-arch");
        res.push("arm64");
        is_device_arch = true;
    } else if target.starts_with("i386-") {
        res.push("-m32");
    } else if target.starts_with("x86_64-") {
        res.push("-m64");
    }

    let sdk = if is_device_arch {"iphoneos"} else {"iphonesimulator"};

    println!("Detecting iOS SDK path for {}", sdk);
    let sdk_path = Command::new("xcrun")
        .arg("--show-sdk-path")
        .arg("--sdk")
        .arg(sdk)
        .stderr(InheritFd(2))
        .output()
        .unwrap()
        .output;

    let sdk_path = String::from_utf8(sdk_path).unwrap();

    res.push("-isysroot");
    res.push(sdk_path.as_slice().trim());

    res.iter().map(|s| s.to_string()).collect::<Vec<_>>()
}
<|endoftext|>


<commit_before>

pub mod graph {
    use std::collections::HashMap;
    use std::ops::Deref;
    use std::mem;

    #[derive(Debug)]
    pub struct Graph {
        elements: i64,
        // we transmute our Boxed vertex into a pointer later
        vertices: HashMap<i64, *mut Vertex>,
    }

    impl Graph {
        pub fn new() -> Box<Graph> {
            let vertices: HashMap<i64, *mut Vertex> = HashMap::new();
            Box::new(Graph{elements:0, vertices:vertices})
        }

        pub fn add_vertex(&mut self) -> VertexProxy {
            let new_id = self.elements + 1;
            self.elements += 1;

            let mut v = Vertex::new(new_id);

            let ptr: *mut Vertex = unsafe { mem::transmute(v) };

            self.vertices.insert(new_id, ptr);

            // return the proxy which knows it's own id
            VertexProxy{id:new_id, v: ptr}
        }
        pub fn get(vertex_id:i64)  {
        }
    }

    /*
    * storing in & out edges seperately should cut down on the number of "things" i have to traverse
    * if a vertex has 10k edges (5k in and out 5k out) then doing something like
    *   g(v).outV()
    * should be ok
    */
    #[derive(Debug)]
    pub struct Vertex {
        pub id: i64,

        // pointers on both sides, yay
        pub out_edges: Vec<*mut Edge>,
        pub in_edges:  Vec<*mut Edge>,
    }

    impl Vertex {
        pub fn new(id: i64) -> Box<Vertex> {
            Box::new(Vertex{id:id,
                            out_edges: Vec::new(),
                            in_edges: Vec::new()})
        }
    }

    pub struct VertexProxy {
        pub id: i64,
        pub v: *mut Vertex,
    }

    impl VertexProxy {
        pub fn add_edge(&mut self, to_vertex: &mut VertexProxy) {
            let in_vertex: &mut Vertex;
            let out_vertex: &mut Vertex;

            unsafe {
                in_vertex =  &mut *(self.v);
                out_vertex = &mut *(to_vertex.v);
            }

            // create the edge
            let mut e = Box::new(Edge{from_vertex: self.v, to_vertex: to_vertex.v});

            let mut edge: *mut Edge = unsafe { mem::transmute(e) };

            in_vertex.out_edges.push(edge);
            out_vertex.in_edges.push(edge);
        }

        pub fn query(self) {

        }
    }

    impl Deref for VertexProxy {
        type Target = Vertex;

        fn deref<'a>(&'a self) -> &'a Vertex {
            unsafe {
                &*(self.v)
            }
        }
    }

    #[derive(Debug)]
    pub struct Edge {
        from_vertex: *const Vertex,
        to_vertex: *const Vertex
    }

    struct EdgeProxy {
        edge: *mut Edge
    }

    impl Deref for EdgeProxy {
        type Target = Edge;
        fn deref<'a>(&'a self) -> &'a Edge {
            unsafe { &*(self.edge) }
        }
    }

}

mod tests {
    use graph::{Graph, Vertex};

    #[test]
    fn test_unsafe_vertex() {
        let v = Vertex::new(1);

        let out_edges = &v.out_edges;
        let in_edges = &v.in_edges;
    }

    #[test]
    fn test_deref() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();
        let vertex = &*v1;
        assert!(vertex.id == 1);
    }

    #[test]
    fn test_new_vertex() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();

        assert_eq!(v1.id, 1);

        unsafe {
            let vertex = &*v1;
            assert_eq!((*v1).id, 1);
        }

        let v2 = g.add_vertex();
        assert!(v2.id == 2);
    }

    #[test]
    fn test_add_edge() {
        let mut g = Graph::new();
        let mut v1 = g.add_vertex();
        let mut v2 = g.add_vertex();

        v1.add_edge(&mut v2);
        v1.add_edge(&mut v2);
        v1.add_edge(&mut v2);

        assert_eq!(v1.out_edges.len(), v2.in_edges.len());

        // ensure the vertex and edge pointers are correct
    }
}
<commit_msg>edge proxy with deref<commit_after>

pub mod graph {
    use std::collections::HashMap;
    use std::ops::Deref;
    use std::mem;

    #[derive(Debug)]
    pub struct Graph {
        elements: i64,
        // we transmute our Boxed vertex into a pointer later
        vertices: HashMap<i64, *mut Vertex>,
    }

    impl Graph {
        pub fn new() -> Box<Graph> {
            let vertices: HashMap<i64, *mut Vertex> = HashMap::new();
            Box::new(Graph{elements:0, vertices:vertices})
        }

        pub fn add_vertex(&mut self) -> VertexProxy {
            let new_id = self.elements + 1;
            self.elements += 1;

            let mut v = Vertex::new(new_id);

            let ptr: *mut Vertex = unsafe { mem::transmute(v) };

            self.vertices.insert(new_id, ptr);

            // return the proxy which knows it's own id
            VertexProxy{id:new_id, v: ptr}
        }
        pub fn get(vertex_id:i64)  {
        }
    }

    /*
    * storing in & out edges seperately should cut down on the number of "things" i have to traverse
    * if a vertex has 10k edges (5k in and out 5k out) then doing something like
    *   g(v).outV()
    * should be ok
    */
    #[derive(Debug)]
    pub struct Vertex {
        pub id: i64,

        // pointers on both sides, yay
        pub out_edges: Vec<*mut Edge>,
        pub in_edges:  Vec<*mut Edge>,
    }

    impl Vertex {
        pub fn new(id: i64) -> Box<Vertex> {
            Box::new(Vertex{id:id,
                            out_edges: Vec::new(),
                            in_edges: Vec::new()})
        }
    }

    pub struct VertexProxy {
        pub id: i64,
        pub v: *mut Vertex,
    }

    impl VertexProxy {
        pub fn add_edge(&mut self, to_vertex: &mut VertexProxy) {
            let in_vertex: &mut Vertex;
            let out_vertex: &mut Vertex;

            unsafe {
                in_vertex =  &mut *(self.v);
                out_vertex = &mut *(to_vertex.v);
            }

            // create the edge
            let mut e = Box::new(Edge{from_vertex: self.v, to_vertex: to_vertex.v});

            let mut edge: *mut Edge = unsafe { mem::transmute(e) };

            in_vertex.out_edges.push(edge);
            out_vertex.in_edges.push(edge);
            EdgeProxy{edge:edge}
        }

        pub fn query(self) {

        }
    }

    impl Deref for VertexProxy {
        type Target = Vertex;

        fn deref<'a>(&'a self) -> &'a Vertex {
            unsafe {
                &*(self.v)
            }
        }
    }

    #[derive(Debug)]
    pub struct Edge {
        from_vertex: *const Vertex,
        to_vertex: *const Vertex
    }

    struct EdgeProxy {
        edge: *mut Edge
    }

    impl Deref for EdgeProxy {
        type Target = Edge;
        fn deref<'a>(&'a self) -> &'a Edge {
            unsafe { &*(self.edge) }
        }
    }

}

mod tests {
    use graph::{Graph, Vertex};

    #[test]
    fn test_unsafe_vertex() {
        let v = Vertex::new(1);

        let out_edges = &v.out_edges;
        let in_edges = &v.in_edges;
    }

    #[test]
    fn test_deref() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();
        let vertex = &*v1;
        assert!(vertex.id == 1);
    }

    #[test]
    fn test_new_vertex() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();

        assert_eq!(v1.id, 1);

        unsafe {
            let vertex = &*v1;
            assert_eq!((*v1).id, 1);
        }

        let v2 = g.add_vertex();
        assert!(v2.id == 2);
    }

    #[test]
    fn test_add_edge() {
        let mut g = Graph::new();
        let mut v1 = g.add_vertex();
        let mut v2 = g.add_vertex();

        v1.add_edge(&mut v2);
        v1.add_edge(&mut v2);
        v1.add_edge(&mut v2);

        assert_eq!(v1.out_edges.len(), v2.in_edges.len());

        // ensure the vertex and edge pointers are correct
    }
}
<|endoftext|>