<commit_before>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate habitat_builder_protocol as protocol;
extern crate habitat_core as hab_core;
extern crate habitat_http_client as hab_http;
extern crate broadcast;
#[macro_use]
extern crate hyper;
#[macro_use]
extern crate log;
extern crate pbr;
extern crate rustc_serialize;
extern crate tee;
extern crate url;

pub mod error;

pub use error::{Error, Result};

use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};

use broadcast::BroadcastWriter;
use hab_core::package::{Identifiable, PackageArchive};
use hab_http::ApiClient;
use hyper::client::{Body, IntoUrl, Response, RequestBuilder};
use hyper::status::StatusCode;
use hyper::header::{Authorization, Bearer};
use hyper::Url;
use protocol::{depotsrv, net};
use rustc_serialize::json;
use tee::TeeReader;

header! { (XFileName, "X-Filename") => [String] }
header! { (ETag, "ETag") => [String] }

pub trait DisplayProgress: Write {
    fn size(&mut self, size: u64);
    fn finish(&mut self);
}

pub struct Client {
    inner: ApiClient,
}

impl Client {
    pub fn new<U: IntoUrl>(hab_depot_url: U,
                           product: &str,
                           version: &str,
                           fs_root_path: Option<&Path>)
                           -> Result<Self> {
        let url = try!(hab_depot_url.into_url());
        Ok(Client { inner: try!(ApiClient::new(&url, product, version, fs_root_path)) })
    }

    /// Download a public key from a remote Depot to the given filepath.
    ///
    /// # Failures
    ///
    /// * Key cannot be found
    /// * Remote Depot is not available
    /// * File cannot be created and written to
    pub fn fetch_origin_key<D, P: ?Sized>(&self,
                                          origin: &str,
                                          revision: &str,
                                          dst_path: &P,
                                          progress: Option<D>)
                                          -> Result<PathBuf>
        where P: AsRef<Path>,
              D: DisplayProgress + Sized
    {
        self.download(&format!("origins/{}/keys/{}", origin, revision),
                      dst_path.as_ref(),
                      progress)
    }

    pub fn show_origin_keys(&self, origin: &str) -> Result<Vec<depotsrv::OriginKeyIdent>> {
        let mut res = try!(self.inner.get(&format!("origins/{}/keys", origin)).send());
        debug!("Response: {:?}", res);

        if res.status != StatusCode::Ok {
            return Err(err_from_response(res));
        };

        let mut encoded = String::new();
        try!(res.read_to_string(&mut encoded));
        debug!("Response body: {:?}", encoded);
        let revisions: Vec<depotsrv::OriginKeyIdent> = json::decode(&encoded).unwrap();
        Ok(revisions)
    }

    /// Upload a public origin key to a remote Depot.
    ///
    /// # Failures
    ///
    /// * Remote Depot is not available
    /// * File cannot be read
    ///
    /// # Panics
    ///
    /// * Authorization token was not set on client
    pub fn put_origin_key<D>(&self,
                             origin: &str,
                             revision: &str,
                             src_path: &Path,
                             token: &str,
                             progress: Option<D>)
                             -> Result<()>
        where D: DisplayProgress + Sized
    {
        let path = format!("origins/{}/keys/{}", &origin, &revision);
        let mut file = try!(File::open(src_path));
        let file_size = try!(file.metadata()).len();

        let result = if let Some(mut progress) = progress {
            progress.size(file_size);
            let mut reader = TeeReader::new(file, progress);
            self.add_authz(self.inner.post(&path), token)
                .body(Body::SizedBody(&mut reader, file_size))
                .send()
        } else {
            self.add_authz(self.inner.post(&path), token)
                .body(Body::SizedBody(&mut file, file_size))
                .send()
        };
        match result {
            Ok(Response { status: StatusCode::Created, .. }) => Ok(()),
            Ok(response) => Err(err_from_response(response)),
            Err(e) => Err(Error::from(e)),
        }
    }

    /// Upload a secret origin key to a remote Depot.
    ///
    /// # Failures
    ///
    /// * Remote Depot is not available
    /// * File cannot be read
    ///
    /// # Panics
    ///
    /// * Authorization token was not set on client
    pub fn put_origin_secret_key<D>(&self,
                                    origin: &str,
                                    revision: &str,
                                    src_path: &Path,
                                    token: &str,
                                    progress: Option<D>)
                                    -> Result<()>
        where D: DisplayProgress + Sized
    {
        let path = format!("origins/{}/secret_keys/{}", &origin, &revision);
        let mut file = try!(File::open(src_path));
        let file_size = try!(file.metadata()).len();

        let result = if let Some(mut progress) = progress {
            progress.size(file_size);
            let mut reader = TeeReader::new(file, progress);
            self.add_authz(self.inner.post(&path), token)
                .body(Body::SizedBody(&mut reader, file_size))
                .send()
        } else {
            self.add_authz(self.inner.post(&path), token)
                .body(Body::SizedBody(&mut file, file_size))
                .send()
        };
        match result {
            Ok(Response { status: StatusCode::Created, .. }) => Ok(()),
            Ok(response) => Err(err_from_response(response)),
            Err(e) => Err(Error::from(e)),
        }
    }

    /// Download the latest release of a package.
    ///
    /// An optional version and release can be specified which, when provided, will increase
    /// specificity of the release retrieved. Specifying a version and no release will retrieve
    /// the latest release of a given version. Specifying both a version and a release will
    /// retrieve that exact package.
    ///
    /// # Failures
    ///
    /// * Package cannot be found
    /// * Remote Depot is not available
    /// * File cannot be created and written to
    pub fn fetch_package<D, I, P: ?Sized>(&self,
                                          ident: I,
                                          dst_path: &P,
                                          progress: Option<D>)
                                          -> Result<PackageArchive>
        where P: AsRef<Path>,
              I: Identifiable,
              D: DisplayProgress + Sized
    {
        match self.download(&format!("pkgs/{}/download", ident),
                            dst_path.as_ref(),
                            progress) {
            Ok(file) => Ok(PackageArchive::new(PathBuf::from(file))),
            Err(e) => Err(e),
        }
    }

    /// Returns a package struct for the latest package.
    ///
    /// An optional version can be specified which will scope the release returned to the latest
    /// release of that package.
    ///
    /// # Failures
    ///
    /// * Package cannot be found
    /// * Remote Depot is not available
    pub fn show_package<I: Identifiable>(&self, ident: I) -> Result<depotsrv::Package> {
        let mut res = try!(self.inner.get(&self.path_show_package(&ident)).send());

        if res.status != StatusCode::Ok {
            return Err(err_from_response(res));
        }

        let mut encoded = String::new();
        try!(res.read_to_string(&mut encoded));
        debug!("Body: {:?}", encoded);
        let package: depotsrv::Package = json::decode(&encoded).unwrap();
        Ok(package)
    }

    /// Upload a package to a remote Depot.
    ///
    /// # Failures
    ///
    /// * Remote Depot is not available
    /// * File cannot be read
    ///
    /// # Panics
    ///
    /// * Authorization token was not set on client
    pub fn put_package<D>(&self,
                          pa: &mut PackageArchive,
                          token: &str,
                          progress: Option<D>)
                          -> Result<()>
        where D: DisplayProgress + Sized
    {
        let checksum = try!(pa.checksum());
        let ident = try!(pa.ident());
        let mut file = try!(File::open(&pa.path));
        let file_size = try!(file.metadata()).len();
        let path = format!("pkgs/{}", ident);
        let customize = |url: &mut Url| {
            url.query_pairs_mut().append_pair("checksum", &checksum);
        };
        debug!("Reading from {}", &pa.path.display());

        let result = if let Some(mut progress) = progress {
            progress.size(file_size);
            let mut reader = TeeReader::new(file, progress);
            self.add_authz(self.inner.post_with_custom_url(&path, customize), token)
                .body(Body::SizedBody(&mut reader, file_size))
                .send()
        } else {
            self.add_authz(self.inner.post_with_custom_url(&path, customize), token)
                .body(Body::SizedBody(&mut file, file_size))
                .send()
        };
        match result {
            Ok(Response { status: StatusCode::Created, .. }) => Ok(()),
            Ok(response) => Err(err_from_response(response)),
            Err(e) => Err(Error::from(e)),
        }
    }

    /// Returns a vector of PackageIdent structs
    ///
    /// # Failures
    ///
    /// * Remote depot unavailable
    pub fn search_package(&self,
                          search_term: String)
                          -> Result<(Vec<hab_core::package::PackageIdent>, bool)> {
        let mut res = try!(self.inner.get(&format!("pkgs/search/{}", search_term)).send());
        match res.status {
            StatusCode::Ok |
            StatusCode::PartialContent => {
                let mut encoded = String::new();
                try!(res.read_to_string(&mut encoded));
                let packages: Vec<hab_core::package::PackageIdent> = json::decode(&encoded)
                    .unwrap();
                Ok((packages, res.status == StatusCode::PartialContent))
            }
            _ => Err(err_from_response(res)),
        }
    }

    fn add_authz<'a>(&'a self, rb: RequestBuilder<'a>, token: &str) -> RequestBuilder {
        rb.header(Authorization(Bearer { token: token.to_string() }))
    }

    fn path_show_package<I: Identifiable>(&self, package: &I) -> String {
        if package.fully_qualified() {
            format!("pkgs/{}", package)
        } else {
            format!("pkgs/{}/latest", package)
        }
    }

    fn download<D>(&self, path: &str, dst_path: &Path, progress: Option<D>) -> Result<PathBuf>
        where D: DisplayProgress + Sized
    {
        let mut res = try!(self.inner.get(path).send());
        debug!("Response: {:?}", res);

        if res.status != hyper::status::StatusCode::Ok {
            return Err(err_from_response(res));
        }
        try!(fs::create_dir_all(&dst_path));

        let file_name = match res.headers.get::<XFileName>() {
            Some(filename) => format!("{}", filename),
            None => return Err(Error::NoXFilename),
        };
        let tmp_file_path = dst_path.join(format!("{}.tmp", file_name));
        let dst_file_path = dst_path.join(file_name);
        debug!("Writing to {}", &tmp_file_path.display());
        let mut f = try!(File::create(&tmp_file_path));
        match progress {
            Some(mut progress) => {
                let size: u64 =
                    res.headers.get::<hyper::header::ContentLength>().map_or(0, |v| **v);
                progress.size(size);
                let mut writer = BroadcastWriter::new(&mut f, progress);
                try!(io::copy(&mut res, &mut writer))
            }
            None => try!(io::copy(&mut res, &mut f)),
        };
        debug!("Moving {} to {}",
               &tmp_file_path.display(),
               &dst_file_path.display());
        try!(fs::rename(&tmp_file_path, &dst_file_path));
        Ok(dst_file_path)
    }
}

fn err_from_response(mut response: hyper::client::Response) -> Error {
    let mut buff = String::new();
    match response.read_to_string(&mut buff) {
        Ok(_) => {
            match json::decode::<net::NetError>(&buff) {
                Ok(err) => Error::APIError(response.status, err.to_string()),
                Err(_) => Error::APIError(response.status, buff),
            }
        }
        Err(_) => {
            buff.truncate(0);
            Error::APIError(response.status, buff)
        }
    }
}
<commit_msg>Fix hab pkg search break<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate habitat_builder_protocol as protocol;
extern crate habitat_core as hab_core;
extern crate habitat_http_client as hab_http;
extern crate broadcast;
#[macro_use]
extern crate hyper;
#[macro_use]
extern crate log;
extern crate pbr;
extern crate rustc_serialize;
extern crate tee;
extern crate url;

