<commit_before>use std::borrow::Cow;
use std::sync::RwLock;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::path::Path;
use serialize::Encodable;
use hyper::status::StatusCode::{self, InternalServerError};
use hyper::server::Response as HyperResponse;
use hyper::header::{Date, HttpDate, Server, ContentType, ContentLength, Header, HeaderFormat};
use hyper::net::{Fresh, Streaming};
use time;
use mimes::{get_media_type, MediaType};
use mustache;
use mustache::Template;
use std::io;
use std::io::{Read, Write, copy};
use std::fs::File;
use {NickelError, Halt, MiddlewareResult, Responder};

pub type TemplateCache = RwLock<HashMap<String, Template>>;

///A container for the response
pub struct Response<'a, T=Fresh> {
    ///the original `hyper::server::Response`
    pub origin: HyperResponse<'a, T>,
    templates: &'a TemplateCache
}

impl<'a> Response<'a, Fresh> {
    pub fn from_internal<'c, 'd>(response: HyperResponse<'c, Fresh>,
                                 templates: &'c TemplateCache)
                                -> Response<'c, Fresh> {
        Response {
            origin: response,
            templates: templates
        }
    }

    /// Sets the content type by it's short form.
    /// Returns the response for chaining.
    ///
    /// # Examples
    /// ```{rust}
    /// use nickel::{Request, Response, MiddlewareResult, Continue};
    /// use nickel::mimes::MediaType;
    ///
    /// fn handler<'a>(_: &mut Request, mut res: Response<'a>) -> MiddlewareResult<'a> {
    ///     res.content_type(MediaType::Html);
    ///     Ok(Continue(res))
    /// }
    /// ```
    pub fn content_type(&mut self, mt: MediaType) -> &mut Response<'a> {
        self.origin.headers_mut().set(ContentType(get_media_type(mt)));
        self
    }

    /// Sets the status code and returns the response for chaining
    ///
    /// # Examples
    /// ```{rust}
    /// use nickel::{Request, Response, MiddlewareResult, Continue};
    /// use nickel::status::StatusCode;
    ///
    /// fn handler<'a>(_: &mut Request, mut res: Response<'a>) -> MiddlewareResult<'a> {
    ///     res.set_status(StatusCode::NotFound);
    ///     Ok(Continue(res))
    /// }
    /// ```
    pub fn set_status(&mut self, status: StatusCode) -> &mut Response<'a> {
        *self.origin.status_mut() = status;
        self
    }

    /// Writes a response
    ///
    /// # Examples
    /// ```{rust}
    /// use nickel::{Request, Response, MiddlewareResult, Halt};
    ///
    /// fn handler<'a>(_: &mut Request, res: Response<'a>) -> MiddlewareResult<'a> {
    ///     res.send("hello world")
    /// }
    /// ```
    #[inline]
    pub fn send<T: Responder>(self, data: T) -> MiddlewareResult<'a> {
        data.respond(self)
    }

    /// Writes a file to the output.
    ///
    /// # Examples
    /// ```{rust}
    /// use nickel::{Request, Response, MiddlewareResult, Halt};
    /// use nickel::status::StatusCode;
    /// use std::path::Path;
    ///
    /// fn handler<'a>(_: &mut Request, mut res: Response<'a>) -> MiddlewareResult<'a> {
    ///     let favicon = Path::new("/assets/favicon.ico");
    ///     res.send_file(favicon)
    /// }
    /// ```
    pub fn send_file(mut self, path: &Path) -> MiddlewareResult<'a> {
        // Chunk the response
        self.origin.headers_mut().remove::<ContentLength>();
        // Determine content type by file extension or default to binary
        self.content_type(path.extension()
                              .and_then(|os| os.to_str())
                              .and_then(|s| s.parse().ok())
                              .unwrap_or(MediaType::Bin));

        match File::open(path) {
            Ok(mut file) => {
                let mut stream = try!(self.start());
                match copy(&mut file, &mut stream) {
                    Ok(_) => Ok(Halt(stream)),
                    Err(e) => stream.bail(format!("Failed to send file: {}", e))
                }
            }
            Err(e) => {
                self.error(InternalServerError,
                           format!("Failed to send file '{:?}': {}", path, e))
            }
        }
    }

    // TODO: This needs to be more sophisticated to return the correct headers
    // not just "some headers" :)
    //
    // Also, it should only set them if not already set.
    fn set_fallback_headers(&mut self) {
        self.set_header_fallback(|| Date(HttpDate(time::now_utc())));
        self.set_header_fallback(|| Server("Nickel".to_string()));
        self.set_header_fallback(|| ContentType(get_media_type(MediaType::Html)));
    }

    /// Return an error with the appropriate status code for error handlers to
    /// provide output for.
    pub fn error<T>(self, status: StatusCode, message: T) -> MiddlewareResult<'a>
            where T: Into<Cow<'static, str>> {
        Err(NickelError::new(self, message, status))
    }

    /// Sets the header if not already set.
    ///
    /// If the header is not set then `f` will be called.
    /// Renders the given template bound with the given data.
    ///
    /// # Examples
    /// ```{rust}
    /// # extern crate nickel;
    /// # extern crate hyper;
    ///
    /// # fn main() {
    /// use nickel::{Request, Response, MiddlewareResult, Halt, MediaType, get_media_type};
    /// use hyper::header::ContentType;
    ///
    /// fn handler<'a>(_: &mut Request, mut res: Response<'a>) -> MiddlewareResult<'a> {
    ///     res.content_type(MediaType::Html);
    ///     res.set_header_fallback(|| {
    ///         panic!("Should not get called");
    ///         ContentType(get_media_type(MediaType::Txt))
    ///     });
    ///     res.send("<h1>Hello World</h1>")
    /// }
    /// # }
    /// ```
    pub fn set_header_fallback<F, H>(&mut self, f: F)
            where H: Header + HeaderFormat, F: FnOnce() -> H {
        let headers = self.origin.headers_mut();
        if !headers.has::<H>() { headers.set(f()) }
    }

    /// Renders the given template bound with the given data.
    ///
    /// # Examples
    /// ```{rust}
    /// use std::collections::HashMap;
    /// use nickel::{Request, Response, MiddlewareResult, Halt};
    ///
    /// fn handler<'a>(_: &mut Request, mut res: Response<'a>) -> MiddlewareResult<'a> {
    ///     let mut data = HashMap::new();
    ///     data.insert("name", "user");
    ///     res.render("examples/assets/template.tpl", &data)
    /// }
    /// ```
    pub fn render<T, P>(self, path: P, data: &T) -> MiddlewareResult<'a>
            where T: Encodable, P: AsRef<str> + Into<String> {
        fn render<'a, T>(res: Response<'a>, template: &Template, data: &T)
                -> MiddlewareResult<'a> where T: Encodable {
            let mut stream = try!(res.start());
            match template.render(&mut stream, data) {
                Ok(()) => Ok(Halt(stream)),
                Err(e) => stream.bail(format!("Problem rendering template: {:?}", e))
            }
        }

        // Fast path doesn't need writer lock
        if let Some(t) = self.templates.read().unwrap().get(path.as_ref()) {
            return render(self, t, data);
        }

        // We didn't find the template, get writers lock
        let mut templates = self.templates.write().unwrap();

        // Additional clone required for now as the entry api doesn't give us a key ref
        let path = path.into();

        // Search again incase there was a race to compile the template
        let template = match templates.entry(path.clone()) {
            Vacant(entry) => {
                match mustache::compile_path(&path) {
                    Ok(template) => entry.insert(template),
                    Err(e) => return self.error(InternalServerError,
                                                format!("Failed to compile template: \
                                                        {}.\nReason: {:?}",
                                                        &path, e))
                }
            },
            Occupied(entry) => entry.into_mut()
        };

        render(self, template, data)
    }

    pub fn start(mut self) -> Result<Response<'a, Streaming>, NickelError<'a>> {
        self.set_fallback_headers();

        let Response { origin, templates } = self;
        match origin.start() {
            Ok(origin) => Ok(Response { origin: origin, templates: templates }),
            Err(e) =>
                unsafe {
                    Err(NickelError::without_response(format!("Failed to start response: {}", e)))
                }
        }
    }
}

impl<'a, 'b> Write for Response<'a, Streaming> {
    #[inline(always)]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.origin.write(buf)
    }

    #[inline(always)]
    fn flush(&mut self) -> io::Result<()> {
        self.origin.flush()
    }
}

impl<'a, 'b> Response<'a, Streaming> {
    /// In the case of an unrecoverable error while a stream is already in
    /// progress, there is no standard way to signal to the client that an
    /// error has occurred. `bail` will drop the connection and log an error
    /// message.
    pub fn bail<T>(self, message: T) -> MiddlewareResult<'a>
            where T: Into<Cow<'static, str>> {
        let _ = self.end();
        unsafe { Err(NickelError::without_response(message)) }
    }

    /// Flushes all writing of a response to the client.
    pub fn end(self) -> io::Result<()> {
        self.origin.end()
    }
}

impl <'a, T> Response<'a, T> {
    /// Gets the current status code for this response
    pub fn status(&self) -> StatusCode {
        self.origin.status()
    }
}

#[test]
fn matches_content_type () {
    use hyper::mime::{Mime, TopLevel, SubLevel};
    let path = &Path::new("test.txt");
    let content_type = path.extension()
                           .and_then(|os| os.to_str())
                           .and_then(|s| s.parse().ok());

    assert_eq!(content_type, Some(MediaType::Txt));
    let content_type = content_type.map(get_media_type).unwrap();

    match content_type {
        Mime(TopLevel::Text, SubLevel::Plain, _) => {}, // OK
        wrong => panic!("Wrong mime: {}", wrong)
    }
}
<commit_msg>feat(response): add `headers` to access current Response headers<commit_after>use std::borrow::Cow;
use std::sync::RwLock;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::path::Path;
use serialize::Encodable;
use hyper::status::StatusCode::{self, InternalServerError};
use hyper::server::Response as HyperResponse;
use hyper::header::{
    Headers, Date, HttpDate, Server, ContentType, ContentLength, Header, HeaderFormat
};
use hyper::net::{Fresh, Streaming};
use time;
use mimes::{get_media_type, MediaType};
use mustache;
use mustache::Template;
use std::io;
use std::io::{Read, Write, copy};
use std::fs::File;
use {NickelError, Halt, MiddlewareResult, Responder};

pub type TemplateCache = RwLock<HashMap<String, Template>>;

///A container for the response
pub struct Response<'a, T=Fresh> {
    ///the original `hyper::server::Response`
    pub origin: HyperResponse<'a, T>,
    templates: &'a TemplateCache
}

impl<'a> Response<'a, Fresh> {
    pub fn from_internal<'c, 'd>(response: HyperResponse<'c, Fresh>,
                                 templates: &'c TemplateCache)
                                -> Response<'c, Fresh> {
        Response {
            origin: response,
            templates: templates
        }
    }

