<commit_before>// Handle incoming requests.
extern crate iron;
extern crate redis;
extern crate rustc_serialize;
extern crate hyper;
extern crate url;

extern crate router;

use std::vec::Vec;
use rustc_serialize::json::Json;

use iron::modifiers::Redirect;
use iron::headers::{CacheControl, CacheDirective};
use iron::prelude::*;
use iron::status;
use iron::Url as iUrl;

use hyper::client::Client;

use router::Router;

use redis::{Commands, Value};

use helpers::{setup_redis, fetch, get_status_or,  local_redir, set_redis_cache};
use github::schedule_update as schedule_github_update;

// The base URL for our badges. We aren't actually compiling them ourselfes,
// but are reusing the great shields.io service.
static BADGE_URL_BASE: &'static str = "https://img.shields.io/badge/";

// Github Finder
// Expand a branch name into the hash, cache the redirect for 5min
// `/github/:user/:repo/badge.svg => /github/:user/:repo/:sha/badge.svg`
pub fn github_finder(req: &mut Request) -> IronResult<Response> {

    // Learn the parameters given to the request
    let router = req.extensions.get::<Router>().unwrap();
    let redis: redis::Connection = setup_redis();
    let hyper_client: Client = Client::new();

    let user = router.find("user").unwrap();
    let repo = router.find("repo").unwrap();
    let branch = router.find("branch").unwrap_or("master");
    let method = router.find("method").unwrap_or("badge.svg");

    // And the cache key we use to keep the map from branch->SHA
    let redis_key = format!("cached-sha/github/{0}/{1}:{2}", user, repo, branch);

    // Let's see if redis has this key. If it does, redirect the request
    // directly
    match redis.get(redis_key.to_owned()) {
        Ok(Value::Data(sha)) => {
            local_redir(&format!("/github/sha/{0}/{1}/{2}/{3}",
                                 user,
                                 repo,
                                 String::from_utf8(sha).unwrap(),
                                 method),
                        &req.url)
        }
        // otherwise, we need to look up the current SHA for the branch
        _ => {
            let github_url = format!("https://api.github.com/repos/{0}/{1}/git/refs/heads/{2}",
                                     user,
                                     repo,
                                     branch);
            // Fetch the content API request for the Github URL,
            // Parse its JSON and try to find the `SHA`-key.
            if let Some(body) = fetch(&hyper_client, &github_url) {
                if let Ok(json) = Json::from_str(&body) {
                    if let Some(&Json::String(ref sha)) = json.find_path(&["object", "sha"]) {
                        // Once found, store the SHA in the cache and redirect
                        // the request to
                        set_redis_cache(&redis, &redis_key, &sha);
                        local_redir(&format!("/github/sha/{0}/{1}/{2}/{3}",
                                             user,
                                             repo,
                                             sha,
                                             method),
                                    &req.url)
                    } else {
                        // If we couldn't find the SHA, then there is a problem
                        // we need to inform the user about. Usually this means
                        // they did a typo or the content moved – either way, we
                        // fire a 404 – Not Found.
                        warn!("{}: SHA not found in JSON: {}", &github_url, &json);
                        Ok(Response::with((status::NotFound,
                                           format!("Couldn't find on Github {}", &github_url))))
                    }
                } else {
                    warn!("{}: Couldn't parse Githubs JSON response: {}",
                          &github_url,
                          &body);
                    Ok(Response::with((status::InternalServerError,
                                       "Couldn't parse Githubs JSON response")))
                }
            } else {
                Ok(Response::with((status::NotFound,
                                   format!("Couldn't find on Github {}", &github_url))))
            }
        }
    }
}

// ## Github Handler
// Handle the request for a status report of a user-repo-sha combination.
// Usually the request ends up here after having been redirected via the
// `github_finder`-handler.
// In this request is where the actual sausage is done.
pub fn github_handler(req: &mut Request) -> IronResult<Response> {

    // First extract all the request information
    let router = req.extensions.get::<Router>().unwrap();
    let redis: redis::Connection = setup_redis();

    let user = router.find("user").unwrap();
    let repo = router.find("repo").unwrap();
    let sha = router.find("sha").unwrap();
    let filename: Vec<&str> = router.find("method")
                                    .unwrap_or("badge.svg")
                                    .rsplitn(2, '.')
                                    .collect();
    let (method, ext) = match filename.len() {
        2 => (filename[1], filename[0]),
        _ => (filename[0], ""),
    };

    // Use `get_status_or` to look up and map the cached result
    // or trigger a `schedule_github_update` if that isn't found yet
    let result_key = format!("result/github/{0}/{1}:{2}", user, repo, sha);
    let (text, color): (String, String) = get_status_or(
        redis.get(result_key.to_owned()),
        || schedule_github_update(&user, &repo, &sha));

    // Then render the response
    let mut response = match method {
        // If this is a simple request for status, just return the result
        "status" => Response::with((status::Ok, text.to_owned())),
        // for the badge, put text, color, base URL and query-parameters from the
        // incoming requests together to the URL we need to forward it to
        "badge" => {
            let target_badge = match req.url.clone().query {
                Some(query) => format!("{}clippy-{}-{}.{}?{}", BADGE_URL_BASE, text, color, ext, query),
                _ => format!("{}clippy-{}-{}.{}", BADGE_URL_BASE, text, color, ext),
            };
            // while linting, use only temporary redirects, so that the actual
            // result will be asked for later
            Response::with((match text.as_str() {
                    "linting" => status::Found,
                    _ => status::MovedPermanently
                }, Redirect(iUrl::parse(&target_badge).unwrap())))
        },
        // emojibadge and fullemojibadge do the same as the request for `badge`,
        // except that they replace the status with appropriate emoji
        "emojibadge" => {
            let emoji = match text.as_str() {
                "linting" => "👷".to_string(),
                "failed" => "😱".to_string(),
                "success" => "👌".to_string(),
                _ => text.replace("errors", "🤕").replace("warnings", "😟")
            };

            let target_badge = match req.url.clone().query {
                Some(query) => format!("{}clippy-{}-{}.{}?{}", BADGE_URL_BASE, emoji, color, ext, query),
                _ => format!("{}clippy-{}-{}.{}", BADGE_URL_BASE, emoji, color, ext),
            };
            Response::with((match color.as_str() {
                    "blue" => status::Found,
                    _ => status::MovedPermanently
                }, Redirect(iUrl::parse(&target_badge).unwrap())))
        },
        "fullemojibadge" => {
            let emoji = match text.as_str() {
                "linting" => "👷".to_string(),
                "failed" => "😱".to_string(),
                "success" => "👌".to_string(),
                _ => text.replace("errors", "🤕").replace("warnings", "😟")
            };

            let target_badge = match req.url.clone().query {
                Some(query) => format!("{}📎-{}-{}.{}?{}", BADGE_URL_BASE, emoji, color, ext, query),
                _ => format!("{}📎-{}-{}.{}", BADGE_URL_BASE, emoji, color, ext),
            };
            Response::with((match color.as_str() {
                    "blue" => status::Found,
                    _ => status::MovedPermanently
                }, Redirect(iUrl::parse(&target_badge).unwrap())))
        },
        // If the request is asking for the logs, fetch those. This isn't particularly
        // simple as the Redis library makes the unwrapping a little bit tricky and hard
        // for rust to guess the proper types. So we have to specify the types and iterator
        // rather explictly at times.
        "log" => {
            let log_key = format!("log/github/{0}/{1}:{2}", user, repo, sha);
            match redis.lrange(log_key.to_owned(), 0, -1) {
                Ok(Some(Value::Bulk(logs))) => {
                    let logs: Vec<String> = logs.iter()
                                                .map(|ref v| {
                                                    match **v {
                                                        Value::Data(ref val) => {
                                        String::from_utf8(val.to_owned())
                                            .unwrap()
                                            .to_owned()
                                    }
                                                        _ => "".to_owned(),
                                                    }
                                                })
                                                .collect();
                    Response::with((status::Ok, logs.join("\n")))
                }
                // if there aren't any logs found, we might just started the
                // process. Let the request know.
                _ => {
                    Response::with((status::Ok, "Started. Please refresh"))
                }
            }
        },
        // Nothing else is supported – but in rust, we have to return all things
        // of the same type. So let's return a `BadRequst` :) .
        _ => Response::with((status::BadRequest, format!("{} Not Implemented.", method))),
    };

    response.headers.set(CacheControl(vec![CacheDirective::NoCache]));
    Ok(response)
}
<commit_msg>Fix comment typo<commit_after>// Handle incoming requests.
extern crate iron;
extern crate redis;
extern crate rustc_serialize;
extern crate hyper;
extern crate url;