pub mod error;

pub use error::{Error, Result};

use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};

use broadcast::BroadcastWriter;
use hab_core::package::{Identifiable, PackageArchive};
use hab_http::ApiClient;
use hyper::client::{Body, IntoUrl, Response, RequestBuilder};
use hyper::status::StatusCode;
use hyper::header::{Authorization, Bearer};
use hyper::Url;
use protocol::{depotsrv, net};
use rustc_serialize::json;
use rustc_serialize::Decodable;
use tee::TeeReader;

header! { (XFileName, "X-Filename") => [String] }
header! { (ETag, "ETag") => [String] }

#[derive(RustcDecodable)]
pub struct PackageResults<T>
    where T: Decodable
{
    pub range_start: isize,
    pub range_end: isize,
    pub total_count: isize,
    pub package_list: Vec<T>,
}

fn package_results_from_json<T: Decodable>(encoded: &str) -> PackageResults<T> {
    let results: PackageResults<T> = json::decode(&encoded).unwrap();
    results
}

pub trait DisplayProgress: Write {
    fn size(&mut self, size: u64);
    fn finish(&mut self);
}

pub struct Client {
    inner: ApiClient,
}

impl Client {
    pub fn new<U: IntoUrl>(hab_depot_url: U,
                           product: &str,
                           version: &str,
                           fs_root_path: Option<&Path>)
                           -> Result<Self> {
        let url = try!(hab_depot_url.into_url());
        Ok(Client { inner: try!(ApiClient::new(&url, product, version, fs_root_path)) })
    }

    /// Download a public key from a remote Depot to the given filepath.
    ///
    /// # Failures
    ///
    /// * Key cannot be found
    /// * Remote Depot is not available
    /// * File cannot be created and written to
    pub fn fetch_origin_key<D, P: ?Sized>(&self,
                                          origin: &str,
                                          revision: &str,
                                          dst_path: &P,
                                          progress: Option<D>)
                                          -> Result<PathBuf>
        where P: AsRef<Path>,
              D: DisplayProgress + Sized
    {
        self.download(&format!("origins/{}/keys/{}", origin, revision),
                      dst_path.as_ref(),
                      progress)
    }

    pub fn show_origin_keys(&self, origin: &str) -> Result<Vec<depotsrv::OriginKeyIdent>> {
        let mut res = try!(self.inner.get(&format!("origins/{}/keys", origin)).send());
        debug!("Response: {:?}", res);

        if res.status != StatusCode::Ok {
            return Err(err_from_response(res));
        };

        let mut encoded = String::new();
        try!(res.read_to_string(&mut encoded));
        debug!("Response body: {:?}", encoded);
        let revisions: Vec<depotsrv::OriginKeyIdent> = json::decode(&encoded).unwrap();
        Ok(revisions)
    }

    /// Upload a public origin key to a remote Depot.
    ///
    /// # Failures
    ///
    /// * Remote Depot is not available
    /// * File cannot be read
    ///
    /// # Panics
    ///
    /// * Authorization token was not set on client
    pub fn put_origin_key<D>(&self,
                             origin: &str,
                             revision: &str,
                             src_path: &Path,
                             token: &str,
                             progress: Option<D>)
                             -> Result<()>
        where D: DisplayProgress + Sized
    {
        let path = format!("origins/{}/keys/{}", &origin, &revision);
        let mut file = try!(File::open(src_path));
        let file_size = try!(file.metadata()).len();

        let result = if let Some(mut progress) = progress {
            progress.size(file_size);
            let mut reader = TeeReader::new(file, progress);
            self.add_authz(self.inner.post(&path), token)
                .body(Body::SizedBody(&mut reader, file_size))
                .send()
        } else {
            self.add_authz(self.inner.post(&path), token)
                .body(Body::SizedBody(&mut file, file_size))
                .send()
        };
        match result {
            Ok(Response { status: StatusCode::Created, .. }) => Ok(()),
            Ok(response) => Err(err_from_response(response)),
            Err(e) => Err(Error::from(e)),
        }
    }

    /// Upload a secret origin key to a remote Depot.
    ///
    /// # Failures
    ///
    /// * Remote Depot is not available
    /// * File cannot be read
    ///
    /// # Panics
    ///
    /// * Authorization token was not set on client
    pub fn put_origin_secret_key<D>(&self,
                                    origin: &str,
                                    revision: &str,
                                    src_path: &Path,
                                    token: &str,
                                    progress: Option<D>)
                                    -> Result<()>
        where D: DisplayProgress + Sized
    {
        let path = format!("origins/{}/secret_keys/{}", &origin, &revision);
        let mut file = try!(File::open(src_path));
        let file_size = try!(file.metadata()).len();

        let result = if let Some(mut progress) = progress {
            progress.size(file_size);
            let mut reader = TeeReader::new(file, progress);
            self.add_authz(self.inner.post(&path), token)
                .body(Body::SizedBody(&mut reader, file_size))
                .send()
        } else {
            self.add_authz(self.inner.post(&path), token)
                .body(Body::SizedBody(&mut file, file_size))
                .send()
        };
        match result {
            Ok(Response { status: StatusCode::Created, .. }) => Ok(()),
            Ok(response) => Err(err_from_response(response)),
            Err(e) => Err(Error::from(e)),
        }
    }

    /// Download the latest release of a package.
    ///
    /// An optional version and release can be specified which, when provided, will increase
    /// specificity of the release retrieved. Specifying a version and no release will retrieve
    /// the latest release of a given version. Specifying both a version and a release will
    /// retrieve that exact package.
    ///
    /// # Failures
    ///
    /// * Package cannot be found
    /// * Remote Depot is not available
    /// * File cannot be created and written to
    pub fn fetch_package<D, I, P: ?Sized>(&self,
                                          ident: I,
                                          dst_path: &P,
                                          progress: Option<D>)
                                          -> Result<PackageArchive>
        where P: AsRef<Path>,
              I: Identifiable,
              D: DisplayProgress + Sized
    {
        match self.download(&format!("pkgs/{}/download", ident),
                            dst_path.as_ref(),
                            progress) {
            Ok(file) => Ok(PackageArchive::new(PathBuf::from(file))),
            Err(e) => Err(e),
        }
    }

    /// Returns a package struct for the latest package.
    ///
    /// An optional version can be specified which will scope the release returned to the latest
    /// release of that package.
    ///
    /// # Failures
    ///
    /// * Package cannot be found
    /// * Remote Depot is not available
    pub fn show_package<I: Identifiable>(&self, ident: I) -> Result<depotsrv::Package> {
        let mut res = try!(self.inner.get(&self.path_show_package(&ident)).send());

        if res.status != StatusCode::Ok {
            return Err(err_from_response(res));
        }

        let mut encoded = String::new();
        try!(res.read_to_string(&mut encoded));
        debug!("Body: {:?}", encoded);
        let package: depotsrv::Package = json::decode(&encoded).unwrap();
        Ok(package)
    }

    /// Upload a package to a remote Depot.
    ///
    /// # Failures
    ///
    /// * Remote Depot is not available
    /// * File cannot be read
    ///
    /// # Panics
    ///
    /// * Authorization token was not set on client
    pub fn put_package<D>(&self,
                          pa: &mut PackageArchive,
                          token: &str,
                          progress: Option<D>)
                          -> Result<()>
        where D: DisplayProgress + Sized
    {
        let checksum = try!(pa.checksum());
        let ident = try!(pa.ident());
        let mut file = try!(File::open(&pa.path));
        let file_size = try!(file.metadata()).len();
        let path = format!("pkgs/{}", ident);
        let customize = |url: &mut Url| {
            url.query_pairs_mut().append_pair("checksum", &checksum);
        };
        debug!("Reading from {}", &pa.path.display());

        let result = if let Some(mut progress) = progress {
            progress.size(file_size);
            let mut reader = TeeReader::new(file, progress);
            self.add_authz(self.inner.post_with_custom_url(&path, customize), token)
                .body(Body::SizedBody(&mut reader, file_size))
                .send()
        } else {
            self.add_authz(self.inner.post_with_custom_url(&path, customize), token)
                .body(Body::SizedBody(&mut file, file_size))
                .send()
        };
        match result {
            Ok(Response { status: StatusCode::Created, .. }) => Ok(()),
            Ok(response) => Err(err_from_response(response)),
            Err(e) => Err(Error::from(e)),
        }
    }

    /// Returns a vector of PackageIdent structs
    ///
    /// # Failures
    ///
    /// * Remote depot unavailable
    pub fn search_package(&self,
                          search_term: String)
                          -> Result<(Vec<hab_core::package::PackageIdent>, bool)> {

        let mut res = try!(self.inner.get(&format!("pkgs/search/{}", search_term)).send());
        match res.status {
            StatusCode::Ok |
            StatusCode::PartialContent => {
                let mut encoded = String::new();
                try!(res.read_to_string(&mut encoded));

                let package_results: PackageResults<hab_core::package::PackageIdent> =
                    package_results_from_json(&encoded);

                let packages: Vec<hab_core::package::PackageIdent> = package_results.package_list;

                Ok((packages, res.status == StatusCode::PartialContent))
            }
            _ => Err(err_from_response(res)),
        }
    }

    fn add_authz<'a>(&'a self, rb: RequestBuilder<'a>, token: &str) -> RequestBuilder {
        rb.header(Authorization(Bearer { token: token.to_string() }))
    }

    fn path_show_package<I: Identifiable>(&self, package: &I) -> String {
        if package.fully_qualified() {
            format!("pkgs/{}", package)
        } else {
            format!("pkgs/{}/latest", package)
        }
    }

    fn download<D>(&self, path: &str, dst_path: &Path, progress: Option<D>) -> Result<PathBuf>
        where D: DisplayProgress + Sized
    {
        let mut res = try!(self.inner.get(path).send());
        debug!("Response: {:?}", res);

        if res.status != hyper::status::StatusCode::Ok {
            return Err(err_from_response(res));
        }
        try!(fs::create_dir_all(&dst_path));

        let file_name = match res.headers.get::<XFileName>() {
            Some(filename) => format!("{}", filename),
            None => return Err(Error::NoXFilename),
        };
        let tmp_file_path = dst_path.join(format!("{}.tmp", file_name));
        let dst_file_path = dst_path.join(file_name);
        debug!("Writing to {}", &tmp_file_path.display());
        let mut f = try!(File::create(&tmp_file_path));
        match progress {
            Some(mut progress) => {
                let size: u64 =
                    res.headers.get::<hyper::header::ContentLength>().map_or(0, |v| **v);
                progress.size(size);
                let mut writer = BroadcastWriter::new(&mut f, progress);
                try!(io::copy(&mut res, &mut writer))
            }
            None => try!(io::copy(&mut res, &mut f)),
        };
        debug!("Moving {} to {}",
               &tmp_file_path.display(),
               &dst_file_path.display());
        try!(fs::rename(&tmp_file_path, &dst_file_path));
        Ok(dst_file_path)
    }
}