    /// Sets the content type by it's short form.
    /// Returns the response for chaining.
    ///
    /// # Examples
    /// ```{rust}
    /// use nickel::{Request, Response, MiddlewareResult, Continue};
    /// use nickel::mimes::MediaType;
    ///
    /// fn handler<'a>(_: &mut Request, mut res: Response<'a>) -> MiddlewareResult<'a> {
    ///     res.content_type(MediaType::Html);
    ///     Ok(Continue(res))
    /// }
    /// ```
    pub fn content_type(&mut self, mt: MediaType) -> &mut Response<'a> {
        self.origin.headers_mut().set(ContentType(get_media_type(mt)));
        self
    }

    /// Sets the status code and returns the response for chaining
    ///
    /// # Examples
    /// ```{rust}
    /// use nickel::{Request, Response, MiddlewareResult, Continue};
    /// use nickel::status::StatusCode;
    ///
    /// fn handler<'a>(_: &mut Request, mut res: Response<'a>) -> MiddlewareResult<'a> {
    ///     res.set_status(StatusCode::NotFound);
    ///     Ok(Continue(res))
    /// }
    /// ```
    pub fn set_status(&mut self, status: StatusCode) -> &mut Response<'a> {
        *self.origin.status_mut() = status;
        self
    }

    /// Writes a response
    ///
    /// # Examples
    /// ```{rust}
    /// use nickel::{Request, Response, MiddlewareResult, Halt};
    ///
    /// fn handler<'a>(_: &mut Request, res: Response<'a>) -> MiddlewareResult<'a> {
    ///     res.send("hello world")
    /// }
    /// ```
    #[inline]
    pub fn send<T: Responder>(self, data: T) -> MiddlewareResult<'a> {
        data.respond(self)
    }

    /// Writes a file to the output.
    ///
    /// # Examples
    /// ```{rust}
    /// use nickel::{Request, Response, MiddlewareResult, Halt};
    /// use nickel::status::StatusCode;
    /// use std::path::Path;
    ///
    /// fn handler<'a>(_: &mut Request, mut res: Response<'a>) -> MiddlewareResult<'a> {
    ///     let favicon = Path::new("/assets/favicon.ico");
    ///     res.send_file(favicon)
    /// }
    /// ```
    pub fn send_file(mut self, path: &Path) -> MiddlewareResult<'a> {
        // Chunk the response
        self.origin.headers_mut().remove::<ContentLength>();
        // Determine content type by file extension or default to binary
        self.content_type(path.extension()
                              .and_then(|os| os.to_str())
                              .and_then(|s| s.parse().ok())
                              .unwrap_or(MediaType::Bin));

        match File::open(path) {
            Ok(mut file) => {
                let mut stream = try!(self.start());
                match copy(&mut file, &mut stream) {
                    Ok(_) => Ok(Halt(stream)),
                    Err(e) => stream.bail(format!("Failed to send file: {}", e))
                }
            }
            Err(e) => {
                self.error(InternalServerError,
                           format!("Failed to send file '{:?}': {}", path, e))
            }
        }
    }

    // TODO: This needs to be more sophisticated to return the correct headers
    // not just "some headers" :)
    //
    // Also, it should only set them if not already set.
    fn set_fallback_headers(&mut self) {
        self.set_header_fallback(|| Date(HttpDate(time::now_utc())));
        self.set_header_fallback(|| Server("Nickel".to_string()));
        self.set_header_fallback(|| ContentType(get_media_type(MediaType::Html)));
    }

    /// Return an error with the appropriate status code for error handlers to
    /// provide output for.
    pub fn error<T>(self, status: StatusCode, message: T) -> MiddlewareResult<'a>
            where T: Into<Cow<'static, str>> {
        Err(NickelError::new(self, message, status))
    }

    /// Sets the header if not already set.
    ///
    /// If the header is not set then `f` will be called.
    /// Renders the given template bound with the given data.
    ///
    /// # Examples
    /// ```{rust}
    /// # extern crate nickel;
    /// # extern crate hyper;
    ///
    /// # fn main() {
    /// use nickel::{Request, Response, MiddlewareResult, Halt, MediaType, get_media_type};
    /// use hyper::header::ContentType;
    ///
    /// fn handler<'a>(_: &mut Request, mut res: Response<'a>) -> MiddlewareResult<'a> {
    ///     res.content_type(MediaType::Html);
    ///     res.set_header_fallback(|| {
    ///         panic!("Should not get called");
    ///         ContentType(get_media_type(MediaType::Txt))
    ///     });
    ///     res.send("<h1>Hello World</h1>")
    /// }
    /// # }
    /// ```
    pub fn set_header_fallback<F, H>(&mut self, f: F)
            where H: Header + HeaderFormat, F: FnOnce() -> H {
        let headers = self.origin.headers_mut();
        if !headers.has::<H>() { headers.set(f()) }
    }

    /// Renders the given template bound with the given data.
    ///
    /// # Examples
    /// ```{rust}
    /// use std::collections::HashMap;
    /// use nickel::{Request, Response, MiddlewareResult, Halt};
    ///
    /// fn handler<'a>(_: &mut Request, mut res: Response<'a>) -> MiddlewareResult<'a> {
    ///     let mut data = HashMap::new();
    ///     data.insert("name", "user");
    ///     res.render("examples/assets/template.tpl", &data)
    /// }
    /// ```
    pub fn render<T, P>(self, path: P, data: &T) -> MiddlewareResult<'a>
            where T: Encodable, P: AsRef<str> + Into<String> {
        fn render<'a, T>(res: Response<'a>, template: &Template, data: &T)
                -> MiddlewareResult<'a> where T: Encodable {
            let mut stream = try!(res.start());
            match template.render(&mut stream, data) {
                Ok(()) => Ok(Halt(stream)),
                Err(e) => stream.bail(format!("Problem rendering template: {:?}", e))
            }
        }

        // Fast path doesn't need writer lock
        if let Some(t) = self.templates.read().unwrap().get(path.as_ref()) {
            return render(self, t, data);
        }

        // We didn't find the template, get writers lock
        let mut templates = self.templates.write().unwrap();

        // Additional clone required for now as the entry api doesn't give us a key ref
        let path = path.into();

        // Search again incase there was a race to compile the template
        let template = match templates.entry(path.clone()) {
            Vacant(entry) => {
                match mustache::compile_path(&path) {
                    Ok(template) => entry.insert(template),
                    Err(e) => return self.error(InternalServerError,
                                                format!("Failed to compile template: \
                                                        {}.\nReason: {:?}",
                                                        &path, e))
                }
            },
            Occupied(entry) => entry.into_mut()
        };

        render(self, template, data)
    }

    pub fn start(mut self) -> Result<Response<'a, Streaming>, NickelError<'a>> {
        self.set_fallback_headers();

        let Response { origin, templates } = self;
        match origin.start() {
            Ok(origin) => Ok(Response { origin: origin, templates: templates }),
            Err(e) =>
                unsafe {
                    Err(NickelError::without_response(format!("Failed to start response: {}", e)))
                }
        }
    }
}

impl<'a, 'b> Write for Response<'a, Streaming> {
    #[inline(always)]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.origin.write(buf)
    }

    #[inline(always)]
    fn flush(&mut self) -> io::Result<()> {
        self.origin.flush()
    }
}

impl<'a, 'b> Response<'a, Streaming> {
    /// In the case of an unrecoverable error while a stream is already in
    /// progress, there is no standard way to signal to the client that an
    /// error has occurred. `bail` will drop the connection and log an error
    /// message.
    pub fn bail<T>(self, message: T) -> MiddlewareResult<'a>
            where T: Into<Cow<'static, str>> {
        let _ = self.end();
        unsafe { Err(NickelError::without_response(message)) }
    }

    /// Flushes all writing of a response to the client.
    pub fn end(self) -> io::Result<()> {
        self.origin.end()
    }
}

impl <'a, T> Response<'a, T> {
    /// The status of this response.
    pub fn status(&self) -> StatusCode {
        self.origin.status()
    }

    /// The headers of this response.
    pub fn headers(&self) -> &Headers {
        self.origin.headers()
    }
}

#[test]
fn matches_content_type () {
    use hyper::mime::{Mime, TopLevel, SubLevel};
    let path = &Path::new("test.txt");
    let content_type = path.extension()
                           .and_then(|os| os.to_str())
                           .and_then(|s| s.parse().ok());

    assert_eq!(content_type, Some(MediaType::Txt));
    let content_type = content_type.map(get_media_type).unwrap();

    match content_type {
        Mime(TopLevel::Text, SubLevel::Plain, _) => {}, // OK
        wrong => panic!("Wrong mime: {}", wrong)
    }
}
<|endoftext|>


<commit_before>//! The module that contains the code handling the HTTP response.

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::convert::From;
use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::io::{Error, ErrorKind};
use std::str;
use std::string::FromUtf8Error;

use curl::easy::Easy;
use mime::Mime;

#[cfg(feature = "rustc-serialization")]
use rustc_serialize;

#[cfg(feature = "serde-serialization")]
use serde;
#[cfg(feature = "serde-serialization")]
use serde_json;

/// Represents an HTTP response.
pub struct Response {
    body: Vec<u8>,
    handle: Easy,
    headers: HashMap<String, String>,
    status_code: u16
}

impl Response {
    /// Creates a `Response` from the results of a successful request.
    ///
    /// You usually don't create a response this way, but get one as result
    /// from `Request.send(...)`.
    pub fn new(mut easy: Easy, headers: Vec<String>, body: Vec<u8>) -> Response {
        let headers =  {
            let mut map: HashMap<String, String> = HashMap::new();
            for header in headers {
                let splitted: Vec<_> = header.splitn(2, ": ")
                                             .map(|part| part.trim())
                                             .filter(|part| part.len() > 0)
                                             .collect();
                if splitted.len() != 2 {
                    continue;
                }

                // For every header, we check whether we've already got an entry
                // with it's key in our dictionary. If so, we append the new value
                // as per https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
                // with a comma.
                match map.entry(splitted[0].to_owned()) {
                    Entry::Occupied(mut e) => {
                        let mut entry = e.get_mut();
                        entry.push_str(", ");
                        entry.push_str(splitted[1]);
                    },
                    Entry::Vacant(e) => {
                        e.insert(splitted[1].to_owned());
                    }
                }
            }
            map
        };
        let status_code = easy.response_code().expect("Failed to get the response status code from cURL.") as u16;
        Response {
            body: body,
            handle: easy,
            headers: headers,
            status_code: status_code
        }
    }

    /// Gets the response body's bytes.
    pub fn body(&self) -> &[u8] {
        &self.body
    }

    /// Gets a mutable reference to the response body's bytes.
    pub fn body_mut(&mut self) -> &mut [u8] {
        &mut self.body
    }

    /// Attempts to read the body as UTF-8 string and returns the result.
    pub fn body_str(&self) -> Option<&str> {
        str::from_utf8(self.body()).ok()
    }

    /// Retreives the content type, if there is one.
    ///
    /// This function also returns none if there has been an error parsing
    /// the mime type.
    pub fn content_type(&self) -> Option<Mime> {
        self.header("Content-Type")
            .and_then(|h| h.parse::<Mime>().ok())
    }

    /// Attempts to get a single header value.
    pub fn header(&self, name: &str) -> Option<&String> {
        self.headers.get(name)
    }

    /// Gets the response headers.
    pub fn headers(&self) -> &HashMap<String, String> {
        &self.headers
    }

    /// Checks whether the returned status code represents a success
    /// (HTTP status code 2xx) or not.
    pub fn is_success(&self) -> bool {
        match self.status_code {
            200...299 => true,
            _ => false
        }
    }

    /// Attempts to decode the response body from JSON to an
    /// object of the given type.
    ///
    /// Returns `ErrorKind::InvalidData` when the server response could not
    /// be read as UTF-8 string or if it could not be deserialized from JSON.
    #[cfg(feature = "rustc-serialization")]
    pub fn json<T: rustc_serialize::Decodable>(&self) -> Result<T, Error> {
        let string = try!(str::from_utf8(&self.body).map_err(|err| Error::new(ErrorKind::InvalidData, err)));
        rustc_serialize::json::decode(string).map_err(|err| Error::new(ErrorKind::InvalidData, err))
    }

    /// Attempts to decode the response body from JSON to an
    /// object of the given type.
    ///
    /// Returns `ErrorKind::InvalidData` when the server response could not
    /// be read as UTF-8 string or if it could not be deserialized from JSON.
    #[cfg(feature = "serde-serialization")]
    pub fn json<T: serde::Deserialize>(&self) -> Result<T, Error> {
        serde_json::from_slice(self.body()).map_err(|err| Error::new(ErrorKind::InvalidData, err))
    }

