<commit_before>//! Hubcaps provides a set of building blocks for interacting with the Github API

#[macro_use]
extern crate log;
#[macro_use]
extern crate hyper;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate url;

// all the modules!
use serde::de::Deserialize;
pub mod users;
pub mod comments;
pub mod review_comments;
pub mod pull_commits;
pub mod keys;
pub mod gists;
pub mod deployments;
pub mod errors;
pub mod hooks;
pub mod issues;
pub mod labels;
pub mod rep;
pub mod releases;
pub mod repositories;
pub mod statuses;
pub mod pulls;
pub mod search;
pub mod organizations;

// fixme: move reps to modules
pub use rep::*;

pub use errors::Error;
use gists::{Gists, UserGists};
use search::Search;
use hyper::Client;
use hyper::client::RequestBuilder;
use hyper::method::Method;
use hyper::header::{qitem, Accept, Authorization, ContentLength, UserAgent};
use hyper::mime::Mime;
use hyper::status::StatusCode;
use repositories::{Repository, Repositories, UserRepositories, OrganizationRepositories};
use organizations::{Organizations, UserOrganizations};
use std::fmt;
use std::io::Read;
use url::Url;
use std::collections::HashMap;

header! { (Link, "Link") => [String] }

const DEFAULT_HOST: &'static str = "https://api.github.com";

/// alias for Result that infers hubcaps::Error as Err
pub type Result<T> = std::result::Result<T, Error>;

enum MediaType {
    Json,
    Preview(&'static str),
}

impl Default for MediaType {
    fn default() -> MediaType {
        MediaType::Json
    }
}

impl From<MediaType> for Mime {
    fn from(media: MediaType) -> Mime {
        match media {
            MediaType::Json => "application/vnd.github.v3+json".parse().unwrap(),
            MediaType::Preview(codename) => {
                format!("application/vnd.github.{}-preview+json", codename).parse().unwrap()
            }
        }
    }
}

/// enum representation of github pull and issue state
#[derive(Clone, Debug, PartialEq)]
pub enum State {
    /// Only open issues
    Open,
    /// Only closed issues
    Closed,
    /// All issues, open or closed
    All,
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   State::Open => "open",
                   State::Closed => "closed",
                   State::All => "all",
               })
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// enum representation of Github list sorting options
#[derive(Clone, Debug, PartialEq)]
pub enum SortDirection {
    /// Sort in ascending order
    Asc,
    /// Sort in descending order
    Desc,
}

impl fmt::Display for SortDirection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   SortDirection::Asc => "asc",
                   SortDirection::Desc => "desc",
               })
    }
}

impl Default for SortDirection {
    fn default() -> SortDirection {
        SortDirection::Asc
    }
}

/// Various forms of authentication credentials supported by Github
#[derive(Debug, PartialEq)]
pub enum Credentials {
    /// No authentication
    None,
    /// Oauth token string
    /// https://developer.github.com/v3/#oauth2-token-sent-in-a-header
    Token(String),
    /// Oauth client id and secret
    /// https://developer.github.com/v3/#oauth2-keysecret
    Client(String, String),
}

impl Default for Credentials {
    fn default() -> Credentials {
        Credentials::None
    }
}

/// Entry point interface for interacting with Github API
pub struct Github {
    host: String,
    agent: String,
    client: Client,
    credentials: Credentials,
}

impl Github {
    /// Create a new Github instance
    pub fn new<A>(agent: A, client: Client, credentials: Credentials) -> Github
        where A: Into<String>
    {
        Github::host(DEFAULT_HOST, agent, client, credentials)
    }

    /// Create a new Github instance hosted at a custom location.
    /// Useful for github enterprise installations ( yourdomain.com/api/v3/ )
    pub fn host<H, A>(host: H, agent: A, client: Client, credentials: Credentials) -> Github
        where H: Into<String>,
              A: Into<String>
    {
        Github {
            host: host.into(),
            agent: agent.into(),
            client: client,
            credentials: credentials,
        }
    }

    /// Return a reference to a Github reposistory
    pub fn repo<O, R>(&self, owner: O, repo: R) -> Repository
        where O: Into<String>,
              R: Into<String>
    {
        Repository::new(self, owner, repo)
    }

    /// Return a reference to the collection of repositories owned by and
    /// associated with an owner
    pub fn user_repos<S>(&self, owner: S) -> UserRepositories
        where S: Into<String>
    {
        UserRepositories::new(self, owner)
    }

    /// Return a reference to the collection of repositories owned by the user
    /// associated with the current authentication credentials
    pub fn repos(&self) -> Repositories {
        Repositories::new(self)
    }

    /// Return a reference to the collection of organizations that the user
    /// associated with the current authentication credentials is in
    pub fn orgs(&self) -> Organizations {
        Organizations::new(self)
    }

    /// Return a reference to the collection of organizations a user
    /// is publicly associated with
    pub fn user_orgs<U>(&self, user: U) -> UserOrganizations
        where U: Into<String>
    {
        UserOrganizations::new(self, user)
    }

    /// Return a reference to an interface that provides access to a user's gists
    pub fn user_gists<O>(&self, owner: O) -> UserGists
        where O: Into<String>
    {
        UserGists::new(self, owner)
    }

    /// Return a reference to an interface that provides access to the
    /// gists belonging to the owner of the token used to configure this client
    pub fn gists(&self) -> Gists {
        Gists::new(self)
    }

    pub fn search(&self) -> Search {
        Search::new(self)
    }

    /// Return a reference to the collection of repositories owned by and
    /// associated with an organization
    pub fn org_repos<O>(&self, org: O) -> OrganizationRepositories
        where O: Into<String>
    {
        OrganizationRepositories::new(self, org)
    }

    fn authenticate(&self, method: Method, url: String) -> RequestBuilder {
        match self.credentials {
            Credentials::Token(ref token) => {
                self.client.request(method, &url).header(Authorization(format!("token {}", token)))
            }
            Credentials::Client(ref id, ref secret) => {

                let mut parsed = Url::parse(&url).unwrap();
                parsed.query_pairs_mut()
                    .append_pair("client_id", id)
                    .append_pair("client_secret", secret);
                self.client.request(method, parsed)
            }
            Credentials::None => self.client.request(method, &url),
        }
    }

    fn iter<'a, D, I>(&'a self, uri: String, into_items: fn(D) -> Vec<I>) -> Result<Iter<'a, D, I>>
        where D: Deserialize
    {
        Iter::new(self, self.host.clone() + &uri, into_items)
    }

    fn request<D>(&self,
                  method: Method,
                  uri: String,
                  body: Option<&[u8]>,
                  media_type: MediaType)
                  -> Result<(Option<Links>, D)>
        where D: Deserialize
    {
        let builder = self.authenticate(method, uri)
            .header(UserAgent(self.agent.to_owned()))
            .header(Accept(vec![qitem(From::from(media_type))]));

        let mut res = try!(match body {
            Some(ref bod) => builder.body(*bod).send(),
            _ => builder.send(),
        });

        let mut body = match res.headers.clone().get::<ContentLength>() {
            Some(&ContentLength(len)) => String::with_capacity(len as usize),
            _ => String::new(),
        };
        try!(res.read_to_string(&mut body));

        let links = res.headers.get::<Link>().map(|&Link(ref value)| Links::new(value.to_owned()));

        debug!("rec response {:#?} {:#?} {}", res.status, res.headers, body);
        match res.status {
            StatusCode::Conflict |
            StatusCode::BadRequest |
            StatusCode::UnprocessableEntity |
            StatusCode::Unauthorized |
            StatusCode::NotFound |
            StatusCode::Forbidden => {
                Err(Error::Fault {
                    code: res.status,
                    error: try!(serde_json::from_str::<errors::ClientError>(&body)),
                })
            }
            _ => Ok((links, try!(serde_json::from_str::<D>(&body)))),
        }
    }

    fn request_entity<D>(&self,
                         method: Method,
                         uri: String,
                         body: Option<&[u8]>,
                         media_type: MediaType)
                         -> Result<D>
        where D: Deserialize
    {
        self.request(method, uri, body, media_type).map(|(_, entity)| entity)
    }

    fn get<D>(&self, uri: &str) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Get, self.host.clone() + uri, None, MediaType::Json)
    }

    fn delete(&self, uri: &str) -> Result<()> {
        match self.request_entity::<()>(Method::Delete,
                                        self.host.clone() + uri,
                                        None,
                                        MediaType::Json) {
            Err(Error::Codec(_)) => Ok(()),
            otherwise => otherwise,
        }
    }

    fn post<D>(&self, uri: &str, message: &[u8]) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Post,
                            self.host.clone() + uri,
                            Some(message),
                            MediaType::Json)
    }

    fn patch<D>(&self, uri: &str, message: &[u8]) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Patch,
                            self.host.clone() + uri,
                            Some(message),
                            MediaType::Json)
    }

    fn put<D>(&self, uri: &str, message: &[u8]) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Put,
                            self.host.clone() + uri,
                            Some(message),
                            MediaType::Json)
    }
}

pub struct Iter<'a, D, I> {
    github: &'a Github,
    next_link: Option<String>,
    into_items: fn(D) -> Vec<I>,
    items: Vec<I>,
}

impl<'a, D, I> Iter<'a, D, I>
    where D: Deserialize
{
    pub fn new(github: &'a Github,
               uri: String,
               into_items: fn(D) -> Vec<I>)
               -> Result<Iter<'a, D, I>> {
        let (links, payload) = try!(github.request::<D>(Method::Get, uri, None, MediaType::Json));
        Ok(Iter {
            github: github,
            next_link: links.and_then(|l| l.next()),
            into_items: into_items,
            items: into_items(payload),
        })
    }

    fn set_next(&mut self, next: Option<String>) {
        self.next_link = next;
    }
}

impl<'a, D, I> Iterator for Iter<'a, D, I>
    where D: Deserialize
{
    type Item = I;
    fn next(&mut self) -> Option<I> {
        self.items.pop().or_else(|| {
            self.next_link.clone().and_then(|ref next_link| {
                self.github
                    .request::<D>(Method::Get, next_link.to_owned(), None, MediaType::Json)
                    .ok()
                    .and_then(|(links, payload)| {
                        self.set_next(links.and_then(|l| l.next()));
                        self.items = (self.into_items)(payload);
                        self.next()
                    })
            })
        })
    }
}