extern crate router;

use std::vec::Vec;
use rustc_serialize::json::Json;

use iron::modifiers::Redirect;
use iron::headers::{CacheControl, CacheDirective};
use iron::prelude::*;
use iron::status;
use iron::Url as iUrl;

use hyper::client::Client;

use router::Router;

use redis::{Commands, Value};

use helpers::{setup_redis, fetch, get_status_or,  local_redir, set_redis_cache};
use github::schedule_update as schedule_github_update;

// The base URL for our badges. We aren't actually compiling them ourselves,
// but are reusing the great shields.io service.
static BADGE_URL_BASE: &'static str = "https://img.shields.io/badge/";

// Github Finder
// Expand a branch name into the hash, cache the redirect for 5min
// `/github/:user/:repo/badge.svg => /github/:user/:repo/:sha/badge.svg`
pub fn github_finder(req: &mut Request) -> IronResult<Response> {

    // Learn the parameters given to the request
    let router = req.extensions.get::<Router>().unwrap();
    let redis: redis::Connection = setup_redis();
    let hyper_client: Client = Client::new();

    let user = router.find("user").unwrap();
    let repo = router.find("repo").unwrap();
    let branch = router.find("branch").unwrap_or("master");
    let method = router.find("method").unwrap_or("badge.svg");

    // And the cache key we use to keep the map from branch->SHA
    let redis_key = format!("cached-sha/github/{0}/{1}:{2}", user, repo, branch);

    // Let's see if redis has this key. If it does, redirect the request
    // directly
    match redis.get(redis_key.to_owned()) {
        Ok(Value::Data(sha)) => {
            local_redir(&format!("/github/sha/{0}/{1}/{2}/{3}",
                                 user,
                                 repo,
                                 String::from_utf8(sha).unwrap(),
                                 method),
                        &req.url)
        }
        // otherwise, we need to look up the current SHA for the branch
        _ => {
            let github_url = format!("https://api.github.com/repos/{0}/{1}/git/refs/heads/{2}",
                                     user,
                                     repo,
                                     branch);
            // Fetch the content API request for the Github URL,
            // Parse its JSON and try to find the `SHA`-key.
            if let Some(body) = fetch(&hyper_client, &github_url) {
                if let Ok(json) = Json::from_str(&body) {
                    if let Some(&Json::String(ref sha)) = json.find_path(&["object", "sha"]) {
                        // Once found, store the SHA in the cache and redirect
                        // the request to
                        set_redis_cache(&redis, &redis_key, &sha);
                        local_redir(&format!("/github/sha/{0}/{1}/{2}/{3}",
                                             user,
                                             repo,
                                             sha,
                                             method),
                                    &req.url)
                    } else {
                        // If we couldn't find the SHA, then there is a problem
                        // we need to inform the user about. Usually this means
                        // they did a typo or the content moved – either way, we
                        // fire a 404 – Not Found.
                        warn!("{}: SHA not found in JSON: {}", &github_url, &json);
                        Ok(Response::with((status::NotFound,
                                           format!("Couldn't find on Github {}", &github_url))))
                    }
                } else {
                    warn!("{}: Couldn't parse Githubs JSON response: {}",
                          &github_url,
                          &body);
                    Ok(Response::with((status::InternalServerError,
                                       "Couldn't parse Githubs JSON response")))
                }
            } else {
                Ok(Response::with((status::NotFound,
                                   format!("Couldn't find on Github {}", &github_url))))
            }
        }
    }
}

// ## Github Handler
// Handle the request for a status report of a user-repo-sha combination.
// Usually the request ends up here after having been redirected via the
// `github_finder`-handler.
// In this request is where the actual sausage is done.
pub fn github_handler(req: &mut Request) -> IronResult<Response> {

    // First extract all the request information
    let router = req.extensions.get::<Router>().unwrap();
    let redis: redis::Connection = setup_redis();

    let user = router.find("user").unwrap();
    let repo = router.find("repo").unwrap();
    let sha = router.find("sha").unwrap();
    let filename: Vec<&str> = router.find("method")
                                    .unwrap_or("badge.svg")
                                    .rsplitn(2, '.')
                                    .collect();
    let (method, ext) = match filename.len() {
        2 => (filename[1], filename[0]),
        _ => (filename[0], ""),
    };

    // Use `get_status_or` to look up and map the cached result
    // or trigger a `schedule_github_update` if that isn't found yet
    let result_key = format!("result/github/{0}/{1}:{2}", user, repo, sha);
    let (text, color): (String, String) = get_status_or(
        redis.get(result_key.to_owned()),
        || schedule_github_update(&user, &repo, &sha));

    // Then render the response
    let mut response = match method {
        // If this is a simple request for status, just return the result
        "status" => Response::with((status::Ok, text.to_owned())),
        // for the badge, put text, color, base URL and query-parameters from the
        // incoming requests together to the URL we need to forward it to
        "badge" => {
            let target_badge = match req.url.clone().query {
                Some(query) => format!("{}clippy-{}-{}.{}?{}", BADGE_URL_BASE, text, color, ext, query),
                _ => format!("{}clippy-{}-{}.{}", BADGE_URL_BASE, text, color, ext),
            };
            // while linting, use only temporary redirects, so that the actual
            // result will be asked for later
            Response::with((match text.as_str() {
                    "linting" => status::Found,
                    _ => status::MovedPermanently
                }, Redirect(iUrl::parse(&target_badge).unwrap())))
        },
        // emojibadge and fullemojibadge do the same as the request for `badge`,
        // except that they replace the status with appropriate emoji
        "emojibadge" => {
            let emoji = match text.as_str() {
                "linting" => "👷".to_string(),
                "failed" => "😱".to_string(),
                "success" => "👌".to_string(),
                _ => text.replace("errors", "🤕").replace("warnings", "😟")
            };

            let target_badge = match req.url.clone().query {
                Some(query) => format!("{}clippy-{}-{}.{}?{}", BADGE_URL_BASE, emoji, color, ext, query),
                _ => format!("{}clippy-{}-{}.{}", BADGE_URL_BASE, emoji, color, ext),
            };
            Response::with((match color.as_str() {
                    "blue" => status::Found,
                    _ => status::MovedPermanently
                }, Redirect(iUrl::parse(&target_badge).unwrap())))
        },
        "fullemojibadge" => {
            let emoji = match text.as_str() {
                "linting" => "👷".to_string(),
                "failed" => "😱".to_string(),
                "success" => "👌".to_string(),
                _ => text.replace("errors", "🤕").replace("warnings", "😟")
            };

            let target_badge = match req.url.clone().query {
                Some(query) => format!("{}📎-{}-{}.{}?{}", BADGE_URL_BASE, emoji, color, ext, query),
                _ => format!("{}📎-{}-{}.{}", BADGE_URL_BASE, emoji, color, ext),
            };
            Response::with((match color.as_str() {
                    "blue" => status::Found,
                    _ => status::MovedPermanently
                }, Redirect(iUrl::parse(&target_badge).unwrap())))
        },
        // If the request is asking for the logs, fetch those. This isn't particularly
        // simple as the Redis library makes the unwrapping a little bit tricky and hard
        // for rust to guess the proper types. So we have to specify the types and iterator
        // rather explictly at times.
        "log" => {
            let log_key = format!("log/github/{0}/{1}:{2}", user, repo, sha);
            match redis.lrange(log_key.to_owned(), 0, -1) {
                Ok(Some(Value::Bulk(logs))) => {
                    let logs: Vec<String> = logs.iter()
                                                .map(|ref v| {
                                                    match **v {
                                                        Value::Data(ref val) => {
                                        String::from_utf8(val.to_owned())
                                            .unwrap()
                                            .to_owned()
                                    }
                                                        _ => "".to_owned(),
                                                    }
                                                })
                                                .collect();
                    Response::with((status::Ok, logs.join("\n")))
                }
                // if there aren't any logs found, we might just started the
                // process. Let the request know.
                _ => {
                    Response::with((status::Ok, "Started. Please refresh"))
                }
            }
        },
        // Nothing else is supported – but in rust, we have to return all things
        // of the same type. So let's return a `BadRequst` :) .
        _ => Response::with((status::BadRequest, format!("{} Not Implemented.", method))),
    };

    response.headers.set(CacheControl(vec![CacheDirective::NoCache]));
    Ok(response)
}
<|endoftext|>