    /// Attempts to decode the response body from JSON into an abstract
    /// JSON representation.
    ///
    /// Returns `ErrorKind::InvalidData` when the server response could not
    /// be read as UTF-8 string or if it could not be deserialized from JSON.
    #[cfg(feature = "rustc-serialization")]
    pub fn json_value(&self) -> Result<rustc_serialize::json::Json, Error> {
        let string = try!(str::from_utf8(&self.body).map_err(|err| Error::new(ErrorKind::InvalidData, err)));
        rustc_serialize::json::Json::from_str(string).map_err(|err| Error::new(ErrorKind::InvalidData, err))
    }

    /// Attempts to decode the response body from JSON into an abstract
    /// JSON representation.
    ///
    /// Returns `ErrorKind::InvalidData` when the server response could not
    /// be read as UTF-8 string or if it could not be deserialized from JSON.
    #[cfg(feature = "serde-serialization")]
    pub fn json_value(&self) -> Result<serde_json::Value, Error> {
        self.json::<serde_json::Value>()
    }

    /// Consumes the response and returns the underlying cURL handle
    /// used for the request.
    ///
    /// Calling `from()` or `into()` does the same.
    pub fn reuse(self) -> Easy {
        self.handle
    }

    /// Gets the response status code.
    pub fn status_code(&self) -> u16 {
        self.status_code
    }
}

impl Debug for Response {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        fmt.debug_struct(stringify!(Response))
            .field("body_str", &self.body_str())
            .field("headers", &self.headers)
            .field("status_code", &self.status_code)
            .finish()
    }
}

impl From<Response> for Easy {
    fn from(response: Response) -> Self {
        response.reuse()
    }
}

impl From<Response> for Vec<u8> {
    fn from(response: Response) -> Self {
        response.body
    }
}

#[cfg(feature = "response-to-string")]
impl ::std::convert::TryFrom<Response> for String {
    type Err = FromUtf8Error;

    fn try_from(response: Response) -> Result<Self, Self::Err> {
        String::from_utf8(response.body)
    }
}<commit_msg>Remove unused import<commit_after>//! The module that contains the code handling the HTTP response.

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::convert::From;
use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::io::{Error, ErrorKind};
use std::str;

use curl::easy::Easy;
use mime::Mime;

#[cfg(feature = "rustc-serialization")]
use rustc_serialize;

#[cfg(feature = "serde-serialization")]
use serde;
#[cfg(feature = "serde-serialization")]
use serde_json;

/// Represents an HTTP response.
pub struct Response {
    body: Vec<u8>,
    handle: Easy,
    headers: HashMap<String, String>,
    status_code: u16
}

impl Response {
    /// Creates a `Response` from the results of a successful request.
    ///
    /// You usually don't create a response this way, but get one as result
    /// from `Request.send(...)`.
    pub fn new(mut easy: Easy, headers: Vec<String>, body: Vec<u8>) -> Response {
        let headers =  {
            let mut map: HashMap<String, String> = HashMap::new();
            for header in headers {
                let splitted: Vec<_> = header.splitn(2, ": ")
                                             .map(|part| part.trim())
                                             .filter(|part| part.len() > 0)
                                             .collect();
                if splitted.len() != 2 {
                    continue;
                }

                // For every header, we check whether we've already got an entry
                // with it's key in our dictionary. If so, we append the new value
                // as per https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
                // with a comma.
                match map.entry(splitted[0].to_owned()) {
                    Entry::Occupied(mut e) => {
                        let mut entry = e.get_mut();
                        entry.push_str(", ");
                        entry.push_str(splitted[1]);
                    },
                    Entry::Vacant(e) => {
                        e.insert(splitted[1].to_owned());
                    }
                }
            }
            map
        };
        let status_code = easy.response_code().expect("Failed to get the response status code from cURL.") as u16;
        Response {
            body: body,
            handle: easy,
            headers: headers,
            status_code: status_code
        }
    }

    /// Gets the response body's bytes.
    pub fn body(&self) -> &[u8] {
        &self.body
    }

    /// Gets a mutable reference to the response body's bytes.
    pub fn body_mut(&mut self) -> &mut [u8] {
        &mut self.body
    }

    /// Attempts to read the body as UTF-8 string and returns the result.
    pub fn body_str(&self) -> Option<&str> {
        str::from_utf8(self.body()).ok()
    }

    /// Retreives the content type, if there is one.
    ///
    /// This function also returns none if there has been an error parsing
    /// the mime type.
    pub fn content_type(&self) -> Option<Mime> {
        self.header("Content-Type")
            .and_then(|h| h.parse::<Mime>().ok())
    }

    /// Attempts to get a single header value.
    pub fn header(&self, name: &str) -> Option<&String> {
        self.headers.get(name)
    }

    /// Gets the response headers.
    pub fn headers(&self) -> &HashMap<String, String> {
        &self.headers
    }

    /// Checks whether the returned status code represents a success
    /// (HTTP status code 2xx) or not.
    pub fn is_success(&self) -> bool {
        match self.status_code {
            200...299 => true,
            _ => false
        }
    }

    /// Attempts to decode the response body from JSON to an
    /// object of the given type.
    ///
    /// Returns `ErrorKind::InvalidData` when the server response could not
    /// be read as UTF-8 string or if it could not be deserialized from JSON.
    #[cfg(feature = "rustc-serialization")]
    pub fn json<T: rustc_serialize::Decodable>(&self) -> Result<T, Error> {
        let string = try!(str::from_utf8(&self.body).map_err(|err| Error::new(ErrorKind::InvalidData, err)));
        rustc_serialize::json::decode(string).map_err(|err| Error::new(ErrorKind::InvalidData, err))
    }

    /// Attempts to decode the response body from JSON to an
    /// object of the given type.
    ///
    /// Returns `ErrorKind::InvalidData` when the server response could not
    /// be read as UTF-8 string or if it could not be deserialized from JSON.
    #[cfg(feature = "serde-serialization")]
    pub fn json<T: serde::Deserialize>(&self) -> Result<T, Error> {
        serde_json::from_slice(self.body()).map_err(|err| Error::new(ErrorKind::InvalidData, err))
    }

    /// Attempts to decode the response body from JSON into an abstract
    /// JSON representation.
    ///
    /// Returns `ErrorKind::InvalidData` when the server response could not
    /// be read as UTF-8 string or if it could not be deserialized from JSON.
    #[cfg(feature = "rustc-serialization")]
    pub fn json_value(&self) -> Result<rustc_serialize::json::Json, Error> {
        let string = try!(str::from_utf8(&self.body).map_err(|err| Error::new(ErrorKind::InvalidData, err)));
        rustc_serialize::json::Json::from_str(string).map_err(|err| Error::new(ErrorKind::InvalidData, err))
    }

    /// Attempts to decode the response body from JSON into an abstract
    /// JSON representation.
    ///
    /// Returns `ErrorKind::InvalidData` when the server response could not
    /// be read as UTF-8 string or if it could not be deserialized from JSON.
    #[cfg(feature = "serde-serialization")]
    pub fn json_value(&self) -> Result<serde_json::Value, Error> {
        self.json::<serde_json::Value>()
    }

    /// Consumes the response and returns the underlying cURL handle
    /// used for the request so that it can be reused.
    ///
    /// Calling `from()` or `into()` does the same.
    pub fn reuse(self) -> Easy {
        self.handle
    }

    /// Gets the response status code.
    pub fn status_code(&self) -> u16 {
        self.status_code
    }
}

impl Debug for Response {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        fmt.debug_struct(stringify!(Response))
            .field("body_str", &self.body_str())
            .field("headers", &self.headers)
            .field("status_code", &self.status_code)
            .finish()
    }
}

impl From<Response> for Easy {
    fn from(response: Response) -> Self {
        response.reuse()
    }
}

impl From<Response> for Vec<u8> {
    fn from(response: Response) -> Self {
        response.body
    }
}

#[cfg(feature = "response-to-string")]
impl ::std::convert::TryFrom<Response> for String {
    type Err = ::std::string::FromUtf8Error;

    fn try_from(response: Response) -> Result<Self, Self::Err> {
        String::from_utf8(response.body)
    }
}<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate piston_window;
extern crate sdl2_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;

use std::cell::RefCell;
use std::rc::Rc;
use std::path::Path;
use piston::window::WindowSettings;
use piston::event::*;
use gfx_graphics::{ Texture, TextureSettings };
use sdl2_window::{ Sdl2Window, OpenGL };
use graphics::draw_state::BlendPreset;
use piston_window::*;

fn main() {
    println!("Press A to change blending");

    let window = Rc::new(RefCell::new(
        Sdl2Window::new(
            OpenGL::_3_2,
            WindowSettings::new(
                "gfx_graphics: draw_state_test",
                [600, 600]
            )
            .exit_on_esc(true)
        )
    ));

    let events = PistonWindow::new(window, empty_app());
    let mut blend = BlendPreset::Alpha;
    let rust_logo = Texture::from_path(&mut events.canvas.borrow_mut().factory,
                                       &Path::new("./assets/rust.png"),
                                       &TextureSettings::new()).unwrap();
    for e in events {
        use piston::input::*;
        use graphics::*;

        e.draw_2d(|c, g| {
            clear([0.8, 0.8, 0.8, 1.0], g);
            Rectangle::new([1.0, 0.0, 0.0, 1.0])
                .draw([0.0, 0.0, 100.0, 100.0],
                      &c.draw_state,
                      c.transform,
                      g);

            let draw_state = c.draw_state.blend(blend);
            Rectangle::new([0.5, 1.0, 0.0, 0.3])
                .draw([50.0, 50.0, 100.0, 100.0],
                      &draw_state,
                      c.transform,
                      g);

            let transform = c.transform.trans(100.0, 100.0);
            // Compute clip rectangle from upper left corner.
            let (clip_x, clip_y, clip_w, clip_h) = (100, 100, 100, 100);
            let (clip_x, clip_y, clip_w, clip_h) =
                (clip_x, c.viewport.unwrap().draw_size[1] as u16 - clip_y - clip_h, clip_w, clip_h);
            let clipped = c.draw_state.scissor(clip_x, clip_y, clip_w, clip_h);
            Image::new().draw(&rust_logo, &clipped, transform, g);

            let transform = c.transform.trans(200.0, 200.0);
            Ellipse::new([1.0, 0.0, 0.0, 1.0])
                .draw([0.0, 0.0, 50.0, 50.0],
                      clip_draw_state(),
                      transform,
                      g);
            Image::new().draw(&rust_logo, inside_draw_state(), transform, g);
        });

        if let Some(Button::Keyboard(Key::A)) = e.press_args() {
            blend = match blend {
                BlendPreset::Alpha => BlendPreset::Add,
                BlendPreset::Add => BlendPreset::Multiply,
                BlendPreset::Multiply => BlendPreset::Invert,
                BlendPreset::Invert => BlendPreset::Alpha,
            };
            println!("Changed blending to {:?}", blend);
        }
    }
}
<commit_msg>Clear stencil buffer<commit_after>extern crate piston;
extern crate graphics;
extern crate piston_window;
extern crate sdl2_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;

use std::cell::RefCell;
use std::rc::Rc;
use std::path::Path;
use piston::window::WindowSettings;
use piston::event::*;
use gfx_graphics::{ Texture, TextureSettings };
use sdl2_window::{ Sdl2Window, OpenGL };
use graphics::draw_state::BlendPreset;
use piston_window::*;