fn err_from_response(mut response: hyper::client::Response) -> Error {
    let mut buff = String::new();
    match response.read_to_string(&mut buff) {
        Ok(_) => {
            match json::decode::<net::NetError>(&buff) {
                Ok(err) => Error::APIError(response.status, err.to_string()),
                Err(_) => Error::APIError(response.status, buff),
            }
        }
        Err(_) => {
            buff.truncate(0);
            Error::APIError(response.status, buff)
        }
    }
}
<|endoftext|>


<commit_before>
use crate::prelude::*;

macro_rules! intrinsic_pat {
    (_) => {
        _
    };
    ($name:ident) => {
        stringify!($name)
    }
}

macro_rules! intrinsic_arg {
    (c $fx:expr, $arg:ident) => {
        $arg
    };
    (v $fx:expr, $arg:ident) => {
        $arg.load_value($fx)
    };
}

macro_rules! intrinsic_match {
    ($fx:expr, $intrinsic:expr, $args:expr, $(
        $($name:tt)|+ $(if $cond:expr)?, |$($a:ident $arg:ident),*| $content:block;
    )*) => {
        match $intrinsic {
            $(
                $(intrinsic_pat!($name))|* $(if $cond)? => {
                    if let [$($arg),*] = *$args {
                        #[allow(unused_parens)]
                        {
                            let ($($arg),*) = (
                                $(intrinsic_arg!($a $fx, $arg)),*
                            );
                            $content
                        }
                    } else {
                        bug!("wrong number of args for intrinsic {:?}", $intrinsic);
                    }
                }
            )*
            _ => unimpl!("unsupported intrinsic {}", $intrinsic),
        }
    };
}

pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    def_id: DefId,
    substs: &'tcx Substs,
    args: Vec<CValue<'tcx>>,
    destination: Option<(CPlace<'tcx>, BasicBlock)>,
) {
    let intrinsic = fx.tcx.item_name(def_id).as_str();
    let intrinsic = &intrinsic[..];

    let ret = match destination {
        Some((place, _)) => place,
        None => {
            // Insert non returning intrinsics here
            match intrinsic {
                "abort" => {
                    fx.bcx.ins().trap(TrapCode::User(!0 - 1));
                }
                "unreachable" => {
                    fx.bcx.ins().trap(TrapCode::User(!0 - 1));
                }
                _ => unimplemented!("unsupported instrinsic {}", intrinsic),
            }
            return;
        }
    };

    let u64_layout = fx.layout_of(fx.tcx.types.u64);
    let usize_layout = fx.layout_of(fx.tcx.types.usize);

    intrinsic_match! {
        fx, intrinsic, args,

        assume, |c _a| {};
        arith_offset, |v base, v offset| {
            let res = fx.bcx.ins().iadd(base, offset);
            let res = CValue::ByVal(res, ret.layout());
            ret.write_cvalue(fx, res);
        };
        likely | unlikely, |c a| {
            ret.write_cvalue(fx, a);
        };
        copy | copy_nonoverlapping, |v src, v dst, v count| {
            let elem_ty = substs.type_at(0);
            let elem_size: u64 = fx.layout_of(elem_ty).size.bytes();
            let elem_size = fx
                .bcx
                .ins()
                .iconst(fx.module.pointer_type(), elem_size as i64);
            assert_eq!(args.len(), 3);
            let byte_amount = fx.bcx.ins().imul(count, elem_size);

            if intrinsic.ends_with("_nonoverlapping") {
                fx.bcx.call_memcpy(fx.isa, dst, src, byte_amount);
            } else {
                fx.bcx.call_memmove(fx.isa, dst, src, byte_amount);
            }
        };
        discriminant_value, |c val| {
            let discr = crate::base::trans_get_discriminant(fx, args[0], ret.layout());
            ret.write_cvalue(fx, discr);
        };
        size_of, | | {
            let size_of = fx.layout_of(substs.type_at(0)).size.bytes();
            let size_of = CValue::const_val(fx, usize_layout.ty, size_of as i64);
            ret.write_cvalue(fx, size_of);
        };
        size_of_val, |c ptr| {
            let layout = fx.layout_of(substs.type_at(0));
            let size = match &layout.ty.sty {
                _ if !layout.is_unsized() => fx
                    .bcx
                    .ins()
                    .iconst(fx.module.pointer_type(), layout.size.bytes() as i64),
                ty::Slice(elem) => {
                    let len = ptr.load_value_pair(fx).1;
                    let elem_size = fx.layout_of(elem).size.bytes();
                    fx.bcx.ins().imul_imm(len, elem_size as i64)
                }
                ty::Dynamic(..) => crate::vtable::size_of_obj(fx, ptr),
                ty => bug!("size_of_val for unknown unsized type {:?}", ty),
            };
            ret.write_cvalue(fx, CValue::ByVal(size, usize_layout));
        };
        min_align_of, | | {
            let min_align = fx.layout_of(substs.type_at(0)).align.abi();
            let min_align = CValue::const_val(fx, usize_layout.ty, min_align as i64);
            ret.write_cvalue(fx, min_align);
        };
        min_align_of_val, |c ptr| {
            let layout = fx.layout_of(substs.type_at(0));
            let align = match &layout.ty.sty {
                _ if !layout.is_unsized() => fx
                    .bcx
                    .ins()
                    .iconst(fx.module.pointer_type(), layout.align.abi() as i64),
                ty::Slice(elem) => {
                    let align = fx.layout_of(elem).align.abi() as i64;
                    fx.bcx.ins().iconst(fx.module.pointer_type(), align)
                }
                ty::Dynamic(..) => crate::vtable::min_align_of_obj(fx, ptr),
                ty => unimplemented!("min_align_of_val for {:?}", ty),
            };
            ret.write_cvalue(fx, CValue::ByVal(align, usize_layout));
        };
        type_id, | | {
            let type_id = fx.tcx.type_id_hash(substs.type_at(0));
            let type_id = CValue::const_val(fx, u64_layout.ty, type_id as i64);
            ret.write_cvalue(fx, type_id);
        };
        _ if intrinsic.starts_with("unchecked_"), |c x, c y| {
            let bin_op = match intrinsic {
                "unchecked_div" => BinOp::Div,
                "unchecked_rem" => BinOp::Rem,
                "unchecked_shl" => BinOp::Shl,
                "unchecked_shr" => BinOp::Shr,
                _ => unimplemented!("intrinsic {}", intrinsic),
            };
            let res = match ret.layout().ty.sty {
                ty::Uint(_) => crate::base::trans_int_binop(
                    fx,
                    bin_op,
                    x,
                    y,
                    ret.layout().ty,
                    false,
                ),
                ty::Int(_) => crate::base::trans_int_binop(
                    fx,
                    bin_op,
                    x,
                    y,
                    ret.layout().ty,
                    true,
                ),
                _ => panic!(),
            };
            ret.write_cvalue(fx, res);
        };
        _ if intrinsic.ends_with("_with_overflow"), |c x, c y| {
            assert_eq!(x.layout().ty, y.layout().ty);
            let bin_op = match intrinsic {
                "add_with_overflow" => BinOp::Add,
                "sub_with_overflow" => BinOp::Sub,
                "mul_with_overflow" => BinOp::Mul,
                _ => unimplemented!("intrinsic {}", intrinsic),
            };
            let res = match args[0].layout().ty.sty {
                ty::Uint(_) => crate::base::trans_checked_int_binop(
                    fx,
                    bin_op,
                    x,
                    y,
                    ret.layout().ty,
                    false,
                ),
                ty::Int(_) => crate::base::trans_checked_int_binop(
                    fx,
                    bin_op,
                    x,
                    y,
                    ret.layout().ty,
                    true,
                ),
                _ => panic!(),
            };
            ret.write_cvalue(fx, res);
        };
        _ if intrinsic.starts_with("overflowing_"), |c x, c y| {
            assert_eq!(x.layout().ty, y.layout().ty);
            let bin_op = match intrinsic {
                "overflowing_add" => BinOp::Add,
                "overflowing_sub" => BinOp::Sub,
                "overflowing_mul" => BinOp::Mul,
                _ => unimplemented!("intrinsic {}", intrinsic),
            };
            let res = match x.layout().ty.sty {
                ty::Uint(_) => crate::base::trans_int_binop(
                    fx,
                    bin_op,
                    x,
                    y,
                    ret.layout().ty,
                    false,
                ),
                ty::Int(_) => crate::base::trans_int_binop(
                    fx,
                    bin_op,
                    x,
                    y,
                    ret.layout().ty,
                    true,
                ),
                _ => panic!(),
            };
            ret.write_cvalue(fx, res);
        };
        offset, |v base, v offset| {
            let res = fx.bcx.ins().iadd(base, offset);
            ret.write_cvalue(fx, CValue::ByVal(res, args[0].layout()));
        };
        transmute, |c from| {
            let src_ty = substs.type_at(0);
            let dst_ty = substs.type_at(1);
            assert_eq!(from.layout().ty, src_ty);
            let addr = from.force_stack(fx);
            let dst_layout = fx.layout_of(dst_ty);
            ret.write_cvalue(fx, CValue::ByRef(addr, dst_layout))
        };
        init, | | {
            let ty = substs.type_at(0);
            let layout = fx.layout_of(ty);
            let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
                kind: StackSlotKind::ExplicitSlot,
                size: layout.size.bytes() as u32,
                offset: None,
            });
            let addr = fx.bcx.ins().stack_addr(pointer_ty(fx.tcx), stack_slot, 0);
            let zero_val = fx.bcx.ins().iconst(types::I8, 0);
            let len_val = fx.bcx.ins().iconst(pointer_ty(fx.tcx), layout.size.bytes() as i64);
            fx.bcx.call_memset(fx.isa, addr, zero_val, len_val);

            let uninit_place = CPlace::from_stack_slot(fx, stack_slot, ty);
            let uninit_val = uninit_place.to_cvalue(fx);
            ret.write_cvalue(fx, uninit_val);
        };
        uninit, | | {
            let ty = substs.type_at(0);
            let layout = fx.layout_of(ty);
            let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
                kind: StackSlotKind::ExplicitSlot,
                size: layout.size.bytes() as u32,
                offset: None,
            });

            let uninit_place = CPlace::from_stack_slot(fx, stack_slot, ty);
            let uninit_val = uninit_place.to_cvalue(fx);
            ret.write_cvalue(fx, uninit_val);
        };
        ctlz | ctlz_nonzero, |v arg| {
            let res = CValue::ByVal(fx.bcx.ins().clz(arg), args[0].layout());
            ret.write_cvalue(fx, res);
        };
        cttz | cttz_nonzero, |v arg| {
            let res = CValue::ByVal(fx.bcx.ins().clz(arg), args[0].layout());
            ret.write_cvalue(fx, res);
        };
        ctpop, |v arg| {
            let res = CValue::ByVal(fx.bcx.ins().popcnt(arg), args[0].layout());
            ret.write_cvalue(fx, res);
        };
        bitreverse, |v arg| {
            let res = CValue::ByVal(fx.bcx.ins().bitrev(arg), args[0].layout());
            ret.write_cvalue(fx, res);
        };
        needs_drop, | | {
            let ty = substs.type_at(0);
            let needs_drop = if ty.needs_drop(fx.tcx, ParamEnv::reveal_all()) {
                1
            } else {
                0
            };
            let needs_drop = CValue::const_val(fx, fx.tcx.types.bool, needs_drop);
            ret.write_cvalue(fx, needs_drop);
        };
        _ if intrinsic.starts_with("atomic_fence"), | | {};
        _ if intrinsic.starts_with("atomic_singlethreadfence"), | | {};
        _ if intrinsic.starts_with("atomic_load"), |c ptr| {
            let inner_layout =
                fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
            let val = CValue::ByRef(ptr.load_value(fx), inner_layout);
            ret.write_cvalue(fx, val);
        };
        _ if intrinsic.starts_with("atomic_store"), |v ptr, c val| {
            let dest = CPlace::Addr(ptr, None, val.layout());
            dest.write_cvalue(fx, val);
        };
        _ if intrinsic.starts_with("atomic_xadd"), |v ptr, v amount| {
            let clif_ty = fx.cton_type(substs.type_at(0)).unwrap();
            let old = fx.bcx.ins().load(clif_ty, MemFlags::new(), ptr, 0);
            let new = fx.bcx.ins().iadd(old, amount);
            fx.bcx.ins().store(MemFlags::new(), new, ptr, 0);
            ret.write_cvalue(fx, CValue::ByVal(old, fx.layout_of(substs.type_at(0))));
        };
        _ if intrinsic.starts_with("atomic_xsub"), |v ptr, v amount| {
            let clif_ty = fx.cton_type(substs.type_at(0)).unwrap();
            let old = fx.bcx.ins().load(clif_ty, MemFlags::new(), ptr, 0);
            let new = fx.bcx.ins().isub(old, amount);
            fx.bcx.ins().store(MemFlags::new(), new, ptr, 0);
            ret.write_cvalue(fx, CValue::ByVal(old, fx.layout_of(substs.type_at(0))));
        };
    }

    if let Some((_, dest)) = destination {
        let ret_ebb = fx.get_ebb(dest);
        fx.bcx.ins().jump(ret_ebb, &[]);
    } else {
        fx.bcx.ins().trap(TrapCode::User(!0));
    }
}
<commit_msg>Improve dsl<commit_after>
use crate::prelude::*;