#[derive(Debug)]
pub struct Links {
    values: HashMap<String, String>,
}

impl Links {
    pub fn new<V>(value: V) -> Links
        where V: Into<String>
    {
        let values = value.into()
            .split(",")
            .map(|link| {
                let parts = link.split(";").collect::<Vec<_>>();
                (parts[1].to_owned().replace(" rel=\"", "").replace("\"", ""),
                 parts[0].to_owned().replace("<", "").replace(">", "").replace(" ", ""))
            })
            .fold(HashMap::new(), |mut acc, (rel, link)| {
                acc.insert(rel, link);
                acc
            });
        Links { values: values }
    }

    pub fn next(&self) -> Option<String> {
        self.values.get("next").map(|s| s.to_owned())
    }

    pub fn prev(&self) -> Option<String> {
        self.values.get("prev").map(|s| s.to_owned())
    }

    pub fn last(&self) -> Option<String> {
        self.values.get("last").map(|s| s.to_owned())
    }
}

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

    #[test]
    fn test_parse_links() {
        let links = Links::new(r#"<linknext>; rel="next", <linklast>; rel="last""#);
        assert_eq!(links.next(), Some("linknext".to_owned()));
        assert_eq!(links.last(), Some("linklast".to_owned()));
    }

    #[test]
    fn default_state() {
        let default: State = Default::default();
        assert_eq!(default, State::Open)
    }

    #[test]
    fn default_sort_direction() {
        let default: SortDirection = Default::default();
        assert_eq!(default, SortDirection::Asc)
    }

    #[test]
    fn default_credentials() {
        let default: Credentials = Default::default();
        assert_eq!(default, Credentials::None)
    }
}
<commit_msg>crate doc<commit_after>//! Hubcaps provides a set of building blocks for interacting with the Github API
//!
//! # Examples
//!
//!  Typical use will require instantiation of a Github client. Which requires
//! a user agent string, a `hyper::Client`, and set of `hubcaps::Credentials`.
//!
//! The hyper client should be configured with tls.
//!
//! ```no_run
//! extern crate hubcaps;
//! extern crate hyper;
//! extern crate hyper_native_tls;
//!
//! use hubcaps::{Credentials, Github};
//! use hyper::Client;
//! use hyper::net::HttpsConnector;
//! use hyper_native_tls::NativeTlsClient;
//!
//! fn main() {
//!   let github = Github::new(
//!     String::from("user-agent-name"),
//!     Client::with_connector(
//!       HttpsConnector::new(
//!         NativeTlsClient::new().unwrap()
//!       )
//!     ),
//!     Credentials::Token(
//!       String::from("personal-access-token")
//!     )
//!   );
//! }
//! ```
//!
//! Github enterprise users will want to create a client with the [Github#host](struct.Github.html#method.host) method
//!
#[macro_use]
extern crate log;
#[macro_use]
extern crate hyper;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate url;

// all the modules!
use serde::de::Deserialize;
pub mod users;
pub mod comments;
pub mod review_comments;
pub mod pull_commits;
pub mod keys;
pub mod gists;
pub mod deployments;
pub mod errors;
pub mod hooks;
pub mod issues;
pub mod labels;
pub mod rep;
pub mod releases;
pub mod repositories;
pub mod statuses;
pub mod pulls;
pub mod search;
pub mod organizations;

// fixme: move reps to modules
pub use rep::*;

pub use errors::Error;
use gists::{Gists, UserGists};
use search::Search;
use hyper::Client;
use hyper::client::RequestBuilder;
use hyper::method::Method;
use hyper::header::{qitem, Accept, Authorization, ContentLength, UserAgent};
use hyper::mime::Mime;
use hyper::status::StatusCode;
use repositories::{Repository, Repositories, UserRepositories, OrganizationRepositories};
use organizations::{Organizations, UserOrganizations};
use std::fmt;
use std::io::Read;
use url::Url;
use std::collections::HashMap;

header! { (Link, "Link") => [String] }

const DEFAULT_HOST: &'static str = "https://api.github.com";

/// alias for Result that infers hubcaps::Error as Err
pub type Result<T> = std::result::Result<T, Error>;

enum MediaType {
    Json,
    Preview(&'static str),
}

impl Default for MediaType {
    fn default() -> MediaType {
        MediaType::Json
    }
}

impl From<MediaType> for Mime {
    fn from(media: MediaType) -> Mime {
        match media {
            MediaType::Json => "application/vnd.github.v3+json".parse().unwrap(),
            MediaType::Preview(codename) => {
                format!("application/vnd.github.{}-preview+json", codename).parse().unwrap()
            }
        }
    }
}

/// enum representation of github pull and issue state
#[derive(Clone, Debug, PartialEq)]
pub enum State {
    /// Only open issues
    Open,
    /// Only closed issues
    Closed,
    /// All issues, open or closed
    All,
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   State::Open => "open",
                   State::Closed => "closed",
                   State::All => "all",
               })
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// enum representation of Github list sorting options
#[derive(Clone, Debug, PartialEq)]
pub enum SortDirection {
    /// Sort in ascending order
    Asc,
    /// Sort in descending order
    Desc,
}

impl fmt::Display for SortDirection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   SortDirection::Asc => "asc",
                   SortDirection::Desc => "desc",
               })
    }
}

impl Default for SortDirection {
    fn default() -> SortDirection {
        SortDirection::Asc
    }
}

/// Various forms of authentication credentials supported by Github
#[derive(Debug, PartialEq)]
pub enum Credentials {
    /// No authentication
    None,
    /// Oauth token string
    /// https://developer.github.com/v3/#oauth2-token-sent-in-a-header
    Token(String),
    /// Oauth client id and secret
    /// https://developer.github.com/v3/#oauth2-keysecret
    Client(String, String),
}

impl Default for Credentials {
    fn default() -> Credentials {
        Credentials::None
    }
}

/// Entry point interface for interacting with Github API
pub struct Github {
    host: String,
    agent: String,
    client: Client,
    credentials: Credentials,
}

impl Github {
    /// Create a new Github instance
    pub fn new<A>(agent: A, client: Client, credentials: Credentials) -> Github
        where A: Into<String>
    {
        Github::host(DEFAULT_HOST, agent, client, credentials)
    }

    /// Create a new Github instance hosted at a custom location.
    /// Useful for github enterprise installations ( yourdomain.com/api/v3/ )
    pub fn host<H, A>(host: H, agent: A, client: Client, credentials: Credentials) -> Github
        where H: Into<String>,
              A: Into<String>
    {
        Github {
            host: host.into(),
            agent: agent.into(),
            client: client,
            credentials: credentials,
        }
    }

    /// Return a reference to a Github reposistory
    pub fn repo<O, R>(&self, owner: O, repo: R) -> Repository
        where O: Into<String>,
              R: Into<String>
    {
        Repository::new(self, owner, repo)
    }

    /// Return a reference to the collection of repositories owned by and
    /// associated with an owner
    pub fn user_repos<S>(&self, owner: S) -> UserRepositories
        where S: Into<String>
    {
        UserRepositories::new(self, owner)
    }

    /// Return a reference to the collection of repositories owned by the user
    /// associated with the current authentication credentials
    pub fn repos(&self) -> Repositories {
        Repositories::new(self)
    }

    /// Return a reference to the collection of organizations that the user
    /// associated with the current authentication credentials is in
    pub fn orgs(&self) -> Organizations {
        Organizations::new(self)
    }

    /// Return a reference to the collection of organizations a user
    /// is publicly associated with
    pub fn user_orgs<U>(&self, user: U) -> UserOrganizations
        where U: Into<String>
    {
        UserOrganizations::new(self, user)
    }

    /// Return a reference to an interface that provides access to a user's gists
    pub fn user_gists<O>(&self, owner: O) -> UserGists
        where O: Into<String>
    {
        UserGists::new(self, owner)
    }

    /// Return a reference to an interface that provides access to the
    /// gists belonging to the owner of the token used to configure this client
    pub fn gists(&self) -> Gists {
        Gists::new(self)
    }

    pub fn search(&self) -> Search {
        Search::new(self)
    }

    /// Return a reference to the collection of repositories owned by and
    /// associated with an organization
    pub fn org_repos<O>(&self, org: O) -> OrganizationRepositories
        where O: Into<String>
    {
        OrganizationRepositories::new(self, org)
    }

    fn authenticate(&self, method: Method, url: String) -> RequestBuilder {
        match self.credentials {
            Credentials::Token(ref token) => {
                self.client.request(method, &url).header(Authorization(format!("token {}", token)))
            }
            Credentials::Client(ref id, ref secret) => {

                let mut parsed = Url::parse(&url).unwrap();
                parsed.query_pairs_mut()
                    .append_pair("client_id", id)
                    .append_pair("client_secret", secret);
                self.client.request(method, parsed)
            }
            Credentials::None => self.client.request(method, &url),
        }
    }