fn main() {
    println!("Press A to change blending");

    let window = Rc::new(RefCell::new(
        Sdl2Window::new(
            OpenGL::_3_2,
            WindowSettings::new(
                "gfx_graphics: draw_state_test",
                [600, 600]
            )
            .exit_on_esc(true)
        )
    ));

    let events = PistonWindow::new(window, empty_app());
    let mut blend = BlendPreset::Alpha;
    let rust_logo = Texture::from_path(&mut events.canvas.borrow_mut().factory,
                                       &Path::new("./assets/rust.png"),
                                       &TextureSettings::new()).unwrap();
    for e in events {
        use piston::input::*;
        use graphics::*;

        e.draw_2d(|c, g| {
            clear([0.8, 0.8, 0.8, 1.0], g);
            g.clear_stencil(0);
            Rectangle::new([1.0, 0.0, 0.0, 1.0])
                .draw([0.0, 0.0, 100.0, 100.0],
                      &c.draw_state,
                      c.transform,
                      g);

            let draw_state = c.draw_state.blend(blend);
            Rectangle::new([0.5, 1.0, 0.0, 0.3])
                .draw([50.0, 50.0, 100.0, 100.0],
                      &draw_state,
                      c.transform,
                      g);

            let transform = c.transform.trans(100.0, 100.0);
            // Compute clip rectangle from upper left corner.
            let (clip_x, clip_y, clip_w, clip_h) = (100, 100, 100, 100);
            let (clip_x, clip_y, clip_w, clip_h) =
                (clip_x, c.viewport.unwrap().draw_size[1] as u16 - clip_y - clip_h, clip_w, clip_h);
            let clipped = c.draw_state.scissor(clip_x, clip_y, clip_w, clip_h);
            Image::new().draw(&rust_logo, &clipped, transform, g);

            let transform = c.transform.trans(200.0, 200.0);
            Ellipse::new([1.0, 0.0, 0.0, 1.0])
                .draw([0.0, 0.0, 50.0, 50.0],
                      clip_draw_state(),
                      transform,
                      g);
            Image::new().draw(&rust_logo, inside_draw_state(), transform, g);
        });

        if let Some(Button::Keyboard(Key::A)) = e.press_args() {
            blend = match blend {
                BlendPreset::Alpha => BlendPreset::Add,
                BlendPreset::Add => BlendPreset::Multiply,
                BlendPreset::Multiply => BlendPreset::Invert,
                BlendPreset::Invert => BlendPreset::Alpha,
            };
            println!("Changed blending to {:?}", blend);
        }
    }
}
<|endoftext|>


<commit_before>//
// base64.rs - base64 implementation
//
// The Base64 Alphabet
//
//  Value Encoding  Value Encoding  Value Encoding  Value Encoding
//   0 A            17 R            34 i            51 z
//   1 B            18 S            35 j            52 0
//   2 C            19 T            36 k            53 1
//   3 D            20 U            37 l            54 2
//   4 E            21 V            38 m            55 3
//   5 F            22 W            39 n            56 4
//   6 G            23 X            40 o            57 5
//   7 H            24 Y            41 p            58 6
//   8 I            25 Z            42 q            59 7
//   9 J            26 a            43 r            60 8
//  10 K            27 b            44 s            61 9
//  11 L            28 c            45 t            62 +
//  12 M            29 d            46 u            63 /
//  13 N            30 e            47 v
//  14 O            31 f            48 w         (pad) =
//  15 P            32 g            49 x
//  16 Q            33 h            50 y
//

use std;

import std::map;

export base64, mk;

const padd: u8 = 61u8;

iface base64 {
    fn encode(src: [u8]) -> [u8];
    fn decode(src: [u8]) -> [u8];
    fn urlsafe_encode(src: [u8]) -> [u8];
    fn urlsafe_decode(src: [u8]) -> [u8];
}

fn mk() -> base64 {
    type _base64 = {table: [u8]};

    impl of base64 for _base64 {
        fn encode(src: [u8]) -> [u8] {
            b64encode(self.table + [43u8, 47u8], src)
        }
        fn decode(src: [u8]) -> [u8] {
            b64decode(self.table + [43u8, 47u8], src)
        }
        fn urlsafe_encode(src: [u8]) -> [u8] {
            b64encode(self.table + [45u8, 95u8], src)
        }
        fn urlsafe_decode(src: [u8]) -> [u8] {
            b64decode(self.table + [45u8, 95u8], src)
        }
    }

    let table = vec::init_elt_mut(62u, 0u8), i = 0u8;
    u8::range(65u8, 91u8)  { |j| table[i] = j; i += 1u8; }
    u8::range(97u8, 123u8) { |j| table[i] = j; i += 1u8; }
    u8::range(48u8, 58u8)  { |j| table[i] = j; i += 1u8; }

    {table: vec::from_mut(table)} as base64
}

inline fn b64idx(x: u8, y: u8, z: u8) -> u8 {
    if 65u8 <= x && x <= 90u8 { x - 65u8 }
    else if 97u8 <= x && x <= 122u8 { x - 97u8 + 26u8 }
    else if 48u8 <= x && x <= 58u8  { x - 48u8 + 52u8 }
    else if x == y { 62u8 }
    else if x == z { 63u8 }
    else { fail "malformed base64 string"; }
}

fn b64encode(table: [u8], src: [u8]) -> [u8] {
    let srclen = vec::len(src);
    let targ = if srclen % 3u == 0u {
        vec::init_elt_mut((srclen / 3u) * 4u, 0u8)
    } else {
        vec::init_elt_mut((srclen / 3u + 1u) * 4u, 0u8)
    };
    let input = vec::init_elt_mut(3u, 0u8);
    let output = vec::init_elt_mut(4u, 0u8);
    let curr = 0u, src_curr = 0u;

    while srclen > 2u {
        input[0] = src[src_curr];
        input[1] = src[src_curr + 1u];
        input[2] = src[src_curr + 2u];
        srclen -= 3u; src_curr += 3u;

        output[0] = input[0] >> 2u8;
        output[1] = ((input[0] &  3u8) << 4u8) | (input[1] >> 4u8);
        output[2] = ((input[1] & 15u8) << 2u8) | (input[2] >> 6u8);
        output[3] = input[2] & 63u8;

        targ[curr] = table[output[0]]; curr += 1u;
        targ[curr] = table[output[1]]; curr += 1u;
        targ[curr] = table[output[2]]; curr += 1u;
        targ[curr] = table[output[3]]; curr += 1u;
    }

    if srclen != 0u {
        input[0] = 0u8; input[1] = 0u8; input[2] = 0u8;

        alt srclen {
          1u {input[0] = src[src_curr];}
          2u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];}
          _  { }
        }

        output[0] = input[0] >> 2u8;
        output[1] = ((input[0] &  3u8) << 4u8) | (input[1] >> 4u8);
        output[2] = ((input[1] & 15u8) << 2u8) | (input[2] >> 6u8);

        targ[curr] = table[output[0]]; curr += 1u;
        targ[curr] = table[output[1]]; curr += 1u;
        targ[curr] = if srclen == 1u { padd } else { table[output[2]] };
        curr += 1u; targ[curr] = padd;
    }

    vec::from_mut(targ)
}

fn b64decode(table: [u8], src: [u8]) -> [u8] {
    let srclen = vec::len(src);

    if srclen % 4u != 0u { fail "malformed base64 string"; }
    if srclen == 0u { ret []; }

    let input  = vec::init_elt_mut(4u, 0u8);
    let output = vec::init_elt_mut(4u, 0u8);
    let targ = if src[srclen - 2u] == padd {
        vec::init_elt_mut(srclen / 4u * 3u - 2u, 0u8)
    } else if src[srclen - 1u] == padd {
        vec::init_elt_mut(srclen / 4u * 3u - 1u, 0u8)
    } else {
        vec::init_elt_mut(srclen / 4u * 3u, 0u8)
    };
    let curr = 0u, src_curr = 0u;

    while srclen > 4u {
        input[0] = src[src_curr];
        input[1] = src[src_curr + 1u];
        input[2] = src[src_curr + 2u];
        input[3] = src[src_curr + 3u];
        srclen -= 4u; src_curr += 4u;

        output[0] = b64idx(input[0], table[62], table[63]);
        output[1] = b64idx(input[1], table[62], table[63]);
        output[2] = b64idx(input[2], table[62], table[63]);
        output[3] = b64idx(input[3], table[62], table[63]);

        targ[curr] = (output[0] << 2u8) | (output[1] >> 4u8);
        curr += 1u;

        targ[curr] = ((output[1] & 15u8) << 4u8) | (output[2] >> 2u8);
        curr += 1u;

        targ[curr] = ((output[2] &  3u8) << 6u8) | output[3];
        curr += 1u;
    }

    if srclen == 4u {
        input[0] = src[src_curr];
        input[1] = src[src_curr + 1u];
        input[2] = src[src_curr + 2u];
        input[3] = src[src_curr + 3u];

        output[0] = b64idx(input[0], table[62], table[63]);
        output[1] = b64idx(input[1], table[62], table[63]);

        targ[curr] = (output[0] << 2u8) | (output[1] >> 4u8);
        curr += 1u;

        if input[2] == padd { ret vec::from_mut(targ); }

        output[2] = b64idx(input[2], table[62], table[63]);

        targ[curr] = ((output[1] & 15u8) << 4u8) | (output[2] >> 2u8);
        curr += 1u;

        if input[3] == padd { ret vec::from_mut(targ); }

        output[3] = b64idx(input[3], table[62], table[63]);

        targ[curr] = ((output[2] & 3u8) << 6u8) | output[3];
    }

    vec::from_mut(targ)
}

#[cfg(test)]
mod tests {
    import core::str::{from_bytes, bytes};
    enum mode {
        t_decode,
        t_encode,
        t_urlsafe_encode,
        t_urlsafe_decode
    }
    fn setup(t: mode) -> map::hashmap<str, str> {
        let m = map::new_str_hash::<str>();
        m.insert("", "");
        alt t {
          t_decode | t_urlsafe_decode {
            m.insert("cGxlYXN1cmUu", "pleasure.");
            m.insert("bGVhc3VyZS4=",  "leasure.");
            m.insert("ZWFzdXJlLg==",   "easure.");
            m.insert("YXN1cmUu",        "asure.");
            m.insert("c3VyZS4=",         "sure.");
          }
          t_encode | t_urlsafe_encode {
            m.insert("pleasure.", "cGxlYXN1cmUu");
            m.insert("leasure.",  "bGVhc3VyZS4=");
            m.insert("easure.",   "ZWFzdXJlLg==");
            m.insert("asure.",        "YXN1cmUu");
            m.insert("sure.",         "c3VyZS4=");
          }
        }
        m
    }
    fn do_test(t: mode) {
        let b64 = mk();
        let m = setup(t);
        m.keys { |k|
            let expected = m.get(k);
            let actual = alt t {
              t_decode { from_bytes(b64.decode(bytes(k))) }
              t_encode { from_bytes(b64.encode(bytes(k))) }
              t_urlsafe_decode { from_bytes(b64.urlsafe_decode(bytes(k))) }
              t_urlsafe_encode { from_bytes(b64.urlsafe_encode(bytes(k))) }
            };
            #debug("expected: %s", expected);
            #debug("actual:   %s", actual);
            assert expected == actual;
        }
    }
    #[test]
    fn decode() { do_test(t_decode); }
    #[test]
    fn encode() { do_test(t_encode); }
    #[test]
    fn urlsafe_decode() { do_test(t_urlsafe_decode); }
    #[test]
    fn urlsafe_encode() { do_test(t_urlsafe_encode); }
}
<commit_msg>add comment to base64.rs<commit_after>//
// base64.rs - base64 implementation
//
// The Base64 Alphabet
//
//  Value Encoding  Value Encoding  Value Encoding  Value Encoding
//   0 A            17 R            34 i            51 z
//   1 B            18 S            35 j            52 0
//   2 C            19 T            36 k            53 1
//   3 D            20 U            37 l            54 2
//   4 E            21 V            38 m            55 3
//   5 F            22 W            39 n            56 4
//   6 G            23 X            40 o            57 5
//   7 H            24 Y            41 p            58 6
//   8 I            25 Z            42 q            59 7
//   9 J            26 a            43 r            60 8
//  10 K            27 b            44 s            61 9
//  11 L            28 c            45 t            62 +
//  12 M            29 d            46 u            63 /
//  13 N            30 e            47 v
//  14 O            31 f            48 w         (pad) =
//  15 P            32 g            49 x
//  16 Q            33 h            50 y
//
// The "URL and Filename safe" Base 64 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 A            17 R            34 i            51 z
//     1 B            18 S            35 j            52 0
//     2 C            19 T            36 k            53 1
//     3 D            20 U            37 l            54 2
//     4 E            21 V            38 m            55 3
//     5 F            22 W            39 n            56 4
//     6 G            23 X            40 o            57 5
//     7 H            24 Y            41 p            58 6
//     8 I            25 Z            42 q            59 7
//     9 J            26 a            43 r            60 8
//    10 K            27 b            44 s            61 9
//    11 L            28 c            45 t            62 - (minus)
//    12 M            29 d            46 u            63 _
//    13 N            30 e            47 v           (underline)
//    14 O            31 f            48 w
//    15 P            32 g            49 x
//    16 Q            33 h            50 y         (pad) =
//