macro_rules! intrinsic_pat {
    (_) => {
        _
    };
    ($name:ident) => {
        stringify!($name)
    }
}

macro_rules! intrinsic_arg {
    (c $fx:expr, $arg:ident) => {
        $arg
    };
    (v $fx:expr, $arg:ident) => {
        $arg.load_value($fx)
    };
}

macro_rules! intrinsic_substs {
    ($substs:expr, $index:expr,) => {};
    ($substs:expr, $index:expr, $first:ident $(,$rest:ident)*) => {
        let $first = $substs.type_at($index);
        intrinsic_substs!($substs, $index+1, $($rest),*);
    };
}

macro_rules! intrinsic_match {
    ($fx:expr, $intrinsic:expr, $substs:expr, $args:expr, $(
        $($name:tt)|+ $(if $cond:expr)?, $(<$($subst:ident),*>)? ($($a:ident $arg:ident),*) $content:block;
    )*) => {
        match $intrinsic {
            $(
                $(intrinsic_pat!($name))|* $(if $cond)? => {
                    #[allow(unused_parens, non_snake_case)]
                    {
                        $(
                            intrinsic_substs!($substs, 0, $($subst),*);
                        )?
                        if let [$($arg),*] = *$args {
                            let ($($arg),*) = (
                                $(intrinsic_arg!($a $fx, $arg)),*
                            );
                            #[warn(unused_parens, non_snake_case)]
                            {
                                $content
                            }
                        } else {
                            bug!("wrong number of args for intrinsic {:?}", $intrinsic);
                        }
                    }
                }
            )*
            _ => unimpl!("unsupported intrinsic {}", $intrinsic),
        }
    };
}

pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    def_id: DefId,
    substs: &'tcx Substs,
    args: Vec<CValue<'tcx>>,
    destination: Option<(CPlace<'tcx>, BasicBlock)>,
) {
    let intrinsic = fx.tcx.item_name(def_id).as_str();
    let intrinsic = &intrinsic[..];

    let ret = match destination {
        Some((place, _)) => place,
        None => {
            // Insert non returning intrinsics here
            match intrinsic {
                "abort" => {
                    fx.bcx.ins().trap(TrapCode::User(!0 - 1));
                }
                "unreachable" => {
                    fx.bcx.ins().trap(TrapCode::User(!0 - 1));
                }
                _ => unimplemented!("unsupported instrinsic {}", intrinsic),
            }
            return;
        }
    };

    let u64_layout = fx.layout_of(fx.tcx.types.u64);
    let usize_layout = fx.layout_of(fx.tcx.types.usize);

    intrinsic_match! {
        fx, intrinsic, substs, args,

        assume, (c _a) {};
        arith_offset, (v base, v offset) {
            let res = fx.bcx.ins().iadd(base, offset);
            let res = CValue::ByVal(res, ret.layout());
            ret.write_cvalue(fx, res);
        };
        likely | unlikely, (c a) {
            ret.write_cvalue(fx, a);
        };
        copy | copy_nonoverlapping, <elem_ty> (v src, v dst, v count) {
            let elem_size: u64 = fx.layout_of(elem_ty).size.bytes();
            let elem_size = fx
                .bcx
                .ins()
                .iconst(fx.module.pointer_type(), elem_size as i64);
            assert_eq!(args.len(), 3);
            let byte_amount = fx.bcx.ins().imul(count, elem_size);

            if intrinsic.ends_with("_nonoverlapping") {
                fx.bcx.call_memcpy(fx.isa, dst, src, byte_amount);
            } else {
                fx.bcx.call_memmove(fx.isa, dst, src, byte_amount);
            }
        };
        discriminant_value, (c val) {
            let discr = crate::base::trans_get_discriminant(fx, val, ret.layout());
            ret.write_cvalue(fx, discr);
        };
        size_of, <T> () {
            let size_of = fx.layout_of(T).size.bytes();
            let size_of = CValue::const_val(fx, usize_layout.ty, size_of as i64);
            ret.write_cvalue(fx, size_of);
        };
        size_of_val, <T> (c ptr) {
            let layout = fx.layout_of(T);
            let size = match &layout.ty.sty {
                _ if !layout.is_unsized() => fx
                    .bcx
                    .ins()
                    .iconst(fx.module.pointer_type(), layout.size.bytes() as i64),
                ty::Slice(elem) => {
                    let len = ptr.load_value_pair(fx).1;
                    let elem_size = fx.layout_of(elem).size.bytes();
                    fx.bcx.ins().imul_imm(len, elem_size as i64)
                }
                ty::Dynamic(..) => crate::vtable::size_of_obj(fx, ptr),
                ty => bug!("size_of_val for unknown unsized type {:?}", ty),
            };
            ret.write_cvalue(fx, CValue::ByVal(size, usize_layout));
        };
        min_align_of, <T> () {
            let min_align = fx.layout_of(T).align.abi();
            let min_align = CValue::const_val(fx, usize_layout.ty, min_align as i64);
            ret.write_cvalue(fx, min_align);
        };
        min_align_of_val, <T> (c ptr) {
            let layout = fx.layout_of(T);
            let align = match &layout.ty.sty {
                _ if !layout.is_unsized() => fx
                    .bcx
                    .ins()
                    .iconst(fx.module.pointer_type(), layout.align.abi() as i64),
                ty::Slice(elem) => {
                    let align = fx.layout_of(elem).align.abi() as i64;
                    fx.bcx.ins().iconst(fx.module.pointer_type(), align)
                }
                ty::Dynamic(..) => crate::vtable::min_align_of_obj(fx, ptr),
                ty => unimplemented!("min_align_of_val for {:?}", ty),
            };
            ret.write_cvalue(fx, CValue::ByVal(align, usize_layout));
        };
        type_id, <T> () {
            let type_id = fx.tcx.type_id_hash(T);
            let type_id = CValue::const_val(fx, u64_layout.ty, type_id as i64);
            ret.write_cvalue(fx, type_id);
        };
        _ if intrinsic.starts_with("unchecked_"), (c x, c y) {
            let bin_op = match intrinsic {
                "unchecked_div" => BinOp::Div,
                "unchecked_rem" => BinOp::Rem,
                "unchecked_shl" => BinOp::Shl,
                "unchecked_shr" => BinOp::Shr,
                _ => unimplemented!("intrinsic {}", intrinsic),
            };
            let res = match ret.layout().ty.sty {
                ty::Uint(_) => crate::base::trans_int_binop(
                    fx,
                    bin_op,
                    x,
                    y,
                    ret.layout().ty,
                    false,
                ),
                ty::Int(_) => crate::base::trans_int_binop(
                    fx,
                    bin_op,
                    x,
                    y,
                    ret.layout().ty,
                    true,
                ),
                _ => panic!(),
            };
            ret.write_cvalue(fx, res);
        };
        _ if intrinsic.ends_with("_with_overflow"), <T> (c x, c y) {
            assert_eq!(x.layout().ty, y.layout().ty);
            let bin_op = match intrinsic {
                "add_with_overflow" => BinOp::Add,
                "sub_with_overflow" => BinOp::Sub,
                "mul_with_overflow" => BinOp::Mul,
                _ => unimplemented!("intrinsic {}", intrinsic),
            };
            let res = match T.sty {
                ty::Uint(_) => crate::base::trans_checked_int_binop(
                    fx,
                    bin_op,
                    x,
                    y,
                    ret.layout().ty,
                    false,
                ),
                ty::Int(_) => crate::base::trans_checked_int_binop(
                    fx,
                    bin_op,
                    x,
                    y,
                    ret.layout().ty,
                    true,
                ),
                _ => panic!(),
            };
            ret.write_cvalue(fx, res);
        };
        _ if intrinsic.starts_with("overflowing_"), <T> (c x, c y) {
            assert_eq!(x.layout().ty, y.layout().ty);
            let bin_op = match intrinsic {
                "overflowing_add" => BinOp::Add,
                "overflowing_sub" => BinOp::Sub,
                "overflowing_mul" => BinOp::Mul,
                _ => unimplemented!("intrinsic {}", intrinsic),
            };
            let res = match T.sty {
                ty::Uint(_) => crate::base::trans_int_binop(
                    fx,
                    bin_op,
                    x,
                    y,
                    ret.layout().ty,
                    false,
                ),
                ty::Int(_) => crate::base::trans_int_binop(
                    fx,
                    bin_op,
                    x,
                    y,
                    ret.layout().ty,
                    true,
                ),
                _ => panic!(),
            };
            ret.write_cvalue(fx, res);
        };
        offset, (v base, v offset) {
            let res = fx.bcx.ins().iadd(base, offset);
            ret.write_cvalue(fx, CValue::ByVal(res, args[0].layout()));
        };
        transmute, <src_ty, dst_ty> (c from) {
            assert_eq!(from.layout().ty, src_ty);
            let addr = from.force_stack(fx);
            let dst_layout = fx.layout_of(dst_ty);
            ret.write_cvalue(fx, CValue::ByRef(addr, dst_layout))
        };
        init, <T> () {
            let layout = fx.layout_of(T);
            let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
                kind: StackSlotKind::ExplicitSlot,
                size: layout.size.bytes() as u32,
                offset: None,
            });
            let addr = fx.bcx.ins().stack_addr(pointer_ty(fx.tcx), stack_slot, 0);
            let zero_val = fx.bcx.ins().iconst(types::I8, 0);
            let len_val = fx.bcx.ins().iconst(pointer_ty(fx.tcx), layout.size.bytes() as i64);
            fx.bcx.call_memset(fx.isa, addr, zero_val, len_val);

            let uninit_place = CPlace::from_stack_slot(fx, stack_slot, T);
            let uninit_val = uninit_place.to_cvalue(fx);
            ret.write_cvalue(fx, uninit_val);
        };
        uninit, <T> () {
            let layout = fx.layout_of(T);
            let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
                kind: StackSlotKind::ExplicitSlot,
                size: layout.size.bytes() as u32,
                offset: None,
            });

            let uninit_place = CPlace::from_stack_slot(fx, stack_slot, T);
            let uninit_val = uninit_place.to_cvalue(fx);
            ret.write_cvalue(fx, uninit_val);
        };
        ctlz | ctlz_nonzero, <T> (v arg) {
            let res = CValue::ByVal(fx.bcx.ins().clz(arg), fx.layout_of(T));
            ret.write_cvalue(fx, res);
        };
        cttz | cttz_nonzero, <T> (v arg) {
            let res = CValue::ByVal(fx.bcx.ins().clz(arg), fx.layout_of(T));
            ret.write_cvalue(fx, res);
        };
        ctpop, <T> (v arg) {
            let res = CValue::ByVal(fx.bcx.ins().popcnt(arg), fx.layout_of(T));
            ret.write_cvalue(fx, res);
        };
        bitreverse, <T> (v arg) {
            let res = CValue::ByVal(fx.bcx.ins().bitrev(arg), fx.layout_of(T));
            ret.write_cvalue(fx, res);
        };
        needs_drop, <T> () {
            let needs_drop = if T.needs_drop(fx.tcx, ParamEnv::reveal_all()) {
                1
            } else {
                0
            };
            let needs_drop = CValue::const_val(fx, fx.tcx.types.bool, needs_drop);
            ret.write_cvalue(fx, needs_drop);
        };
        _ if intrinsic.starts_with("atomic_fence"), () {};
        _ if intrinsic.starts_with("atomic_singlethreadfence"), () {};
        _ if intrinsic.starts_with("atomic_load"), (c ptr) {
            let inner_layout =
                fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
            let val = CValue::ByRef(ptr.load_value(fx), inner_layout);
            ret.write_cvalue(fx, val);
        };
        _ if intrinsic.starts_with("atomic_store"), (v ptr, c val) {
            let dest = CPlace::Addr(ptr, None, val.layout());
            dest.write_cvalue(fx, val);
        };
        _ if intrinsic.starts_with("atomic_xadd"), <T> (v ptr, v amount) {
            let clif_ty = fx.cton_type(T).unwrap();
            let old = fx.bcx.ins().load(clif_ty, MemFlags::new(), ptr, 0);
            let new = fx.bcx.ins().iadd(old, amount);
            fx.bcx.ins().store(MemFlags::new(), new, ptr, 0);
            ret.write_cvalue(fx, CValue::ByVal(old, fx.layout_of(T)));
        };
        _ if intrinsic.starts_with("atomic_xsub"), <T> (v ptr, v amount) {
            let clif_ty = fx.cton_type(T).unwrap();
            let old = fx.bcx.ins().load(clif_ty, MemFlags::new(), ptr, 0);
            let new = fx.bcx.ins().isub(old, amount);
            fx.bcx.ins().store(MemFlags::new(), new, ptr, 0);
            ret.write_cvalue(fx, CValue::ByVal(old, fx.layout_of(T)));
        };
    }

    if let Some((_, dest)) = destination {
        let ret_ebb = fx.get_ebb(dest);
        fx.bcx.ins().jump(ret_ebb, &[]);
    } else {
        fx.bcx.ins().trap(TrapCode::User(!0));
    }
}
<|endoftext|>