    fn iter<'a, D, I>(&'a self, uri: String, into_items: fn(D) -> Vec<I>) -> Result<Iter<'a, D, I>>
        where D: Deserialize
    {
        Iter::new(self, self.host.clone() + &uri, into_items)
    }

    fn request<D>(&self,
                  method: Method,
                  uri: String,
                  body: Option<&[u8]>,
                  media_type: MediaType)
                  -> Result<(Option<Links>, D)>
        where D: Deserialize
    {
        let builder = self.authenticate(method, uri)
            .header(UserAgent(self.agent.to_owned()))
            .header(Accept(vec![qitem(From::from(media_type))]));

        let mut res = try!(match body {
            Some(ref bod) => builder.body(*bod).send(),
            _ => builder.send(),
        });

        let mut body = match res.headers.clone().get::<ContentLength>() {
            Some(&ContentLength(len)) => String::with_capacity(len as usize),
            _ => String::new(),
        };
        try!(res.read_to_string(&mut body));

        let links = res.headers.get::<Link>().map(|&Link(ref value)| Links::new(value.to_owned()));

        debug!("rec response {:#?} {:#?} {}", res.status, res.headers, body);
        match res.status {
            StatusCode::Conflict |
            StatusCode::BadRequest |
            StatusCode::UnprocessableEntity |
            StatusCode::Unauthorized |
            StatusCode::NotFound |
            StatusCode::Forbidden => {
                Err(Error::Fault {
                    code: res.status,
                    error: try!(serde_json::from_str::<errors::ClientError>(&body)),
                })
            }
            _ => Ok((links, try!(serde_json::from_str::<D>(&body)))),
        }
    }

    fn request_entity<D>(&self,
                         method: Method,
                         uri: String,
                         body: Option<&[u8]>,
                         media_type: MediaType)
                         -> Result<D>
        where D: Deserialize
    {
        self.request(method, uri, body, media_type).map(|(_, entity)| entity)
    }

    fn get<D>(&self, uri: &str) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Get, self.host.clone() + uri, None, MediaType::Json)
    }

    fn delete(&self, uri: &str) -> Result<()> {
        match self.request_entity::<()>(Method::Delete,
                                        self.host.clone() + uri,
                                        None,
                                        MediaType::Json) {
            Err(Error::Codec(_)) => Ok(()),
            otherwise => otherwise,
        }
    }

    fn post<D>(&self, uri: &str, message: &[u8]) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Post,
                            self.host.clone() + uri,
                            Some(message),
                            MediaType::Json)
    }

    fn patch<D>(&self, uri: &str, message: &[u8]) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Patch,
                            self.host.clone() + uri,
                            Some(message),
                            MediaType::Json)
    }

    fn put<D>(&self, uri: &str, message: &[u8]) -> Result<D>
        where D: Deserialize
    {
        self.request_entity(Method::Put,
                            self.host.clone() + uri,
                            Some(message),
                            MediaType::Json)
    }
}

pub struct Iter<'a, D, I> {
    github: &'a Github,
    next_link: Option<String>,
    into_items: fn(D) -> Vec<I>,
    items: Vec<I>,
}

impl<'a, D, I> Iter<'a, D, I>
    where D: Deserialize
{
    pub fn new(github: &'a Github,
               uri: String,
               into_items: fn(D) -> Vec<I>)
               -> Result<Iter<'a, D, I>> {
        let (links, payload) = try!(github.request::<D>(Method::Get, uri, None, MediaType::Json));
        Ok(Iter {
            github: github,
            next_link: links.and_then(|l| l.next()),
            into_items: into_items,
            items: into_items(payload),
        })
    }

    fn set_next(&mut self, next: Option<String>) {
        self.next_link = next;
    }
}

impl<'a, D, I> Iterator for Iter<'a, D, I>
    where D: Deserialize
{
    type Item = I;
    fn next(&mut self) -> Option<I> {
        self.items.pop().or_else(|| {
            self.next_link.clone().and_then(|ref next_link| {
                self.github
                    .request::<D>(Method::Get, next_link.to_owned(), None, MediaType::Json)
                    .ok()
                    .and_then(|(links, payload)| {
                        self.set_next(links.and_then(|l| l.next()));
                        self.items = (self.into_items)(payload);
                        self.next()
                    })
            })
        })
    }
}

#[derive(Debug)]
pub struct Links {
    values: HashMap<String, String>,
}

impl Links {
    pub fn new<V>(value: V) -> Links
        where V: Into<String>
    {
        let values = value.into()
            .split(",")
            .map(|link| {
                let parts = link.split(";").collect::<Vec<_>>();
                (parts[1].to_owned().replace(" rel=\"", "").replace("\"", ""),
                 parts[0].to_owned().replace("<", "").replace(">", "").replace(" ", ""))
            })
            .fold(HashMap::new(), |mut acc, (rel, link)| {
                acc.insert(rel, link);
                acc
            });
        Links { values: values }
    }

    pub fn next(&self) -> Option<String> {
        self.values.get("next").map(|s| s.to_owned())
    }

    pub fn prev(&self) -> Option<String> {
        self.values.get("prev").map(|s| s.to_owned())
    }

    pub fn last(&self) -> Option<String> {
        self.values.get("last").map(|s| s.to_owned())
    }
}

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

    #[test]
    fn test_parse_links() {
        let links = Links::new(r#"<linknext>; rel="next", <linklast>; rel="last""#);
        assert_eq!(links.next(), Some("linknext".to_owned()));
        assert_eq!(links.last(), Some("linklast".to_owned()));
    }

    #[test]
    fn default_state() {
        let default: State = Default::default();
        assert_eq!(default, State::Open)
    }

    #[test]
    fn default_sort_direction() {
        let default: SortDirection = Default::default();
        assert_eq!(default, SortDirection::Asc)
    }

    #[test]
    fn default_credentials() {
        let default: Credentials = Default::default();
        assert_eq!(default, Credentials::None)
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Samuel Loretan <tynril@gmail.com>

//! Triangulate a set of points

/// A two dimentional point.
#[derive(Clone, Copy, Debug)]
pub struct Point {
    x: f64,
    y: f64,
}

impl Point {
    /// Makes a new point from xy coordinates.
    pub fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }
}

/// A triangle, represented by indexes into a vertice list.
#[derive(Debug, PartialEq)]
pub struct Triangle(usize, usize, usize);

/// An edge, represented by indexes into a vertice list.
#[derive(Debug)]
struct Edge(usize, usize);

impl PartialEq for Edge {
    fn eq(&self, other: &Edge) -> bool {
        (self.0 == other.1 && self.1 == other.0) || (self.0 == other.0 && self.1 == other.1)
    }
}

/// Triangulate a given set of points. The returned triangles are indices into the  list of points.
pub fn triangulate(points: &mut Vec<Point>) -> Vec<Triangle> {
    // Make sure we have enough points to do a triangulation.
    let points_count = points.len();
    if points_count < 3 {
        panic!("Can't triangulate less than three points.")
    }
    let max_triangles = points_count * 4;

    // Find the bounds of the space that contains our points.
    let mut min_point = points[0];
    let mut max_point = min_point;
    for point in points.iter() {
        if point.x > max_point.x {
            max_point.x = point.x;
        }
        if point.y > max_point.y {
            max_point.y = point.y;
        }
        if point.x < min_point.x {
            min_point.x = point.x;
        }
        if point.y < min_point.y {
            min_point.y = point.y;
        }
    }
    let delta_point = Point {
        x: max_point.x - min_point.x,
        y: max_point.y - min_point.y,
    };
    let delta_max = if delta_point.x > delta_point.y {
        delta_point.x
    } else {
        delta_point.y
    };
    let mid_point = Point {
        x: (max_point.x + min_point.x) * 0.5,
        y: (max_point.y + min_point.y) * 0.5,
    };

    // Compute the supertriangle, which encompasses all the input points.
    points.push(Point::new(mid_point.x - 2.0 * delta_max, mid_point.y - delta_max));
    points.push(Point::new(mid_point.x, mid_point.y + 2.0 * delta_max));
    points.push(Point::new(mid_point.x + 2.0 * delta_max, mid_point.y - delta_max));

    // The list of triangles we're gonna fill, initialized with the super-triangle.
    let mut triangles = vec![Triangle(points_count, points_count + 1, points_count + 2)];

    // Include each of the input point into the mesh.
    for i in 0..points_count {
        // Storage for the edges
        let mut edges = Vec::<Edge>::new();

        {
            let mut j = 0;
            while j < triangles.len() {
                if in_circle(points[i],
                             points[triangles[j].0],
                             points[triangles[j].1],
                             points[triangles[j].2]) {
                    edges.push(Edge(triangles[j].0, triangles[j].1));
                    edges.push(Edge(triangles[j].1, triangles[j].2));
                    edges.push(Edge(triangles[j].2, triangles[j].0));
                    triangles.remove(j);
                } else {
                    j += 1;
                }
            }
        }

        // Continue if we've exhausted the array.
        if i >= points_count {
            continue;
        }

        // Remove duplicate edges.

        if edges.len() > 1 {
            let mut j = edges.len() - 2;
            loop {
                let mut k = edges.len() - 1;
                while k >= j + 1 {
                    if edges[j] == edges[k] {
                        edges.remove(k);
                        edges.remove(j);
                        k -= 2;
                    } else {
                        k -= 1;
                    }
                }
                if j > 0 {
                    j -= 1;
                } else {
                    break;
                }
            }
        }

        // Form new triangles from the remaining edges. Edges are added in clockwise order.
        {
            let mut j = 0;
            while j < edges.len() {
                if triangles.len() >= max_triangles {
                    panic!("Exceeded maximum edges");
                }
                triangles.push(Triangle(edges[j].0, edges[j].1, i));
                j += 1;
            }
        }
    }

    // Remove triangles with supertriangle vertices
    let mut i = triangles.len() - 1;
    loop {
        if triangles[i].0 >= points_count || triangles[i].1 >= points_count ||
           triangles[i].2 >= points_count {
            triangles.remove(i);
        }
        if i > 0 {
            i -= 1;
        } else {
            break;
        }
    }

    // Remove the supertriangle vertices
    points.pop();
    points.pop();
    points.pop();

    triangles
}

/// Returns true if the first point lies inside (or on the edge of) the circumcircle made from the
/// three other points.
fn in_circle(p: Point, pc1: Point, pc2: Point, pc3: Point) -> bool {
    // Handle coincident points.
    if (pc1.y - pc2.y).abs() < std::f64::EPSILON && (pc2.y - pc3.y).abs() < std::f64::EPSILON {
        return false;
    }

    let m1: f64;
    let m2: f64;
    let mx1: f64;
    let mx2: f64;
    let my1: f64;
    let my2: f64;
    let xc: f64;
    let yc: f64;

    if (pc2.y - pc1.y).abs() < std::f64::EPSILON {
        m2 = 0.0 - (pc3.x - pc2.x) / (pc3.y - pc2.y);
        mx2 = (pc2.x + pc3.x) * 0.5;
        my2 = (pc2.y + pc3.y) * 0.5;
        xc = (pc2.x + pc1.x) * 0.5;
        yc = m2 * (xc - mx2) + my2;
    } else if (pc3.y - pc2.y).abs() < std::f64::EPSILON {
        m1 = 0.0 - (pc2.x - pc1.x) / (pc2.y - pc1.y);
        mx1 = (pc1.x + pc2.x) * 0.5;
        my1 = (pc1.y + pc2.y) * 0.5;
        xc = (pc3.x + pc2.x) * 0.5;
        yc = m1 * (xc - mx1) + my1;
    } else {
        m1 = 0.0 - (pc2.x - pc1.x) / (pc2.y - pc1.y);
        m2 = 0.0 - (pc3.x - pc2.x) / (pc3.y - pc2.y);
        mx1 = (pc1.x + pc2.x) * 0.5;
        mx2 = (pc2.x + pc3.x) * 0.5;
        my1 = (pc1.y + pc2.y) * 0.5;
        my2 = (pc2.y + pc3.y) * 0.5;
        xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
        yc = m1 * (xc - mx1) + my1;
    }

    let rsqr = (pc2.x - xc).powf(2.0) + (pc2.y - yc).powf(2.0);
    let drsqr = (p.x - xc).powf(2.0) + (p.y - yc).powf(2.0);

    drsqr <= rsqr
}

#[cfg(test)]
mod test {
    use super::{Point, Triangle, triangulate};

    #[test]
    fn test_simple() {
        let mut points =
            vec![Point::new(10.0, 10.0), Point::new(25.0, 15.0), Point::new(15.0, 25.0)];

        let tris: Vec<Triangle> = triangulate(&mut points);

        assert_eq!(tris.len(), 1);
        assert_eq!(tris[..], [Triangle(1, 0, 2)][..]);
    }

    #[test]
    fn test_four_triangles() {
        let mut points = vec![Point::new(10.0, 10.0),
                              Point::new(25.0, 15.0),
                              Point::new(15.0, 25.0),
                              Point::new(30.0, 25.0),
                              Point::new(40.0, 15.0)];

        let tris: Vec<Triangle> = triangulate(&mut points);
        assert_eq!(tris.len(), 4);

        let expected_tris =
            [Triangle(1, 0, 2), Triangle(1, 2, 3), Triangle(0, 1, 4), Triangle(1, 3, 4)];
        assert_eq!(tris[..], expected_tris[..]);
    }

    #[test]
    fn test_overlapping() {
        let mut points =
            vec![Point::new(10.0, 10.0), Point::new(25.0, 15.0), Point::new(25.0, 15.0)];

        let tris: Vec<Triangle> = triangulate(&mut points);

        assert_eq!(tris.len(), 1);
        assert_eq!(tris[..], [Triangle(0, 1, 2)][..]);
    }

    #[test]
    fn test_complex() {
        let mut points = vec![Point::new(601.0, 535.0),
                              Point::new(895.0, 666.0),
                              Point::new(876.0, 110.0),
                              Point::new(448.0, 36.0),
                              Point::new(829.0, 512.0),
                              Point::new(742.0, 363.0),
                              Point::new(267.0, 152.0),
                              Point::new(331.0, 244.0),
                              Point::new(623.0, 335.0),
                              Point::new(245.0, 119.0),
                              Point::new(104.0, 522.0),
                              Point::new(285.0, 561.0),
                              Point::new(282.0, 17.0),
                              Point::new(836.0, 20.0),
                              Point::new(667.0, 462.0),
                              Point::new(65.0, 216.0),
                              Point::new(839.0, 178.0),
                              Point::new(11.0, 264.0),
                              Point::new(181.0, 479.0),
                              Point::new(168.0, 90.0),
                              Point::new(348.0, 504.0),
                              Point::new(688.0, 605.0),
                              Point::new(329.0, 432.0),
                              Point::new(627.0, 461.0),
                              Point::new(450.0, 514.0)];

        let tris: Vec<Triangle> = triangulate(&mut points);

        let expected_tris = [Triangle(1, 2, 4),
                             Triangle(3, 6, 7),
                             Triangle(3, 7, 8),
                             Triangle(6, 3, 12),
                             Triangle(9, 6, 12),
                             Triangle(12, 3, 13),
                             Triangle(4, 5, 14),
                             Triangle(5, 8, 14),
                             Triangle(7, 6, 15),
                             Triangle(4, 2, 16),
                             Triangle(5, 4, 16),
                             Triangle(8, 5, 16),
                             Triangle(3, 8, 16),
                             Triangle(13, 3, 16),
                             Triangle(2, 13, 16),
                             Triangle(10, 11, 18),
                             Triangle(7, 15, 18),
                             Triangle(15, 17, 18),
                             Triangle(17, 10, 18),
                             Triangle(6, 9, 19),
                             Triangle(15, 6, 19),
                             Triangle(9, 12, 19),
                             Triangle(17, 15, 19),
                             Triangle(1, 4, 21),
                             Triangle(4, 14, 21),
                             Triangle(14, 0, 21),
                             Triangle(8, 7, 22),
                             Triangle(7, 18, 22),
                             Triangle(18, 11, 22),
                             Triangle(11, 20, 22),
                             Triangle(0, 14, 23),
                             Triangle(14, 8, 23),
                             Triangle(20, 11, 24),
                             Triangle(11, 21, 24),
                             Triangle(21, 0, 24),
                             Triangle(8, 22, 24),
                             Triangle(23, 8, 24),
                             Triangle(0, 23, 24),
                             Triangle(22, 20, 24)];

        assert_eq!(tris.len(), 39);
        assert_eq!(tris[..], expected_tris[..]);
    }
}
<commit_msg>The input points are a non-mutable borrow now.<commit_after>// Copyright 2017 Samuel Loretan <tynril@gmail.com>

//! Triangulate a set of points

/// A two dimentional point.
#[derive(Clone, Copy, Debug)]
pub struct Point {
    x: f64,
    y: f64,
}

impl Point {
    /// Makes a new point from xy coordinates.
    pub fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }
}