<commit_before>use internal::ColorComponent;
use math::{
    hsv,
    margin_rectangle,
    relative_rectangle,
    relative_source_rectangle,
    Scalar,
};
use radians::Radians;

/// Implemented by contexts that contains color.
pub trait Colored: Sized {
    /// Multiplies with red, green, blue and alpha values.
    fn mul_rgba(
        &self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> Self;

    /// Mixes the current color with white.
    ///
    /// 0 is black and 1 is white.
    #[inline(always)]
    fn tint(&self, f: ColorComponent) -> Self {
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Mixes the current color with black.
    ///
    /// 0 is white and 1 is black.
    #[inline(always)]
    fn shade(&self, f: ColorComponent) -> Self {
        let f = 1.0 - f;
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Rotates hue by degrees.
    #[inline(always)]
    fn hue_deg(&self, angle: ColorComponent) -> Self {
        let pi: ColorComponent = Radians::_180();
        self.hue_rad(angle * pi / 180.0)
    }

    /// Rotates hue by radians.
    fn hue_rad(&self, angle: ColorComponent) -> Self;
}

/*
impl<T: Get<Color> + Set<Color> + Clone> Colored for T {
    #[inline(always)]
    fn mul_rgba(
        &self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> Self {
        let Color(col) = self.get();
        self.clone().set(Color([col[0] * r, col[1] * g, col[2] * b, col[3] * a]))
    }

    #[inline(always)]
    fn hue_rad(&self, angle: ColorComponent) -> Self {
        let Color(val) = self.get();
        self.clone().set(Color(hsv(val, angle, 1.0, 1.0)))
    }
}
*/

/// Should be implemented by contexts that have rectangle information.
pub trait Rectangled: Sized {
    /// Shrinks the current rectangle equally by all sides.
    fn margin(&self, m: Scalar) -> Self;

    /// Expands the current rectangle equally by all sides.
    #[inline(always)]
    fn expand(&self, m: Scalar) -> Self {
        self.margin(-m)
    }

    /// Moves to a relative rectangle using the current rectangle as tile.
    fn rel(&self, x: Scalar, y: Scalar) -> Self;
}

/*
impl<T: Get<Rect> + Set<Rect> + Clone> Rectangled for T {
    #[inline(always)]
    fn margin(&self, m: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(margin_rectangle(val, m)))
    }

    #[inline(always)]
    fn rel(&self, x: Scalar, y: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(relative_rectangle(val, [x, y])))
    }
}
*/

/// Should be implemented by contexts that
/// have source rectangle information.
pub trait SourceRectangled {
    /// Adds a source rectangle.
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self;

    /// Moves to a relative source rectangle using
    /// the current source rectangle as tile.
    fn src_rel(&self, x: i32, y: i32) -> Self;

    /// Flips the source rectangle horizontally.
    fn src_flip_h(&self) -> Self;

    /// Flips the source rectangle vertically.
    fn src_flip_v(&self) -> Self;

    /// Flips the source rectangle horizontally and vertically.
    fn src_flip_hv(&self) -> Self;
}

/*
impl<T: Get<SrcRect>
      + Set<SrcRect>
      + Clone
> SourceRectangled for T {
    #[inline(always)]
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self {
        self.clone().set(SrcRect([x, y, w, h]))
    }

    #[inline(always)]
    fn src_rel(&self, x: i32, y: i32) -> Self {
        let SrcRect(val) = self.get();
        self.clone().set(SrcRect(
            relative_source_rectangle(val, x, y)
        ))
    }

    #[inline(always)]
    fn src_flip_h(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1],
            -source_rect[2],
            source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_v(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0],
            source_rect[1] + source_rect[3],
            source_rect[2],
            -source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_hv(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1] + source_rect[3],
            -source_rect[2],
            -source_rect[3]
        ]))
    }
}
*/
<commit_msg>Implemented `Colored` for `Color`<commit_after>use internal::{ Color, ColorComponent };
use math::{
    hsv,
    margin_rectangle,
    relative_rectangle,
    relative_source_rectangle,
    Scalar,
};
use radians::Radians;

/// Implemented by contexts that contains color.
pub trait Colored: Sized {
    /// Multiplies with red, green, blue and alpha values.
    fn mul_rgba(
        &self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> Self;

    /// Mixes the current color with white.
    ///
    /// 0 is black and 1 is white.
    #[inline(always)]
    fn tint(&self, f: ColorComponent) -> Self {
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Mixes the current color with black.
    ///
    /// 0 is white and 1 is black.
    #[inline(always)]
    fn shade(&self, f: ColorComponent) -> Self {
        let f = 1.0 - f;
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Rotates hue by degrees.
    #[inline(always)]
    fn hue_deg(&self, angle: ColorComponent) -> Self {
        let pi: ColorComponent = Radians::_180();
        self.hue_rad(angle * pi / 180.0)
    }

    /// Rotates hue by radians.
    fn hue_rad(&self, angle: ColorComponent) -> Self;
}

impl Colored for Color {
    #[inline(always)]
    fn mul_rgba(
        &self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> Self {
        [self[0] * r, self[1] * g, self[2] * b, self[3] * a]
    }

    #[inline(always)]
    fn hue_rad(&self, angle: ColorComponent) -> Self {
        hsv(*self, angle, 1.0, 1.0)
    }
}

/// Should be implemented by contexts that have rectangle information.
pub trait Rectangled: Sized {
    /// Shrinks the current rectangle equally by all sides.
    fn margin(&self, m: Scalar) -> Self;

    /// Expands the current rectangle equally by all sides.
    #[inline(always)]
    fn expand(&self, m: Scalar) -> Self {
        self.margin(-m)
    }

    /// Moves to a relative rectangle using the current rectangle as tile.
    fn rel(&self, x: Scalar, y: Scalar) -> Self;
}

/*
impl<T: Get<Rect> + Set<Rect> + Clone> Rectangled for T {
    #[inline(always)]
    fn margin(&self, m: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(margin_rectangle(val, m)))
    }

    #[inline(always)]
    fn rel(&self, x: Scalar, y: Scalar) -> Self {
        let Rect(val) = self.get();
        self.clone().set(Rect(relative_rectangle(val, [x, y])))
    }
}
*/

/// Should be implemented by contexts that
/// have source rectangle information.
pub trait SourceRectangled {
    /// Adds a source rectangle.
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self;

    /// Moves to a relative source rectangle using
    /// the current source rectangle as tile.
    fn src_rel(&self, x: i32, y: i32) -> Self;

    /// Flips the source rectangle horizontally.
    fn src_flip_h(&self) -> Self;

    /// Flips the source rectangle vertically.
    fn src_flip_v(&self) -> Self;

    /// Flips the source rectangle horizontally and vertically.
    fn src_flip_hv(&self) -> Self;
}

/*
impl<T: Get<SrcRect>
      + Set<SrcRect>
      + Clone
> SourceRectangled for T {
    #[inline(always)]
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self {
        self.clone().set(SrcRect([x, y, w, h]))
    }

    #[inline(always)]
    fn src_rel(&self, x: i32, y: i32) -> Self {
        let SrcRect(val) = self.get();
        self.clone().set(SrcRect(
            relative_source_rectangle(val, x, y)
        ))
    }

    #[inline(always)]
    fn src_flip_h(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1],
            -source_rect[2],
            source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_v(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0],
            source_rect[1] + source_rect[3],
            source_rect[2],
            -source_rect[3]
        ]))
    }

    #[inline(always)]
    fn src_flip_hv(&self) -> Self {
        let SrcRect(source_rect) = self.get();
        self.clone().set(SrcRect([
            source_rect[0] + source_rect[2],
            source_rect[1] + source_rect[3],
            -source_rect[2],
            -source_rect[3]
        ]))
    }
}
*/
<|endoftext|>


<commit_before>use ::libc::{self, c_int, O_EXCL, O_RDWR, O_CREAT};
use std::io;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::fs::{self, File, OpenOptions};
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::ffi::{OsStr, CString};
use ::util::tmpname;

// Stolen from std.
fn cstr(path: &Path) -> io::Result<CString> {
    path.as_os_str().to_cstring().ok_or(
        io::Error::new(io::ErrorKind::InvalidInput, "path contained a null"))
}

fn create_unix(dir: &Path) -> io::Result<File> {
    loop {
        let name = tmpname();
        let tmp_path = dir.join(OsStr::from_bytes(&name));
        return match unsafe {
            libc::open(try!(cstr(&tmp_path)).as_ptr(), O_EXCL | O_RDWR | O_CREAT, 0o600)
        } {
            -1 => {
                let err = io::Error::last_os_error();
                if err.kind() == io::ErrorKind::AlreadyExists {
                    continue;
                } else {
                    Err(err)
                }
            }
            fd => {
                let f = FromRawFd::from_raw_fd(fd);
                // I should probably tell the user this failed but the temporary file creation
                // didn't really fail...
                let _ = fs::remove_file(tmp_path);
                Ok(f)
            }
        }
    }
}

#[cfg(target_os = "linux")]
fn create_linux(dir: &Path) -> io::Result<File> {
    const O_TMPFILE: libc::c_int = 4259840;
    let dir = try!(cstr(dir));

    match unsafe {
        libc::open(dir.as_ptr(), O_EXCL | O_TMPFILE | O_RDWR, 0o600)
    } {
        -1 => Err(io::Error::last_os_error()),
        fd => Ok(FromRawFd::from_raw_fd(fd)),
    }
}

#[cfg(target_os = "linux")]
pub fn create(dir: &Path) -> io::Result<File> {
    create_linux(dir).or_else(|_| create_unix(dir))
}

#[cfg(not(target_os = "linux"))]
#[inline(always)]
pub fn create(dir: &Path, num_readers: usize) -> io::Result<File> {
    create_unix(dir, num_readers)
}

pub fn reopen(f: &File) -> io::Result<File> {
    OpenOptions::new().read(true).write(true).create(false).open(format!("/dev/fd/{}", f.as_raw_fd()))
}
<commit_msg>Set close on exec.<commit_after>use ::libc::{self, c_int, O_EXCL, O_RDWR, O_CREAT};
use std::io;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::fs::{self, File, OpenOptions};
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::ffi::{OsStr, CString};
use ::util::tmpname;

// Stolen from std.
fn cstr(path: &Path) -> io::Result<CString> {
    path.as_os_str().to_cstring().ok_or(
        io::Error::new(io::ErrorKind::InvalidInput, "path contained a null"))
}

fn create_unix(dir: &Path) -> io::Result<File> {
    loop {
        let name = tmpname();
        let tmp_path = dir.join(OsStr::from_bytes(&name));
        return match unsafe {
            libc::open(try!(cstr(&tmp_path)).as_ptr(), O_CLOEXEC | O_EXCL | O_RDWR | O_CREAT, 0o600)
        } {
            -1 => {
                let err = io::Error::last_os_error();
                if err.kind() == io::ErrorKind::AlreadyExists {
                    continue;
                } else {
                    Err(err)
                }
            }
            fd => {
                let f = FromRawFd::from_raw_fd(fd);
                // I should probably tell the user this failed but the temporary file creation
                // didn't really fail...
                let _ = fs::remove_file(tmp_path);
                Ok(f)
            }
        }
    }
}

#[cfg(target_os = "linux")]
fn create_linux(dir: &Path) -> io::Result<File> {
    const O_TMPFILE: libc::c_int = 4259840;
    let dir = try!(cstr(dir));

    match unsafe {
        libc::open(dir.as_ptr(), O_CLOEXEC | O_EXCL | O_TMPFILE | O_RDWR, 0o600)
    } {
        -1 => Err(io::Error::last_os_error()),
        fd => Ok(FromRawFd::from_raw_fd(fd)),
    }
}

#[cfg(target_os = "linux")]
pub fn create(dir: &Path) -> io::Result<File> {
    create_linux(dir).or_else(|_| create_unix(dir))
}

#[cfg(not(target_os = "linux"))]
#[inline(always)]
pub fn create(dir: &Path, num_readers: usize) -> io::Result<File> {
    create_unix(dir, num_readers)
}

pub fn reopen(f: &File) -> io::Result<File> {
    OpenOptions::new().read(true).write(true).create(false).open(format!("/dev/fd/{}", f.as_raw_fd()))
}
<|endoftext|>


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

use rustc_hash::FxHashMap;
use serde::Deserialize;
use serde_with::{serde_as, DisplayFromStr, SpaceSeparator, StringWithSeparator};
use shakmaty::{
    fen::Fen,
    san::San,
    uci::Uci,
    variant::{Variant, VariantPosition},
    zobrist::Zobrist,
    ByColor, CastlingMode, Chess, Color, Outcome, Position, Setup,
};
use tokio::sync::Mutex;

use crate::{
    api::{Error, LilaVariant},
    db::Database,
    model::{
        GameId, GamePlayer, Key, KeyBuilder, LaxDate, LichessEntry, LichessGame, MastersEntry,
        MastersGameWithId, Mode, Speed,
    },
    util::ByColorDef,
};

#[derive(Clone)]
pub struct MastersImporter {
    db: Arc<Database>,
    mutex: Arc<Mutex<()>>,
}

impl MastersImporter {
    pub fn new(db: Arc<Database>) -> MastersImporter {
        MastersImporter {
            db,
            mutex: Arc::new(Mutex::new(())),
        }
    }

    pub async fn import(&self, body: MastersGameWithId) -> Result<(), Error> {
        if body.game.players.white.rating / 2 + body.game.players.black.rating / 2 < 2200 {
            return Err(Error::RejectedImport(body.id));
        }

        let _guard = self.mutex.lock();
        let masters_db = self.db.masters();
        if masters_db
            .has_game(body.id)
            .expect("check for masters game")
        {
            return Err(Error::DuplicateGame(body.id));
        }

        let mut without_loops: FxHashMap<Key, (Uci, Color)> =
            FxHashMap::with_capacity_and_hasher(body.game.moves.len(), Default::default());
        let mut pos: Zobrist<Chess, u128> = Zobrist::default();
        let mut final_key = None;
        for uci in &body.game.moves {
            let key = KeyBuilder::masters()
                .with_zobrist(Variant::Chess, pos.zobrist_hash())
                .with_year(body.game.date.year());
            final_key = Some(key.clone());
            let m = uci.to_move(&pos)?;
            without_loops.insert(key, (Uci::from_chess960(&m), pos.turn()));
            pos.play_unchecked(&m);
        }

        if let Some(final_key) = final_key {
            if masters_db.has(final_key).expect("check for masters entry") {
                return Err(Error::DuplicateGame(body.id));
            }
        }

        let mut batch = masters_db.batch();
        batch.put_game(body.id, &body.game);
        for (key, (uci, turn)) in without_loops {
            batch.merge(
                key,
                MastersEntry::new_single(
                    uci,
                    body.id,
                    Outcome::from_winner(body.game.winner),
                    body.game.players.by_color(turn).rating,
                    body.game.players.by_color(!turn).rating,
                ),
            );
        }

        batch.commit().expect("commit masters game");
        Ok(())
    }
}

#[serde_as]
#[derive(Deserialize)]
pub struct LichessGameImport {
    variant: LilaVariant,
    speed: Speed,
    #[serde_as(as = "Option<DisplayFromStr>")]
    fen: Option<Fen>,
    #[serde_as(as = "DisplayFromStr")]
    id: GameId,
    #[serde_as(as = "DisplayFromStr")]
    date: LaxDate,
    #[serde(flatten, with = "ByColorDef")]
    players: ByColor<GamePlayer>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    winner: Option<Color>,
    #[serde_as(as = "StringWithSeparator<SpaceSeparator, San>")]
    moves: Vec<San>,
}

#[derive(Clone)]
pub struct LichessImporter {
    db: Arc<Database>,
    mutex: Arc<Mutex<()>>,
}

impl LichessImporter {
    pub fn new(db: Arc<Database>) -> LichessImporter {
        LichessImporter {
            db,
            mutex: Arc::new(Mutex::new(())),
        }
    }

    pub async fn import(&self, game: LichessGameImport) -> Result<(), Error> {
        let _guard = self.mutex.lock();

        let lichess_db = self.db.lichess();

        if lichess_db
            .game(game.id)
            .expect("get game info")
            .map_or(false, |info| info.indexed_lichess)
        {
            log::warn!("lichess game {} already imported", game.id);
            return Ok(());
        }

        let month = match game.date.month() {
            Some(month) => month,
            None => {
                log::error!("lichess game {} missing month", game.id);
                return Err(Error::RejectedImport(game.id));
            }
        };
        let outcome = Outcome::from_winner(game.winner);
        let variant = Variant::from(game.variant);

        let mut pos: Zobrist<_, u128> = Zobrist::new(match game.fen {
            Some(fen) => {
                VariantPosition::from_setup(variant, &fen, CastlingMode::Chess960)?
            }
            None => VariantPosition::new(variant),
        });

        let mut without_loops: FxHashMap<Key, (Uci, Color)> =
            FxHashMap::with_capacity_and_hasher(game.moves.len(), Default::default());
        for san in game.moves {
            let m = san.to_move(&pos)?;
            without_loops.insert(
                KeyBuilder::lichess()
                    .with_zobrist(variant, pos.zobrist_hash())
                    .with_month(month),
                (Uci::from_chess960(&m), pos.turn()),
            );
            pos.play_unchecked(&m);
        }

        let mut batch = lichess_db.batch();
        batch.merge_game(
            game.id,
            LichessGame {
                mode: Mode::Rated,
                indexed_player: Default::default(),
                indexed_lichess: true,
                outcome,
                players: game.players.clone(),
                month,
                speed: game.speed,
            },
        );
        for (key, (uci, turn)) in without_loops {
            batch.merge_lichess(
                key,
                LichessEntry::new_single(
                    uci,
                    game.speed,
                    game.id,
                    outcome,
                    game.players.by_color(turn).rating,
                    game.players.by_color(!turn).rating,
                ),
            );
        }

        batch.commit().expect("commit lichess game");
        Ok(())
    }
}
<commit_msg>limit plies in lichess db<commit_after>use std::sync::Arc;

use rustc_hash::FxHashMap;
use serde::Deserialize;
use serde_with::{serde_as, DisplayFromStr, SpaceSeparator, StringWithSeparator};
use shakmaty::{
    fen::Fen,
    san::San,
    uci::Uci,
    variant::{Variant, VariantPosition},
    zobrist::Zobrist,
    ByColor, CastlingMode, Chess, Color, Outcome, Position, Setup,
};
use tokio::sync::Mutex;

use crate::{
    api::{Error, LilaVariant},
    db::Database,
    model::{
        GameId, GamePlayer, Key, KeyBuilder, LaxDate, LichessEntry, LichessGame, MastersEntry,
        MastersGameWithId, Mode, Speed,
    },
    util::ByColorDef,
};

const MAX_PLIES: usize = 50;

#[derive(Clone)]
pub struct MastersImporter {
    db: Arc<Database>,
    mutex: Arc<Mutex<()>>,
}

impl MastersImporter {
    pub fn new(db: Arc<Database>) -> MastersImporter {
        MastersImporter {
            db,
            mutex: Arc::new(Mutex::new(())),
        }
    }

    pub async fn import(&self, body: MastersGameWithId) -> Result<(), Error> {
        if body.game.players.white.rating / 2 + body.game.players.black.rating / 2 < 2200 {
            return Err(Error::RejectedImport(body.id));
        }

        let _guard = self.mutex.lock();
        let masters_db = self.db.masters();
        if masters_db
            .has_game(body.id)
            .expect("check for masters game")
        {
            return Err(Error::DuplicateGame(body.id));
        }

        let mut without_loops: FxHashMap<Key, (Uci, Color)> =
            FxHashMap::with_capacity_and_hasher(body.game.moves.len(), Default::default());
        let mut pos: Zobrist<Chess, u128> = Zobrist::default();
        let mut final_key = None;
        for uci in &body.game.moves {
            let key = KeyBuilder::masters()
                .with_zobrist(Variant::Chess, pos.zobrist_hash())
                .with_year(body.game.date.year());
            final_key = Some(key.clone());
            let m = uci.to_move(&pos)?;
            without_loops.insert(key, (Uci::from_chess960(&m), pos.turn()));
            pos.play_unchecked(&m);
        }

        if let Some(final_key) = final_key {
            if masters_db.has(final_key).expect("check for masters entry") {
                return Err(Error::DuplicateGame(body.id));
            }
        }

        let mut batch = masters_db.batch();
        batch.put_game(body.id, &body.game);
        for (key, (uci, turn)) in without_loops {
            batch.merge(
                key,
                MastersEntry::new_single(
                    uci,
                    body.id,
                    Outcome::from_winner(body.game.winner),
                    body.game.players.by_color(turn).rating,
                    body.game.players.by_color(!turn).rating,
                ),
            );
        }

        batch.commit().expect("commit masters game");
        Ok(())
    }
}

#[serde_as]
#[derive(Deserialize)]
pub struct LichessGameImport {
    variant: LilaVariant,
    speed: Speed,
    #[serde_as(as = "Option<DisplayFromStr>")]
    fen: Option<Fen>,
    #[serde_as(as = "DisplayFromStr")]
    id: GameId,
    #[serde_as(as = "DisplayFromStr")]
    date: LaxDate,
    #[serde(flatten, with = "ByColorDef")]
    players: ByColor<GamePlayer>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    winner: Option<Color>,
    #[serde_as(as = "StringWithSeparator<SpaceSeparator, San>")]
    moves: Vec<San>,
}

#[derive(Clone)]
pub struct LichessImporter {
    db: Arc<Database>,
    mutex: Arc<Mutex<()>>,
}

impl LichessImporter {
    pub fn new(db: Arc<Database>) -> LichessImporter {
        LichessImporter {
            db,
            mutex: Arc::new(Mutex::new(())),
        }
    }

    pub async fn import(&self, game: LichessGameImport) -> Result<(), Error> {
        let _guard = self.mutex.lock();

        let lichess_db = self.db.lichess();

        if lichess_db
            .game(game.id)
            .expect("get game info")
            .map_or(false, |info| info.indexed_lichess)
        {
            log::warn!("lichess game {} already imported", game.id);
            return Ok(());
        }

        let month = match game.date.month() {
            Some(month) => month,
            None => {
                log::error!("lichess game {} missing month", game.id);
                return Err(Error::RejectedImport(game.id));
            }
        };
        let outcome = Outcome::from_winner(game.winner);
        let variant = Variant::from(game.variant);

        let mut pos: Zobrist<_, u128> = Zobrist::new(match game.fen {
            Some(fen) => VariantPosition::from_setup(variant, &fen, CastlingMode::Chess960)?,
            None => VariantPosition::new(variant),
        });

        let mut without_loops: FxHashMap<Key, (Uci, Color)> =
            FxHashMap::with_capacity_and_hasher(game.moves.len(), Default::default());
        for (ply, san) in game.moves.into_iter().enumerate() {
            if ply >= MAX_PLIES {
                break;
            }

            let m = san.to_move(&pos)?;
            without_loops.insert(
                KeyBuilder::lichess()
                    .with_zobrist(variant, pos.zobrist_hash())
                    .with_month(month),
                (Uci::from_chess960(&m), pos.turn()),
            );
            pos.play_unchecked(&m);
        }

        let mut batch = lichess_db.batch();
        batch.merge_game(
            game.id,
            LichessGame {
                mode: Mode::Rated,
                indexed_player: Default::default(),
                indexed_lichess: true,
                outcome,
                players: game.players.clone(),
                month,
                speed: game.speed,
            },
        );
        for (key, (uci, turn)) in without_loops {
            batch.merge_lichess(
                key,
                LichessEntry::new_single(
                    uci,
                    game.speed,
                    game.id,
                    outcome,
                    game.players.by_color(turn).rating,
                    game.players.by_color(!turn).rating,
                ),
            );
        }

        batch.commit().expect("commit lichess game");
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![feature(std_misc,core,io,collections,std_misc,unsafe_destructor,path,env,plugin)]
extern crate tracer;

extern crate docopt;
extern crate "rustc-serialize" as rustc_serialize;
#[plugin] #[no_link] extern crate docopt_macros;

use tracer::{Scene, Renderer, RenderOptions, PPMStdoutRGBABufferWriter, FileOrAnyWriter};
use std::default::Default;
use std::env;
use std::sync::{TaskPool, Arc};
use std::old_io;
use std::old_path::Path;

docopt!(Args derive Show, "
Usage: rtrace (<OUTPUT-FILE>|-)
       rtrace --help

<OUTPUT-FILE>|-     Either a file with .tga extension, or - to write file to stdout
");

#[allow(dead_code)]
fn main() {
    let s: Arc<Scene> = Arc::new(Default::default());
    let pool: TaskPool  = TaskPool::new(env::var_string("RTRACEMAXPROCS")
                                                            .ok()
                                                            .unwrap_or("1".to_string())
                                                            .parse::<usize>().ok()
                                                            .unwrap_or(1));

    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
    let mut output = if args.arg_OUTPUT_FILE != "-" {
        let p = Path::new(args.arg_OUTPUT_FILE);
        if p.extension().unwrap_or(b".UNSET") != b"tga" {
            println!("Output file '{}' must have the tga extension, e.g. {}", p.as_str().unwrap(), p.with_extension(b"tga").as_str().unwrap());
            return;
        }
        let open_file = old_io::BufferedWriter::new(old_io::File::create(&p)
                                                    .ok()
                                                    .expect("Could not open output file"));
        FileOrAnyWriter::FileWriter(open_file)
    } else {
        FileOrAnyWriter::AnyWriter(old_io::stdout())
    };

    let options = RenderOptions {   width: 1024,
                                    height: 1024,
                                    samples_per_pixel: 1 };

    Renderer::render(&options, s.clone(),
                     &mut PPMStdoutRGBABufferWriter::new(false, &mut output), &pool);
    env::set_exit_status(0);
}<commit_msg>Added more options to allow setting all render attributes<commit_after>#![feature(std_misc,core,io,collections,std_misc,unsafe_destructor,path,env,plugin)]
extern crate tracer;

extern crate docopt;
extern crate "rustc-serialize" as rustc_serialize;
#[plugin] #[no_link] extern crate docopt_macros;

use tracer::{Scene, Renderer, RenderOptions, PPMStdoutRGBABufferWriter, FileOrAnyWriter};
use std::default::Default;
use std::env;
use std::sync::{TaskPool, Arc};
use std::old_io;
use std::old_path::Path;

docopt!(Args derive Show, "
Usage: rtrace [options] (<OUTPUT-FILE>|-)
       rtrace --help

Options:
--width <X>                    The width of the output image [default: 1024]
--height <Y>                   The height of the output image [default: 1024]
--samples-per-pixel <SAMPLES>  Amount of samples per pixel. 4 means 16 over-samples [default: 1]

<OUTPUT-FILE>|-     Either a file with .tga extension, or - to write file to stdout
"
, flag_samples_per_pixel: u16
, flag_height: u16
, flag_width: u16);

#[allow(dead_code)]
fn main() {
    let s: Arc<Scene> = Arc::new(Default::default());
    let pool: TaskPool  = TaskPool::new(env::var_string("RTRACEMAXPROCS")
                                                            .ok()
                                                            .unwrap_or("1".to_string())
                                                            .parse::<usize>().ok()
                                                            .unwrap_or(1));

    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
    let mut output = if args.arg_OUTPUT_FILE != "-" {
        let p = Path::new(args.arg_OUTPUT_FILE);
        if p.extension().unwrap_or(b".UNSET") != b"tga" {
            println!("Output file '{}' must have the tga extension, e.g. {}", p.as_str().unwrap(), p.with_extension(b"tga").as_str().unwrap());
            return;
        }
        let open_file = old_io::BufferedWriter::new(old_io::File::create(&p)
                                                    .ok()
                                                    .expect("Could not open output file"));
        FileOrAnyWriter::FileWriter(open_file)
    } else {
        FileOrAnyWriter::AnyWriter(old_io::stdout())
    };

    let options = RenderOptions {   width: args.flag_width,
                                    height: args.flag_height,
                                    samples_per_pixel: args.flag_samples_per_pixel };

    Renderer::render(&options, s.clone(),
                     &mut PPMStdoutRGBABufferWriter::new(false, &mut output), &pool);
    env::set_exit_status(0);
}<|endoftext|>


<commit_before>pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
}

impl Model {
    pub fn init() -> Model {
        Model {
            board: Board::new(),
            turn: Turn::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
        }
    }
}

pub enum Turn {
    White,
    Black,
}

pub struct Board {
    // The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    // up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
    // as a ragged array won't work (since each row would have to be a different type).
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5]
        };

        // (0, 0) is the only empty hex
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // Conveniently, every other hex has exactly two pieces on it in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    pub fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!("Tried to get field on removed hex: {:?}", coord),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => hex[coord.f as usize] = field,
            None => panic!("Tried to set field on removed hex: {:?}", coord),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord {
                f: (coord.f + 1) % 6,
                ..*coord
            },
            FieldCoord {
                f: (coord.f + 5) % 6,
                ..*coord
            },
        ];

        for (i, neighbor) in coord.to_hex().get_neighbors() {
            if coord.f == i && self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
                break;
            }
        }
        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for neighbor in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&neighbor));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert_eq!(
            self.get_field(from),
            &Field::Piece,
            "Cannot move non-existant piece at {:?}",
            from
        );
        assert!(
            self.get_field_vertex_neighbors(from).contains(to),
            "Cannot move piece at {:?} to non-vertex neighbor {:?}",
            from,
            to
        );
        assert_eq!(
            self.get_field(to),
            &Field::Empty,
            "Cannot move piece at {:?} to occupied field at {:?}",
            from,
            to
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert_eq!(
            self.get_field(coord),
            &Field::Piece,
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
    }

    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    pub fn get_hex_neighbors(&self, coord: &HexCoord) -> Vec<HexCoord> {
        coord
            .get_neighbors()
            .iter()
            .filter_map(|&(_, c)| match *self.get_hex(&c) {
                Some(_) => Some(c),
                None => None,
            })
            .collect()
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for (i, neighbor) in coord.get_neighbors() {
            if self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
            }
        }
        neighbors
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => {
                if hex.iter().any(|&f| match f {
                    Field::Piece => true,
                    Field::Empty => false,
                }) {
                    return false;
                }
            }
            None => {
                panic!(
                    "Can't call Board::is_hex_removable on a removed hex: {:?}",
                    coord
                )
            }
        }

        let neighbor_idxs: Vec<u32> = coord.get_neighbors().iter().map(|&(i, _)| i).collect();
        let neighbor_idxs_slice = neighbor_idxs.as_slice();

        match neighbor_idxs_slice.len() {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 => true,
            2 => {
                let valid_idx_combos = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [0, 5]];
                valid_idx_combos.iter().any(|c| c == neighbor_idxs_slice)
            }
            3 => {
                let valid_idx_combos = [
                    [0, 1, 2],
                    [1, 2, 3],
                    [2, 3, 4],
                    [3, 4, 5],
                    [0, 4, 5],
                    [0, 1, 5],
                ];
                valid_idx_combos.iter().any(|c| c == neighbor_idxs_slice)
            }
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Tried to remove non-removable hex at {:?}",
            coord
        );
        self.set_hex(coord, None);
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6);
        FieldCoord { x, y, f }
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2);
        HexCoord { x, y }
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    // We return a Vec of tuples so that get_hex_field_neighbors and is_hex_removable know which
    // neighbors are on which side of the hex. They need to know this for different reasons:
    //   * get_hex_field_neighbors: the index of each neighboring field depends on which hex
    //                              neighbor that field neighbor is on
    //   * is_hex_removable: a hex is removable only if it is "attached to the board by 3 or less
    //                       adjacent sides"
    fn get_neighbors(&self) -> Vec<(u32, HexCoord)> {
        let mut neighbors = vec![];

        if self.y < 2 && (self.x + self.y) != 2 {
            neighbors.push((0, HexCoord::new(self.x, self.y + 1)));
        }
        if (self.x + self.y) != 2 && self.x < 2 {
            neighbors.push((1, HexCoord::new(self.x + 1, self.y)));
        }
        if self.x < 2 && self.y > -2 {
            neighbors.push((2, HexCoord::new(self.x + 1, self.y - 1)));
        }
        if self.y > -2 && (self.x + self.y) > -2 {
            neighbors.push((3, HexCoord::new(self.x, self.y - 1)));
        }
        if (self.x + self.y) > -2 && self.x > -2 {
            neighbors.push((4, HexCoord::new(self.x - 1, self.y)));
        }
        if self.x > -2 && self.y < 2 {
            neighbors.push((5, HexCoord::new(self.x - 1, self.y + 1)));
        }

        neighbors
    }
}
<commit_msg>Improve error messages<commit_after>pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
}