use std;

import std::map;

export base64, mk;

const padd: u8 = 61u8;

iface base64 {
    fn encode(src: [u8]) -> [u8];
    fn decode(src: [u8]) -> [u8];
    fn urlsafe_encode(src: [u8]) -> [u8];
    fn urlsafe_decode(src: [u8]) -> [u8];
}

fn mk() -> base64 {
    type _base64 = {table: [u8]};

    impl of base64 for _base64 {
        fn encode(src: [u8]) -> [u8] {
            b64encode(self.table + [43u8, 47u8], src)
        }
        fn decode(src: [u8]) -> [u8] {
            b64decode(self.table + [43u8, 47u8], src)
        }
        fn urlsafe_encode(src: [u8]) -> [u8] {
            b64encode(self.table + [45u8, 95u8], src)
        }
        fn urlsafe_decode(src: [u8]) -> [u8] {
            b64decode(self.table + [45u8, 95u8], src)
        }
    }

    let table = vec::init_elt_mut(62u, 0u8), i = 0u8;
    u8::range(65u8, 91u8)  { |j| table[i] = j; i += 1u8; }
    u8::range(97u8, 123u8) { |j| table[i] = j; i += 1u8; }
    u8::range(48u8, 58u8)  { |j| table[i] = j; i += 1u8; }

    {table: vec::from_mut(table)} as base64
}

inline fn b64idx(x: u8, y: u8, z: u8) -> u8 {
    if 65u8 <= x && x <= 90u8 { x - 65u8 }
    else if 97u8 <= x && x <= 122u8 { x - 97u8 + 26u8 }
    else if 48u8 <= x && x <= 58u8  { x - 48u8 + 52u8 }
    else if x == y { 62u8 }
    else if x == z { 63u8 }
    else { fail "malformed base64 string"; }
}

fn b64encode(table: [u8], src: [u8]) -> [u8] {
    let srclen = vec::len(src);
    let targ = if srclen % 3u == 0u {
        vec::init_elt_mut((srclen / 3u) * 4u, 0u8)
    } else {
        vec::init_elt_mut((srclen / 3u + 1u) * 4u, 0u8)
    };
    let input = vec::init_elt_mut(3u, 0u8);
    let output = vec::init_elt_mut(4u, 0u8);
    let curr = 0u, src_curr = 0u;

    while srclen > 2u {
        input[0] = src[src_curr];
        input[1] = src[src_curr + 1u];
        input[2] = src[src_curr + 2u];
        srclen -= 3u; src_curr += 3u;

        output[0] = input[0] >> 2u8;
        output[1] = ((input[0] &  3u8) << 4u8) | (input[1] >> 4u8);
        output[2] = ((input[1] & 15u8) << 2u8) | (input[2] >> 6u8);
        output[3] = input[2] & 63u8;

        targ[curr] = table[output[0]]; curr += 1u;
        targ[curr] = table[output[1]]; curr += 1u;
        targ[curr] = table[output[2]]; curr += 1u;
        targ[curr] = table[output[3]]; curr += 1u;
    }

    if srclen != 0u {
        input[0] = 0u8; input[1] = 0u8; input[2] = 0u8;

        alt srclen {
          1u {input[0] = src[src_curr];}
          2u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];}
          _  { }
        }

        output[0] = input[0] >> 2u8;
        output[1] = ((input[0] &  3u8) << 4u8) | (input[1] >> 4u8);
        output[2] = ((input[1] & 15u8) << 2u8) | (input[2] >> 6u8);

        targ[curr] = table[output[0]]; curr += 1u;
        targ[curr] = table[output[1]]; curr += 1u;
        targ[curr] = if srclen == 1u { padd } else { table[output[2]] };
        curr += 1u; targ[curr] = padd;
    }

    vec::from_mut(targ)
}

fn b64decode(table: [u8], src: [u8]) -> [u8] {
    let srclen = vec::len(src);

    if srclen % 4u != 0u { fail "malformed base64 string"; }
    if srclen == 0u { ret []; }

    let input  = vec::init_elt_mut(4u, 0u8);
    let output = vec::init_elt_mut(4u, 0u8);
    let targ = if src[srclen - 2u] == padd {
        vec::init_elt_mut(srclen / 4u * 3u - 2u, 0u8)
    } else if src[srclen - 1u] == padd {
        vec::init_elt_mut(srclen / 4u * 3u - 1u, 0u8)
    } else {
        vec::init_elt_mut(srclen / 4u * 3u, 0u8)
    };
    let curr = 0u, src_curr = 0u;

    while srclen > 4u {
        input[0] = src[src_curr];
        input[1] = src[src_curr + 1u];
        input[2] = src[src_curr + 2u];
        input[3] = src[src_curr + 3u];
        srclen -= 4u; src_curr += 4u;

        output[0] = b64idx(input[0], table[62], table[63]);
        output[1] = b64idx(input[1], table[62], table[63]);
        output[2] = b64idx(input[2], table[62], table[63]);
        output[3] = b64idx(input[3], table[62], table[63]);

        targ[curr] = (output[0] << 2u8) | (output[1] >> 4u8);
        curr += 1u;

        targ[curr] = ((output[1] & 15u8) << 4u8) | (output[2] >> 2u8);
        curr += 1u;

        targ[curr] = ((output[2] &  3u8) << 6u8) | output[3];
        curr += 1u;
    }

    if srclen == 4u {
        input[0] = src[src_curr];
        input[1] = src[src_curr + 1u];
        input[2] = src[src_curr + 2u];
        input[3] = src[src_curr + 3u];

        output[0] = b64idx(input[0], table[62], table[63]);
        output[1] = b64idx(input[1], table[62], table[63]);

        targ[curr] = (output[0] << 2u8) | (output[1] >> 4u8);
        curr += 1u;

        if input[2] == padd { ret vec::from_mut(targ); }

        output[2] = b64idx(input[2], table[62], table[63]);

        targ[curr] = ((output[1] & 15u8) << 4u8) | (output[2] >> 2u8);
        curr += 1u;

        if input[3] == padd { ret vec::from_mut(targ); }

        output[3] = b64idx(input[3], table[62], table[63]);

        targ[curr] = ((output[2] & 3u8) << 6u8) | output[3];
    }

    vec::from_mut(targ)
}

#[cfg(test)]
mod tests {
    import core::str::{from_bytes, bytes};
    enum mode {
        t_decode,
        t_encode,
        t_urlsafe_encode,
        t_urlsafe_decode
    }
    fn setup(t: mode) -> map::hashmap<str, str> {
        let m = map::new_str_hash::<str>();
        m.insert("", "");
        alt t {
          t_decode | t_urlsafe_decode {
            m.insert("cGxlYXN1cmUu", "pleasure.");
            m.insert("bGVhc3VyZS4=",  "leasure.");
            m.insert("ZWFzdXJlLg==",   "easure.");
            m.insert("YXN1cmUu",        "asure.");
            m.insert("c3VyZS4=",         "sure.");
          }
          t_encode | t_urlsafe_encode {
            m.insert("pleasure.", "cGxlYXN1cmUu");
            m.insert("leasure.",  "bGVhc3VyZS4=");
            m.insert("easure.",   "ZWFzdXJlLg==");
            m.insert("asure.",        "YXN1cmUu");
            m.insert("sure.",         "c3VyZS4=");
          }
        }
        m
    }
    fn do_test(t: mode) {
        let b64 = mk();
        let m = setup(t);
        m.keys { |k|
            let expected = m.get(k);
            let actual = alt t {
              t_decode { from_bytes(b64.decode(bytes(k))) }
              t_encode { from_bytes(b64.encode(bytes(k))) }
              t_urlsafe_decode { from_bytes(b64.urlsafe_decode(bytes(k))) }
              t_urlsafe_encode { from_bytes(b64.urlsafe_encode(bytes(k))) }
            };
            #debug("expected: %s", expected);
            #debug("actual:   %s", actual);
            assert expected == actual;
        }
    }
    #[test]
    fn decode() { do_test(t_decode); }
    #[test]
    fn encode() { do_test(t_encode); }
    #[test]
    fn urlsafe_decode() { do_test(t_urlsafe_decode); }
    #[test]
    fn urlsafe_encode() { do_test(t_urlsafe_encode); }
}
<|endoftext|>


<commit_before>use proc_macro2::{Span, TokenStream};
use shared::{map_lifetimes, map_type_params, split_for_impl};
use syn::{
    self, Data, DataEnum, DataStruct, DeriveInput, Field, Fields, FieldsNamed, FieldsUnnamed,
    Generics, Ident, Variant,
};

use attr;

pub fn derive(input: TokenStream) -> TokenStream {
    let derive_input = syn::parse2(input).expect("Input is checked by rustc");

    let container = attr::Container::from_ast(&derive_input);

    let DeriveInput {
        ident,
        data,
        generics,
        ..
    } = derive_input;

    let tokens = match data {
        Data::Struct(ast) => derive_struct(&container, ast, ident, generics),
        Data::Enum(ast) => derive_enum(&container, ast, ident, generics),
        Data::Union(_) => panic!("Unions are not supported"),
    };

    tokens.into()
}