/// A triangle, represented by indexes into a vertice list.
#[derive(Debug, PartialEq)]
pub struct Triangle(usize, usize, usize);

/// An edge, represented by indexes into a vertice list.
#[derive(Debug)]
struct Edge(usize, usize);

impl PartialEq for Edge {
    /// Compare edges regardless of directionality.
    fn eq(&self, other: &Edge) -> bool {
        (self.0 == other.1 && self.1 == other.0) || (self.0 == other.0 && self.1 == other.1)
    }
}

/// An indexable view over two slices.
struct TwoSlices<'a, T: 'a>(&'a [T], &'a [T]);

use std::ops::Index;
impl<'a, T: 'a> Index<usize> for TwoSlices<'a, T> {
    type Output = T;
    fn index(&self, index: usize) -> &T {
        if index < self.0.len() {
            &self.0[index]
        } else {
            &self.1[index - self.0.len()]
        }
    }
}

/// Triangulate a given set of points. The returned triangles are indices into the  list of points.
pub fn triangulate(points: &[Point]) -> Vec<Triangle> {
    // Make sure we have enough points to do a triangulation.
    let points_count = points.len();
    if points_count < 3 {
        panic!("Can't triangulate less than three points.")
    }
    let max_triangles = points_count * 4;

    // Find the bounds of the space that contains our points.
    let mut min_point = points[0];
    let mut max_point = min_point;
    for point in points {
        if point.x > max_point.x {
            max_point.x = point.x;
        }
        if point.y > max_point.y {
            max_point.y = point.y;
        }
        if point.x < min_point.x {
            min_point.x = point.x;
        }
        if point.y < min_point.y {
            min_point.y = point.y;
        }
    }
    let delta_point = Point {
        x: max_point.x - min_point.x,
        y: max_point.y - min_point.y,
    };
    let delta_max = if delta_point.x > delta_point.y {
        delta_point.x
    } else {
        delta_point.y
    };
    let mid_point = Point {
        x: (max_point.x + min_point.x) * 0.5,
        y: (max_point.y + min_point.y) * 0.5,
    };

    // Compute the supertriangle, which encompasses all the input points.
    let supertriangle = [Point::new(mid_point.x - 2.0 * delta_max, mid_point.y - delta_max),
                         Point::new(mid_point.x, mid_point.y + 2.0 * delta_max),
                         Point::new(mid_point.x + 2.0 * delta_max, mid_point.y - delta_max)];

    // Make an iterable slice of our points and the supertriangle.
    let all_points = TwoSlices(points, &supertriangle);

    // The list of triangles we're gonna fill, initialized with the super-triangle.
    let mut triangles = vec![Triangle(points_count, points_count + 1, points_count + 2)];

    // Include each of the input point into the mesh.
    for i in 0..points_count {
        // Storage for the edges
        let mut edges = Vec::<Edge>::new();

        {
            let mut j = 0;
            while j < triangles.len() {
                if in_circle(all_points[i],
                             all_points[triangles[j].0],
                             all_points[triangles[j].1],
                             all_points[triangles[j].2]) {
                    edges.push(Edge(triangles[j].0, triangles[j].1));
                    edges.push(Edge(triangles[j].1, triangles[j].2));
                    edges.push(Edge(triangles[j].2, triangles[j].0));
                    triangles.remove(j);
                } else {
                    j += 1;
                }
            }
        }

        // Remove duplicate edges.
        if edges.len() > 1 {
            let mut j = edges.len() - 2;
            loop {
                let mut k = edges.len() - 1;
                while k >= j + 1 {
                    if edges[j] == edges[k] {
                        edges.remove(k);
                        edges.remove(j);
                        k -= 2;
                    } else {
                        k -= 1;
                    }
                }
                if j > 0 {
                    j -= 1;
                } else {
                    break;
                }
            }
        }

        // Form new triangles from the remaining edges. Edges are added in clockwise order.
        {
            let mut j = 0;
            while j < edges.len() {
                if triangles.len() >= max_triangles {
                    panic!("Exceeded maximum edges");
                }
                triangles.push(Triangle(edges[j].0, edges[j].1, i));
                j += 1;
            }
        }
    }

    // Remove triangles with supertriangle vertices
    let mut i = triangles.len() - 1;
    loop {
        if triangles[i].0 >= points_count || triangles[i].1 >= points_count ||
           triangles[i].2 >= points_count {
            triangles.remove(i);
        }
        if i > 0 {
            i -= 1;
        } else {
            break;
        }
    }

    triangles
}