impl Model {
    pub fn init() -> Model {
        Model {
            board: Board::new(),
            turn: Turn::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
        }
    }
}

pub enum Turn {
    White,
    Black,
}

pub struct Board {
    // The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    // up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
    // as a ragged array won't work (since each row would have to be a different type).
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5]
        };

        // (0, 0) is the only empty hex
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // Conveniently, every other hex has exactly two pieces on it in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    pub fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!("Cannot get field on removed hex {:?}", coord),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => hex[coord.f as usize] = field,
            None => panic!("Cannot set field on removed hex {:?}", coord),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord {
                f: (coord.f + 1) % 6,
                ..*coord
            },
            FieldCoord {
                f: (coord.f + 5) % 6,
                ..*coord
            },
        ];

        for (i, neighbor) in coord.to_hex().get_neighbors() {
            if coord.f == i && self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
                break;
            }
        }
        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for neighbor in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&neighbor));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert_eq!(
            self.get_field(from),
            &Field::Piece,
            "There is no piece at {:?} to move",
            from
        );
        assert!(
            self.get_field_vertex_neighbors(from).contains(to),
            "Cannot move piece at {:?} to non-vertex neighbor {:?}",
            from,
            to
        );
        assert_eq!(
            self.get_field(to),
            &Field::Empty,
            "Cannot move piece at {:?} to occupied neighbor {:?}",
            from,
            to
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert_eq!(
            self.get_field(coord),
            &Field::Piece,
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
    }

    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    pub fn get_hex_neighbors(&self, coord: &HexCoord) -> Vec<HexCoord> {
        coord
            .get_neighbors()
            .iter()
            .filter_map(|&(_, c)| match *self.get_hex(&c) {
                Some(_) => Some(c),
                None => None,
            })
            .collect()
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for (i, neighbor) in coord.get_neighbors() {
            if self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
            }
        }
        neighbors
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => {
                if hex.iter().any(|&f| match f {
                    Field::Piece => true,
                    Field::Empty => false,
                }) {
                    return false;
                }
            }
            None => panic!("The hex at {:?} has already been removed", coord),
        }

        let neighbor_idxs: Vec<u32> = coord.get_neighbors().iter().map(|&(i, _)| i).collect();
        let neighbor_idxs_slice = neighbor_idxs.as_slice();

        match neighbor_idxs_slice.len() {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 => true,
            2 => {
                let valid_idx_combos = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [0, 5]];
                valid_idx_combos.iter().any(|c| c == neighbor_idxs_slice)
            }
            3 => {
                let valid_idx_combos = [
                    [0, 1, 2],
                    [1, 2, 3],
                    [2, 3, 4],
                    [3, 4, 5],
                    [0, 4, 5],
                    [0, 1, 5],
                ];
                valid_idx_combos.iter().any(|c| c == neighbor_idxs_slice)
            }
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            self.get_hex_neighbors(coord).len(),
        );
        self.set_hex(coord, None);
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6);
        FieldCoord { x, y, f }
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2);
        HexCoord { x, y }
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    // We return a Vec of tuples so that get_hex_field_neighbors and is_hex_removable know which
    // neighbors are on which side of the hex. They need to know this for different reasons:
    //   * get_hex_field_neighbors: the index of each neighboring field depends on which hex
    //                              neighbor that field neighbor is on
    //   * is_hex_removable: a hex is removable only if it is "attached to the board by 3 or less
    //                       adjacent sides"
    fn get_neighbors(&self) -> Vec<(u32, HexCoord)> {
        let mut neighbors = vec![];

        if self.y < 2 && (self.x + self.y) != 2 {
            neighbors.push((0, HexCoord::new(self.x, self.y + 1)));
        }
        if (self.x + self.y) != 2 && self.x < 2 {
            neighbors.push((1, HexCoord::new(self.x + 1, self.y)));
        }
        if self.x < 2 && self.y > -2 {
            neighbors.push((2, HexCoord::new(self.x + 1, self.y - 1)));
        }
        if self.y > -2 && (self.x + self.y) > -2 {
            neighbors.push((3, HexCoord::new(self.x, self.y - 1)));
        }
        if (self.x + self.y) > -2 && self.x > -2 {
            neighbors.push((4, HexCoord::new(self.x - 1, self.y)));
        }
        if self.x > -2 && self.y < 2 {
            neighbors.push((5, HexCoord::new(self.x - 1, self.y + 1)));
        }

        neighbors
    }
}
<|endoftext|>