<commit_before>mod token;

use std::str::Chars;

use self::token::Token;

#[derive(Debug)]
struct Lexed<'a> {
    chars: Chars<'a>,
}

impl<'a> Lexed<'a> {
    fn new(chars: Chars<'a>) -> Lexed {
        Lexed {
            chars: chars,
        }
    }
}

impl<'a> Iterator for Lexed<'a> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        match self.chars.next() {
            Some(c) => Some(next_int(c, &mut self.chars)),
            None    => None,
        }
    }
}

fn next_int(first_char: char, chars: &mut Chars) -> Token {
    let mut s = String::new();
    s.push(first_char);
    loop {
        match chars.next() {
            Some(c) => s.push(c),
            None => return Token::IntTok(s)
        }
    }
}

fn lex(chars: Chars) -> Lexed {
    Lexed::new(chars)
}

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

    fn assert_lex(input: &str, output: &[Token]) {
        let actual: Vec<Token> = lex(input.chars()).collect();
        let actual: &[Token] = actual.as_ref();
        assert_eq!(actual, output);
    }

    fn intt(chars: &str) -> Token {
        Token::IntTok(String::from(chars))
    }

    #[test]
    fn single_character_int() {
        assert_lex("3", &[intt("3")]);
        assert_lex("9", &[intt("9")]);
    }

    #[test]
    fn multiple_character_int() {
        assert_lex("31", &[intt("31")]);

        let long_int = "01234567891111111111012345678911111111110123456789";
        assert_lex(long_int, &[intt(long_int)]);
    }
}
<commit_msg>A non-digit signals the end of an int<commit_after>mod token;

use std::str::Chars;

use self::token::Token;

#[derive(Debug)]
struct Lexed<'a> {
    chars: Chars<'a>,
}

impl<'a> Lexed<'a> {
    fn new(chars: Chars<'a>) -> Lexed {
        Lexed {
            chars: chars,
        }
    }
}

impl<'a> Iterator for Lexed<'a> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        match self.chars.next() {
            Some(c) => Some(next_int(c, &mut self.chars)),
            None    => None,
        }
    }
}

fn next_int(first_char: char, chars: &mut Chars) -> Token {
    let mut s = String::new();
    s.push(first_char);
    loop {
        match chars.next() {
            Some(c) if within_int_char(c)  => s.push(c),
            _ => return Token::IntTok(s)
        }
    }
}

fn within_int_char(c: char) -> bool {
    match c {
        '0' ... '9' => true,
        _           => false,
    }
}

fn lex(chars: Chars) -> Lexed {
    Lexed::new(chars)
}

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

    fn assert_lex(input: &str, output: &[Token]) {
        let actual: Vec<Token> = lex(input.chars()).collect();
        let actual: &[Token] = actual.as_ref();
        assert_eq!(actual, output);
    }

    fn intt(chars: &str) -> Token {
        Token::IntTok(String::from(chars))
    }

    #[test]
    fn single_character_int() {
        assert_lex("3", &[intt("3")]);
        assert_lex("9", &[intt("9")]);
    }

    #[test]
    fn multiple_character_int() {
        assert_lex("31", &[intt("31")]);

        let long_int = "01234567891111111111012345678911111111110123456789";
        assert_lex(long_int, &[intt(long_int)]);
    }

    #[test]
    fn several_ints() {
        assert_lex("31 420", &[intt("31"), intt("420")]);
    }
}
<|endoftext|>


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

/*!

Defines the `Ord` and `Eq` comparison traits.

This module defines both `Ord` and `Eq` traits which are used by the compiler
to implement comparison operators.
Rust programs may implement `Ord` to overload the `<`, `<=`, `>`, and `>=` operators,
and may implement `Eq` to overload the `==` and `!=` operators.

For example, to define a type with a customized definition for the Eq operators,
you could do the following:

```rust
// Our type.
struct SketchyNum {
    num : int
}

// Our implementation of `Eq` to support `==` and `!=`.
impl Eq for SketchyNum {
    // Our custom eq allows numbers which are near eachother to be equal! :D
    fn eq(&self, other: &SketchyNum) -> bool {
        (self.num - other.num).abs() < 5
    }
}

// Now these binary operators will work when applied!
assert!(SketchyNum {num: 37} == SketchyNum {num: 34});
assert!(SketchyNum {num: 25} != SketchyNum {num: 57});
```

*/

/**
* Trait for values that can be compared for equality and inequality.
*
* This trait allows partial equality, where types can be unordered instead of strictly equal or
* unequal. For example, with the built-in floating-point types `a == b` and `a != b` will both
* evaluate to false if either `a` or `b` is NaN (cf. IEEE 754-2008 section 5.11).
*
* Eq only requires the `eq` method to be implemented; `ne` is its negation by default.
*
* Eventually, this will be implemented by default for types that implement `TotalEq`.
*/
#[lang="eq"]
pub trait Eq {
    /// This method tests for `self` and `other` values to be equal, and is used by `==`.
    fn eq(&self, other: &Self) -> bool;

    /// This method tests for `!=`.
    #[inline]
    fn ne(&self, other: &Self) -> bool { !self.eq(other) }
}

/// Trait for equality comparisons where `a == b` and `a != b` are strict inverses.
pub trait TotalEq: Eq {
    // FIXME #13101: this method is used solely by #[deriving] to
    // assert that every component of a type implements #[deriving]
    // itself, the current deriving infrastructure means doing this
    // assertion without using a method on this trait is nearly
    // impossible.
    //
    // This should never be implemented by hand.
    #[doc(hidden)]
    #[inline(always)]
    fn assert_receiver_is_total_eq(&self) {}
}

/// A macro which defines an implementation of TotalEq for a given type.
macro_rules! totaleq_impl(
    ($t:ty) => {
        impl TotalEq for $t {}
    }
)

totaleq_impl!(bool)

totaleq_impl!(u8)
totaleq_impl!(u16)
totaleq_impl!(u32)
totaleq_impl!(u64)

totaleq_impl!(i8)
totaleq_impl!(i16)
totaleq_impl!(i32)
totaleq_impl!(i64)

totaleq_impl!(int)
totaleq_impl!(uint)

totaleq_impl!(char)

/// An ordering is, e.g, a result of a comparison between two values.
#[deriving(Clone, Eq, Show)]
pub enum Ordering {
   /// An ordering where a compared value is less [than another].
   Less = -1,
   /// An ordering where a compared value is equal [to another].
   Equal = 0,
   /// An ordering where a compared value is greater [than another].
   Greater = 1
}

/// Trait for types that form a total order.
pub trait TotalOrd: TotalEq + Ord {
    /// This method returns an ordering between `self` and `other` values.
    ///
    /// By convention, `self.cmp(&other)` returns the ordering matching
    /// the expression `self <operator> other` if true.  For example:
    ///
    /// ```
    /// assert_eq!( 5u.cmp(&10), Less);     // because 5 < 10
    /// assert_eq!(10u.cmp(&5),  Greater);  // because 10 > 5
    /// assert_eq!( 5u.cmp(&5),  Equal);    // because 5 == 5
    /// ```
    fn cmp(&self, other: &Self) -> Ordering;
}