/// Returns true if the first point lies inside (or on the edge of) the circumcircle made from the
/// three other points.
fn in_circle(p: Point, pc1: Point, pc2: Point, pc3: Point) -> bool {
    // Handle coincident points.
    if (pc1.y - pc2.y).abs() < std::f64::EPSILON && (pc2.y - pc3.y).abs() < std::f64::EPSILON {
        return false;
    }

    let m1: f64;
    let m2: f64;
    let mx1: f64;
    let mx2: f64;
    let my1: f64;
    let my2: f64;
    let xc: f64;
    let yc: f64;

    if (pc2.y - pc1.y).abs() < std::f64::EPSILON {
        m2 = 0.0 - (pc3.x - pc2.x) / (pc3.y - pc2.y);
        mx2 = (pc2.x + pc3.x) * 0.5;
        my2 = (pc2.y + pc3.y) * 0.5;
        xc = (pc2.x + pc1.x) * 0.5;
        yc = m2 * (xc - mx2) + my2;
    } else if (pc3.y - pc2.y).abs() < std::f64::EPSILON {
        m1 = 0.0 - (pc2.x - pc1.x) / (pc2.y - pc1.y);
        mx1 = (pc1.x + pc2.x) * 0.5;
        my1 = (pc1.y + pc2.y) * 0.5;
        xc = (pc3.x + pc2.x) * 0.5;
        yc = m1 * (xc - mx1) + my1;
    } else {
        m1 = 0.0 - (pc2.x - pc1.x) / (pc2.y - pc1.y);
        m2 = 0.0 - (pc3.x - pc2.x) / (pc3.y - pc2.y);
        mx1 = (pc1.x + pc2.x) * 0.5;
        mx2 = (pc2.x + pc3.x) * 0.5;
        my1 = (pc1.y + pc2.y) * 0.5;
        my2 = (pc2.y + pc3.y) * 0.5;
        xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
        yc = m1 * (xc - mx1) + my1;
    }

    let rsqr = (pc2.x - xc).powf(2.0) + (pc2.y - yc).powf(2.0);
    let drsqr = (p.x - xc).powf(2.0) + (p.y - yc).powf(2.0);

    drsqr <= rsqr
}

#[cfg(test)]
mod test {
    use super::{Point, Triangle, triangulate};

    #[test]
    fn test_simple() {
        let points = vec![Point::new(10.0, 10.0), Point::new(25.0, 15.0), Point::new(15.0, 25.0)];

        let tris: Vec<Triangle> = triangulate(&points);

        assert_eq!(tris.len(), 1);
        assert_eq!(tris[..], [Triangle(1, 0, 2)][..]);
    }

    #[test]
    fn test_four_triangles() {
        let points = vec![Point::new(10.0, 10.0),
                          Point::new(25.0, 15.0),
                          Point::new(15.0, 25.0),
                          Point::new(30.0, 25.0),
                          Point::new(40.0, 15.0)];

        let tris: Vec<Triangle> = triangulate(&points);
        assert_eq!(tris.len(), 4);

        let expected_tris =
            [Triangle(1, 0, 2), Triangle(1, 2, 3), Triangle(0, 1, 4), Triangle(1, 3, 4)];
        assert_eq!(tris[..], expected_tris[..]);
    }

    #[test]
    fn test_overlapping() {
        let points = vec![Point::new(10.0, 10.0), Point::new(25.0, 15.0), Point::new(25.0, 15.0)];

        let tris: Vec<Triangle> = triangulate(&points);

        assert_eq!(tris.len(), 1);
        assert_eq!(tris[..], [Triangle(0, 1, 2)][..]);
    }