fn derive_struct(
    container: &attr::Container,
    ast: DataStruct,
    ident: Ident,
    generics: Generics,
) -> TokenStream {
    let cons = match ast.fields {
        Fields::Named(FieldsNamed { named, .. }) => gen_struct_cons(&ident, named),
        Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => gen_tuple_struct_cons(&ident, unnamed),
        Fields::Unit => quote! { #ident },
    };

    gen_impl(container, ident, generics, cons)
}

fn gen_struct_cons<I>(ident: &Ident, fields: I) -> TokenStream
where
    I: IntoIterator<Item = Field>,
{
    // lookup each field by its name and then convert to its type using the Getable
    // impl of the fields type
    let field_initializers = fields.into_iter().map(|field| {
        let field_ty = &field.ty;
        let ident = field
            .ident
            .as_ref()
            .expect("Struct fields always have names");
        let quoted_ident = format!("{}", quote! { #ident });

        quote! {
            #ident: if let Some(val) = data.lookup_field(vm, #quoted_ident) {
                <#field_ty as _gluon_api::Getable<'__vm, '__value>>::from_value(vm, val)
            } else {
                panic!("Cannot find the field '{}'. Do the type definitions match?", #quoted_ident);
            }
        }
    });

    let unpack_data = unpack_data();
    quote! {
        #unpack_data

        #ident {
            #(#field_initializers,)*
        }
    }
}

fn gen_tuple_struct_cons<I>(ident: &Ident, fields: I) -> TokenStream
where
    I: IntoIterator<Item = Field>,
{
    let mut fields = fields.into_iter().fuse();

    // Treat newtype structs as just their inner type
    let (first, second) = (fields.next(), fields.next());
    match (&first, &second) {
        (Some(field_ty), None) => {
            return quote! {
                #ident (
                <#field_ty as _gluon_api::Getable<'__vm, '__value>>::from_value(vm, variants)
                )
            }
        }
        _ => (),
    }

    // do the lookup using the tag, because tuple structs don't have field names
    let field_initializers = first
        .into_iter()
        .chain(second)
        .chain(fields)
        .enumerate()
        .map(|(tag, field)| {
            let field_ty = &field.ty;

            quote! {
                if let Some(val) = data.get_variant(#tag) {
                    <#field_ty as _gluon_api::Getable<'__vm, '__value>>::from_value(vm, val)
                } else {
                    panic!("Cannot find the field with tag '{}'. Do the type definitions match?", #tag);
                }
            }
        });

    let unpack_data = unpack_data();
    quote! {
        #unpack_data

        #ident (
            #(#field_initializers,)*
        )
    }
}

fn derive_enum(
    container: &attr::Container,
    ast: DataEnum,
    ident: Ident,
    generics: Generics,
) -> TokenStream {
    let cons;
    {
        let variants = ast
            .variants
            .iter()
            .enumerate()
            .map(|(tag, variant)| gen_variant_match(&ident, tag, variant));

        let unpack_data = unpack_data();

        // data contains the the data for each field of a variant; the variant of the passed value
        // is defined by the tag(), which is defined by order of the variants (the first variant is 0)
        cons = quote! {
            #unpack_data

            match data.tag() as usize {
                #(#variants,)*
                tag => panic!("Unexpected tag: '{}'. Do the type definitions match?", tag)
            }
        };
    }

    gen_impl(container, ident, generics, cons)
}

fn gen_impl(
    container: &attr::Container,
    ident: Ident,
    generics: Generics,
    push_impl: TokenStream,
) -> TokenStream {
    // lifetime bounds like '__vm: 'a, 'a: '__vm (which implies => 'a == '__vm)
    // writing bounds like this is a lot easier than actually replacing all lifetimes
    // with '__vm
    let lifetime_bounds = create_lifetime_bounds(&generics);

    // generate bounds like T: Getable for every type parameter
    let getable_bounds = create_getable_bounds(&generics);

    let (impl_generics, ty_generics, where_clause) =
        split_for_impl(&generics, &["'__vm", "'__value"]);

    let dummy_const = Ident::new(&format!("_IMPL_GETABLE_FOR_{}", ident), Span::call_site());

    let gluon = match container.crate_name {
        attr::CrateName::Some(ref ident) => quote!{
            use #ident::api as _gluon_api;
            use #ident::thread as _gluon_thread;
            use #ident::Variants as _GluonVariants;
        },
        attr::CrateName::GluonVm => quote!{
            use api as _gluon_api;
            use thread as _gluon_thread;
            use Variants as _GluonVariants;
        },
        attr::CrateName::None => quote!{
            use gluon::vm::api as _gluon_api;
            use gluon::vm::thread as _gluon_thread;
            use gluon::vm::Variants as _GluonVariants;
        },
    };

    quote! {
        #[allow(non_upper_case_globals)]
        const #dummy_const: () = {
            #gluon

            #[automatically_derived]
            #[allow(unused_attributes, unused_variables)]
            impl #impl_generics _gluon_api::Getable<'__vm, '__value> for #ident #ty_generics
            #where_clause #(#getable_bounds,)* #(#lifetime_bounds),*
            {
                fn from_value(vm: &'__vm _gluon_thread::Thread, variants: _GluonVariants<'__value>) -> Self {
                    #push_impl
                }
            }
        };
    }
}

fn gen_variant_match(ident: &Ident, tag: usize, variant: &Variant) -> TokenStream {
    let variant_ident = &variant.ident;

    // depending on the type of the variant we need to generate different constructors
    // for the enum
    match &variant.fields {
        Fields::Unit => quote! {
            #tag => #ident::#variant_ident
        },
        // both constructors that need to marshall values extract them by using the index
        // of the field to get the content from Data::get_variant;
        // the data variable was assigned in the function body above
        Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
            let cons = gen_tuple_variant_cons(unnamed);

            quote! {
                #tag => #ident::#variant_ident#cons
            }
        }
        Fields::Named(FieldsNamed { named, .. }) => {
            let cons = gen_struct_variant_cons(named);

            quote! {
                #tag => #ident::#variant_ident#cons
            }
        }
    }
}