impl TotalEq for Ordering {}
impl TotalOrd for Ordering {
    #[inline]
    fn cmp(&self, other: &Ordering) -> Ordering {
        (*self as int).cmp(&(*other as int))
    }
}

impl Ord for Ordering {
    #[inline]
    fn lt(&self, other: &Ordering) -> bool { (*self as int) < (*other as int) }
}

/// A macro which defines an implementation of TotalOrd for a given type.
macro_rules! totalord_impl(
    ($t:ty) => {
        impl TotalOrd for $t {
            #[inline]
            fn cmp(&self, other: &$t) -> Ordering {
                if *self < *other { Less }
                else if *self > *other { Greater }
                else { Equal }
            }
        }
    }
)

totalord_impl!(u8)
totalord_impl!(u16)
totalord_impl!(u32)
totalord_impl!(u64)

totalord_impl!(i8)
totalord_impl!(i16)
totalord_impl!(i32)
totalord_impl!(i64)

totalord_impl!(int)
totalord_impl!(uint)

totalord_impl!(char)

/**
 * Combine orderings, lexically.
 *
 * For example for a type `(int, int)`, two comparisons could be done.
 * If the first ordering is different, the first ordering is all that must be returned.
 * If the first ordering is equal, then second ordering is returned.
*/
#[inline]
pub fn lexical_ordering(o1: Ordering, o2: Ordering) -> Ordering {
    match o1 {
        Equal => o2,
        _ => o1
    }
}

/**
* Trait for values that can be compared for a sort-order.
*
* Ord only requires implementation of the `lt` method,
* with the others generated from default implementations.
*
* However it remains possible to implement the others separately,
* for compatibility with floating-point NaN semantics
* (cf. IEEE 754-2008 section 5.11).
*/
#[lang="ord"]
pub trait Ord: Eq {
    /// This method tests less than (for `self` and `other`) and is used by the `<` operator.
    fn lt(&self, other: &Self) -> bool;

    /// This method tests less than or equal to (`<=`).
    #[inline]
    fn le(&self, other: &Self) -> bool { !other.lt(self) }

    /// This method tests greater than (`>`).
    #[inline]
    fn gt(&self, other: &Self) -> bool {  other.lt(self) }

    /// This method tests greater than or equal to (`>=`).
    #[inline]
    fn ge(&self, other: &Self) -> bool { !self.lt(other) }
}

/// The equivalence relation. Two values may be equivalent even if they are
/// of different types. The most common use case for this relation is
/// container types; e.g. it is often desirable to be able to use `&str`
/// values to look up entries in a container with `~str` keys.
pub trait Equiv<T> {
    /// Implement this function to decide equivalent values.
    fn equiv(&self, other: &T) -> bool;
}

/// Compare and return the minimum of two values.
#[inline]
pub fn min<T: TotalOrd>(v1: T, v2: T) -> T {
    if v1 < v2 { v1 } else { v2 }
}

/// Compare and return the maximum of two values.
#[inline]
pub fn max<T: TotalOrd>(v1: T, v2: T) -> T {
    if v1 > v2 { v1 } else { v2 }
}

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

    #[test]
    fn test_int_totalord() {
        assert_eq!(5u.cmp(&10), Less);
        assert_eq!(10u.cmp(&5), Greater);
        assert_eq!(5u.cmp(&5), Equal);
        assert_eq!((-5u).cmp(&12), Less);
        assert_eq!(12u.cmp(-5), Greater);
    }

    #[test]
    fn test_ordering_order() {
        assert!(Less < Equal);
        assert_eq!(Greater.cmp(&Less), Greater);
    }

    #[test]
    fn test_lexical_ordering() {
        fn t(o1: Ordering, o2: Ordering, e: Ordering) {
            assert_eq!(lexical_ordering(o1, o2), e);
        }

        let xs = [Less, Equal, Greater];
        for &o in xs.iter() {
            t(Less, o, Less);
            t(Equal, o, o);
            t(Greater, o, Greater);
         }
    }

    #[test]
    fn test_user_defined_eq() {
        // Our type.
        struct SketchyNum {
            num : int
        }

        // Our implementation of `Eq` to support `==` and `!=`.
        impl Eq for SketchyNum {
            // Our custom eq allows numbers which are near eachother to be equal! :D
            fn eq(&self, other: &SketchyNum) -> bool {
                (self.num - other.num).abs() < 5
            }
        }

        // Now these binary operators will work when applied!
        assert!(SketchyNum {num: 37} == SketchyNum {num: 34});
        assert!(SketchyNum {num: 25} != SketchyNum {num: 57});
    }
}
<commit_msg>Add requirements of TotalEq and TotalOrd<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Defines the `Ord` and `Eq` comparison traits.

This module defines both `Ord` and `Eq` traits which are used by the compiler
to implement comparison operators.
Rust programs may implement `Ord` to overload the `<`, `<=`, `>`, and `>=` operators,
and may implement `Eq` to overload the `==` and `!=` operators.

For example, to define a type with a customized definition for the Eq operators,
you could do the following:

```rust
// Our type.
struct SketchyNum {
    num : int
}

// Our implementation of `Eq` to support `==` and `!=`.
impl Eq for SketchyNum {
    // Our custom eq allows numbers which are near eachother to be equal! :D
    fn eq(&self, other: &SketchyNum) -> bool {
        (self.num - other.num).abs() < 5
    }
}

// Now these binary operators will work when applied!
assert!(SketchyNum {num: 37} == SketchyNum {num: 34});
assert!(SketchyNum {num: 25} != SketchyNum {num: 57});
```

*/

/**
* Trait for values that can be compared for equality and inequality.
*
* This trait allows partial equality, where types can be unordered instead of strictly equal or
* unequal. For example, with the built-in floating-point types `a == b` and `a != b` will both
* evaluate to false if either `a` or `b` is NaN (cf. IEEE 754-2008 section 5.11).
*
* Eq only requires the `eq` method to be implemented; `ne` is its negation by default.
*
* Eventually, this will be implemented by default for types that implement `TotalEq`.
*/
#[lang="eq"]
pub trait Eq {
    /// This method tests for `self` and `other` values to be equal, and is used by `==`.
    fn eq(&self, other: &Self) -> bool;

    /// This method tests for `!=`.
    #[inline]
    fn ne(&self, other: &Self) -> bool { !self.eq(other) }
}

/**
 * Trait for equality comparisons which are [equivalence relations](
 * https://en.wikipedia.org/wiki/Equivalence_relation).
 *
 * This means, that in addition to `a == b` and `a != b` being strict inverses,
 * the equality must be (for all `a`, `b` and `c`):
 *
 * - reflexive: `a == a`;
 * - symmetric: `a == b` implies `b == a`; and
 * - transitive: `a == b` and `b == c` implies `a == c`.
 */

pub trait TotalEq: Eq {
    // FIXME #13101: this method is used solely by #[deriving] to
    // assert that every component of a type implements #[deriving]
    // itself, the current deriving infrastructure means doing this
    // assertion without using a method on this trait is nearly
    // impossible.
    //
    // This should never be implemented by hand.
    #[doc(hidden)]
    #[inline(always)]
    fn assert_receiver_is_total_eq(&self) {}
}

/// A macro which defines an implementation of TotalEq for a given type.
macro_rules! totaleq_impl(
    ($t:ty) => {
        impl TotalEq for $t {}
    }
)

totaleq_impl!(bool)

totaleq_impl!(u8)
totaleq_impl!(u16)
totaleq_impl!(u32)
totaleq_impl!(u64)

totaleq_impl!(i8)
totaleq_impl!(i16)
totaleq_impl!(i32)
totaleq_impl!(i64)

totaleq_impl!(int)
totaleq_impl!(uint)

totaleq_impl!(char)

/// An ordering is, e.g, a result of a comparison between two values.
#[deriving(Clone, Eq, Show)]
pub enum Ordering {
   /// An ordering where a compared value is less [than another].
   Less = -1,
   /// An ordering where a compared value is equal [to another].
   Equal = 0,
   /// An ordering where a compared value is greater [than another].
   Greater = 1
}

/**
 * Trait for types that form a [total order](
 * https://en.wikipedia.org/wiki/Total_order).
 *
 * An order is a total order if it is (for all `a`, `b` and `c`):
 *
 * - total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b`
 *   is true; and
 * - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for
 *   both `==` and `>`.
 */
pub trait TotalOrd: TotalEq + Ord {
    /// This method returns an ordering between `self` and `other` values.
    ///
    /// By convention, `self.cmp(&other)` returns the ordering matching
    /// the expression `self <operator> other` if true.  For example:
    ///
    /// ```
    /// assert_eq!( 5u.cmp(&10), Less);     // because 5 < 10
    /// assert_eq!(10u.cmp(&5),  Greater);  // because 10 > 5
    /// assert_eq!( 5u.cmp(&5),  Equal);    // because 5 == 5
    /// ```
    fn cmp(&self, other: &Self) -> Ordering;
}

impl TotalEq for Ordering {}
impl TotalOrd for Ordering {
    #[inline]
    fn cmp(&self, other: &Ordering) -> Ordering {
        (*self as int).cmp(&(*other as int))
    }
}

impl Ord for Ordering {
    #[inline]
    fn lt(&self, other: &Ordering) -> bool { (*self as int) < (*other as int) }
}

/// A macro which defines an implementation of TotalOrd for a given type.
macro_rules! totalord_impl(
    ($t:ty) => {
        impl TotalOrd for $t {
            #[inline]
            fn cmp(&self, other: &$t) -> Ordering {
                if *self < *other { Less }
                else if *self > *other { Greater }
                else { Equal }
            }
        }
    }
)

totalord_impl!(u8)
totalord_impl!(u16)
totalord_impl!(u32)
totalord_impl!(u64)

totalord_impl!(i8)
totalord_impl!(i16)
totalord_impl!(i32)
totalord_impl!(i64)

totalord_impl!(int)
totalord_impl!(uint)

totalord_impl!(char)

/**
 * Combine orderings, lexically.
 *
 * For example for a type `(int, int)`, two comparisons could be done.
 * If the first ordering is different, the first ordering is all that must be returned.
 * If the first ordering is equal, then second ordering is returned.
*/
#[inline]
pub fn lexical_ordering(o1: Ordering, o2: Ordering) -> Ordering {
    match o1 {
        Equal => o2,
        _ => o1
    }
}

/**
* Trait for values that can be compared for a sort-order.
*
* Ord only requires implementation of the `lt` method,
* with the others generated from default implementations.
*
* However it remains possible to implement the others separately,
* for compatibility with floating-point NaN semantics
* (cf. IEEE 754-2008 section 5.11).
*/
#[lang="ord"]
pub trait Ord: Eq {
    /// This method tests less than (for `self` and `other`) and is used by the `<` operator.
    fn lt(&self, other: &Self) -> bool;

    /// This method tests less than or equal to (`<=`).
    #[inline]
    fn le(&self, other: &Self) -> bool { !other.lt(self) }

    /// This method tests greater than (`>`).
    #[inline]
    fn gt(&self, other: &Self) -> bool {  other.lt(self) }