    #[test]
    fn test_complex() {
        let points = vec![Point::new(601.0, 535.0),
                          Point::new(895.0, 666.0),
                          Point::new(876.0, 110.0),
                          Point::new(448.0, 36.0),
                          Point::new(829.0, 512.0),
                          Point::new(742.0, 363.0),
                          Point::new(267.0, 152.0),
                          Point::new(331.0, 244.0),
                          Point::new(623.0, 335.0),
                          Point::new(245.0, 119.0),
                          Point::new(104.0, 522.0),
                          Point::new(285.0, 561.0),
                          Point::new(282.0, 17.0),
                          Point::new(836.0, 20.0),
                          Point::new(667.0, 462.0),
                          Point::new(65.0, 216.0),
                          Point::new(839.0, 178.0),
                          Point::new(11.0, 264.0),
                          Point::new(181.0, 479.0),
                          Point::new(168.0, 90.0),
                          Point::new(348.0, 504.0),
                          Point::new(688.0, 605.0),
                          Point::new(329.0, 432.0),
                          Point::new(627.0, 461.0),
                          Point::new(450.0, 514.0)];

        let tris: Vec<Triangle> = triangulate(&points);

        let expected_tris = [Triangle(1, 2, 4),
                             Triangle(3, 6, 7),
                             Triangle(3, 7, 8),
                             Triangle(6, 3, 12),
                             Triangle(9, 6, 12),
                             Triangle(12, 3, 13),
                             Triangle(4, 5, 14),
                             Triangle(5, 8, 14),
                             Triangle(7, 6, 15),
                             Triangle(4, 2, 16),
                             Triangle(5, 4, 16),
                             Triangle(8, 5, 16),
                             Triangle(3, 8, 16),
                             Triangle(13, 3, 16),
                             Triangle(2, 13, 16),
                             Triangle(10, 11, 18),
                             Triangle(7, 15, 18),
                             Triangle(15, 17, 18),
                             Triangle(17, 10, 18),
                             Triangle(6, 9, 19),
                             Triangle(15, 6, 19),
                             Triangle(9, 12, 19),
                             Triangle(17, 15, 19),
                             Triangle(1, 4, 21),
                             Triangle(4, 14, 21),
                             Triangle(14, 0, 21),
                             Triangle(8, 7, 22),
                             Triangle(7, 18, 22),
                             Triangle(18, 11, 22),
                             Triangle(11, 20, 22),
                             Triangle(0, 14, 23),
                             Triangle(14, 8, 23),
                             Triangle(20, 11, 24),
                             Triangle(11, 21, 24),
                             Triangle(21, 0, 24),
                             Triangle(8, 22, 24),
                             Triangle(23, 8, 24),
                             Triangle(0, 23, 24),
                             Triangle(22, 20, 24)];

        assert_eq!(tris.len(), 39);
        assert_eq!(tris[..], expected_tris[..]);
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![cfg_attr(test, deny(warnings))]
#![doc(html_root_url = "https://docs.rs/reqwest/0.10.0-alpha.2")]

//! # reqwest
//!
//! The `reqwest` crate provides a convenient, higher-level HTTP
//! [`Client`][client].
//!
//! It handles many of the things that most people just expect an HTTP client
//! to do for them.
//!
//! - Async and [blocking](blocking) Clients
//! - Plain bodies, [JSON](#json), [urlencoded](#forms), [multipart](multipart)
//! - Customizable [redirect policy](#redirect-policies)
//! - HTTP [Proxies](#proxies)
//! - Uses system-native [TLS](#tls)
//! - Cookies
//!
//! The [`reqwest::Client`][client] is asynchronous. For applications wishing
//! to only make a few HTTP requests, the [`reqwest::blocking`](blocking) API
//! may be more convenient.
//!
//! Additional learning resources include:
//!
//! - [The Rust Cookbook](https://rust-lang-nursery.github.io/rust-cookbook/web/clients.html)
//! - [Reqwest Repository Examples](https://github.com/seanmonstar/reqwest/tree/master/examples)
//!
//! ## Making a GET request
//!
//! For a single request, you can use the [`get`][get] shortcut method.
//!
//! ```rust
//! # async fn run() -> Result<(), reqwest::Error> {
//! let body = reqwest::get("https://www.rust-lang.org")
//!     .await?
//!     .text()
//!     .await?;
//!
//! println!("body = {:?}", body);
//! # Ok(())
//! # }
//! ```
//!
//! **NOTE**: If you plan to perform multiple requests, it is best to create a
//! [`Client`][client] and reuse it, taking advantage of keep-alive connection
//! pooling.
//!
//! ## Making POST requests (or setting request bodies)
//!
//! There are several ways you can set the body of a request. The basic one is
//! by using the `body()` method of a [`RequestBuilder`][builder]. This lets you set the
//! exact raw bytes of what the body should be. It accepts various types,
//! including `String`, `Vec<u8>`, and `File`. If you wish to pass a custom
//! type, you can use the `reqwest::Body` constructors.
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # async fn run() -> Result<(), Error> {
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .body("the exact body that is sent")
//!     .send()
//!     .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### Forms
//!
//! It's very common to want to send form data in a request body. This can be
//! done with any type that can be serialized into form data.
//!
//! This can be an array of tuples, or a `HashMap`, or a custom type that
//! implements [`Serialize`][serde].
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # async fn run() -> Result<(), Error> {
//! // This will POST a body of `foo=bar&baz=quux`
//! let params = [("foo", "bar"), ("baz", "quux")];
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .form(&params)
//!     .send()
//!     .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### JSON
//!
//! There is also a `json` method helper on the [`RequestBuilder`][builder] that works in
//! a similar fashion the `form` method. It can take any value that can be
//! serialized into JSON. The feature `json` is required.
//!
//! ```rust
//! # use reqwest::Error;
//! # use std::collections::HashMap;
//! #
//! # #[cfg(feature = "json")]
//! # async fn run() -> Result<(), Error> {
//! // This will POST a body of `{"lang":"rust","body":"json"}`
//! let mut map = HashMap::new();
//! map.insert("lang", "rust");
//! map.insert("body", "json");
//!
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .json(&map)
//!     .send()
//!     .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Redirect Policies
//!
//! By default, a `Client` will automatically handle HTTP redirects, detecting
//! loops, and having a maximum redirect chain of 10 hops. To customize this
//! behavior, a [`RedirectPolicy`][redirect] can used with a `ClientBuilder`.
//!
//! ## Cookies
//!
//! The automatic storing and sending of session cookies can be enabled with
//! the [`cookie_store`][ClientBuilder::cookie_store] method on `ClientBuilder`.
//!
//! ## Proxies
//!
//! **NOTE**: System proxies are enabled by default.
//!
//! System proxies look in environment variables to set HTTP or HTTPS proxies.
//!
//! `HTTP_PROXY` or `http_proxy` provide http proxies for http connections while
//! `HTTPS_PROXY` or `https_proxy` provide HTTPS proxies for HTTPS connections.
//!
//! These can be overwritten by adding a [`Proxy`](Proxy) to `ClientBuilder`
//! i.e. `let proxy = reqwest::Proxy::http("https://secure.example")?;`
//! or disabled by calling `ClientBuilder::no_proxy()`.
//!
//! ## TLS
//!
//! By default, a `Client` will make use of system-native transport layer
//! security to connect to HTTPS destinations. This means schannel on Windows,
//! Security-Framework on macOS, and OpenSSL on Linux.
//!
//! - Additional X509 certificates can be configured on a `ClientBuilder` with the
//!   [`Certificate`](Certificate) type.
//! - Client certificates can be add to a `ClientBuilder` with the
//!   [`Identity`][Identity] type.
//! - Various parts of TLS can also be configured or even disabled on the
//!   `ClientBuilder`.
//!
//! ## Optional Features
//!
//! The following are a list of [Cargo features][cargo-features] that can be
//! enabled or disabled:
//!
//! - **default-tls** *(enabled by default)*: Provides TLS support via the
//!   `native-tls` library to connect over HTTPS.
//! - **default-tls-vendored**: Enables the `vendored` feature of `native-tls`.
//! - **blocking**: Provides the [blocking][] client API.
//! - **cookies**: Provides cookie session support.
//! - **gzip**: Provides response body gzip decompression.
//! - **json**: Provides serialization and deserialization for JSON bodies.
//! - **stream**: Adds support for `futures::Stream`.
//!
//!
//! [hyper]: http://hyper.rs
//! [client]: ./struct.Client.html
//! [response]: ./struct.Response.html
//! [get]: ./fn.get.html
//! [builder]: ./struct.RequestBuilder.html
//! [serde]: http://serde.rs
//! [redirect]: ./struct.RedirectPolicy.html
//! [Proxy]: ./struct.Proxy.html
//! [cargo-features]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section

////! - **rustls-tls**: Provides TLS support via the `rustls` library.
////! - **socks**: Provides SOCKS5 proxy support.
////! - **trust-dns**: Enables a trust-dns async resolver instead of default
////!   threadpool using `getaddrinfo`.

macro_rules! if_wasm {
    ($($item:item)*) => {$(
        #[cfg(target_arch = "wasm32")]
        $item
    )*}
}

macro_rules! if_hyper {
    ($($item:item)*) => {$(
        #[cfg(not(target_arch = "wasm32"))]
        $item
    )*}
}

pub use http::header;
pub use http::Method;
pub use http::{StatusCode, Version};
pub use url::Url;

// universal mods
#[macro_use]
mod error;
mod into_url;

pub use self::error::{Error, Result};
pub use self::into_url::IntoUrl;

/// Shortcut method to quickly make a `GET` request.
///
/// See also the methods on the [`reqwest::Response`](./struct.Response.html)
/// type.
///
/// **NOTE**: This function creates a new internal `Client` on each call,
/// and so should not be used if making many requests. Create a
/// [`Client`](./struct.Client.html) instead.
///
/// # Examples
///
/// ```rust
/// # async fn run() -> Result<(), reqwest::Error> {
/// let body = reqwest::get("https://www.rust-lang.org").await?
///     .text().await?;
/// # Ok(())
/// # }
/// ```
///
/// # Errors
///
/// This function fails if:
///
/// - native TLS backend cannot be initialized
/// - supplied `Url` cannot be parsed
/// - there was an error while sending request
/// - redirect loop was detected
/// - redirect limit was exhausted
pub async fn get<T: IntoUrl>(url: T) -> crate::Result<Response> {
    Client::builder().build()?.get(url).send().await
}

fn _assert_impls() {
    fn assert_send<T: Send>() {}
    fn assert_sync<T: Sync>() {}
    fn assert_clone<T: Clone>() {}

    assert_send::<Client>();
    assert_sync::<Client>();
    assert_clone::<Client>();

    assert_send::<Request>();
    assert_send::<RequestBuilder>();

    #[cfg(not(target_arch = "wasm32"))]
    {
        assert_send::<Response>();
    }

    assert_send::<Error>();
    assert_sync::<Error>();
}

if_hyper! {
    #[cfg(test)]
    #[macro_use]
    extern crate doc_comment;

    #[macro_use]
    extern crate lazy_static;

    #[cfg(test)]
    doctest!("../README.md");

    pub use self::async_impl::{
        multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response,
    };
    pub use self::proxy::Proxy;
    pub use self::redirect::{RedirectAction, RedirectAttempt, RedirectPolicy};
    #[cfg(feature = "tls")]
    pub use self::tls::{Certificate, Identity};

    mod async_impl;
    #[cfg(feature = "blocking")]
    pub mod blocking;
    mod connect;
    #[cfg(feature = "cookies")]
    pub mod cookie;
    //#[cfg(feature = "trust-dns")]
    //mod dns;
    mod proxy;
    mod redirect;
    #[cfg(feature = "tls")]
    mod tls;

    #[doc(hidden)]
    #[deprecated(note = "types moved to top of crate")]
    pub mod r#async {
        pub use crate::async_impl::{
            multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response,
        };
    }
}

if_wasm! {
    mod wasm;

    pub use self::wasm::{Body, Client, ClientBuilder, Request, RequestBuilder, Response};
}
<commit_msg>Export the `ResponseBuilderExt` trait again (#738)<commit_after>#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![cfg_attr(test, deny(warnings))]
#![doc(html_root_url = "https://docs.rs/reqwest/0.10.0-alpha.2")]

//! # reqwest
//!
//! The `reqwest` crate provides a convenient, higher-level HTTP
//! [`Client`][client].
//!
//! It handles many of the things that most people just expect an HTTP client
//! to do for them.
//!
//! - Async and [blocking](blocking) Clients
//! - Plain bodies, [JSON](#json), [urlencoded](#forms), [multipart](multipart)
//! - Customizable [redirect policy](#redirect-policies)
//! - HTTP [Proxies](#proxies)
//! - Uses system-native [TLS](#tls)
//! - Cookies
//!
//! The [`reqwest::Client`][client] is asynchronous. For applications wishing
//! to only make a few HTTP requests, the [`reqwest::blocking`](blocking) API
//! may be more convenient.
//!
//! Additional learning resources include:
//!
//! - [The Rust Cookbook](https://rust-lang-nursery.github.io/rust-cookbook/web/clients.html)
//! - [Reqwest Repository Examples](https://github.com/seanmonstar/reqwest/tree/master/examples)
//!
//! ## Making a GET request
//!
//! For a single request, you can use the [`get`][get] shortcut method.
//!
//! ```rust
//! # async fn run() -> Result<(), reqwest::Error> {
//! let body = reqwest::get("https://www.rust-lang.org")
//!     .await?
//!     .text()
//!     .await?;
//!
//! println!("body = {:?}", body);
//! # Ok(())
//! # }
//! ```
//!
//! **NOTE**: If you plan to perform multiple requests, it is best to create a
//! [`Client`][client] and reuse it, taking advantage of keep-alive connection
//! pooling.
//!
//! ## Making POST requests (or setting request bodies)
//!
//! There are several ways you can set the body of a request. The basic one is
//! by using the `body()` method of a [`RequestBuilder`][builder]. This lets you set the
//! exact raw bytes of what the body should be. It accepts various types,
//! including `String`, `Vec<u8>`, and `File`. If you wish to pass a custom
//! type, you can use the `reqwest::Body` constructors.
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # async fn run() -> Result<(), Error> {
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .body("the exact body that is sent")
//!     .send()
//!     .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### Forms
//!
//! It's very common to want to send form data in a request body. This can be
//! done with any type that can be serialized into form data.
//!
//! This can be an array of tuples, or a `HashMap`, or a custom type that
//! implements [`Serialize`][serde].
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # async fn run() -> Result<(), Error> {
//! // This will POST a body of `foo=bar&baz=quux`
//! let params = [("foo", "bar"), ("baz", "quux")];
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .form(&params)
//!     .send()
//!     .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### JSON
//!
//! There is also a `json` method helper on the [`RequestBuilder`][builder] that works in
//! a similar fashion the `form` method. It can take any value that can be
//! serialized into JSON. The feature `json` is required.
//!
//! ```rust
//! # use reqwest::Error;
//! # use std::collections::HashMap;
//! #
//! # #[cfg(feature = "json")]
//! # async fn run() -> Result<(), Error> {
//! // This will POST a body of `{"lang":"rust","body":"json"}`
//! let mut map = HashMap::new();
//! map.insert("lang", "rust");
//! map.insert("body", "json");
//!
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .json(&map)
//!     .send()
//!     .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Redirect Policies
//!
//! By default, a `Client` will automatically handle HTTP redirects, detecting
//! loops, and having a maximum redirect chain of 10 hops. To customize this
//! behavior, a [`RedirectPolicy`][redirect] can used with a `ClientBuilder`.
//!
//! ## Cookies
//!
//! The automatic storing and sending of session cookies can be enabled with
//! the [`cookie_store`][ClientBuilder::cookie_store] method on `ClientBuilder`.
//!
//! ## Proxies
//!
//! **NOTE**: System proxies are enabled by default.
//!
//! System proxies look in environment variables to set HTTP or HTTPS proxies.
//!
//! `HTTP_PROXY` or `http_proxy` provide http proxies for http connections while
//! `HTTPS_PROXY` or `https_proxy` provide HTTPS proxies for HTTPS connections.
//!
//! These can be overwritten by adding a [`Proxy`](Proxy) to `ClientBuilder`
//! i.e. `let proxy = reqwest::Proxy::http("https://secure.example")?;`
//! or disabled by calling `ClientBuilder::no_proxy()`.
//!
//! ## TLS
//!
//! By default, a `Client` will make use of system-native transport layer
//! security to connect to HTTPS destinations. This means schannel on Windows,
//! Security-Framework on macOS, and OpenSSL on Linux.
//!
//! - Additional X509 certificates can be configured on a `ClientBuilder` with the
//!   [`Certificate`](Certificate) type.
//! - Client certificates can be add to a `ClientBuilder` with the
//!   [`Identity`][Identity] type.
//! - Various parts of TLS can also be configured or even disabled on the
//!   `ClientBuilder`.
//!
//! ## Optional Features
//!
//! The following are a list of [Cargo features][cargo-features] that can be
//! enabled or disabled:
//!
//! - **default-tls** *(enabled by default)*: Provides TLS support via the
//!   `native-tls` library to connect over HTTPS.
//! - **default-tls-vendored**: Enables the `vendored` feature of `native-tls`.
//! - **blocking**: Provides the [blocking][] client API.
//! - **cookies**: Provides cookie session support.
//! - **gzip**: Provides response body gzip decompression.
//! - **json**: Provides serialization and deserialization for JSON bodies.
//! - **stream**: Adds support for `futures::Stream`.
//!
//!
//! [hyper]: http://hyper.rs
//! [client]: ./struct.Client.html
//! [response]: ./struct.Response.html
//! [get]: ./fn.get.html
//! [builder]: ./struct.RequestBuilder.html
//! [serde]: http://serde.rs
//! [redirect]: ./struct.RedirectPolicy.html
//! [Proxy]: ./struct.Proxy.html
//! [cargo-features]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section

////! - **rustls-tls**: Provides TLS support via the `rustls` library.
////! - **socks**: Provides SOCKS5 proxy support.
////! - **trust-dns**: Enables a trust-dns async resolver instead of default
////!   threadpool using `getaddrinfo`.

macro_rules! if_wasm {
    ($($item:item)*) => {$(
        #[cfg(target_arch = "wasm32")]
        $item
    )*}
}

macro_rules! if_hyper {
    ($($item:item)*) => {$(
        #[cfg(not(target_arch = "wasm32"))]
        $item
    )*}
}

pub use http::header;
pub use http::Method;
pub use http::{StatusCode, Version};
pub use url::Url;

// universal mods
#[macro_use]
mod error;
mod into_url;

pub use self::error::{Error, Result};
pub use self::into_url::IntoUrl;

/// Shortcut method to quickly make a `GET` request.
///
/// See also the methods on the [`reqwest::Response`](./struct.Response.html)
/// type.
///
/// **NOTE**: This function creates a new internal `Client` on each call,
/// and so should not be used if making many requests. Create a
/// [`Client`](./struct.Client.html) instead.
///
/// # Examples
///
/// ```rust
/// # async fn run() -> Result<(), reqwest::Error> {
/// let body = reqwest::get("https://www.rust-lang.org").await?
///     .text().await?;
/// # Ok(())
/// # }
/// ```
///
/// # Errors
///
/// This function fails if:
///
/// - native TLS backend cannot be initialized
/// - supplied `Url` cannot be parsed
/// - there was an error while sending request
/// - redirect loop was detected
/// - redirect limit was exhausted
pub async fn get<T: IntoUrl>(url: T) -> crate::Result<Response> {
    Client::builder().build()?.get(url).send().await
}

fn _assert_impls() {
    fn assert_send<T: Send>() {}
    fn assert_sync<T: Sync>() {}
    fn assert_clone<T: Clone>() {}

    assert_send::<Client>();
    assert_sync::<Client>();
    assert_clone::<Client>();

    assert_send::<Request>();
    assert_send::<RequestBuilder>();

    #[cfg(not(target_arch = "wasm32"))]
    {
        assert_send::<Response>();
    }

    assert_send::<Error>();
    assert_sync::<Error>();
}

if_hyper! {
    #[cfg(test)]
    #[macro_use]
    extern crate doc_comment;

    #[macro_use]
    extern crate lazy_static;

    #[cfg(test)]
    doctest!("../README.md");

    pub use self::async_impl::{
        multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response, ResponseBuilderExt,
    };
    pub use self::proxy::Proxy;
    pub use self::redirect::{RedirectAction, RedirectAttempt, RedirectPolicy};
    #[cfg(feature = "tls")]
    pub use self::tls::{Certificate, Identity};

    mod async_impl;
    #[cfg(feature = "blocking")]
    pub mod blocking;
    mod connect;
    #[cfg(feature = "cookies")]
    pub mod cookie;
    //#[cfg(feature = "trust-dns")]
    //mod dns;
    mod proxy;
    mod redirect;
    #[cfg(feature = "tls")]
    mod tls;

    #[doc(hidden)]
    #[deprecated(note = "types moved to top of crate")]
    pub mod r#async {
        pub use crate::async_impl::{
            multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response,
        };
    }
}

if_wasm! {
    mod wasm;

    pub use self::wasm::{Body, Client, ClientBuilder, Request, RequestBuilder, Response};
}
<|endoftext|>


<commit_before>#![no_std]

pub mod prelude;

// TODO documentation
// TODO attributes
// TODO MACROS
#[macro_export] macro_rules! lisp {
    // empty
    () => (());
    (()) => (());