fn gen_tuple_variant_cons<'a, I>(fields: I) -> TokenStream
where
    I: IntoIterator<Item = &'a Field>,
{
    let fields = fields.into_iter().enumerate().map(|(idx, field)| {
        let field_ty = &field.ty;

        quote! {
            if let Some(val) = data.get_variant(#idx) {
                <#field_ty as _gluon_api::Getable<'__vm, '__value>>::from_value(vm, val)
            } else {
                panic!("Enum does not contain data at index '{}'. Do the type definitions match?", #idx)
            }
        }
    });

    quote!{
        (#(#fields),*)
    }
}

fn gen_struct_variant_cons<'a, I>(fields: I) -> TokenStream
where
    I: IntoIterator<Item = &'a Field>,
{
    let fields = fields.into_iter().enumerate().map(|(idx, field)| {
        let field_ty = &field.ty;
        let field_ident = field
            .ident
            .as_ref()
            .expect("Struct fields always have names");

        quote! {
            #field_ident: if let Some(val) = data.get_variant(#idx) {
                <#field_ty as _gluon_api::Getable<'__vm, '__value>>::from_value(vm, val)
            } else {
                panic!("Enum does not contain data at index '{}'. Do the type definitions match?", #idx)
            }
        }
    });

    quote!{
        {#(#fields),*}
    }
}

fn create_getable_bounds(generics: &Generics) -> Vec<TokenStream> {
    map_type_params(generics, |ty| {
        quote! {
            #ty: _gluon_api::Getable<'__vm, '__value>
        }
    })
}

fn create_lifetime_bounds(generics: &Generics) -> Vec<TokenStream> {
    map_lifetimes(generics, |lifetime| {
        quote! { #lifetime: '__vm, '__vm: #lifetime }
    })
}

fn unpack_data() -> TokenStream {
    quote! {
        let data = match variants.as_ref() {
            _gluon_api::ValueRef::Data(data) => data,
            val => panic!("Unexpected value: '{:?}'. Do the type definitions match?", val),
        };
    }
}
<commit_msg>feat: Bound derive(Getable) by 'value byte default<commit_after>use proc_macro2::{Span, TokenStream};
use shared::{map_lifetimes, map_type_params, split_for_impl};
use syn::{
    self, Data, DataEnum, DataStruct, DeriveInput, Field, Fields, FieldsNamed, FieldsUnnamed,
    Generics, Ident, Variant,
};

use attr;

pub fn derive(input: TokenStream) -> TokenStream {
    let derive_input = syn::parse2(input).expect("Input is checked by rustc");

    let container = attr::Container::from_ast(&derive_input);

    let DeriveInput {
        ident,
        data,
        generics,
        ..
    } = derive_input;

    let tokens = match data {
        Data::Struct(ast) => derive_struct(&container, ast, ident, generics),
        Data::Enum(ast) => derive_enum(&container, ast, ident, generics),
        Data::Union(_) => panic!("Unions are not supported"),
    };

    tokens.into()
}

fn derive_struct(
    container: &attr::Container,
    ast: DataStruct,
    ident: Ident,
    generics: Generics,
) -> TokenStream {
    let cons = match ast.fields {
        Fields::Named(FieldsNamed { named, .. }) => gen_struct_cons(&ident, named),
        Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => gen_tuple_struct_cons(&ident, unnamed),
        Fields::Unit => quote! { #ident },
    };

    gen_impl(container, ident, generics, cons)
}

fn gen_struct_cons<I>(ident: &Ident, fields: I) -> TokenStream
where
    I: IntoIterator<Item = Field>,
{
    // lookup each field by its name and then convert to its type using the Getable
    // impl of the fields type
    let field_initializers = fields.into_iter().map(|field| {
        let field_ty = &field.ty;
        let ident = field
            .ident
            .as_ref()
            .expect("Struct fields always have names");
        let quoted_ident = format!("{}", quote! { #ident });

        quote! {
            #ident: if let Some(val) = data.lookup_field(vm, #quoted_ident) {
                <#field_ty as _gluon_api::Getable<'__vm, '__value>>::from_value(vm, val)
            } else {
                panic!("Cannot find the field '{}'. Do the type definitions match?", #quoted_ident);
            }
        }
    });

    let unpack_data = unpack_data();
    quote! {
        #unpack_data

        #ident {
            #(#field_initializers,)*
        }
    }
}

fn gen_tuple_struct_cons<I>(ident: &Ident, fields: I) -> TokenStream
where
    I: IntoIterator<Item = Field>,
{
    let mut fields = fields.into_iter().fuse();

    // Treat newtype structs as just their inner type
    let (first, second) = (fields.next(), fields.next());
    match (&first, &second) {
        (Some(field_ty), None) => {
            return quote! {
                #ident (
                <#field_ty as _gluon_api::Getable<'__vm, '__value>>::from_value(vm, variants)
                )
            }
        }
        _ => (),
    }

    // do the lookup using the tag, because tuple structs don't have field names
    let field_initializers = first
        .into_iter()
        .chain(second)
        .chain(fields)
        .enumerate()
        .map(|(tag, field)| {
            let field_ty = &field.ty;

            quote! {
                if let Some(val) = data.get_variant(#tag) {
                    <#field_ty as _gluon_api::Getable<'__vm, '__value>>::from_value(vm, val)
                } else {
                    panic!("Cannot find the field with tag '{}'. Do the type definitions match?", #tag);
                }
            }
        });

    let unpack_data = unpack_data();
    quote! {
        #unpack_data

        #ident (
            #(#field_initializers,)*
        )
    }
}

fn derive_enum(
    container: &attr::Container,
    ast: DataEnum,
    ident: Ident,
    generics: Generics,
) -> TokenStream {
    let cons;
    {
        let variants = ast
            .variants
            .iter()
            .enumerate()
            .map(|(tag, variant)| gen_variant_match(&ident, tag, variant));

        let unpack_data = unpack_data();

        // data contains the the data for each field of a variant; the variant of the passed value
        // is defined by the tag(), which is defined by order of the variants (the first variant is 0)
        cons = quote! {
            #unpack_data

            match data.tag() as usize {
                #(#variants,)*
                tag => panic!("Unexpected tag: '{}'. Do the type definitions match?", tag)
            }
        };
    }

    gen_impl(container, ident, generics, cons)
}

fn gen_impl(
    container: &attr::Container,
    ident: Ident,
    generics: Generics,
    push_impl: TokenStream,
) -> TokenStream {
    // lifetime bounds like '__vm: 'a, 'a: '__vm (which implies => 'a == '__vm)
    // writing bounds like this is a lot easier than actually replacing all lifetimes
    // with '__vm
    let lifetime_bounds = create_lifetime_bounds(&generics);

    // generate bounds like T: Getable for every type parameter
    let getable_bounds = create_getable_bounds(&generics);

    let (impl_generics, ty_generics, where_clause) =
        split_for_impl(&generics, &["'__vm", "'__value"]);

    let dummy_const = Ident::new(&format!("_IMPL_GETABLE_FOR_{}", ident), Span::call_site());

    let gluon = match container.crate_name {
        attr::CrateName::Some(ref ident) => quote!{
            use #ident::api as _gluon_api;
            use #ident::thread as _gluon_thread;
            use #ident::Variants as _GluonVariants;
        },
        attr::CrateName::GluonVm => quote!{
            use api as _gluon_api;
            use thread as _gluon_thread;
            use Variants as _GluonVariants;
        },
        attr::CrateName::None => quote!{
            use gluon::vm::api as _gluon_api;
            use gluon::vm::thread as _gluon_thread;
            use gluon::vm::Variants as _GluonVariants;
        },
    };

    quote! {
        #[allow(non_upper_case_globals)]
        const #dummy_const: () = {
            #gluon

            #[automatically_derived]
            #[allow(unused_attributes, unused_variables)]
            impl #impl_generics _gluon_api::Getable<'__vm, '__value> for #ident #ty_generics
            #where_clause #(#getable_bounds,)* #(#lifetime_bounds),*
            {
                fn from_value(vm: &'__vm _gluon_thread::Thread, variants: _GluonVariants<'__value>) -> Self {
                    #push_impl
                }
            }
        };
    }
}

fn gen_variant_match(ident: &Ident, tag: usize, variant: &Variant) -> TokenStream {
    let variant_ident = &variant.ident;

    // depending on the type of the variant we need to generate different constructors
    // for the enum
    match &variant.fields {
        Fields::Unit => quote! {
            #tag => #ident::#variant_ident
        },
        // both constructors that need to marshall values extract them by using the index
        // of the field to get the content from Data::get_variant;
        // the data variable was assigned in the function body above
        Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
            let cons = gen_tuple_variant_cons(unnamed);

            quote! {
                #tag => #ident::#variant_ident#cons
            }
        }
        Fields::Named(FieldsNamed { named, .. }) => {
            let cons = gen_struct_variant_cons(named);

            quote! {
                #tag => #ident::#variant_ident#cons
            }
        }
    }
}

fn gen_tuple_variant_cons<'a, I>(fields: I) -> TokenStream
where
    I: IntoIterator<Item = &'a Field>,
{
    let fields = fields.into_iter().enumerate().map(|(idx, field)| {
        let field_ty = &field.ty;

        quote! {
            if let Some(val) = data.get_variant(#idx) {
                <#field_ty as _gluon_api::Getable<'__vm, '__value>>::from_value(vm, val)
            } else {
                panic!("Enum does not contain data at index '{}'. Do the type definitions match?", #idx)
            }
        }
    });

    quote!{
        (#(#fields),*)
    }
}

fn gen_struct_variant_cons<'a, I>(fields: I) -> TokenStream
where
    I: IntoIterator<Item = &'a Field>,
{
    let fields = fields.into_iter().enumerate().map(|(idx, field)| {
        let field_ty = &field.ty;
        let field_ident = field
            .ident
            .as_ref()
            .expect("Struct fields always have names");

        quote! {
            #field_ident: if let Some(val) = data.get_variant(#idx) {
                <#field_ty as _gluon_api::Getable<'__vm, '__value>>::from_value(vm, val)
            } else {
                panic!("Enum does not contain data at index '{}'. Do the type definitions match?", #idx)
            }
        }
    });

    quote!{
        {#(#fields),*}
    }
}

fn create_getable_bounds(generics: &Generics) -> Vec<TokenStream> {
    map_type_params(generics, |ty| {
        quote! {
            #ty: _gluon_api::Getable<'__vm, '__value>
        }
    })
}

fn create_lifetime_bounds(generics: &Generics) -> Vec<TokenStream> {
    map_lifetimes(generics, |lifetime| {
        quote! { #lifetime: '__value, '__value: #lifetime }
    })
}

fn unpack_data() -> TokenStream {
    quote! {
        let data = match variants.as_ref() {
            _gluon_api::ValueRef::Data(data) => data,
            val => panic!("Unexpected value: '{:?}'. Do the type definitions match?", val),
        };
    }
}
<|endoftext|>


<commit_before>use command_prelude::*;

use std::io::{self, BufRead};

use cargo::core::{Source, SourceId};
use cargo::sources::RegistrySource;
use cargo::util::{CargoError, CargoResultExt};
use cargo::ops;

pub fn cli() -> App {
    subcommand("login")
        .about(
            "Save an api token from the registry locally. \
             If token is not specified, it will be read from stdin.",
        )
        .arg(Arg::with_name("token"))
        .arg(opt("host", "Host to set the token for").value_name("HOST"))
        .arg(opt("registry", "Registry to use").value_name("REGISTRY"))
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let registry = args.registry(config)?;

    let token = match args.value_of("token") {
        Some(token) => token.to_string(),
        None => {
            let host = match registry {
                Some(ref _registry) => {
                    return Err(format_err!(
                        "token must be provided when \
                         --registry is provided."
                    ).into());
                }
                None => {
                    let src = SourceId::crates_io(config)?;
                    let mut src = RegistrySource::remote(&src, config);
                    src.update()?;
                    let config = src.config()?.unwrap();
                    args.value_of("host")
                        .map(|s| s.to_string())
                        .unwrap_or_else(|| config.api.unwrap())
                }
            };
            println!("please visit {}me and paste the API Token below", host);
            let mut line = String::new();
            let input = io::stdin();
            input
                .lock()
                .read_line(&mut line)
                .chain_err(|| "failed to read stdin")
                .map_err(CargoError::from)?;
            line.trim().to_string()
        }
    };

    ops::registry_login(config, token, registry)?;
    Ok(())
}
<commit_msg>Auto merge of #6078 - jdxcode:login-url, r=alexcrichton<commit_after>use command_prelude::*;

use std::io::{self, BufRead};

use cargo::core::{Source, SourceId};
use cargo::sources::RegistrySource;
use cargo::util::{CargoError, CargoResultExt};
use cargo::ops;

pub fn cli() -> App {
    subcommand("login")
        .about(
            "Save an api token from the registry locally. \
             If token is not specified, it will be read from stdin.",
        )
        .arg(Arg::with_name("token"))
        .arg(opt("host", "Host to set the token for").value_name("HOST"))
        .arg(opt("registry", "Registry to use").value_name("REGISTRY"))
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let registry = args.registry(config)?;

    let token = match args.value_of("token") {
        Some(token) => token.to_string(),
        None => {
            let host = match registry {
                Some(ref _registry) => {
                    return Err(format_err!(
                        "token must be provided when \
                         --registry is provided."
                    ).into());
                }
                None => {
                    let src = SourceId::crates_io(config)?;
                    let mut src = RegistrySource::remote(&src, config);
                    src.update()?;
                    let config = src.config()?.unwrap();
                    args.value_of("host")
                        .map(|s| s.to_string())
                        .unwrap_or_else(|| config.api.unwrap())
                }
            };
            println!("please visit {}/me and paste the API Token below", host);
            let mut line = String::new();
            let input = io::stdin();
            input
                .lock()
                .read_line(&mut line)
                .chain_err(|| "failed to read stdin")
                .map_err(CargoError::from)?;
            line.trim().to_string()
        }
    };

    ops::registry_login(config, token, registry)?;
    Ok(())
}
<|endoftext|>


<commit_before>// run-pass

// rust-lang/rust#64655: with panic=unwind, a panic from a subroutine
// should still run destructors as it unwinds the stack. However,
// bugs with how the nounwind LLVM attribute was applied led to this
// simple case being mishandled *if* you had optimization *and* fat
// LTO turned on.

// This test is the closest thing to a "regression test" we can do
// without actually spawning subprocesses and comparing stderr
// results.
//
// This test takes the code from the above issue and adapts it to
// better fit our test infrastructure:
//
// * Instead of relying on `println!` to observe whether the destructor
//   is run, we instead run the code in a spawned thread and
//   communicate the destructor's operation via a synchronous atomic
//   in static memory.
//
// * To keep the output from confusing a casual user, we override the
//   panic hook to be a no-op (rather than printing a message to
//   stderr).
//
// (pnkfelix has confirmed by hand that these additions do not mask
// the underlying bug.)

// LTO settings cannot be combined with -C prefer-dynamic
// no-prefer-dynamic

// The revisions combine each lto setting with each optimization
// setting; pnkfelix observed three differing behaviors at opt-levels
// 0/1/2+3 for this test, so it seems prudent to be thorough.

// revisions: no0 no1 no2 no3 thin0 thin1 thin2 thin3 fat0 fat1 fat2  fat3

//[no0]compile-flags: -C opt-level=0 -C lto=no
//[no1]compile-flags: -C opt-level=1 -C lto=no
//[no2]compile-flags: -C opt-level=2 -C lto=no
//[no3]compile-flags: -C opt-level=3 -C lto=no
//[thin0]compile-flags: -C opt-level=0 -C lto=thin
//[thin1]compile-flags: -C opt-level=1 -C lto=thin
//[thin2]compile-flags: -C opt-level=2 -C lto=thin
//[thin3]compile-flags: -C opt-level=3 -C lto=thin
//[fat0]compile-flags: -C opt-level=0 -C lto=fat
//[fat1]compile-flags: -C opt-level=1 -C lto=fat
//[fat2]compile-flags: -C opt-level=2 -C lto=fat
//[fat3]compile-flags: -C opt-level=3 -C lto=fat

fn main() {
    use std::sync::atomic::{AtomicUsize, Ordering};

    static SHARED: AtomicUsize = AtomicUsize::new(0);

    assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 0);

    let old_hook = std::panic::take_hook();

    std::panic::set_hook(Box::new(|_| { } )); // no-op on panic.

    let handle = std::thread::spawn(|| {
        struct Droppable;
        impl Drop for Droppable {
            fn drop(&mut self) {
                SHARED.fetch_add(1, Ordering::SeqCst);
            }
        }

        let _guard = Droppable;
        None::<()>.expect("???");
    });

    let wait = handle.join();

    // reinstate handler to ease observation of assertion failures.
    std::panic::set_hook(old_hook);

    assert!(wait.is_err());

    assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 1);
}

<commit_msg>Update issue-64655-extern-rust-must-allow-unwind.rs<commit_after>// run-pass

// rust-lang/rust#64655: with panic=unwind, a panic from a subroutine
// should still run destructors as it unwinds the stack. However,
// bugs with how the nounwind LLVM attribute was applied led to this
// simple case being mishandled *if* you had optimization *and* fat
// LTO turned on.

// This test is the closest thing to a "regression test" we can do
// without actually spawning subprocesses and comparing stderr
// results.
//
// This test takes the code from the above issue and adapts it to
// better fit our test infrastructure:
//
// * Instead of relying on `println!` to observe whether the destructor
//   is run, we instead run the code in a spawned thread and
//   communicate the destructor's operation via a synchronous atomic
//   in static memory.
//
// * To keep the output from confusing a casual user, we override the
//   panic hook to be a no-op (rather than printing a message to
//   stderr).
//
// (pnkfelix has confirmed by hand that these additions do not mask
// the underlying bug.)

// LTO settings cannot be combined with -C prefer-dynamic
// no-prefer-dynamic

// The revisions combine each lto setting with each optimization
// setting; pnkfelix observed three differing behaviors at opt-levels
// 0/1/2+3 for this test, so it seems prudent to be thorough.

// revisions: no0 no1 no2 no3 thin0 thin1 thin2 thin3 fat0 fat1 fat2  fat3

//[no0]compile-flags: -C opt-level=0 -C lto=no
//[no1]compile-flags: -C opt-level=1 -C lto=no
//[no2]compile-flags: -C opt-level=2 -C lto=no
//[no3]compile-flags: -C opt-level=3 -C lto=no
//[thin0]compile-flags: -C opt-level=0 -C lto=thin
//[thin1]compile-flags: -C opt-level=1 -C lto=thin
//[thin2]compile-flags: -C opt-level=2 -C lto=thin
//[thin3]compile-flags: -C opt-level=3 -C lto=thin
//[fat0]compile-flags: -C opt-level=0 -C lto=fat
//[fat1]compile-flags: -C opt-level=1 -C lto=fat
//[fat2]compile-flags: -C opt-level=2 -C lto=fat
//[fat3]compile-flags: -C opt-level=3 -C lto=fat

fn main() {
    use std::sync::atomic::{AtomicUsize, Ordering};

    static SHARED: AtomicUsize = AtomicUsize::new(0);

    assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 0);

    let old_hook = std::panic::take_hook();

    std::panic::set_hook(Box::new(|_| { } )); // no-op on panic.

    let handle = std::thread::spawn(|| {
        struct Droppable;
        impl Drop for Droppable {
            fn drop(&mut self) {
                SHARED.fetch_add(1, Ordering::SeqCst);
            }
        }

        let _guard = Droppable;
        None::<()>.expect("???");
    });

    let wait = handle.join();

    // reinstate handler to ease observation of assertion failures.
    std::panic::set_hook(old_hook);

    assert!(wait.is_err());

    assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 1);
}
<|endoftext|>


<commit_before>// This example implements a sudoku solver:
// https://en.wikipedia.org/wiki/Sudoku
// using an evolutionary algorithm.

extern crate rand;

// internal crates
extern crate darwin_rs;

use rand::Rng;

// internal modules
use darwin_rs::{Individual, SimulationBuilder, Error};

// A cell is a 3x3 sub field inside the 9x9 sudoku field
fn fitness_of_one_cell(sudoku: &Vec<u8>, row: usize, col: usize) -> f64 {
    let mut number_occurence = vec![0, 0, 0, 0, 0, 0, 0, 0, 0];
    let mut error = 0.0;

    for i in 0..3 {
        for j in 0..3 {
            let data = sudoku[(((row + i) * 9) + col + j) as usize];

            if data > 0 && data < 10 {
                number_occurence[(data - 1) as usize] = number_occurence[(data - 1) as usize] + 1;
            } else {
                error = error + 1.0;
            }
        }
    }

    for number in number_occurence {
        if number != 1 {
            error = error + 1.0;
        }
    }

    error
}

fn fitness_of_one_row(sudoku: &Vec<u8>, row: usize) -> f64 {
    let mut number_occurence = vec![0, 0, 0, 0, 0, 0, 0, 0, 0];
    let mut error = 0.0;

    for col in 0..9 {
        let number = sudoku[(row * 9) + col];
        if number > 0 && number < 10 {
            number_occurence[(number - 1) as usize] = number_occurence[(number - 1) as usize] + 1;
        } else {
            error = error + 1.0;
        }
    }

    // Each number must be unique, otherwise increase error
    for number in number_occurence {
        if number != 1 {
            error = error + 1.0;
        }
    }

    error
}

fn fitness_of_one_col(sudoku: &Vec<u8>, col: usize) -> f64 {
    let mut number_occurence = vec![0, 0, 0, 0, 0, 0, 0, 0, 0];
    let mut error = 0.0;

    for row in 0..9 {
        let number = sudoku[(row * 9) + col];
        if number > 0 && number < 10 {
            number_occurence[(number - 1) as usize] = number_occurence[(number - 1) as usize] + 1;
        } else {
            error = error + 1.0;
        }
    }

    // Each number must be unique, otherwise increase error
    for number in number_occurence {
        if number != 1 {
            error = error + 1.0;
        }
    }

    error
}

#[derive(Debug, Clone)]
struct Sudoku {
    original: Vec<u8>,
    solved: Vec<u8>,
}

// implement trait functions mutate and calculate_fitness:
impl Individual for Sudoku {
    fn new() -> Sudoku {
        let mut sudoku = Sudoku {
            // Taken from Wikipedia: https://en.wikipedia.org/wiki/Sudoku
            original: vec![5, 3, 4, 6, 7, 8, 9, 1, 2, 6, 7, 2, 1, 9, 5, 3, 4, 8, 1, 9, 8, 3, 4, 2,
                           5, 6, 7, 8, 5, 9, 7, 6, 1, 4, 2, 3, 4, 2, 6, 8, 5, 3, 7, 9, 1, 7, 1, 3,
                           9, 2, 4, 8, 5, 6, 0, 6, 0, 0, 0, 0, 2, 8, 0, 0, 0, 0, 4, 1, 9, 0, 0, 5,
                           0, 0, 0, 0, 8, 0, 0, 7, 9],
            solved: Vec::new(),
        };

        sudoku.solved = sudoku.original.clone();

        sudoku
    }

    fn mutate(&mut self) {
        let mut rng = rand::thread_rng();

        let mut index: usize = rng.gen_range(0, self.original.len());

        // pick free (= not pre set) position
        while self.original[index] != 0 {
            index = rng.gen_range(0, self.original.len());
        }

        // and set it to a random value
        self.solved[index] = rng.gen_range(1, 10);
    }

    // fitness means here: how many errors
    fn calculate_fitness(&self) -> f64 {
        let mut result = 0.0;

        for i in 0..9 {
            result = result + fitness_of_one_row(&self.solved, i);
            result = result + fitness_of_one_col(&self.solved, i);
        }

        let mut i = 0;
        let mut j = 0;

        loop {
            result = result + fitness_of_one_cell(&self.solved, i, j);

            i = i + 3;
            if i >= 9 {
                i = 0;
                j = j + 3;
                if j >= 9 {
                    break;
                }
            }
        }

        result
    }
}

fn main() {
    println!("Darwin test: sudoku solver");

    let sudoku_builder = SimulationBuilder::<Sudoku>::new()
        .fitness(0.0)
        .threads(2)
        .individuals(100)
        .increasing_exp_mutation_rate(1.01)
        .finalize();

    match sudoku_builder {
        Err(Error::TooLowEndIteration) => println!("more than 10 iteratons needed"),
        Err(Error::TooLowIndividuals) => println!("more than 2 individuals needed"),
        Ok(mut sudoku_simulation) => {
            sudoku_simulation.run();

            println!("total run time: {} ms", sudoku_simulation.total_time_in_ms);
            println!("improvement factor: {}",
                     sudoku_simulation.improvement_factor);
            println!("number of iterations: {}",
                     sudoku_simulation.iteration_counter);

            sudoku_simulation.print_fitness();

            // print solution
            for row in 0..9 {
                for col in 0..9 {
                    print!("{} | ",
                           sudoku_simulation.population[0].individual.solved[(row * 9) + col]);
                }
                println!("\n");
            }

        }
    }

}
<commit_msg>Fix clippy warnings in the sudoku example.<commit_after>// This example implements a sudoku solver:
// https://en.wikipedia.org/wiki/Sudoku
// using an evolutionary algorithm.

extern crate rand;

// internal crates
extern crate darwin_rs;

use rand::Rng;

// internal modules
use darwin_rs::{Individual, SimulationBuilder, Error};

// A cell is a 3x3 sub field inside the 9x9 sudoku field
fn fitness_of_one_cell(sudoku: &[u8], row: usize, col: usize) -> f64 {
    let mut number_occurence = vec![0, 0, 0, 0, 0, 0, 0, 0, 0];
    let mut error = 0.0;

    for i in 0..3 {
        for j in 0..3 {
            let data = sudoku[(((row + i) * 9) + col + j) as usize];

            if data > 0 && data < 10 {
                number_occurence[(data - 1) as usize] += 1;
            } else {
                error += 1.0;
            }
        }
    }

    for number in number_occurence {
        if number != 1 {
            error += 1.0;
        }
    }

    error
}

fn fitness_of_one_row(sudoku: &[u8], row: usize) -> f64 {
    let mut number_occurence = vec![0, 0, 0, 0, 0, 0, 0, 0, 0];
    let mut error = 0.0;

    for col in 0..9 {
        let number = sudoku[(row * 9) + col];
        if number > 0 && number < 10 {
            number_occurence[(number - 1) as usize] += 1;
        } else {
            error += 1.0;
        }
    }

    // Each number must be unique, otherwise increase error
    for number in number_occurence {
        if number != 1 {
            error += 1.0;
        }
    }

    error
}

fn fitness_of_one_col(sudoku: &[u8], col: usize) -> f64 {
    let mut number_occurence = vec![0, 0, 0, 0, 0, 0, 0, 0, 0];
    let mut error = 0.0;

    for row in 0..9 {
        let number = sudoku[(row * 9) + col];
        if number > 0 && number < 10 {
            number_occurence[(number - 1) as usize] += 1;
        } else {
            error += 1.0;
        }
    }

    // Each number must be unique, otherwise increase error
    for number in number_occurence {
        if number != 1 {
            error += 1.0;
        }
    }

    error
}

#[derive(Debug, Clone)]
struct Sudoku {
    original: Vec<u8>,
    solved: Vec<u8>,
}

// implement trait functions mutate and calculate_fitness:
impl Individual for Sudoku {
    fn new() -> Sudoku {
        let mut sudoku = Sudoku {
            // Taken from Wikipedia: https://en.wikipedia.org/wiki/Sudoku
            original: vec![5, 3, 4, 6, 7, 8, 9, 1, 2, 6, 7, 2, 1, 9, 5, 3, 4, 8, 1, 9, 8, 3, 4, 2,
                           5, 6, 7, 8, 5, 9, 7, 6, 1, 4, 2, 3, 4, 2, 6, 8, 5, 3, 7, 9, 1, 7, 1, 3,
                           9, 2, 4, 8, 5, 6, 0, 6, 0, 0, 0, 0, 2, 8, 0, 0, 0, 0, 4, 1, 9, 0, 0, 5,
                           0, 0, 0, 0, 8, 0, 0, 7, 9],
            solved: Vec::new(),
        };

        sudoku.solved = sudoku.original.clone();

        sudoku
    }

    fn mutate(&mut self) {
        let mut rng = rand::thread_rng();

        let mut index: usize = rng.gen_range(0, self.original.len());

        // pick free (= not pre set) position
        while self.original[index] != 0 {
            index = rng.gen_range(0, self.original.len());
        }

        // and set it to a random value
        self.solved[index] = rng.gen_range(1, 10);
    }

    // fitness means here: how many errors
    fn calculate_fitness(&self) -> f64 {
        let mut result = 0.0;

        for i in 0..9 {
            result += fitness_of_one_row(&self.solved, i);
            result += fitness_of_one_col(&self.solved, i);
        }

        let mut i = 0;
        let mut j = 0;

        loop {
            result += fitness_of_one_cell(&self.solved, i, j);

            i += 3;
            if i >= 9 {
                i = 0;
                j += 3;
                if j >= 9 {
                    break;
                }
            }
        }

        result
    }
}

fn main() {
    println!("Darwin test: sudoku solver");

    let sudoku_builder = SimulationBuilder::<Sudoku>::new()
        .fitness(0.0)
        .threads(2)
        .individuals(100)
        .increasing_exp_mutation_rate(1.01)
        .finalize();

    match sudoku_builder {
        Err(Error::TooLowEndIteration) => println!("more than 10 iteratons needed"),
        Err(Error::TooLowIndividuals) => println!("more than 2 individuals needed"),
        Ok(mut sudoku_simulation) => {
            sudoku_simulation.run();

            println!("total run time: {} ms", sudoku_simulation.total_time_in_ms);
            println!("improvement factor: {}",
                     sudoku_simulation.improvement_factor);
            println!("number of iterations: {}",
                     sudoku_simulation.iteration_counter);

            sudoku_simulation.print_fitness();

            // print solution
            for row in 0..9 {
                for col in 0..9 {
                    print!("{} | ",
                           sudoku_simulation.population[0].individual.solved[(row * 9) + col]);
                }
                println!("\n");
            }

        }
    }

}
<|endoftext|>