    /// This method tests greater than or equal to (`>=`).
    #[inline]
    fn ge(&self, other: &Self) -> bool { !self.lt(other) }
}

/// The equivalence relation. Two values may be equivalent even if they are
/// of different types. The most common use case for this relation is
/// container types; e.g. it is often desirable to be able to use `&str`
/// values to look up entries in a container with `~str` keys.
pub trait Equiv<T> {
    /// Implement this function to decide equivalent values.
    fn equiv(&self, other: &T) -> bool;
}

/// Compare and return the minimum of two values.
#[inline]
pub fn min<T: TotalOrd>(v1: T, v2: T) -> T {
    if v1 < v2 { v1 } else { v2 }
}

/// Compare and return the maximum of two values.
#[inline]
pub fn max<T: TotalOrd>(v1: T, v2: T) -> T {
    if v1 > v2 { v1 } else { v2 }
}

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

    #[test]
    fn test_int_totalord() {
        assert_eq!(5u.cmp(&10), Less);
        assert_eq!(10u.cmp(&5), Greater);
        assert_eq!(5u.cmp(&5), Equal);
        assert_eq!((-5u).cmp(&12), Less);
        assert_eq!(12u.cmp(-5), Greater);
    }

    #[test]
    fn test_ordering_order() {
        assert!(Less < Equal);
        assert_eq!(Greater.cmp(&Less), Greater);
    }

    #[test]
    fn test_lexical_ordering() {
        fn t(o1: Ordering, o2: Ordering, e: Ordering) {
            assert_eq!(lexical_ordering(o1, o2), e);
        }

        let xs = [Less, Equal, Greater];
        for &o in xs.iter() {
            t(Less, o, Less);
            t(Equal, o, o);
            t(Greater, o, Greater);
         }
    }

    #[test]
    fn test_user_defined_eq() {
        // Our type.
        struct SketchyNum {
            num : int
        }

        // Our implementation of `Eq` to support `==` and `!=`.
        impl Eq for SketchyNum {
            // Our custom eq allows numbers which are near eachother to be equal! :D
            fn eq(&self, other: &SketchyNum) -> bool {
                (self.num - other.num).abs() < 5
            }
        }

        // Now these binary operators will work when applied!
        assert!(SketchyNum {num: 37} == SketchyNum {num: 34});
        assert!(SketchyNum {num: 25} != SketchyNum {num: 57});
    }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]
#![allow(clippy::cast_lossless, clippy::unseparated_literal_suffix)]

macro_rules! test {
    (
        $(
            $(#[$attr:meta])*
            $name:ident($value:expr, $expected:expr)
        ),*
    ) => {
        $(
            $(#[$attr])*
            #[test]
            fn $name() {
                #[cfg(feature = "std")]
                {
                    let mut buf = [b'\0'; 40];
                    let len = itoa::write(&mut buf[..], $value).unwrap();
                    assert_eq!(&buf[0..len], $expected.as_bytes());
                }

                let mut s = String::new();
                itoa::fmt(&mut s, $value).unwrap();
                assert_eq!(s, $expected);
            }
        )*
    }
}

test! {
    test_u64_0(0u64, "0"),
    test_u64_half(<u32>::max_value() as u64, "4294967295"),
    test_u64_max(<u64>::max_value(), "18446744073709551615"),
    test_i64_min(<i64>::min_value(), "-9223372036854775808"),

    test_i16_0(0i16, "0"),
    test_i16_min(<i16>::min_value(), "-32768"),

    test_u128_0(0u128, "0"),
    test_u128_max(<u128>::max_value(), "340282366920938463463374607431768211455"),
    test_i128_min(<i128>::min_value(), "-170141183460469231731687303715884105728")
}
<commit_msg>Eliminate itoa::write and itoa::fmt from tests<commit_after>#![allow(non_snake_case)]
#![allow(clippy::cast_lossless, clippy::unseparated_literal_suffix)]

macro_rules! test {
    (
        $(
            $(#[$attr:meta])*
            $name:ident($value:expr, $expected:expr)
        ),*
    ) => {
        $(
            $(#[$attr])*
            #[test]
            fn $name() {
                let mut buffer = itoa::Buffer::new();
                let s = buffer.format($value);
                assert_eq!(s, $expected);
            }
        )*
    }
}

test! {
    test_u64_0(0u64, "0"),
    test_u64_half(<u32>::max_value() as u64, "4294967295"),
    test_u64_max(<u64>::max_value(), "18446744073709551615"),
    test_i64_min(<i64>::min_value(), "-9223372036854775808"),

    test_i16_0(0i16, "0"),
    test_i16_min(<i16>::min_value(), "-32768"),

    test_u128_0(0u128, "0"),
    test_u128_max(<u128>::max_value(), "340282366920938463463374607431768211455"),
    test_i128_min(<i128>::min_value(), "-170141183460469231731687303715884105728")
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use error::Error;

use super::{Request, Response, IronResult};

/// `Handler`s are responsible for handling requests by creating Responses from Requests.
///
/// By default, bare functions and variants of Chain implement `Handler`.
///
/// `Handler`s are allowed to return errors, and if they do, their `catch` method is called and the
/// error is propagated to `AfterMiddleware`.
pub trait Handler: Send + Sync {
    /// Produce a `Response` from a Request, with the possibility of error.
    ///
    /// If this returns an Err, `catch` is called with the error.
    fn call(&self, &mut Request) -> IronResult<Response>;

    /// If `Handler`'s call method produces an Err, then this method is called
    /// to produce a `Response` and possibly handle the error.
    ///
    /// If the passed-in error is not handled, it should be returned as the second
    /// item in the returned tuple. If it is handled, then `Ok(())` can be returned
    /// instead to indicate that all is good with the Response.
    fn catch(&self, &mut Request, Box<Error>) -> (Response, IronResult<()>);
}

/// `BeforeMiddleware` are fired before a `Handler` is called inside of a Chain.
///
/// `BeforeMiddleware` are responsible for doing request pre-processing that requires
/// the ability to change control-flow, such as authorization middleware, or for editing
/// the request by modifying the headers.
///
/// `BeforeMiddleware` only have access to the Request, if you need to modify or read a Response,
/// you will need `AfterMiddleware`.
pub trait BeforeMiddleware: Send + Sync {
    /// Do whatever work this middleware should do with a `Request` object.
    ///
    /// An error here is propagated by the containing Chain to, first, this Middleware's
    /// `catch` method, then every subsequent `BeforeMiddleware`'s `catch` methods until one returns
    /// Ok(()) or the Chain's `Handler` is reached, at which point the `Handler`'s `catch` method is
    /// called to produce an error Response.
    fn before(&self, &mut Request) -> IronResult<()>;

    /// Try to `catch` an error thrown by this Middleware or a previous `BeforeMiddleware`.
    ///
    /// Should only return Ok(()) if the error has been completely handled and a Chain
    /// can proceed as normal.
    fn catch(&self, _: &mut Request, err: Box<Error>) -> IronResult<()> {
        Err(err)
    }
}

pub trait AfterMiddleware: Send + Sync {
    fn after(&self, &mut Request, &mut Response) -> IronResult<()>;

    // This response was generated by the `catch` function of Handlers and is abnormal in some way.
    fn catch(&self, _: &mut Request, _: &mut Response, err: Box<Error>) -> IronResult<()> {
        Err(err)
    }
}

pub trait AroundMiddleware: Handler {
    fn around(&mut self, handler: Box<Handler + Send + Sync>);
}

pub trait Chain: Handler {
    fn new<H: Handler>(H) -> Self;

    fn link<B, A>(&mut self, (B, A)) where A: AfterMiddleware, B: BeforeMiddleware;

    fn link_before<B>(&mut self, B) where B: BeforeMiddleware;

    fn link_after<A>(&mut self, A) where A: AfterMiddleware;

    fn around<A>(&mut self, A) where A: AroundMiddleware;
}

pub struct ChainBuilder {
    befores: Vec<Box<BeforeMiddleware + Send + Sync>>,
    afters: Vec<Box<AfterMiddleware + Send + Sync>>,
    handler: Box<Handler + Send + Sync>
}

impl Chain for ChainBuilder {
    fn new<H: Handler>(handler: H) -> ChainBuilder {
        ChainBuilder {
            befores: vec![],
            afters: vec![],
            handler: box handler as Box<Handler + Send + Sync>
        }
    }

    fn link<B, A>(&mut self, link: (B, A))
    where A: AfterMiddleware, B: BeforeMiddleware {
        let (before, after) = link;
        self.befores.push(box before as Box<BeforeMiddleware + Send + Sync>);
        self.afters.push(box after as Box<AfterMiddleware + Send + Sync>);
    }

    fn link_before<B>(&mut self, before: B) where B: BeforeMiddleware {
        self.befores.push(box before as Box<BeforeMiddleware + Send + Sync>);
    }

    fn link_after<A>(&mut self, after: A) where A: AfterMiddleware {
        self.afters.push(box after as Box<AfterMiddleware + Send + Sync>);
    }

    fn around<A>(&mut self, mut around: A) where A: AroundMiddleware {
        use std::mem;

        let old = mem::replace(&mut self.handler, box Nop as Box<Handler + Send + Sync>);
        around.around(old);
        self.handler = box around as Box<Handler + Send + Sync>;
    }
}

impl Handler for ChainBuilder {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        let before_result = helpers::run_befores(req, self.befores.as_slice(), None);

        let (res, err) = match before_result {
            Ok(()) => match self.handler.call(req) {
                Ok(res) => (res, None),
                Err(e) => helpers::run_handler_catch(req, e, &self.handler)
            },
            Err(e) => helpers::run_handler_catch(req, e, &self.handler)
        };

        helpers::run_afters(req, res, err, self.afters.as_slice())
    }

    fn catch(&self, req: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) {
        let before_result = helpers::run_befores(req, self.befores.as_slice(), Some(err));

        let (res, err) = match before_result {
            Ok(()) => match self.handler.call(req) {
                Ok(res) => (res, None),
                Err(e) => helpers::run_handler_catch(req, e, &self.handler)
            },
            Err(e) => helpers::run_handler_catch(req, e, &self.handler)
        };

        match helpers::run_afters(req, res, err, self.afters.as_slice()) {
            Ok(res) => (res, Ok(())),
            // FIXME: Make 500
            Err(err) => (Response::new(), Err(err))
        }
    }
}

impl Handler for fn(&mut Request) -> IronResult<Response> {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        self.call(req)
    }

    fn catch(&self, _: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) {
        // FIXME: Make Response a 500
        (Response::new(), Err(err))
    }
}

pub struct Nop;

impl Handler for Nop {
    fn call(&self, _: &mut Request) -> IronResult<Response> {
        Ok(Response::new())
    }

    fn catch(&self, _: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) {
        // FIXME: Make Response a 500
        (Response::new(), Err(err))
    }
}

impl Handler for Box<Handler + Send + Sync> {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        self.call(req)
    }

    fn catch(&self, req: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) {
        self.catch(req, err)
    }
}

impl Handler for Arc<Box<Handler + Send + Sync>> {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        self.call(req)
    }

    fn catch(&self, req: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) {
        self.catch(req, err)
    }
}

mod helpers {
    use super::super::{Request, Response, IronResult};
    use super::{AfterMiddleware, BeforeMiddleware, Handler};
    use error::Error;

    pub fn run_befores(req: &mut Request, befores: &[Box<BeforeMiddleware>], err: Option<Box<Error>>) -> IronResult<()> {
        match err {
            Some(mut e) => {
                for (i, before) in befores.iter().enumerate() {
                    match before.catch(req, e) {
                        Ok(_) => return run_befores(req, befores, None),
                        Err(new) => e = new
                    }
                }
                Err(e)
            },

            None => {
                for (i, before) in befores.iter().enumerate() {
                    match before.before(req) {
                        Ok(_) => (),
                        Err(err) => return run_befores(req, befores.slice_from(i), Some(err))
                    }
                }
                Ok(())
            }
        }
    }

    pub fn run_afters(req: &mut Request, mut res: Response, err: Option<Box<Error>>,
                  afters: &[Box<AfterMiddleware>]) -> IronResult<Response> {
        match err {
            Some(mut e) => {
                for (i, after) in afters.iter().enumerate() {
                    match after.catch(req, &mut res, e) {
                        Ok(_) => return run_afters(req, res, None, afters),
                        Err(new) => e = new
                    }
                }
                Err(e)
            },

            None => {
                for (i, after) in afters.iter().enumerate() {
                    match after.after(req, &mut res) {
                        Ok(_) => (),
                        Err(err) => return run_afters(req, res, Some(err), afters.slice_from(i))
                    }
                }
                Ok(res)
            }
        }
    }

    pub fn run_handler_catch(req: &mut Request, err: Box<Error>,
                         handler: &Box<Handler>) -> (Response, Option<Box<Error>>) {
        match handler.catch(req, err) {
            (res, Ok(())) => (res, None),
            (res, Err(e)) => (res, Some(e))
        }
    }
}

<commit_msg>(doc) Documented AfterMiddleware.<commit_after>use std::sync::Arc;
use error::Error;

use super::{Request, Response, IronResult};

/// `Handler`s are responsible for handling requests by creating Responses from Requests.
///
/// By default, bare functions and variants of Chain implement `Handler`.
///
/// `Handler`s are allowed to return errors, and if they do, their `catch` method is called and the
/// error is propagated to `AfterMiddleware`.
pub trait Handler: Send + Sync {
    /// Produce a `Response` from a Request, with the possibility of error.
    ///
    /// If this returns an Err, `catch` is called with the error.
    fn call(&self, &mut Request) -> IronResult<Response>;

    /// If `Handler`'s call method produces an Err, then this method is called
    /// to produce a `Response` and possibly handle the error.
    ///
    /// If the passed-in error is not handled, it should be returned as the second
    /// item in the returned tuple. If it is handled, then `Ok(())` can be returned
    /// instead to indicate that all is good with the Response.
    fn catch(&self, &mut Request, Box<Error>) -> (Response, IronResult<()>);
}

/// `BeforeMiddleware` are fired before a `Handler` is called inside of a Chain.
///
/// `BeforeMiddleware` are responsible for doing request pre-processing that requires
/// the ability to change control-flow, such as authorization middleware, or for editing
/// the request by modifying the headers.
///
/// `BeforeMiddleware` only have access to the Request, if you need to modify or read a Response,
/// you will need `AfterMiddleware`.
pub trait BeforeMiddleware: Send + Sync {
    /// Do whatever work this middleware should do with a `Request` object.
    ///
    /// An error here is propagated by the containing Chain to, first, this Middleware's
    /// `catch` method, then every subsequent `BeforeMiddleware`'s `catch` methods until one returns
    /// Ok(()) or the Chain's `Handler` is reached, at which point the `Handler`'s `catch` method is
    /// called to produce an error Response.
    fn before(&self, &mut Request) -> IronResult<()>;

    /// Try to `catch` an error thrown by this Middleware or a previous `BeforeMiddleware`.
    ///
    /// Should only return Ok(()) if the error has been completely handled and a Chain
    /// can proceed as normal.
    fn catch(&self, _: &mut Request, err: Box<Error>) -> IronResult<()> {
        Err(err)
    }
}

/// `AfterMiddleware` are fired after a `Handler` is called inside of a Chain.
///
/// `AfterMiddleware` receive both a `Request` and a `Response` and are responsible for doing
/// any response-post-processing.
///
/// `AfterMiddleware` should *not* usually overwrite the contents of a Response. In
/// the common case, a complete response is generated by the Chain's `Handler` and
/// `AfterMiddleware` simply do post-processing of that Response, such as
/// adding headers or logging.
pub trait AfterMiddleware: Send + Sync {
    /// Do whatever work this middleware needs to do with both a `Request` and `Response` objects.
    ///
    /// An error here is propagated by the containing Chain down to this and any later
    /// `AfterMiddleware`'s `catch` methods, which can attempt to handle the error or modify
    /// the `Response` to indicate to a client that something went wrong.
    fn after(&self, &mut Request, &mut Response) -> IronResult<()>;

    /// Try to catch an error thrown by previous `AfterMiddleware`, the `Handler`, or a previous
    /// `BeforeMiddleware`.
    ///
    /// The response was generated by the `catch` function of `Handler`s and is abnormal or
    /// errored in some way.
    fn catch(&self, _: &mut Request, _: &mut Response, err: Box<Error>) -> IronResult<()> {
        Err(err)
    }
}

pub trait AroundMiddleware: Handler {
    fn around(&mut self, handler: Box<Handler + Send + Sync>);
}

pub trait Chain: Handler {
    fn new<H: Handler>(H) -> Self;

    fn link<B, A>(&mut self, (B, A)) where A: AfterMiddleware, B: BeforeMiddleware;

    fn link_before<B>(&mut self, B) where B: BeforeMiddleware;

    fn link_after<A>(&mut self, A) where A: AfterMiddleware;

    fn around<A>(&mut self, A) where A: AroundMiddleware;
}

pub struct ChainBuilder {
    befores: Vec<Box<BeforeMiddleware + Send + Sync>>,
    afters: Vec<Box<AfterMiddleware + Send + Sync>>,
    handler: Box<Handler + Send + Sync>
}

impl Chain for ChainBuilder {
    fn new<H: Handler>(handler: H) -> ChainBuilder {
        ChainBuilder {
            befores: vec![],
            afters: vec![],
            handler: box handler as Box<Handler + Send + Sync>
        }
    }

    fn link<B, A>(&mut self, link: (B, A))
    where A: AfterMiddleware, B: BeforeMiddleware {
        let (before, after) = link;
        self.befores.push(box before as Box<BeforeMiddleware + Send + Sync>);
        self.afters.push(box after as Box<AfterMiddleware + Send + Sync>);
    }

    fn link_before<B>(&mut self, before: B) where B: BeforeMiddleware {
        self.befores.push(box before as Box<BeforeMiddleware + Send + Sync>);
    }

    fn link_after<A>(&mut self, after: A) where A: AfterMiddleware {
        self.afters.push(box after as Box<AfterMiddleware + Send + Sync>);
    }

    fn around<A>(&mut self, mut around: A) where A: AroundMiddleware {
        use std::mem;

        let old = mem::replace(&mut self.handler, box Nop as Box<Handler + Send + Sync>);
        around.around(old);
        self.handler = box around as Box<Handler + Send + Sync>;
    }
}

impl Handler for ChainBuilder {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        let before_result = helpers::run_befores(req, self.befores.as_slice(), None);

        let (res, err) = match before_result {
            Ok(()) => match self.handler.call(req) {
                Ok(res) => (res, None),
                Err(e) => helpers::run_handler_catch(req, e, &self.handler)
            },
            Err(e) => helpers::run_handler_catch(req, e, &self.handler)
        };

        helpers::run_afters(req, res, err, self.afters.as_slice())
    }

    fn catch(&self, req: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) {
        let before_result = helpers::run_befores(req, self.befores.as_slice(), Some(err));

        let (res, err) = match before_result {
            Ok(()) => match self.handler.call(req) {
                Ok(res) => (res, None),
                Err(e) => helpers::run_handler_catch(req, e, &self.handler)
            },
            Err(e) => helpers::run_handler_catch(req, e, &self.handler)
        };

        match helpers::run_afters(req, res, err, self.afters.as_slice()) {
            Ok(res) => (res, Ok(())),
            // FIXME: Make 500
            Err(err) => (Response::new(), Err(err))
        }
    }
}