    // special forms
    ((ns $($ns_form:tt)*) $($body:tt)*) => {
        $(lisp!($ns_form);)*
        $(lisp!($body);)*
    };
    ((extern [$($krate:tt)*])) => {
        $(lisp!(@krate $krate);)*
    };
    ((use [$($uze:tt)*])) => {
        $(lisp!(@uze $uze);)*
    };
    ((lambda ($($argn:ident)*) $($body:tt)*)) => {
        // regular lambda
        |$($argn),*| { $(lisp!($body));* }
    };
    ((lambda (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {
        // regular lambda
        |$($argn:$argt),*| -> $ret { $(lisp!($body));* }
    };
    ((lambda $s:ident (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {{
        // recursive lambda
        // $s MUST NOT be "self"
        // recurse by calling ($s ...)
        // FIXME recursive lambdas can't capture variables

        lisp!((rust { fn $s($($argn: $argt),*) -> $ret { $(lisp!($body));* } $s }))
    }};
    ((defn $name:ident () $($body:tt)*)) => {
        fn $name() {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&$selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&$selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&mut $selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&mut $selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident: Box<Self>) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph: Box<Self> $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([$(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($($argn:$argt),*) -> $ret {
            $(lisp!($body));*
        }
    };

    ((defstruct $name:ident $(($typ:ty))*)) => {
        struct $name($($typ),*);
    };
    ((defstruct $name:ident $(($field:ident $typ:ty))*)) => {
        struct $name { $($field: $typ),* }
    };
    ((defstruct $name:ident <$($gen:ident)*>)) => {
        struct $name<$($gen),*>;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($typ:ty))*)) => {
        struct $name<$($gen),*>($($typ),*) where $($wty: $($wtr)*),*;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($field:ident $typ:ty))*)) => {
        struct $name<$($gen),*> where $($wty: $($wtr)*),* { $($field: $typ),* }
    };

    ((deftype $name:ident $typ:ty)) => { type $name = $typ; };
    ((deftype $name:ident <$($gen:ident)*> $typ:ty)) => { type $name<$($gen),*> = $typ; };

    ((defimpl ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl $trate for $typ {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) (where $(($wty:ident $($wtr:tt)*))*) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };

    ((if $cond:tt $yes:tt $no:tt)) => {
        if lisp!($cond) { lisp!($yes) } else { lisp!($no) }
    };
    ((while $cond:tt $($body:tt)*)) => {
        while lisp!($cond) { $(lisp!($body));* }
    };
    // TODO for loops
    ((match $var:tt $(($cond:pat) $arm:tt)*)) => {
        match lisp!($var) {
            $($cond => lisp!($arm)),*
        }
    };
    ((do $($stmts:tt)*)) => {{
        $(lisp!($stmts));*
    }};

    // variables
    ((let [] $($body:tt)*)) => {{
        $(lisp!($body));*
    }};
    ((let [mut $var:ident $val:tt $($bindings:tt)*] $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        lisp!((let [$($bindings)*] $($body)*))
    }};
    ((let [$var:ident $val:tt $($bindings:tt)*] $($body:tt)*)) => {{
        let $var = lisp!($val);
        lisp!((let [$($bindings)*] $($body)*))
    }};
    ((:= $var:ident $val:tt)) => {
        $var = lisp!($val);
    };

    // escape hatch
    ((rust $body:block)) => {
        { $body }
    };

    // list parsing
    (($($elem:tt)*)) => {
        lisp!(@list $($elem),*)
    };

    // parsers for unary and binary operators
    (@list -,    $arg:tt   ) => { lisp!(@unary  _neg,   $arg   ) };
    (@list !,    $arg:tt   ) => { lisp!(@unary  _not,   $arg   ) };
    (@list +,  $($arg:tt),*) => { lisp!(@binary _add, $($arg),*) };
    (@list &,  $($arg:tt),*) => { lisp!(@binary _and, $($arg),*) };
    (@list |,  $($arg:tt),*) => { lisp!(@binary _or,  $($arg),*) };
    (@list ^,  $($arg:tt),*) => { lisp!(@binary _xor, $($arg),*) };
    (@list /,  $($arg:tt),*) => { lisp!(@binary _div, $($arg),*) };
    (@list *,  $($arg:tt),*) => { lisp!(@binary _mul, $($arg),*) };
    (@list %,  $($arg:tt),*) => { lisp!(@binary _rem, $($arg),*) };
    (@list <<, $($arg:tt),*) => { lisp!(@binary _shl, $($arg),*) };
    (@list >>, $($arg:tt),*) => { lisp!(@binary _shr, $($arg),*) };
    (@list -,  $($arg:tt),*) => { lisp!(@binary _sub, $($arg),*) };
    (@list ==, $($arg:tt),*) => { lisp!(@binary _eq,  $($arg),*) };
    (@list !=, $($arg:tt),*) => { lisp!(@binary _ne,  $($arg),*) };
    (@list >,  $($arg:tt),*) => { lisp!(@binary _gt,  $($arg),*) };
    (@list <,  $($arg:tt),*) => { lisp!(@binary _lt,  $($arg),*) };
    (@list >=, $($arg:tt),*) => { lisp!(@binary _ge,  $($arg),*) };
    (@list <=, $($arg:tt),*) => { lisp!(@binary _le,  $($arg),*) };

    // generically turn unary/binary operators into function calls
    // binary operators can be used as n-ary operators through @reduce
    (@unary  $op:ident, $a:tt)        => { lisp!(@list $op, $a)     };
    (@binary $op:ident, $a:tt, $b:tt) => { lisp!(@list $op, $a, $b) };
    (@binary $op:ident, $a:tt, $b:tt, $($rest:tt),+) =>
                                               { lisp!(@reduce $op,
                                                       ($op $a $b),
                                                       $($rest),+) };

    // reduce implementation
    // TODO external entry point for @reduce
    (@reduce $op:ident, $acc:tt)                       => { lisp!($acc)          };
    (@reduce $op:ident, $acc:tt, $a:tt)                => { lisp!(@reduce $op,
                                                                  ($op $acc $a)) };
    (@reduce $op:ident, $acc:tt, $a:tt, $($rest:tt),+) => { lisp!(@reduce $op,
                                                                  ($op $acc $a),
                                                                  $($rest),+)    };
    // ns form helpers
    (@krate $(^$attr:meta)* $krate:ident) => {
        $(#[$attr:meta])*
        extern crate $krate;
    };
    (@krate $(^$attr:meta)* ($krate:ident $alias:ident)) => {
        $(#[$attr:meta])*
        extern crate $krate as $alias;
    };
    (@uze ($($head:ident)*)) => { use $($head)::*; };
    (@uze ($($head:ident)* { $($multiple:ident)* })) => {
        lisp!(@uze mult ($($head)*) { $($multiple)* });
    };
    (@uze mult $head:tt { $($multiple:ident)* }) => {
        $(lisp!(@uze mult out $head $multiple);)*
    };
    (@uze mult out ($($head:ident)*) $multiple:ident) => {
        use $($head)::*::$multiple;
    };

    // macro calls
    (@list $mac:ident, !) => {
        $mac!()
    };
    (@list $mac:ident, !, $($arg:tt),*) => {
        $mac!($(lisp!($arg)),*)
    };

    // struct constructors
    (@list $name:ident, ., $(($member:ident $val:tt)),*) => {
        $name { $($member: lisp!($val))* }
    };

    // function calls
    (@list $name:expr) => {
        lisp!($name)()
    };
    (@list $name:expr, $($arg:tt),*) => {
        lisp!($name)($(lisp!($arg)),*)
    };

    // one expression
    ($e:expr) => ($e);
}
<commit_msg>fix unary & and *<commit_after>#![no_std]

pub mod prelude;

// TODO documentation
// TODO attributes
// TODO MACROS
#[macro_export] macro_rules! lisp {
    // empty
    () => (());
    (()) => (());

    // special forms
    ((ns $($ns_form:tt)*) $($body:tt)*) => {
        $(lisp!($ns_form);)*
        $(lisp!($body);)*
    };
    ((extern [$($krate:tt)*])) => {
        $(lisp!(@krate $krate);)*
    };
    ((use [$($uze:tt)*])) => {
        $(lisp!(@uze $uze);)*
    };
    ((lambda ($($argn:ident)*) $($body:tt)*)) => {
        // regular lambda
        |$($argn),*| { $(lisp!($body));* }
    };
    ((lambda (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {
        // regular lambda
        |$($argn:$argt),*| -> $ret { $(lisp!($body));* }
    };
    ((lambda $s:ident (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {{
        // recursive lambda
        // $s MUST NOT be "self"
        // recurse by calling ($s ...)
        // FIXME recursive lambdas can't capture variables

        lisp!((rust { fn $s($($argn: $argt),*) -> $ret { $(lisp!($body));* } $s }))
    }};
    ((defn $name:ident () $($body:tt)*)) => {
        fn $name() {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&$selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&$selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&mut $selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&mut $selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident: Box<Self>) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph: Box<Self> $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([$(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($($argn:$argt),*) -> $ret {
            $(lisp!($body));*
        }
    };

    ((defstruct $name:ident $(($typ:ty))*)) => {
        struct $name($($typ),*);
    };
    ((defstruct $name:ident $(($field:ident $typ:ty))*)) => {
        struct $name { $($field: $typ),* }
    };
    ((defstruct $name:ident <$($gen:ident)*>)) => {
        struct $name<$($gen),*>;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($typ:ty))*)) => {
        struct $name<$($gen),*>($($typ),*) where $($wty: $($wtr)*),*;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($field:ident $typ:ty))*)) => {
        struct $name<$($gen),*> where $($wty: $($wtr)*),* { $($field: $typ),* }
    };

    ((deftype $name:ident $typ:ty)) => { type $name = $typ; };
    ((deftype $name:ident <$($gen:ident)*> $typ:ty)) => { type $name<$($gen),*> = $typ; };

    ((defimpl ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl $trate for $typ {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) (where $(($wty:ident $($wtr:tt)*))*) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };

    ((if $cond:tt $yes:tt $no:tt)) => {
        if lisp!($cond) { lisp!($yes) } else { lisp!($no) }
    };
    ((while $cond:tt $($body:tt)*)) => {
        while lisp!($cond) { $(lisp!($body));* }
    };
    // TODO for loops
    ((match $var:tt $(($cond:pat) $arm:tt)*)) => {
        match lisp!($var) {
            $($cond => lisp!($arm)),*
        }
    };
    ((do $($stmts:tt)*)) => {{
        $(lisp!($stmts));*
    }};

    // variables
    ((let [] $($body:tt)*)) => {{
        $(lisp!($body));*
    }};
    ((let [mut $var:ident $val:tt $($bindings:tt)*] $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        lisp!((let [$($bindings)*] $($body)*))
    }};
    ((let [$var:ident $val:tt $($bindings:tt)*] $($body:tt)*)) => {{
        let $var = lisp!($val);
        lisp!((let [$($bindings)*] $($body)*))
    }};
    ((:= $var:ident $val:tt)) => {
        $var = lisp!($val);
    };

    // escape hatch
    ((rust $body:block)) => {
        { $body }
    };

    // list parsing
    (($($elem:tt)*)) => {
        lisp!(@list $($elem),*)
    };

    // parsers for unary and binary operators
    (@list -,    $arg:tt   ) => { lisp!(@unary  _neg,   $arg   ) };
    (@list !,    $arg:tt   ) => { lisp!(@unary  _not,   $arg   ) };
    (@list +,  $($arg:tt),*) => { lisp!(@binary _add, $($arg),*) };
    (@list &,  $arg:tt) => { &lisp!($arg) };
    (@list &,  $($arg:tt),*) => { lisp!(@binary _and, $($arg),*) };
    (@list |,  $($arg:tt),*) => { lisp!(@binary _or,  $($arg),*) };
    (@list ^,  $($arg:tt),*) => { lisp!(@binary _xor, $($arg),*) };
    (@list /,  $($arg:tt),*) => { lisp!(@binary _div, $($arg),*) };
    (@list *,  $arg:tt) => { *lisp!($arg) };
    (@list *,  $($arg:tt),*) => { lisp!(@binary _mul, $($arg),*) };
    (@list %,  $($arg:tt),*) => { lisp!(@binary _rem, $($arg),*) };
    (@list <<, $($arg:tt),*) => { lisp!(@binary _shl, $($arg),*) };
    (@list >>, $($arg:tt),*) => { lisp!(@binary _shr, $($arg),*) };
    (@list -,  $($arg:tt),*) => { lisp!(@binary _sub, $($arg),*) };
    (@list ==, $($arg:tt),*) => { lisp!(@binary _eq,  $($arg),*) };
    (@list !=, $($arg:tt),*) => { lisp!(@binary _ne,  $($arg),*) };
    (@list >,  $($arg:tt),*) => { lisp!(@binary _gt,  $($arg),*) };
    (@list <,  $($arg:tt),*) => { lisp!(@binary _lt,  $($arg),*) };
    (@list >=, $($arg:tt),*) => { lisp!(@binary _ge,  $($arg),*) };
    (@list <=, $($arg:tt),*) => { lisp!(@binary _le,  $($arg),*) };

    // generically turn unary/binary operators into function calls
    // binary operators can be used as n-ary operators through @reduce
    (@unary  $op:ident, $a:tt)        => { lisp!(@list $op, $a)     };
    (@binary $op:ident, $a:tt, $b:tt) => { lisp!(@list $op, $a, $b) };
    (@binary $op:ident, $a:tt, $b:tt, $($rest:tt),+) =>
                                               { lisp!(@reduce $op,
                                                       ($op $a $b),
                                                       $($rest),+) };

    // reduce implementation
    // TODO external entry point for @reduce
    (@reduce $op:ident, $acc:tt)                       => { lisp!($acc)          };
    (@reduce $op:ident, $acc:tt, $a:tt)                => { lisp!(@reduce $op,
                                                                  ($op $acc $a)) };
    (@reduce $op:ident, $acc:tt, $a:tt, $($rest:tt),+) => { lisp!(@reduce $op,
                                                                  ($op $acc $a),
                                                                  $($rest),+)    };
    // ns form helpers
    (@krate $(^$attr:meta)* $krate:ident) => {
        $(#[$attr:meta])*
        extern crate $krate;
    };
    (@krate $(^$attr:meta)* ($krate:ident $alias:ident)) => {
        $(#[$attr:meta])*
        extern crate $krate as $alias;
    };
    (@uze ($($head:ident)*)) => { use $($head)::*; };
    (@uze ($($head:ident)* { $($multiple:ident)* })) => {
        lisp!(@uze mult ($($head)*) { $($multiple)* });
    };
    (@uze mult $head:tt { $($multiple:ident)* }) => {
        $(lisp!(@uze mult out $head $multiple);)*
    };
    (@uze mult out ($($head:ident)*) $multiple:ident) => {
        use $($head)::*::$multiple;
    };

    // macro calls
    (@list $mac:ident, !) => {
        $mac!()
    };
    (@list $mac:ident, !, $($arg:tt),*) => {
        $mac!($(lisp!($arg)),*)
    };

    // struct constructors
    (@list $name:ident, ., $(($member:ident $val:tt)),*) => {
        $name { $($member: lisp!($val))* }
    };

    // function calls
    (@list $name:expr) => {
        lisp!($name)()
    };
    (@list $name:expr, $($arg:tt),*) => {
        lisp!($name)($(lisp!($arg)),*)
    };

    // one expression
    ($e:expr) => ($e);
}
<|endoftext|>