<commit_before>use crate::utils::span_lint;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Detects giving a mutable reference to a function that only
    /// requires an immutable reference.
    ///
    /// **Why is this bad?** The immutable reference rules out all other references
    /// to the value. Also the code misleads about the intent of the call site.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// my_vec.push(&mut value)
    /// ```
    pub UNNECESSARY_MUT_PASSED,
    style,
    "an argument passed as a mutable reference although the callee only demands an immutable reference"
}

declare_lint_pass!(UnnecessaryMutPassed => [UNNECESSARY_MUT_PASSED]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
        match e.kind {
            ExprKind::Call(ref fn_expr, ref arguments) => {
                if let ExprKind::Path(ref path) = fn_expr.kind {
                    check_arguments(
                        cx,
                        arguments,
                        cx.tables.expr_ty(fn_expr),
                        &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
                    );
                }
            },
            ExprKind::MethodCall(ref path, _, ref arguments) => {
                let def_id = cx.tables.type_dependent_def_id(e.hir_id).unwrap();
                let substs = cx.tables.node_substs(e.hir_id);
                let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
                check_arguments(cx, arguments, method_type, &path.ident.as_str())
            },
            _ => (),
        }
    }
}

fn check_arguments<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    arguments: &[Expr<'_>],
    type_definition: Ty<'tcx>,
    name: &str,
) {
    match type_definition.kind {
        ty::FnDef(..) | ty::FnPtr(_) => {
            let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
            for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
                match parameter.kind {
                    ty::Ref(_, _, Mutability::Not)
                    | ty::RawPtr(ty::TypeAndMut {
                        mutbl: Mutability::Not, ..
                    }) => {
                        if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind {
                            span_lint(
                                cx,
                                UNNECESSARY_MUT_PASSED,
                                argument.span,
                                &format!("The function/method `{}` doesn't need a mutable reference", name),
                            );
                        }
                    },
                    _ => (),
                }
            }
        },
        _ => (),
    }
}
<commit_msg>Auto merge of #5639 - nickrtorres:unnecessary-mut-passed-doc-cleanup, r=phansch<commit_after>use crate::utils::span_lint;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Detects passing a mutable reference to a function that only
    /// requires an immutable reference.
    ///
    /// **Why is this bad?** The immutable reference rules out all other references
    /// to the value. Also the code misleads about the intent of the call site.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// my_vec.push(&mut value)
    /// ```
    pub UNNECESSARY_MUT_PASSED,
    style,
    "an argument passed as a mutable reference although the callee only demands an immutable reference"
}