impl Handler for fn(&mut Request) -> IronResult<Response> {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        self.call(req)
    }

    fn catch(&self, _: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) {
        // FIXME: Make Response a 500
        (Response::new(), Err(err))
    }
}

pub struct Nop;

impl Handler for Nop {
    fn call(&self, _: &mut Request) -> IronResult<Response> {
        Ok(Response::new())
    }

    fn catch(&self, _: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) {
        // FIXME: Make Response a 500
        (Response::new(), Err(err))
    }
}

impl Handler for Box<Handler + Send + Sync> {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        self.call(req)
    }

    fn catch(&self, req: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) {
        self.catch(req, err)
    }
}

impl Handler for Arc<Box<Handler + Send + Sync>> {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        self.call(req)
    }

    fn catch(&self, req: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) {
        self.catch(req, err)
    }
}

mod helpers {
    use super::super::{Request, Response, IronResult};
    use super::{AfterMiddleware, BeforeMiddleware, Handler};
    use error::Error;

    pub fn run_befores(req: &mut Request, befores: &[Box<BeforeMiddleware>], err: Option<Box<Error>>) -> IronResult<()> {
        match err {
            Some(mut e) => {
                for (i, before) in befores.iter().enumerate() {
                    match before.catch(req, e) {
                        Ok(_) => return run_befores(req, befores, None),
                        Err(new) => e = new
                    }
                }
                Err(e)
            },

            None => {
                for (i, before) in befores.iter().enumerate() {
                    match before.before(req) {
                        Ok(_) => (),
                        Err(err) => return run_befores(req, befores.slice_from(i), Some(err))
                    }
                }
                Ok(())
            }
        }
    }

    pub fn run_afters(req: &mut Request, mut res: Response, err: Option<Box<Error>>,
                  afters: &[Box<AfterMiddleware>]) -> IronResult<Response> {
        match err {
            Some(mut e) => {
                for (i, after) in afters.iter().enumerate() {
                    match after.catch(req, &mut res, e) {
                        Ok(_) => return run_afters(req, res, None, afters),
                        Err(new) => e = new
                    }
                }
                Err(e)
            },

            None => {
                for (i, after) in afters.iter().enumerate() {
                    match after.after(req, &mut res) {
                        Ok(_) => (),
                        Err(err) => return run_afters(req, res, Some(err), afters.slice_from(i))
                    }
                }
                Ok(res)
            }
        }
    }

    pub fn run_handler_catch(req: &mut Request, err: Box<Error>,
                         handler: &Box<Handler>) -> (Response, Option<Box<Error>>) {
        match handler.catch(req, err) {
            (res, Ok(())) => (res, None),
            (res, Err(e)) => (res, Some(e))
        }
    }
}

<|endoftext|>


<commit_before><commit_msg>Use external `mime_guess`<commit_after><|endoftext|>