declare_lint_pass!(UnnecessaryMutPassed => [UNNECESSARY_MUT_PASSED]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
        match e.kind {
            ExprKind::Call(ref fn_expr, ref arguments) => {
                if let ExprKind::Path(ref path) = fn_expr.kind {
                    check_arguments(
                        cx,
                        arguments,
                        cx.tables.expr_ty(fn_expr),
                        &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
                    );
                }
            },
            ExprKind::MethodCall(ref path, _, ref arguments) => {
                let def_id = cx.tables.type_dependent_def_id(e.hir_id).unwrap();
                let substs = cx.tables.node_substs(e.hir_id);
                let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
                check_arguments(cx, arguments, method_type, &path.ident.as_str())
            },
            _ => (),
        }
    }
}

fn check_arguments<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    arguments: &[Expr<'_>],
    type_definition: Ty<'tcx>,
    name: &str,
) {
    match type_definition.kind {
        ty::FnDef(..) | ty::FnPtr(_) => {
            let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
            for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
                match parameter.kind {
                    ty::Ref(_, _, Mutability::Not)
                    | ty::RawPtr(ty::TypeAndMut {
                        mutbl: Mutability::Not, ..
                    }) => {
                        if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind {
                            span_lint(
                                cx,
                                UNNECESSARY_MUT_PASSED,
                                argument.span,
                                &format!("The function/method `{}` doesn't need a mutable reference", name),
                            );
                        }
                    },
                    _ => (),
                }
            }
        },
        _ => (),
    }
}
<|endoftext|>