<commit_before>//! A [`SpriteBatch`](struct.SpriteBatch.html) is a way to
//! efficiently draw a large number of copies of the same image, or part
//! of the same image.  It's useful for implementing tiled maps,
//! spritesheets, particles, and other such things.
//!
//! Essentially this uses a technique called "instancing" to queue up
//! a large amount of location/position data in a buffer, then feed it
//! to the graphics card all in one go.
//!
//! Also it's super slow in `rustc`'s default debug mode, because
//! `rustc` adds a lot of checking to the vector accesses and math.
//! If you use it, it's recommended to crank up the `opt-level` for
//! debug mode in your game's `Cargo.toml`.

use std::convert::TryFrom;

use crate::context::Context;
use crate::error;
use crate::error::GameResult;
use crate::graphics::shader::BlendMode;
use crate::graphics::types::FilterMode;
use crate::graphics::{self, transform_rect, BackendSpec, DrawParam, Matrix4, Rect, Transform};
use gfx::Factory;

/// A `SpriteBatch` draws a number of copies of the same image, using a single draw call.
///
/// This is generally faster than drawing the same sprite with many
/// invocations of [`draw()`](../fn.draw.html), though it has a bit of
/// overhead to set up the batch.  This overhead makes it run very
/// slowly in `debug` mode because it spends a lot of time on array
/// bounds checking and un-optimized math; you need to build with
/// optimizations enabled to really get the speed boost.
#[derive(Debug, Clone, PartialEq)]
pub struct SpriteBatch {
    image: graphics::Image,
    sprites: Vec<graphics::DrawParam>,
    blend_mode: Option<BlendMode>,
}

/// An index of a particular sprite in a `SpriteBatch`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SpriteIdx(pub usize);

impl SpriteBatch {
    /// Creates a new `SpriteBatch`, drawing with the given image.
    ///
    /// Takes ownership of the `Image`, but cloning an `Image` is
    /// cheap since they have an internal `Arc` containing the actual
    /// image data.
    pub fn new(image: graphics::Image) -> Self {
        Self {
            image,
            sprites: vec![],
            blend_mode: None,
        }
    }

    /// Adds a new sprite to the sprite batch.
    ///
    /// Returns a handle with which to modify the sprite using
    /// [`set()`](#method.set)
    pub fn add<P>(&mut self, param: P) -> SpriteIdx
    where
        P: Into<graphics::DrawParam>,
    {
        self.sprites.push(param.into());
        SpriteIdx(self.sprites.len() - 1)
    }

    /// Alters a sprite in the batch to use the given draw params
    pub fn set<P>(&mut self, handle: SpriteIdx, param: P) -> GameResult
    where
        P: Into<graphics::DrawParam>,
    {
        if handle.0 < self.sprites.len() {
            self.sprites[handle.0] = param.into();
            Ok(())
        } else {
            Err(error::GameError::RenderError(String::from(
                "Provided index is out of bounds.",
            )))
        }
    }

    /// Returns a reference to the sprites.
    pub fn get_sprites(&self) -> &[DrawParam] {
        &self.sprites
    }

    /// Returns a mutable reference to the sprites.
    ///
    /// Please note that manually altering items in this slice
    /// will not automatically invalidate the buffer, you will
    /// have to manually call `flush()` or `flush_range()` later.
    pub fn get_sprites_mut(&mut self) -> &mut [DrawParam] {
        &mut self.sprites
    }

    /// Immediately sends all data in the batch to the graphics card.
    ///
    /// Generally just calling [`graphics::draw()`](../fn.draw.html) on the `SpriteBatch`
    /// will do this automatically.
    fn flush(&self, ctx: &mut Context, image: &graphics::Image) -> GameResult {
        // This is a little awkward but this is the right place
        // to do whatever transformations need to happen to DrawParam's.
        // We have a Context, and *everything* must pass through this
        // function to be drawn, so.
        // Though we do awkwardly have to allocate a new vector.
        // ...though upon benchmarking, the actual allocation is basically nothing,
        // the cost in debug mode is alllll math.
        let new_sprites = self
            .sprites
            .iter()
            .map(|param| {
                // Copy old params
                let src_width = param.src.w;
                let src_height = param.src.h;
                let new_param = match param.trans {
                    Transform::Values { scale, .. } => {
                        let new_scale = mint::Vector2 {
                            x: scale.x * src_width * f32::from(image.width),
                            y: scale.y * src_height * f32::from(image.height),
                        };
                        param.scale(new_scale)
                    }
                    Transform::Matrix(_) => *param,
                };
                let primitive_param = new_param;
                primitive_param.to_instance_properties(ctx.gfx_context.is_srgb())
            })
            .collect::<Vec<_>>();

        let gfx = &mut ctx.gfx_context;
        if gfx.data.rect_instance_properties.len() < self.sprites.len() {
            gfx.data.rect_instance_properties = gfx.factory.create_buffer(
                self.sprites.len(),
                gfx::buffer::Role::Vertex,
                gfx::memory::Usage::Dynamic,
                gfx::memory::Bind::TRANSFER_DST,
            )?;
        }
        gfx.encoder
            .update_buffer(&gfx.data.rect_instance_properties, &new_sprites[..], 0)?;
        Ok(())
    }

    /// Removes all data from the sprite batch.
    pub fn clear(&mut self) {
        self.sprites.clear();
    }

    /// Unwraps and returns the contained `Image`
    pub fn into_inner(self) -> graphics::Image {
        self.image
    }

    /// Replaces the contained `Image`, returning the old one.
    pub fn set_image(&mut self, image: graphics::Image) -> graphics::Image {
        use std::mem;
        mem::replace(&mut self.image, image)
    }

    /// Get the filter mode for the SpriteBatch.
    pub fn filter(&self) -> FilterMode {
        self.image.filter()
    }

    /// Set the filter mode for the SpriteBatch.
    pub fn set_filter(&mut self, mode: FilterMode) {
        self.image.set_filter(mode);
    }
}

impl graphics::Drawable for SpriteBatch {
    fn draw(&self, ctx: &mut Context, param: DrawParam) -> GameResult {
        // scale the offset according to the dimensions of the spritebatch
        // but only if there is an offset (it's too expensive to calculate the dimensions to always to this)
        let mut new_param = param;
        if let Transform::Values { offset, .. } = param.trans {
            if offset != [0.0, 0.0].into() {
                if let Some(dim) = self.dimensions(ctx) {
                    let new_offset = mint::Vector2 {
                        x: offset.x * dim.w + dim.x,
                        y: offset.y * dim.h + dim.y,
                    };
                    new_param = param.offset(new_offset);
                }
            }
        }
        // Awkwardly we must update values on all sprites and such.
        // Also awkwardly we have this chain of colors with differing priorities.
        self.flush(ctx, &self.image)?;
        let gfx = &mut ctx.gfx_context;
        let sampler = gfx
            .samplers
            .get_or_insert(self.image.sampler_info, gfx.factory.as_mut());
        gfx.data.vbuf = gfx.quad_vertex_buffer.clone();
        let typed_thingy = gfx
            .backend_spec
            .raw_to_typed_shader_resource(self.image.texture.clone());
        gfx.data.tex = (typed_thingy, sampler);

        let mut slice = gfx.quad_slice.clone();
        slice.instances = Some((u32::try_from(self.sprites.len()).unwrap(), 0));
        // It's a little silly converting this mint matrix back to a glam
        // one but it's simpler than the alternative.
        let m = Matrix4::from(new_param.trans.to_bare_matrix());
        gfx.set_global_mvp(m)?;
        let previous_mode: Option<BlendMode> = if let Some(mode) = self.blend_mode {
            let current_mode = gfx.blend_mode();
            if current_mode != mode {
                gfx.set_blend_mode(mode)?;
                Some(current_mode)
            } else {
                None
            }
        } else {
            None
        };
        gfx.draw(Some(&slice))?;
        if let Some(mode) = previous_mode {
            gfx.set_blend_mode(mode)?;
        }
        gfx.set_global_mvp(graphics::Matrix4::IDENTITY)?;
        Ok(())
    }
    fn dimensions(&self, _ctx: &mut Context) -> Option<Rect> {
        if self.sprites.is_empty() {
            return None;
        }
        let dimensions = self.image.dimensions();
        self.sprites
            .iter()
            .map(|&param| transform_rect(dimensions, param))
            .fold(None, |acc: Option<Rect>, rect| {
                Some(if let Some(acc) = acc {
                    acc.combine_with(rect)
                } else {
                    rect
                })
            })
    }
    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.blend_mode = mode;
    }
    fn blend_mode(&self) -> Option<BlendMode> {
        self.blend_mode
    }
}
<commit_msg>updated explanation on flushing<commit_after>//! A [`SpriteBatch`](struct.SpriteBatch.html) is a way to
//! efficiently draw a large number of copies of the same image, or part
//! of the same image.  It's useful for implementing tiled maps,
//! spritesheets, particles, and other such things.
//!
//! Essentially this uses a technique called "instancing" to queue up
//! a large amount of location/position data in a buffer, then feed it
//! to the graphics card all in one go.
//!
//! Also it's super slow in `rustc`'s default debug mode, because
//! `rustc` adds a lot of checking to the vector accesses and math.
//! If you use it, it's recommended to crank up the `opt-level` for
//! debug mode in your game's `Cargo.toml`.

use std::convert::TryFrom;

use crate::context::Context;
use crate::error;
use crate::error::GameResult;
use crate::graphics::shader::BlendMode;
use crate::graphics::types::FilterMode;
use crate::graphics::{self, transform_rect, BackendSpec, DrawParam, Matrix4, Rect, Transform};
use gfx::Factory;

/// A `SpriteBatch` draws a number of copies of the same image, using a single draw call.
///
/// This is generally faster than drawing the same sprite with many
/// invocations of [`draw()`](../fn.draw.html), though it has a bit of
/// overhead to set up the batch.  This overhead makes it run very
/// slowly in `debug` mode because it spends a lot of time on array
/// bounds checking and un-optimized math; you need to build with
/// optimizations enabled to really get the speed boost.
#[derive(Debug, Clone, PartialEq)]
pub struct SpriteBatch {
    image: graphics::Image,
    sprites: Vec<graphics::DrawParam>,
    blend_mode: Option<BlendMode>,
}

/// An index of a particular sprite in a `SpriteBatch`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SpriteIdx(pub usize);

impl SpriteBatch {
    /// Creates a new `SpriteBatch`, drawing with the given image.
    ///
    /// Takes ownership of the `Image`, but cloning an `Image` is
    /// cheap since they have an internal `Arc` containing the actual
    /// image data.
    pub fn new(image: graphics::Image) -> Self {
        Self {
            image,
            sprites: vec![],
            blend_mode: None,
        }
    }

    /// Adds a new sprite to the sprite batch.
    ///
    /// Returns a handle with which to modify the sprite using
    /// [`set()`](#method.set)
    pub fn add<P>(&mut self, param: P) -> SpriteIdx
    where
        P: Into<graphics::DrawParam>,
    {
        self.sprites.push(param.into());
        SpriteIdx(self.sprites.len() - 1)
    }

    /// Alters a sprite in the batch to use the given draw params
    pub fn set<P>(&mut self, handle: SpriteIdx, param: P) -> GameResult
    where
        P: Into<graphics::DrawParam>,
    {
        if handle.0 < self.sprites.len() {
            self.sprites[handle.0] = param.into();
            Ok(())
        } else {
            Err(error::GameError::RenderError(String::from(
                "Provided index is out of bounds.",
            )))
        }
    }

    /// Returns a reference to the sprites.
    pub fn get_sprites(&self) -> &[DrawParam] {
        &self.sprites
    }

    /// Returns a mutable reference to the sprites.
    ///
    /// Unlike with `MeshBatch`, manually calling `flush` after altering sprites
    /// in this slice is currently unnecessary, as `SpriteBatch` flushes automatically
    /// on every draw call. This might change in the future though.
    pub fn get_sprites_mut(&mut self) -> &mut [DrawParam] {
        &mut self.sprites
    }

    /// Immediately sends all data in the batch to the graphics card.
    ///
    /// Generally just calling [`graphics::draw()`](../fn.draw.html) on the `SpriteBatch`
    /// will do this automatically.
    fn flush(&self, ctx: &mut Context, image: &graphics::Image) -> GameResult {
        // This is a little awkward but this is the right place
        // to do whatever transformations need to happen to DrawParam's.
        // We have a Context, and *everything* must pass through this
        // function to be drawn, so.
        // Though we do awkwardly have to allocate a new vector.
        // ...though upon benchmarking, the actual allocation is basically nothing,
        // the cost in debug mode is alllll math.
        let new_sprites = self
            .sprites
            .iter()
            .map(|param| {
                // Copy old params
                let src_width = param.src.w;
                let src_height = param.src.h;
                let new_param = match param.trans {
                    Transform::Values { scale, .. } => {
                        let new_scale = mint::Vector2 {
                            x: scale.x * src_width * f32::from(image.width),
                            y: scale.y * src_height * f32::from(image.height),
                        };
                        param.scale(new_scale)
                    }
                    Transform::Matrix(_) => *param,
                };
                let primitive_param = new_param;
                primitive_param.to_instance_properties(ctx.gfx_context.is_srgb())
            })
            .collect::<Vec<_>>();

        let gfx = &mut ctx.gfx_context;
        if gfx.data.rect_instance_properties.len() < self.sprites.len() {
            gfx.data.rect_instance_properties = gfx.factory.create_buffer(
                self.sprites.len(),
                gfx::buffer::Role::Vertex,
                gfx::memory::Usage::Dynamic,
                gfx::memory::Bind::TRANSFER_DST,
            )?;
        }
        gfx.encoder
            .update_buffer(&gfx.data.rect_instance_properties, &new_sprites[..], 0)?;
        Ok(())
    }

    /// Removes all data from the sprite batch.
    pub fn clear(&mut self) {
        self.sprites.clear();
    }

    /// Unwraps and returns the contained `Image`
    pub fn into_inner(self) -> graphics::Image {
        self.image
    }

    /// Replaces the contained `Image`, returning the old one.
    pub fn set_image(&mut self, image: graphics::Image) -> graphics::Image {
        use std::mem;
        mem::replace(&mut self.image, image)
    }

    /// Get the filter mode for the SpriteBatch.
    pub fn filter(&self) -> FilterMode {
        self.image.filter()
    }

    /// Set the filter mode for the SpriteBatch.
    pub fn set_filter(&mut self, mode: FilterMode) {
        self.image.set_filter(mode);
    }
}

impl graphics::Drawable for SpriteBatch {
    fn draw(&self, ctx: &mut Context, param: DrawParam) -> GameResult {
        // scale the offset according to the dimensions of the spritebatch
        // but only if there is an offset (it's too expensive to calculate the dimensions to always to this)
        let mut new_param = param;
        if let Transform::Values { offset, .. } = param.trans {
            if offset != [0.0, 0.0].into() {
                if let Some(dim) = self.dimensions(ctx) {
                    let new_offset = mint::Vector2 {
                        x: offset.x * dim.w + dim.x,
                        y: offset.y * dim.h + dim.y,
                    };
                    new_param = param.offset(new_offset);
                }
            }
        }
        // Awkwardly we must update values on all sprites and such.
        // Also awkwardly we have this chain of colors with differing priorities.
        self.flush(ctx, &self.image)?;
        let gfx = &mut ctx.gfx_context;
        let sampler = gfx
            .samplers
            .get_or_insert(self.image.sampler_info, gfx.factory.as_mut());
        gfx.data.vbuf = gfx.quad_vertex_buffer.clone();
        let typed_thingy = gfx
            .backend_spec
            .raw_to_typed_shader_resource(self.image.texture.clone());
        gfx.data.tex = (typed_thingy, sampler);

        let mut slice = gfx.quad_slice.clone();
        slice.instances = Some((u32::try_from(self.sprites.len()).unwrap(), 0));
        // It's a little silly converting this mint matrix back to a glam
        // one but it's simpler than the alternative.
        let m = Matrix4::from(new_param.trans.to_bare_matrix());
        gfx.set_global_mvp(m)?;
        let previous_mode: Option<BlendMode> = if let Some(mode) = self.blend_mode {
            let current_mode = gfx.blend_mode();
            if current_mode != mode {
                gfx.set_blend_mode(mode)?;
                Some(current_mode)
            } else {
                None
            }
        } else {
            None
        };
        gfx.draw(Some(&slice))?;
        if let Some(mode) = previous_mode {
            gfx.set_blend_mode(mode)?;
        }
        gfx.set_global_mvp(graphics::Matrix4::IDENTITY)?;
        Ok(())
    }
    fn dimensions(&self, _ctx: &mut Context) -> Option<Rect> {
        if self.sprites.is_empty() {
            return None;
        }
        let dimensions = self.image.dimensions();
        self.sprites
            .iter()
            .map(|&param| transform_rect(dimensions, param))
            .fold(None, |acc: Option<Rect>, rect| {
                Some(if let Some(acc) = acc {
                    acc.combine_with(rect)
                } else {
                    rect
                })
            })
    }
    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.blend_mode = mode;
    }
    fn blend_mode(&self) -> Option<BlendMode> {
        self.blend_mode
    }
}
<|endoftext|>


<commit_before>use crate::{db::connect_db, error::Result};
use failure::err_msg;
use log::debug;
use regex::Regex;

/// Fields we need use in cratesfyi
#[derive(Debug)]
struct GitHubFields {
    description: String,
    stars: i64,
    forks: i64,
    issues: i64,
    last_commit: time::Timespec,
}

/// Updates github fields in crates table
pub fn github_updater() -> Result<()> {
    let conn = connect_db()?;

    // TODO: This query assumes repository field in Cargo.toml is
    //       always the same across all versions of a crate
    for row in &conn.query(
        "SELECT DISTINCT ON (crates.name)
                crates.name,
                crates.id,
                releases.repository_url
         FROM crates
         INNER JOIN releases ON releases.crate_id = crates.id
         WHERE releases.repository_url ~ '^https*://github.com' AND
               (crates.github_last_update < NOW() - INTERVAL '1 day' OR
                crates.github_last_update IS NULL)
         ORDER BY crates.name, releases.release_time DESC",
        &[],
    )? {
        let crate_name: String = row.get(0);
        let crate_id: i32 = row.get(1);
        let repository_url: String = row.get(2);

        if let Err(err) = get_github_path(&repository_url[..])
            .ok_or_else(|| err_msg("Failed to get github path"))
            .and_then(|path| get_github_fields(&path[..]))
            .and_then(|fields| {
                conn.execute(
                    "UPDATE crates
                     SET github_description = $1,
                         github_stars = $2, github_forks = $3,
                         github_issues = $4, github_last_commit = $5,
                         github_last_update = NOW() WHERE id = $6",
                    &[
                        &fields.description,
                        &(fields.stars as i32),
                        &(fields.forks as i32),
                        &(fields.issues as i32),
                        &(fields.last_commit),
                        &crate_id,
                    ],
                )
                .or_else(|e| Err(e.into()))
            })
        {
            debug!("Failed to update github fields of: {} {}", crate_name, err);
        }

        // sleep for rate limits
        use std::thread;
        use std::time::Duration;
        thread::sleep(Duration::from_secs(2));
    }

    Ok(())
}

fn get_github_fields(path: &str) -> Result<GitHubFields> {
    use rustc_serialize::json::Json;

    let body = {
        use reqwest::header::USER_AGENT;
        use reqwest::{Client, StatusCode};
        use std::env;
        use std::io::Read;

        let client = Client::new();
        let mut body = String::new();

        let mut resp = client
            .get(&format!("https://api.github.com/repos/{}", path)[..])
            .header(
                USER_AGENT,
                format!("cratesfyi/{}", env!("CARGO_PKG_VERSION")),
            )
            .basic_auth(
                env::var("CRATESFYI_GITHUB_USERNAME")
                    .ok()
                    .unwrap_or_default(),
                env::var("CRATESFYI_GITHUB_ACCESSTOKEN").ok(),
            )
            .send()?;

        if resp.status() != StatusCode::OK {
            return Err(err_msg("Failed to get github data"));
        }

        resp.read_to_string(&mut body)?;
        body
    };

    let json = Json::from_str(&body[..])?;
    let obj = json.as_object().unwrap();

    Ok(GitHubFields {
        description: obj
            .get("description")
            .and_then(|d| d.as_string())
            .unwrap_or("")
            .to_string(),
        stars: obj
            .get("stargazers_count")
            .and_then(|d| d.as_i64())
            .unwrap_or(0),
        forks: obj.get("forks_count").and_then(|d| d.as_i64()).unwrap_or(0),
        issues: obj.get("open_issues").and_then(|d| d.as_i64()).unwrap_or(0),
        last_commit: time::strptime(
            obj.get("pushed_at")
                .and_then(|d| d.as_string())
                .unwrap_or(""),
            "%Y-%m-%dT%H:%M:%S",
        )
        .unwrap_or_else(|_| time::now())
        .to_timespec(),
    })
}

fn get_github_path(url: &str) -> Option<String> {
    let re = Regex::new(r"https?://github\.com/([\w\._-]+)/([\w\._-]+)").unwrap();
    match re.captures(url) {
        Some(cap) => {
            let username = cap.get(1).unwrap().as_str();
            let reponame = cap.get(2).unwrap().as_str();

            let reponame = if reponame.ends_with(".git") {
                reponame.split(".git").next().unwrap()
            } else {
                reponame
            };

            Some(format!("{}/{}", username, reponame))
        }

        None => None,
    }
}

#[cfg(test)]
mod test {
    use super::{get_github_fields, get_github_path, github_updater};

    #[test]
    fn test_get_github_path() {
        assert_eq!(
            get_github_path("https://github.com/onur/cratesfyi"),
            Some("onur/cratesfyi".to_string())
        );
        assert_eq!(
            get_github_path("http://github.com/onur/cratesfyi"),
            Some("onur/cratesfyi".to_string())
        );
        assert_eq!(
            get_github_path("https://github.com/onur/cratesfyi.git"),
            Some("onur/cratesfyi".to_string())
        );
        assert_eq!(
            get_github_path("https://github.com/onur23cmD_M_R_L_/crates_fy-i"),
            Some("onur23cmD_M_R_L_/crates_fy-i".to_string())
        );
        assert_eq!(
            get_github_path("https://github.com/docopt/docopt.rs"),
            Some("docopt/docopt.rs".to_string())
        );
    }

    #[test]
    #[ignore]
    fn test_get_github_fields() {
        let _ = env_logger::try_init();
        let fields = get_github_fields("onur/cratesfyi");
        assert!(fields.is_ok());

        let fields = fields.unwrap();
        assert!(fields.description != "".to_string());
        assert!(fields.stars >= 0);
        assert!(fields.forks >= 0);
        assert!(fields.issues >= 0);

        use time;
        assert!(fields.last_commit <= time::now().to_timespec());
    }

    #[test]
    #[ignore]
    fn test_github_updater() {
        let _ = env_logger::try_init();
        assert!(github_updater().is_ok());
    }
}
<commit_msg>Update src/utils/github_updater.rs<commit_after>use crate::{db::connect_db, error::Result};
use failure::err_msg;
use log::debug;
use regex::Regex;

/// Fields we need use in cratesfyi
#[derive(Debug)]
struct GitHubFields {
    description: String,
    stars: i64,
    forks: i64,
    issues: i64,
    last_commit: time::Timespec,
}

/// Updates github fields in crates table
pub fn github_updater() -> Result<()> {
    let conn = connect_db()?;

    // TODO: This query assumes repository field in Cargo.toml is
    //       always the same across all versions of a crate
    for row in &conn.query(
        "SELECT DISTINCT ON (crates.name)
                crates.name,
                crates.id,
                releases.repository_url
         FROM crates
         INNER JOIN releases ON releases.crate_id = crates.id
         WHERE releases.repository_url ~ '^https*://github.com' AND
               (crates.github_last_update < NOW() - INTERVAL '1 day' OR
                crates.github_last_update IS NULL)
         ORDER BY crates.name, releases.release_time DESC",
        &[],
    )? {
        let crate_name: String = row.get(0);
        let crate_id: i32 = row.get(1);
        let repository_url: String = row.get(2);

        if let Err(err) = get_github_path(&repository_url[..])
            .ok_or_else(|| err_msg("Failed to get github path"))
            .and_then(|path| get_github_fields(&path[..]))
            .and_then(|fields| {
                conn.execute(
                    "UPDATE crates
                     SET github_description = $1,
                         github_stars = $2, github_forks = $3,
                         github_issues = $4, github_last_commit = $5,
                         github_last_update = NOW()
                     WHERE id = $6",
                    &[
                        &fields.description,
                        &(fields.stars as i32),
                        &(fields.forks as i32),
                        &(fields.issues as i32),
                        &(fields.last_commit),
                        &crate_id,
                    ],
                )
                .or_else(|e| Err(e.into()))
            })
        {
            debug!("Failed to update github fields of: {} {}", crate_name, err);
        }

        // sleep for rate limits
        use std::thread;
        use std::time::Duration;
        thread::sleep(Duration::from_secs(2));
    }

    Ok(())
}

fn get_github_fields(path: &str) -> Result<GitHubFields> {
    use rustc_serialize::json::Json;

    let body = {
        use reqwest::header::USER_AGENT;
        use reqwest::{Client, StatusCode};
        use std::env;
        use std::io::Read;

        let client = Client::new();
        let mut body = String::new();

        let mut resp = client
            .get(&format!("https://api.github.com/repos/{}", path)[..])
            .header(
                USER_AGENT,
                format!("cratesfyi/{}", env!("CARGO_PKG_VERSION")),
            )
            .basic_auth(
                env::var("CRATESFYI_GITHUB_USERNAME")
                    .ok()
                    .unwrap_or_default(),
                env::var("CRATESFYI_GITHUB_ACCESSTOKEN").ok(),
            )
            .send()?;

        if resp.status() != StatusCode::OK {
            return Err(err_msg("Failed to get github data"));
        }

        resp.read_to_string(&mut body)?;
        body
    };

    let json = Json::from_str(&body[..])?;
    let obj = json.as_object().unwrap();

    Ok(GitHubFields {
        description: obj
            .get("description")
            .and_then(|d| d.as_string())
            .unwrap_or("")
            .to_string(),
        stars: obj
            .get("stargazers_count")
            .and_then(|d| d.as_i64())
            .unwrap_or(0),
        forks: obj.get("forks_count").and_then(|d| d.as_i64()).unwrap_or(0),
        issues: obj.get("open_issues").and_then(|d| d.as_i64()).unwrap_or(0),
        last_commit: time::strptime(
            obj.get("pushed_at")
                .and_then(|d| d.as_string())
                .unwrap_or(""),
            "%Y-%m-%dT%H:%M:%S",
        )
        .unwrap_or_else(|_| time::now())
        .to_timespec(),
    })
}

fn get_github_path(url: &str) -> Option<String> {
    let re = Regex::new(r"https?://github\.com/([\w\._-]+)/([\w\._-]+)").unwrap();
    match re.captures(url) {
        Some(cap) => {
            let username = cap.get(1).unwrap().as_str();
            let reponame = cap.get(2).unwrap().as_str();

            let reponame = if reponame.ends_with(".git") {
                reponame.split(".git").next().unwrap()
            } else {
                reponame
            };

            Some(format!("{}/{}", username, reponame))
        }

        None => None,
    }
}

#[cfg(test)]
mod test {
    use super::{get_github_fields, get_github_path, github_updater};

    #[test]
    fn test_get_github_path() {
        assert_eq!(
            get_github_path("https://github.com/onur/cratesfyi"),
            Some("onur/cratesfyi".to_string())
        );
        assert_eq!(
            get_github_path("http://github.com/onur/cratesfyi"),
            Some("onur/cratesfyi".to_string())
        );
        assert_eq!(
            get_github_path("https://github.com/onur/cratesfyi.git"),
            Some("onur/cratesfyi".to_string())
        );
        assert_eq!(
            get_github_path("https://github.com/onur23cmD_M_R_L_/crates_fy-i"),
            Some("onur23cmD_M_R_L_/crates_fy-i".to_string())
        );
        assert_eq!(
            get_github_path("https://github.com/docopt/docopt.rs"),
            Some("docopt/docopt.rs".to_string())
        );
    }

    #[test]
    #[ignore]
    fn test_get_github_fields() {
        let _ = env_logger::try_init();
        let fields = get_github_fields("onur/cratesfyi");
        assert!(fields.is_ok());

        let fields = fields.unwrap();
        assert!(fields.description != "".to_string());
        assert!(fields.stars >= 0);
        assert!(fields.forks >= 0);
        assert!(fields.issues >= 0);

        use time;
        assert!(fields.last_commit <= time::now().to_timespec());
    }

    #[test]
    #[ignore]
    fn test_github_updater() {
        let _ = env_logger::try_init();
        assert!(github_updater().is_ok());
    }
}
<|endoftext|>


<commit_before>use std::io::Write;
use std::collections::HashMap;

use parser::html::Expression as Expr;
use parser::html::Statement as Stmt;
use parser::html::Statement::{Store};
use util::join;
use super::Generator;
use super::ast::{Statement, Param, Expression};
use super::ast::Expression as E;
use super::ast::Statement as S;

fn attr<'x, S: AsRef<str>>(e: Expression, v: S) -> Expression {
    E::Attr(Box::new(e), v.as_ref().to_string())
}

impl<'a, W:Write+'a> Generator<'a, W> {

    fn event_func(&self, e: &Expr) -> Expression {
        // TODO(tailhook) add conditional ev(event) parameter
        E::Function(None, vec![], vec![
            S::Return(self.compile_expr(e)),
        ])
    }

    pub fn element(&self, name: &String,
        classes: &Vec<(String, Option<Expr>)>,
        attributes: &Vec<(String, Expr)>,
        body: &Vec<Stmt>)
        -> Expression
    {
        use parser::html::Link as L;
        use parser::html::LinkDest as D;

        let mut properties = vec![
                (String::from("tag"), Expression::Str(name.clone())),
        ];
        let mut statements = vec![];
        let mut events = HashMap::new();
        for item in body.iter() {
            match item {
                &Stmt::Let(ref name, ref value) => {
                    statements.push(Statement::Var(name.clone(),
                        self.compile_expr(value)));
                }
                &Store(ref name, ref value) => {
                    let prop = String::from("store_") +name;
                    statements.push(Statement::Var(name.clone(),
                        E::Or(
                            Box::new(E::And(
                                Box::new(E::Name(String::from("old_node"))),
                                Box::new(E::Attr(Box::new(
                                        E::Name(String::from("old_node"))),
                                        prop.clone())))),
                            Box::new(self.compile_expr(value)))));
                    properties.push((prop, E::Name(name.clone())));
                }
                &Stmt::Link(ref links) => {
                    for lnk in links {
                        match lnk {
                            &L::One(ref s, D::Stream(ref expr)) => {
                                events.entry(s.clone()).or_insert(vec!()).push(
                                    E::Attr(Box::new(self.compile_expr(expr)),
                                        String::from("handle_event")),
                                    );
                            }
                            &L::Multi(ref names, D::Stream(ref expr)) => {
                                let v = format!("_stream_{}",
                                    statements.len());
                                statements.push(Statement::Var(
                                    v.clone(),
                                    self.compile_expr(expr)));
                                for &(ref aname, ref ename) in names {
                                    let ev = ename.as_ref()
                                             .unwrap_or(aname).clone();
                                    events.entry(ev.clone()).or_insert(vec!())
                                        .push(attr(
                                            attr(E::Name(v.clone()), &aname),
                                            "handle_event"));
                                }
                            }
                            &L::One(ref s, D::Mapping(ref val, ref dest)) => {
                                events.entry(s.clone()).or_insert(vec!()).push(
                                    attr(
                                    E::Call(Box::new(
                                        attr(self.compile_expr(dest), "map")),
                                        vec![ self.event_func(val) ]),
                                    "handle_event",
                                ));
                            }
                            &L::Multi(ref names, D::Mapping(ref val, ref dest))
                            => {
                                let v = format!("_stream_{}",
                                    statements.len());
                                statements.push(Statement::Var(
                                    v.clone(),
                                    self.compile_expr(dest)));
                                for &(ref aname, ref event) in names {
                                    let ename = event.as_ref()
                                             .unwrap_or(aname).clone();
                                    events.entry(ename).or_insert(vec!()).push(
                                        attr(
                                        E::Call(Box::new(attr(
                                            attr(E::Name(v.clone()), aname),
                                            "map")),
                                            vec![ self.event_func(val) ]),
                                        "handle_event"),
                                    );
                                }
                            }
                        }
                    }
                }
                _ => {}
            }
        }
        if classes.len() > 0 || attributes.len() > 0 {
            properties.push(
                (String::from("attrs"),
                    self.attrs(name, classes, attributes)));
        }
        if body.len() > 0 {
            properties.push(
                (String::from("children"), self.fragment(&body)));
        }
        if events.len() > 0 {
            properties.push( (String::from("events"), Expression::Object(
                events.into_iter().map(|(k, mut v)| {
                    if v.len() == 1 {
                        (k, v.pop().unwrap())
                    } else {
                        (k, Expression::List(v))
                    }
                }).collect()
            )));
        }
        if statements.len() > 0 {
            statements.push(
                Statement::Return(Expression::Object(properties)));
            return Expression::Function(None,
                vec![Param {
                    name: String::from("old_node"),
                    default_value: None,
                }],
                statements);
        } else {
            return Expression::Object(properties);
        }
    }

    fn attrs(&self, name: &String, cls: &Vec<(String, Option<Expr>)>,
        attrs: &Vec<(String, Expr)>)
        -> Expression
    {
        let mut class_literals = vec!();
        let mut class_expr = vec!();
        if cls.len() > 0 || self.bare_element_names.contains(name) {
            class_literals.push(self.block_name.to_string());
        }
        for &(ref cname, ref opt_cond) in cls {
            if let &Some(ref cond) = opt_cond {
                class_expr.push(Expression::Ternary(
                    Box::new(self.compile_expr(cond)),
                    Box::new(Expression::Str(cname.clone())),
                    Box::new(Expression::Str(String::from("")))));
            } else {
                class_literals.push(cname.clone());
            }
        }
        let mut rattrs = vec!();
        for &(ref name, ref value) in attrs {
            if &name[..] == "class" {
                class_expr.push(self.compile_expr(value));
            } else {
                rattrs.push((name.clone(), self.compile_expr(value)));
            }
        }
        if class_literals.len() > 0 {
            class_expr.insert(0,
                Expression::Str(join(class_literals.iter(), " ")));
        }
        if class_expr.len() > 0 {
            let first = class_expr.remove(0);
            rattrs.push((String::from("class"), class_expr.into_iter()
                .fold(first, |acc, val|
                    Expression::Add(Box::new(
                        Expression::Add(
                            Box::new(acc),
                            Box::new(Expression::Str(String::from(" "))))),
                        Box::new(val)))));
        }
        Expression::Object(rattrs)
    }

}
<commit_msg>Add optional "owner_destroyed" stream for stores<commit_after>use std::io::Write;
use std::collections::HashMap;

use parser::html::Expression as Expr;
use parser::html::Statement as Stmt;
use parser::html::Statement::{Store};
use util::join;
use super::Generator;
use super::ast::{Statement, Param, Expression};
use super::ast::Expression as E;
use super::ast::Statement as S;

fn attr<'x, S: AsRef<str>>(e: Expression, v: S) -> Expression {
    E::Attr(Box::new(e), v.as_ref().to_string())
}

impl<'a, W:Write+'a> Generator<'a, W> {

    fn event_func(&self, e: &Expr) -> Expression {
        // TODO(tailhook) add conditional ev(event) parameter
        E::Function(None, vec![], vec![
            S::Return(self.compile_expr(e)),
        ])
    }

    pub fn element(&self, name: &String,
        classes: &Vec<(String, Option<Expr>)>,
        attributes: &Vec<(String, Expr)>,
        body: &Vec<Stmt>)
        -> Expression
    {
        use parser::html::Link as L;
        use parser::html::LinkDest as D;

        let mut properties = vec![
                (String::from("tag"), Expression::Str(name.clone())),
        ];
        let mut statements = vec![];
        let mut events = HashMap::new();
        for item in body.iter() {
            match item {
                &Stmt::Let(ref name, ref value) => {
                    statements.push(Statement::Var(name.clone(),
                        self.compile_expr(value)));
                }
                &Store(ref name, ref value) => {
                    let prop = String::from("store_") +name;
                    statements.push(Statement::Var(name.clone(),
                        E::Or(
                            Box::new(E::And(
                                Box::new(E::Name(String::from("old_node"))),
                                Box::new(E::Attr(Box::new(
                                        E::Name(String::from("old_node"))),
                                        prop.clone())))),
                            Box::new(self.compile_expr(value)))));
                    properties.push((prop, E::Name(name.clone())));
                    events.entry(String::from("$destroyed"))
                    .or_insert(vec!()).push(
                        E::Ternary(
                            Box::new(attr(E::Name(name.clone()),
                                "owner_destroyed")),
                            Box::new(attr(
                                attr(E::Name(name.clone()), "owner_destroyed"),
                                "handle_event")),
                            Box::new(E::Function(None, vec![], vec![])),
                        ));
                }
                &Stmt::Link(ref links) => {
                    for lnk in links {
                        match lnk {
                            &L::One(ref s, D::Stream(ref expr)) => {
                                events.entry(s.clone()).or_insert(vec!()).push(
                                    E::Attr(Box::new(self.compile_expr(expr)),
                                        String::from("handle_event")),
                                    );
                            }
                            &L::Multi(ref names, D::Stream(ref expr)) => {
                                let v = format!("_stream_{}",
                                    statements.len());
                                statements.push(Statement::Var(
                                    v.clone(),
                                    self.compile_expr(expr)));
                                for &(ref aname, ref ename) in names {
                                    let ev = ename.as_ref()
                                             .unwrap_or(aname).clone();
                                    events.entry(ev.clone()).or_insert(vec!())
                                        .push(attr(
                                            attr(E::Name(v.clone()), &aname),
                                            "handle_event"));
                                }
                            }
                            &L::One(ref s, D::Mapping(ref val, ref dest)) => {
                                events.entry(s.clone()).or_insert(vec!()).push(
                                    attr(
                                    E::Call(Box::new(
                                        attr(self.compile_expr(dest), "map")),
                                        vec![ self.event_func(val) ]),
                                    "handle_event",
                                ));
                            }
                            &L::Multi(ref names, D::Mapping(ref val, ref dest))
                            => {
                                let v = format!("_stream_{}",
                                    statements.len());
                                statements.push(Statement::Var(
                                    v.clone(),
                                    self.compile_expr(dest)));
                                for &(ref aname, ref event) in names {
                                    let ename = event.as_ref()
                                             .unwrap_or(aname).clone();
                                    events.entry(ename).or_insert(vec!()).push(
                                        attr(
                                        E::Call(Box::new(attr(
                                            attr(E::Name(v.clone()), aname),
                                            "map")),
                                            vec![ self.event_func(val) ]),
                                        "handle_event"),
                                    );
                                }
                            }
                        }
                    }
                }
                _ => {}
            }
        }
        if classes.len() > 0 || attributes.len() > 0 {
            properties.push(
                (String::from("attrs"),
                    self.attrs(name, classes, attributes)));
        }
        if body.len() > 0 {
            properties.push(
                (String::from("children"), self.fragment(&body)));
        }
        if events.len() > 0 {
            properties.push( (String::from("events"), Expression::Object(
                events.into_iter().map(|(k, mut v)| {
                    if v.len() == 1 {
                        (k, v.pop().unwrap())
                    } else {
                        (k, Expression::List(v))
                    }
                }).collect()
            )));
        }
        if statements.len() > 0 {
            statements.push(
                Statement::Return(Expression::Object(properties)));
            return Expression::Function(None,
                vec![Param {
                    name: String::from("old_node"),
                    default_value: None,
                }],
                statements);
        } else {
            return Expression::Object(properties);
        }
    }

    fn attrs(&self, name: &String, cls: &Vec<(String, Option<Expr>)>,
        attrs: &Vec<(String, Expr)>)
        -> Expression
    {
        let mut class_literals = vec!();
        let mut class_expr = vec!();
        if cls.len() > 0 || self.bare_element_names.contains(name) {
            class_literals.push(self.block_name.to_string());
        }
        for &(ref cname, ref opt_cond) in cls {
            if let &Some(ref cond) = opt_cond {
                class_expr.push(Expression::Ternary(
                    Box::new(self.compile_expr(cond)),
                    Box::new(Expression::Str(cname.clone())),
                    Box::new(Expression::Str(String::from("")))));
            } else {
                class_literals.push(cname.clone());
            }
        }
        let mut rattrs = vec!();
        for &(ref name, ref value) in attrs {
            if &name[..] == "class" {
                class_expr.push(self.compile_expr(value));
            } else {
                rattrs.push((name.clone(), self.compile_expr(value)));
            }
        }
        if class_literals.len() > 0 {
            class_expr.insert(0,
                Expression::Str(join(class_literals.iter(), " ")));
        }
        if class_expr.len() > 0 {
            let first = class_expr.remove(0);
            rattrs.push((String::from("class"), class_expr.into_iter()
                .fold(first, |acc, val|
                    Expression::Add(Box::new(
                        Expression::Add(
                            Box::new(acc),
                            Box::new(Expression::Str(String::from(" "))))),
                        Box::new(val)))));
        }
        Expression::Object(rattrs)
    }

}
<|endoftext|>


<commit_before>extern crate rand;
extern crate sync;

#[cfg(test)]
extern crate test;

use std::slice;
use std::cmp;
use std::str;
use std::fmt;
use std::rt;
use std::option;
use std::io::Timer;
use rand::{task_rng, Rng};
use sync::{Arc, Future};

#[cfg(test)]
use test::BenchHarness;

static LIVE_CELL: char = '@';
static DEAD_CELL: char = '.';

fn main() {
  let mut brd = Board::new(65, 250).random();
  let mut timer = Timer::new().unwrap();

  let periodic = timer.periodic(64);
  loop {
    println!("\x1b[H\x1b[2J{}", brd);
    periodic.recv();
    brd = brd.parallel_next_generation();
  }
}

#[deriving(Eq)]
struct Board {
  board: ~[bool],
  rows: uint,
  cols: uint
}

impl Board {
  fn new(rows: uint, cols: uint) -> Board {
    let new_board = slice::from_elem(rows * cols, false);
    Board { board: new_board, rows: rows, cols: cols }
  }

  fn len(&self) -> uint {
    self.rows * self.cols
  }

  fn random(&self) -> Board {
    let board = task_rng().gen_vec(self.len());

    Board { board: board, rows: self.rows, cols: self.cols }
  }

  fn next_generation(&self) -> Board {
    let new_brd = slice::from_fn(self.len(), |cell| self.successor_cell(cell));
    Board { board: new_brd, rows: self.rows, cols: self.cols }
  }

  fn parallel_next_generation(&self) -> Board {
    let length = self.len();
    let num_tasks = cmp::min(rt::default_sched_threads(), length);
    let shared_brd = Arc::new(self.clone());
    let all_tasks = slice::from_fn(length, |i| i);
    let tasks: ~[&[uint]] = all_tasks.chunks(length / num_tasks).collect();

    fn future_batch(task_brd: Arc<Board>, task: ~[uint]) -> Future<~[bool]> {
      Future::spawn(proc()
        task.iter().map(|&idx| task_brd.successor_cell(idx)).collect()
      )
    }

    let future_batches: ~[Future<~[bool]>] = tasks.move_iter().map(|task| {
      future_batch(shared_brd.clone(), task.into_owned())
    }).collect();

    let mut new_brd: ~[bool] = slice::with_capacity(length);

    for b in future_batches.move_iter() {
      new_brd = slice::append(new_brd, b.unwrap());
    }

    Board { board: new_brd, rows: self.rows, cols: self.cols }
  }

  fn cell_live(&self, x: uint, y: uint) -> bool {
    !(x >= self.cols || y >= self.rows) && self.board[y * self.cols + x]
  }

  fn living_neighbors(&self, x: uint, y: uint) -> uint {
    let neighbors = [
      self.cell_live(x-1, y-1), self.cell_live(x, y-1), self.cell_live(x+1, y-1),
      self.cell_live(x-1, y+0),                         self.cell_live(x+1, y+0),
      self.cell_live(x-1, y+1), self.cell_live(x, y+1), self.cell_live(x+1, y+1),
    ];
    neighbors.iter().count(|&x| x)
  }

  fn successor_cell(&self, cell:uint) -> bool {
    self.successor(cell % self.cols, cell / self.cols)
  }

  fn successor(&self, x:uint, y:uint) -> bool {
    let neighbors = self.living_neighbors(x, y);
    if self.cell_live(x, y) {
      neighbors == 2 || neighbors == 3
    } else {
      neighbors == 3
    }
  }

  fn from_str(string: &str) -> Option<Board> {
    let rows: ~[&str] = string.split_terminator('\n').collect();
    let (row_cnt, col_cnt) = (rows[0].len(), rows.len());

    if rows.iter().any(|x| x.len() != row_cnt) { return None; };

    let brd = option::collect(
      rows.concat().chars().map(|c| match c {
        LIVE_CELL => Some(true),
        DEAD_CELL => Some(false),
        _         => None
      })
    );

    match brd {
      Some(board) => Some(Board { board: board, rows: row_cnt, cols: col_cnt }),
      None        => None
    }
  }
}

impl fmt::Show for Board {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

    fn row_to_str(row: &[bool]) -> ~str {
      let chars: ~[char] = row.iter().map(|&cell|
        if cell {LIVE_CELL} else {DEAD_CELL}
      ).collect();
      str::from_chars(chars)
    }

    let rows: ~[~str] = self.board.as_slice().chunks(self.cols).map(|row|
      row_to_str(row)
    ).collect();

    write!(f.buf, "{}", rows.connect("\n"))
  }
}

impl Clone for Board {
  fn clone(&self) -> Board {
    Board { board: self.board.clone(), rows: self.rows, cols: self.cols }
  }
}

#[cfg(test)]
fn testing_board(n: int) -> Board {
  let brds = [
    ".@.\n" +
    ".@@\n" +
    ".@@\n"
    ,
    "...\n" +
    "@@@\n" +
    "...\n"
    ,
    ".@.\n" +
    ".@.\n" +
    ".@.\n" ];
  Board::from_str(brds[n]).unwrap()
}

#[test]
fn test_cell_live() {
  let brd = testing_board(0);
  assert!(!brd.cell_live(0, 0));
  assert!(brd.cell_live(2, 2));
}

#[test]
fn test_live_count() {
  let brd = testing_board(0);
  assert!(brd.living_neighbors(0, 0) == 2);
  assert!(brd.living_neighbors(2, 2) == 3);
}

#[test]
fn test_next_generation() {
  assert!(testing_board(1).next_generation() == testing_board(2))
}

#[test]
fn test_parallel_next_generation() {
  assert!(testing_board(1).parallel_next_generation() == testing_board(2))
}

#[bench]
fn bench_random(b: &mut BenchHarness) {
  let brd = Board::new(200,200);
  b.iter(|| {brd.random();})
}

#[bench]
fn bench_hundred_generations(b: &mut BenchHarness) {
  let mut brd = Board::new(200,200).random();
  b.iter(|| {
    for _ in range(0,100) { brd = brd.next_generation() }
  });
}

#[bench]
fn bench_hundred_parallel_generations(b: &mut BenchHarness) {
  let mut brd = Board::new(200,200).random();
  b.iter(|| {
    for _ in range(0,100) { brd = brd.parallel_next_generation() }
  });
}
<commit_msg>derive Clone, instead to implementing it<commit_after>extern crate rand;
extern crate sync;

#[cfg(test)]
extern crate test;

use std::slice;
use std::cmp;
use std::str;
use std::fmt;
use std::rt;
use std::option;
use std::io::Timer;
use rand::{task_rng, Rng};
use sync::{Arc, Future};

#[cfg(test)]
use test::BenchHarness;

static LIVE_CELL: char = '@';
static DEAD_CELL: char = '.';

fn main() {
  let mut brd = Board::new(65, 250).random();
  let mut timer = Timer::new().unwrap();

  let periodic = timer.periodic(64);
  loop {
    println!("\x1b[H\x1b[2J{}", brd);
    periodic.recv();
    brd = brd.parallel_next_generation();
  }
}

#[deriving(Eq, Clone)]
struct Board {
  board: ~[bool],
  rows: uint,
  cols: uint
}

impl Board {
  fn new(rows: uint, cols: uint) -> Board {
    let new_board = slice::from_elem(rows * cols, false);
    Board { board: new_board, rows: rows, cols: cols }
  }

  fn len(&self) -> uint {
    self.rows * self.cols
  }

  fn random(&self) -> Board {
    let board = task_rng().gen_vec(self.len());

    Board { board: board, rows: self.rows, cols: self.cols }
  }

  fn next_generation(&self) -> Board {
    let new_brd = slice::from_fn(self.len(), |cell| self.successor_cell(cell));
    Board { board: new_brd, rows: self.rows, cols: self.cols }
  }

  fn parallel_next_generation(&self) -> Board {
    let length = self.len();
    let num_tasks = cmp::min(rt::default_sched_threads(), length);
    let shared_brd = Arc::new(self.clone());
    let all_tasks = slice::from_fn(length, |i| i);
    let tasks: ~[&[uint]] = all_tasks.chunks(length / num_tasks).collect();

    fn future_batch(task_brd: Arc<Board>, task: ~[uint]) -> Future<~[bool]> {
      Future::spawn(proc()
        task.iter().map(|&idx| task_brd.successor_cell(idx)).collect()
      )
    }

    let future_batches: ~[Future<~[bool]>] = tasks.move_iter().map(|task| {
      future_batch(shared_brd.clone(), task.into_owned())
    }).collect();

    let mut new_brd: ~[bool] = slice::with_capacity(length);

    for b in future_batches.move_iter() {
      new_brd = slice::append(new_brd, b.unwrap());
    }

    Board { board: new_brd, rows: self.rows, cols: self.cols }
  }

  fn cell_live(&self, x: uint, y: uint) -> bool {
    !(x >= self.cols || y >= self.rows) && self.board[y * self.cols + x]
  }

  fn living_neighbors(&self, x: uint, y: uint) -> uint {
    let neighbors = [
      self.cell_live(x-1, y-1), self.cell_live(x, y-1), self.cell_live(x+1, y-1),
      self.cell_live(x-1, y+0),                         self.cell_live(x+1, y+0),
      self.cell_live(x-1, y+1), self.cell_live(x, y+1), self.cell_live(x+1, y+1),
    ];
    neighbors.iter().count(|&x| x)
  }

  fn successor_cell(&self, cell:uint) -> bool {
    self.successor(cell % self.cols, cell / self.cols)
  }

  fn successor(&self, x:uint, y:uint) -> bool {
    let neighbors = self.living_neighbors(x, y);
    if self.cell_live(x, y) {
      neighbors == 2 || neighbors == 3
    } else {
      neighbors == 3
    }
  }

  fn from_str(string: &str) -> Option<Board> {
    let rows: ~[&str] = string.split_terminator('\n').collect();
    let (row_cnt, col_cnt) = (rows[0].len(), rows.len());

    if rows.iter().any(|x| x.len() != row_cnt) { return None; };

    let brd = option::collect(
      rows.concat().chars().map(|c| match c {
        LIVE_CELL => Some(true),
        DEAD_CELL => Some(false),
        _         => None
      })
    );

    match brd {
      Some(board) => Some(Board { board: board, rows: row_cnt, cols: col_cnt }),
      None        => None
    }
  }
}

impl fmt::Show for Board {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

    fn row_to_str(row: &[bool]) -> ~str {
      let chars: ~[char] = row.iter().map(|&cell|
        if cell {LIVE_CELL} else {DEAD_CELL}
      ).collect();
      str::from_chars(chars)
    }

    let rows: ~[~str] = self.board.as_slice().chunks(self.cols).map(|row|
      row_to_str(row)
    ).collect();

    write!(f.buf, "{}", rows.connect("\n"))
  }
}

#[cfg(test)]
fn testing_board(n: int) -> Board {
  let brds = [
    ".@.\n" +
    ".@@\n" +
    ".@@\n"
    ,
    "...\n" +
    "@@@\n" +
    "...\n"
    ,
    ".@.\n" +
    ".@.\n" +
    ".@.\n" ];
  Board::from_str(brds[n]).unwrap()
}

#[test]
fn test_cell_live() {
  let brd = testing_board(0);
  assert!(!brd.cell_live(0, 0));
  assert!(brd.cell_live(2, 2));
}

#[test]
fn test_live_count() {
  let brd = testing_board(0);
  assert!(brd.living_neighbors(0, 0) == 2);
  assert!(brd.living_neighbors(2, 2) == 3);
}

#[test]
fn test_next_generation() {
  assert!(testing_board(1).next_generation() == testing_board(2))
}

#[test]
fn test_parallel_next_generation() {
  assert!(testing_board(1).parallel_next_generation() == testing_board(2))
}

#[bench]
fn bench_random(b: &mut BenchHarness) {
  let brd = Board::new(200,200);
  b.iter(|| {brd.random();})
}

#[bench]
fn bench_hundred_generations(b: &mut BenchHarness) {
  let mut brd = Board::new(200,200).random();
  b.iter(|| {
    for _ in range(0,100) { brd = brd.next_generation() }
  });
}

#[bench]
fn bench_hundred_parallel_generations(b: &mut BenchHarness) {
  let mut brd = Board::new(200,200).random();
  b.iter(|| {
    for _ in range(0,100) { brd = brd.parallel_next_generation() }
  });
}
<|endoftext|>


<commit_before>///Lazy git tool
use std::env::args as cmd_args;
use std::process::{Command, Stdio};

///Executes git command with arguments
///Building sequence of arguments like .arg(@arg)
macro_rules! exec_git_cmd {
    (all_fd=>$fd:expr, $($arg:expr),*) => { Command::new("git")$(.arg($arg))*.stdout($fd).stderr($fd).status().unwrap(); };
    (stdout=>$stdout:expr, stderr=>$stderr:expr, $($arg:expr),*) => { Command::new("git")$(.arg($arg))*.stdout($stdout).stderr($stderr).status().unwrap(); };
    (stdout=>$stdout:expr, $($arg:expr),*) => { Command::new("git")$(.arg($arg))*.stdout($stdout).status().unwrap(); };
    (stderr=>$stderr:expr, $($arg:expr),*) => { Command::new("git")$(.arg($arg))*.stderr($stderr).status().unwrap(); };
    ($($arg:expr),*) => { Command::new("git")$(.arg($arg))*.status().unwrap(); };
}

///Print with prefix >>>
macro_rules! trace {
    ($($arg:expr),*) => { println!(">>>{}", [$(format!("{}", $arg),)*].connect(" ")); }
}

#[inline(always)]
fn usage() {
    println!("lgit [option]\n");
    println!("options:");
    println!("  amend [edit] - amend all changes into last commit");
    println!("  add - add all changes");
    println!("  clean - undo all changes");
    println!("  push [force] - push current branch");
    println!("  commit [message] - commit with message");
    println!("  fetch - get updates from upstream\n");
}

///Amend changes
fn git_amend() {
    git_add();
    if let Some(arg3) = cmd_args().skip(2).next() {
        if arg3 == "edit" { exec_git_cmd!("commit", "--amend"); }
        else { trace!("Incorrect amend argument:", arg3); }
    }
    else { exec_git_cmd!("commit", "--amend", "--no-edit"); }
}

///Fetch changes from upstream
fn git_fetch() {
    exec_git_cmd!("checkout", "master");
    exec_git_cmd!("fetch", "upstream");
    exec_git_cmd!("merge", "upstream/master");
}

///Push the current branch
fn git_push() {
    if let Some(arg3) = cmd_args().skip(2).next() {
        if arg3 =="force" { exec_git_cmd!("push", "--force", "origin", "HEAD"); }
        else { trace!("Incorrect push argument:", arg3); }
    }
    else { exec_git_cmd!("push", "origin", "HEAD"); }
}

///Add all changes
fn git_add() {
    exec_git_cmd!("add", "--all");
}

///Undo all changes
fn git_clean() {
    exec_git_cmd!("checkout", "-f");
    exec_git_cmd!("clean", "-fdq");
}

///Commit with message
fn git_commit() {
    if cmd_args().skip(2).len() == 0 {
        trace!("Empty commit message");
    }
    else {
        let args: Vec<String> = cmd_args().skip(2).collect();
        exec_git_cmd!("commit", "-m", args.connect(" "));
    }
}

///Unexpected argument handler
fn unexpected(arg: &str) {
    trace!("Unexpected argument:", arg);
    usage();
}

fn main() {
    //To check if git repo present
    if !exec_git_cmd!(stderr=>Stdio::null(), "rev-parse", "-q").success() {
        trace!("Not a git repository");
        return;
    }
    else if cmd_args().len() < 2 {
        usage();
        return;
    }

    match cmd_args().skip(1).next().unwrap().as_ref() {
        "amend"  => git_amend(),
        "fetch"  => git_fetch(),
        "push"   => git_push(),
        "add"    => git_add(),
        "clean"  => git_clean(),
        "commit" => git_commit(),
        arg @ _  => unexpected(&arg),
    }
}
<commit_msg>Rust: update lgit<commit_after>///Lazy git tool
use std::env::args as cmd_args;
use std::process::{Command, Stdio};

///Executes git command with arguments
///Building sequence of arguments like .arg(@arg)
macro_rules! exec_git_cmd {
    (all_fd=>$fd:expr, $($arg:expr),*) => { Command::new("git")$(.arg($arg))*.stdout($fd).stderr($fd).status().unwrap(); };
    (stdout=>$stdout:expr, stderr=>$stderr:expr, $($arg:expr),*) => { Command::new("git")$(.arg($arg))*.stdout($stdout).stderr($stderr).status().unwrap(); };
    (stdout=>$stdout:expr, $($arg:expr),*) => { Command::new("git")$(.arg($arg))*.stdout($stdout).status().unwrap(); };
    (stderr=>$stderr:expr, $($arg:expr),*) => { Command::new("git")$(.arg($arg))*.stderr($stderr).status().unwrap(); };
    ($($arg:expr),*) => { Command::new("git")$(.arg($arg))*.status().unwrap(); };
}

///Print with prefix >>>
macro_rules! trace {
    ($($arg:expr),*) => { println!(">>>{}", [$(format!("{}", $arg),)*].connect(" ")); }
}

#[inline(always)]
fn usage() {
    println!("lgit [option]\n");
    println!("options:");
    println!("  amend [edit] - amend all changes into last commit");
    println!("  add - add all changes");
    println!("  clean - undo all changes");
    println!("  push [force] - push current branch");
    println!("  commit [message] - commit with message(newline symbols can be used)");
    println!("  fetch - get updates from upstream\n");
}

///Amend changes
fn git_amend() {
    git_add();
    if let Some(arg3) = cmd_args().skip(2).next() {
        if arg3 == "edit" { exec_git_cmd!("commit", "--amend"); }
        else { trace!("Incorrect amend argument:", arg3); }
    }
    else { exec_git_cmd!("commit", "--amend", "--no-edit"); }
}

///Fetch changes from upstream
fn git_fetch() {
    exec_git_cmd!("checkout", "master");
    exec_git_cmd!("fetch", "upstream");
    exec_git_cmd!("merge", "upstream/master");
}

///Push the current branch
fn git_push() {
    if let Some(arg3) = cmd_args().skip(2).next() {
        if arg3 =="force" { exec_git_cmd!("push", "--force", "origin", "HEAD"); }
        else { trace!("Incorrect push argument:", arg3); }
    }
    else { exec_git_cmd!("push", "origin", "HEAD"); }
}

///Add all changes
fn git_add() {
    exec_git_cmd!("add", "--all");
}

///Undo all changes
fn git_clean() {
    exec_git_cmd!("checkout", "-f");
    exec_git_cmd!("clean", "-fdq");
}

///Commit with message
fn git_commit() {
    if cmd_args().skip(2).len() == 0 {
        trace!("Empty commit message");
    }
    else {
        let args: Vec<String> = cmd_args().skip(2).collect();
        exec_git_cmd!("commit", "-m", args.connect(" ").replace("\\n", "\n"));
    }
}

///Unexpected argument handler
fn unexpected(arg: &str) {
    trace!("Unexpected argument:", arg);
    usage();
}

fn main() {
    //To check if git repo present
    if !exec_git_cmd!(stderr=>Stdio::null(), "rev-parse", "-q").success() {
        trace!("Not a git repository");
        return;
    }
    else if cmd_args().len() < 2 {
        usage();
        return;
    }

    match cmd_args().skip(1).next().unwrap().as_ref() {
        "amend"  => git_amend(),
        "fetch"  => git_fetch(),
        "push"   => git_push(),
        "add"    => git_add(),
        "clean"  => git_clean(),
        "commit" => git_commit(),
        arg @ _  => unexpected(&arg),
    }
}
<|endoftext|>


<commit_before>use either::Either;
use hir::{db::AstDatabase, InFile};
use ide_db::{assists::Assist, source_change::SourceChange};
use rustc_hash::FxHashMap;
use stdx::format_to;
use syntax::{algo, ast::make, AstNode, SyntaxNodePtr};
use text_edit::TextEdit;

use crate::{fix, Diagnostic, DiagnosticsContext};

// Diagnostic: missing-fields
//
// This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
//
// Example:
//
// ```rust
// struct A { a: u8, b: u8 }
//
// let a = A { a: 10 };
// ```
pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic {
    let mut message = String::from("missing structure fields:\n");
    for field in &d.missed_fields {
        format_to!(message, "- {}\n", field);
    }

    let ptr = InFile::new(
        d.file,
        d.field_list_parent_path
            .clone()
            .map(SyntaxNodePtr::from)
            .unwrap_or_else(|| d.field_list_parent.clone().either(|it| it.into(), |it| it.into())),
    );

    Diagnostic::new("missing-fields", message, ctx.sema.diagnostics_display_range(ptr).range)
        .with_fixes(fixes(ctx, d))
}

fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Assist>> {
    // Note that although we could add a diagnostics to
    // fill the missing tuple field, e.g :
    // `struct A(usize);`
    // `let a = A { 0: () }`
    // but it is uncommon usage and it should not be encouraged.
    if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
        return None;
    }

    let root = ctx.sema.db.parse_or_expand(d.file)?;
    let field_list_parent = match &d.field_list_parent {
        Either::Left(record_expr) => record_expr.to_node(&root),
        // FIXE: patterns should be fixable as well.
        Either::Right(_) => return None,
    };
    let old_field_list = field_list_parent.record_expr_field_list()?;
    let new_field_list = old_field_list.clone_for_update();
    let mut locals = FxHashMap::default();
    ctx.sema.scope(field_list_parent.syntax()).process_all_names(&mut |name, def| {
        if let hir::ScopeDef::Local(local) = def {
            locals.insert(name.clone(), local);
        }
    });
    let missing_fields = ctx.sema.record_literal_missing_fields(&field_list_parent);
    for (f, ty) in missing_fields.iter() {
        let field_expr = if let Some(local_candidate) = locals.get(&f.name(ctx.sema.db)) {
            let candidate_ty = local_candidate.ty(ctx.sema.db);
            if ty.could_unify_with(ctx.sema.db, &candidate_ty) {
                None
            } else {
                Some(make::expr_unit())
            }
        } else {
            Some(make::expr_unit())
        };
        let field =
            make::record_expr_field(make::name_ref(&f.name(ctx.sema.db).to_string()), field_expr)
                .clone_for_update();
        new_field_list.add_field(field);
    }

    let edit = {
        let mut builder = TextEdit::builder();
        algo::diff(old_field_list.syntax(), new_field_list.syntax()).into_text_edit(&mut builder);
        builder.finish()
    };
    Some(vec![fix(
        "fill_missing_fields",
        "Fill struct fields",
        SourceChange::from_text_edit(d.file.original_file(ctx.sema.db), edit),
        ctx.sema.original_range(field_list_parent.syntax()).range,
    )])
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_diagnostics, check_fix};

    #[test]
    fn missing_record_pat_field_diagnostic() {
        check_diagnostics(
            r#"
struct S { foo: i32, bar: () }
fn baz(s: S) {
    let S { foo: _ } = s;
      //^ error: missing structure fields:
      //| - bar
}
"#,
        );
    }

    #[test]
    fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
        check_diagnostics(
            r"
struct S { foo: i32, bar: () }
fn baz(s: S) -> i32 {
    match s {
        S { foo, .. } => foo,
    }
}
",
        )
    }

    #[test]
    fn missing_record_pat_field_box() {
        check_diagnostics(
            r"
struct S { s: Box<u32> }
fn x(a: S) {
    let S { box s } = a;
}
",
        )
    }

    #[test]
    fn missing_record_pat_field_ref() {
        check_diagnostics(
            r"
struct S { s: u32 }
fn x(a: S) {
    let S { ref s } = a;
}
",
        )
    }

    #[test]
    fn range_mapping_out_of_macros() {
        // FIXME: this is very wrong, but somewhat tricky to fix.
        check_fix(
            r#"
fn some() {}
fn items() {}
fn here() {}

macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }

fn main() {
    let _x = id![Foo { a: $042 }];
}

pub struct Foo { pub a: i32, pub b: i32 }
"#,
            r#"
fn some(, b: () ) {}
fn items() {}
fn here() {}

macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }

fn main() {
    let _x = id![Foo { a: 42 }];
}

pub struct Foo { pub a: i32, pub b: i32 }
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_empty() {
        check_fix(
            r#"
struct TestStruct { one: i32, two: i64 }

fn test_fn() {
    let s = TestStruct {$0};
}
"#,
            r#"
struct TestStruct { one: i32, two: i64 }

fn test_fn() {
    let s = TestStruct { one: (), two: () };
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_self() {
        check_fix(
            r#"
struct TestStruct { one: i32 }

impl TestStruct {
    fn test_fn() { let s = Self {$0}; }
}
"#,
            r#"
struct TestStruct { one: i32 }

impl TestStruct {
    fn test_fn() { let s = Self { one: () }; }
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_enum() {
        check_fix(
            r#"
enum Expr {
    Bin { lhs: Box<Expr>, rhs: Box<Expr> }
}

impl Expr {
    fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr {
        Expr::Bin {$0 }
    }
}
"#,
            r#"
enum Expr {
    Bin { lhs: Box<Expr>, rhs: Box<Expr> }
}

impl Expr {
    fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr {
        Expr::Bin { lhs, rhs }
    }
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_partial() {
        check_fix(
            r#"
struct TestStruct { one: i32, two: i64 }

fn test_fn() {
    let s = TestStruct{ two: 2$0 };
}
"#,
            r"
struct TestStruct { one: i32, two: i64 }

fn test_fn() {
    let s = TestStruct{ two: 2, one: () };
}
",
        );
    }

    #[test]
    fn test_fill_struct_fields_raw_ident() {
        check_fix(
            r#"
struct TestStruct { r#type: u8 }

fn test_fn() {
    TestStruct { $0 };
}
"#,
            r"
struct TestStruct { r#type: u8 }

fn test_fn() {
    TestStruct { r#type: ()  };
}
",
        );
    }

    #[test]
    fn test_fill_struct_fields_no_diagnostic() {
        check_diagnostics(
            r#"
struct TestStruct { one: i32, two: i64 }

fn test_fn() {
    let one = 1;
    let s = TestStruct{ one, two: 2 };
}
        "#,
        );
    }

    #[test]
    fn test_fill_struct_fields_no_diagnostic_on_spread() {
        check_diagnostics(
            r#"
struct TestStruct { one: i32, two: i64 }

fn test_fn() {
    let one = 1;
    let s = TestStruct{ ..a };
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_blank_line() {
        check_fix(
            r#"
struct S { a: (), b: () }

fn f() {
    S {
        $0
    };
}
"#,
            r#"
struct S { a: (), b: () }

fn f() {
    S {
        a: (),
        b: (),
    };
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_shorthand() {
        check_fix(
            r#"
struct S { a: &'static str, b: i32 }

fn f() {
    let a = "hello";
    let b = 1i32;
    S {
        $0
    };
}
"#,
            r#"
struct S { a: &'static str, b: i32 }

fn f() {
    let a = "hello";
    let b = 1i32;
    S {
        a,
        b,
    };
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_shorthand_ty_mismatch() {
        check_fix(
            r#"
struct S { a: &'static str, b: i32 }

fn f() {
    let a = "hello";
    let b = 1usize;
    S {
        $0
    };
}
"#,
            r#"
struct S { a: &'static str, b: i32 }

fn f() {
    let a = "hello";
    let b = 1usize;
    S {
        a,
        b: (),
    };
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_shorthand_unifies() {
        check_fix(
            r#"
struct S<T> { a: &'static str, b: T }

fn f() {
    let a = "hello";
    let b = 1i32;
    S {
        $0
    };
}
"#,
            r#"
struct S<T> { a: &'static str, b: T }

fn f() {
    let a = "hello";
    let b = 1i32;
    S {
        a,
        b,
    };
}
"#,
        );
    }

    #[test]
    fn import_extern_crate_clash_with_inner_item() {
        // This is more of a resolver test, but doesn't really work with the hir_def testsuite.

        check_diagnostics(
            r#"
//- /lib.rs crate:lib deps:jwt
mod permissions;

use permissions::jwt;

fn f() {
    fn inner() {}
    jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
}

//- /permissions.rs
pub mod jwt  {
    pub struct Claims {}
}

//- /jwt/lib.rs crate:jwt
pub struct Claims {
    field: u8,
}
        "#,
        );
    }
}
<commit_msg>Add coverage mark for struct init shorthand test<commit_after>use either::Either;
use hir::{db::AstDatabase, InFile};
use ide_db::{assists::Assist, source_change::SourceChange};
use rustc_hash::FxHashMap;
use stdx::format_to;
use syntax::{algo, ast::make, AstNode, SyntaxNodePtr};
use text_edit::TextEdit;

use crate::{fix, Diagnostic, DiagnosticsContext};

// Diagnostic: missing-fields
//
// This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
//
// Example:
//
// ```rust
// struct A { a: u8, b: u8 }
//
// let a = A { a: 10 };
// ```
pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic {
    let mut message = String::from("missing structure fields:\n");
    for field in &d.missed_fields {
        format_to!(message, "- {}\n", field);
    }

    let ptr = InFile::new(
        d.file,
        d.field_list_parent_path
            .clone()
            .map(SyntaxNodePtr::from)
            .unwrap_or_else(|| d.field_list_parent.clone().either(|it| it.into(), |it| it.into())),
    );

    Diagnostic::new("missing-fields", message, ctx.sema.diagnostics_display_range(ptr).range)
        .with_fixes(fixes(ctx, d))
}

fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Assist>> {
    // Note that although we could add a diagnostics to
    // fill the missing tuple field, e.g :
    // `struct A(usize);`
    // `let a = A { 0: () }`
    // but it is uncommon usage and it should not be encouraged.
    if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
        return None;
    }

    let root = ctx.sema.db.parse_or_expand(d.file)?;
    let field_list_parent = match &d.field_list_parent {
        Either::Left(record_expr) => record_expr.to_node(&root),
        // FIXE: patterns should be fixable as well.
        Either::Right(_) => return None,
    };
    let old_field_list = field_list_parent.record_expr_field_list()?;
    let new_field_list = old_field_list.clone_for_update();
    let mut locals = FxHashMap::default();
    ctx.sema.scope(field_list_parent.syntax()).process_all_names(&mut |name, def| {
        if let hir::ScopeDef::Local(local) = def {
            locals.insert(name.clone(), local);
        }
    });
    let missing_fields = ctx.sema.record_literal_missing_fields(&field_list_parent);
    for (f, ty) in missing_fields.iter() {
        let field_expr = if let Some(local_candidate) = locals.get(&f.name(ctx.sema.db)) {
            cov_mark::hit!(field_shorthand);
            let candidate_ty = local_candidate.ty(ctx.sema.db);
            if ty.could_unify_with(ctx.sema.db, &candidate_ty) {
                None
            } else {
                Some(make::expr_unit())
            }
        } else {
            Some(make::expr_unit())
        };
        let field =
            make::record_expr_field(make::name_ref(&f.name(ctx.sema.db).to_string()), field_expr)
                .clone_for_update();
        new_field_list.add_field(field);
    }

    let edit = {
        let mut builder = TextEdit::builder();
        algo::diff(old_field_list.syntax(), new_field_list.syntax()).into_text_edit(&mut builder);
        builder.finish()
    };
    Some(vec![fix(
        "fill_missing_fields",
        "Fill struct fields",
        SourceChange::from_text_edit(d.file.original_file(ctx.sema.db), edit),
        ctx.sema.original_range(field_list_parent.syntax()).range,
    )])
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_diagnostics, check_fix};

    #[test]
    fn missing_record_pat_field_diagnostic() {
        check_diagnostics(
            r#"
struct S { foo: i32, bar: () }
fn baz(s: S) {
    let S { foo: _ } = s;
      //^ error: missing structure fields:
      //| - bar
}
"#,
        );
    }

    #[test]
    fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
        check_diagnostics(
            r"
struct S { foo: i32, bar: () }
fn baz(s: S) -> i32 {
    match s {
        S { foo, .. } => foo,
    }
}
",
        )
    }

    #[test]
    fn missing_record_pat_field_box() {
        check_diagnostics(
            r"
struct S { s: Box<u32> }
fn x(a: S) {
    let S { box s } = a;
}
",
        )
    }

    #[test]
    fn missing_record_pat_field_ref() {
        check_diagnostics(
            r"
struct S { s: u32 }
fn x(a: S) {
    let S { ref s } = a;
}
",
        )
    }

    #[test]
    fn range_mapping_out_of_macros() {
        // FIXME: this is very wrong, but somewhat tricky to fix.
        check_fix(
            r#"
fn some() {}
fn items() {}
fn here() {}

macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }

fn main() {
    let _x = id![Foo { a: $042 }];
}

pub struct Foo { pub a: i32, pub b: i32 }
"#,
            r#"
fn some(, b: () ) {}
fn items() {}
fn here() {}

macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }

fn main() {
    let _x = id![Foo { a: 42 }];
}

pub struct Foo { pub a: i32, pub b: i32 }
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_empty() {
        check_fix(
            r#"
struct TestStruct { one: i32, two: i64 }

fn test_fn() {
    let s = TestStruct {$0};
}
"#,
            r#"
struct TestStruct { one: i32, two: i64 }

fn test_fn() {
    let s = TestStruct { one: (), two: () };
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_self() {
        check_fix(
            r#"
struct TestStruct { one: i32 }

impl TestStruct {
    fn test_fn() { let s = Self {$0}; }
}
"#,
            r#"
struct TestStruct { one: i32 }

impl TestStruct {
    fn test_fn() { let s = Self { one: () }; }
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_enum() {
        check_fix(
            r#"
enum Expr {
    Bin { lhs: Box<Expr>, rhs: Box<Expr> }
}

impl Expr {
    fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr {
        Expr::Bin {$0 }
    }
}
"#,
            r#"
enum Expr {
    Bin { lhs: Box<Expr>, rhs: Box<Expr> }
}

impl Expr {
    fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr {
        Expr::Bin { lhs, rhs }
    }
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_partial() {
        check_fix(
            r#"
struct TestStruct { one: i32, two: i64 }

fn test_fn() {
    let s = TestStruct{ two: 2$0 };
}
"#,
            r"
struct TestStruct { one: i32, two: i64 }

fn test_fn() {
    let s = TestStruct{ two: 2, one: () };
}
",
        );
    }

    #[test]
    fn test_fill_struct_fields_raw_ident() {
        check_fix(
            r#"
struct TestStruct { r#type: u8 }

fn test_fn() {
    TestStruct { $0 };
}
"#,
            r"
struct TestStruct { r#type: u8 }

fn test_fn() {
    TestStruct { r#type: ()  };
}
",
        );
    }

    #[test]
    fn test_fill_struct_fields_no_diagnostic() {
        check_diagnostics(
            r#"
struct TestStruct { one: i32, two: i64 }

fn test_fn() {
    let one = 1;
    let s = TestStruct{ one, two: 2 };
}
        "#,
        );
    }

    #[test]
    fn test_fill_struct_fields_no_diagnostic_on_spread() {
        check_diagnostics(
            r#"
struct TestStruct { one: i32, two: i64 }

fn test_fn() {
    let one = 1;
    let s = TestStruct{ ..a };
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_blank_line() {
        check_fix(
            r#"
struct S { a: (), b: () }

fn f() {
    S {
        $0
    };
}
"#,
            r#"
struct S { a: (), b: () }

fn f() {
    S {
        a: (),
        b: (),
    };
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_shorthand() {
        cov_mark::check!(field_shorthand);
        check_fix(
            r#"
struct S { a: &'static str, b: i32 }

fn f() {
    let a = "hello";
    let b = 1i32;
    S {
        $0
    };
}
"#,
            r#"
struct S { a: &'static str, b: i32 }

fn f() {
    let a = "hello";
    let b = 1i32;
    S {
        a,
        b,
    };
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_shorthand_ty_mismatch() {
        check_fix(
            r#"
struct S { a: &'static str, b: i32 }

fn f() {
    let a = "hello";
    let b = 1usize;
    S {
        $0
    };
}
"#,
            r#"
struct S { a: &'static str, b: i32 }

fn f() {
    let a = "hello";
    let b = 1usize;
    S {
        a,
        b: (),
    };
}
"#,
        );
    }

    #[test]
    fn test_fill_struct_fields_shorthand_unifies() {
        check_fix(
            r#"
struct S<T> { a: &'static str, b: T }

fn f() {
    let a = "hello";
    let b = 1i32;
    S {
        $0
    };
}
"#,
            r#"
struct S<T> { a: &'static str, b: T }

fn f() {
    let a = "hello";
    let b = 1i32;
    S {
        a,
        b,
    };
}
"#,
        );
    }

    #[test]
    fn import_extern_crate_clash_with_inner_item() {
        // This is more of a resolver test, but doesn't really work with the hir_def testsuite.

        check_diagnostics(
            r#"
//- /lib.rs crate:lib deps:jwt
mod permissions;

use permissions::jwt;

fn f() {
    fn inner() {}
    jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
}

//- /permissions.rs
pub mod jwt  {
    pub struct Claims {}
}

//- /jwt/lib.rs crate:jwt
pub struct Claims {
    field: u8,
}
        "#,
        );
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};

/// Marker for unsanitized input.
pub struct Unsanitary;

/// Marker for sanitized input.
pub struct Sanitary;

/// Nondeterministic finite automata.
#[derive(Deserialize, Serialize)]
pub struct Nfa<T> {
    /// Marker to ensure that the state machine has been validated before it is used for any
    /// computations.
    #[serde(skip_serializing, default)]
    sanitized: T,

    /// The final (accepting) states of the automata.
    final_states: HashSet<String>,

    /// The alphabet of symbols the automata accepts.
    alphabet: HashSet<String>,

    /// The nodes within the automata. Each node has a set of mappings from alphabet symbols to
    /// other states.
    nodes: HashMap<String, HashMap<String, HashSet<String>>>
}

impl Nfa<Unsanitary> {
    // todo -- add error type
    fn check(self) -> Result<Nfa<Sanitary>, ()> {
        unimplemented!()
    }
}

impl Nfa<Sanitary> {

}
<commit_msg>basic checking for nfa<commit_after>use std::collections::{HashMap, HashSet};

/// Marker for unsanitized input.
#[derive(Default)]
pub struct Unsanitary;

/// Marker for sanitized input.
pub struct Sanitary;

/// Nondeterministic finite automata.
#[derive(Deserialize, Serialize)]
pub struct Nfa<T> {
    /// Marker to ensure that the state machine has been validated before it is used for any
    /// computations.
    #[serde(skip_serializing, default)]
    _sanitized: T,

    /// The final (accepting) states of the automata.
    final_states: HashSet<String>,

    /// The alphabet of symbols the automata accepts.
    alphabet: HashSet<String>,

    /// The nodes within the automata. Each node has a set of mappings from alphabet symbols to
    /// other states.
    nodes: HashMap<String, HashMap<String, HashSet<String>>>,
}

impl Nfa<Unsanitary> {
    // todo -- add error type
    pub fn check(self) -> Result<Nfa<Sanitary>, ()> {
        let Nfa {
            final_states,
            alphabet,
            nodes,
            ..
        } = self;

        if !final_states.iter().all(|state| nodes.contains_key(state)) {
            return Err(());
        }

        if !nodes.iter().all(|(_node, maps)| {
            maps.iter().all(|(symbol, _)| alphabet.contains(symbol))
        }) {
            return Err(());
        }

        Ok(Nfa {
            _sanitized: Sanitary,
            final_states,
            alphabet,
            nodes,
        })
    }
}

impl Nfa<Sanitary> {}
<|endoftext|>


<commit_before>use std::ffi::OsStr;
use std::path::Path;
use std::{env, fs};

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();

    rerun_if_env_changed("OUT_DIR");
    rerun_if_env_changed("CMAKE_PREFIX_PATH");
    rerun_if_env_changed("ROSRUST_MSG_PATH");

    let cmake_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or_default()
        .split(':')
        .filter_map(append_share_folder)
        .collect::<Vec<String>>();
    let cmake_alt_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or_default()
        .split(':')
        .filter_map(append_src_folder)
        .collect::<Vec<String>>();
    let extra_paths = env::var("ROSRUST_MSG_PATH")
        .unwrap_or_default()
        .split(':')
        .map(String::from)
        .collect::<Vec<String>>();
    let paths = cmake_paths
        .iter()
        .chain(cmake_alt_paths.iter())
        .chain(extra_paths.iter())
        .collect::<Vec<_>>();
    for path in &paths {
        rerun_if_folder_content_changed(Path::new(path));
    }

    let messages = paths
        .iter()
        .flat_map(|path| find_all_messages_and_services(Path::new(path)))
        .collect::<Vec<(String, String)>>();

    let file_name = format!("{}/{}", out_dir, "messages.rs");

    let package_names = messages
        .iter()
        .map(|(pkg, msg)| format!("{}/{}", pkg, msg))
        .collect::<Vec<String>>()
        .join(",");
    let package_tuples = messages
        .iter()
        .map(|(pkg, msg)| format!("(\"{}\",\"{}\")", pkg, msg))
        .collect::<Vec<String>>()
        .join(",");

    let file_content = format!(
        r#"
rosrust::rosmsg_include!({},IGNORE_BAD);
pub static MESSAGES: &[(&str, &str)]=&[{}];
        "#,
        package_names, package_tuples
    );

    fs::write(&file_name, &file_content).unwrap();
}

fn rerun_if_file_changed(key: &str) {
    println!("cargo:rerun-if-changed={}", key);
}

fn rerun_if_env_changed(key: &str) {
    println!("cargo:rerun-if-env-changed={}", key);
}

pub fn rerun_if_folder_content_changed(folder: &Path) {
    if !folder.is_dir() {
        if folder.extension() == Some(OsStr::new("msg"))
            || folder.extension() == Some(OsStr::new("srv"))
        {
            if let Some(name) = folder.to_str() {
                rerun_if_file_changed(name);
            }
        }
        return;
    }
    if let Some(name) = folder.to_str() {
        rerun_if_file_changed(name);
    }
    if let Ok(children) = fs::read_dir(folder) {
        for child in children.filter_map(Result::ok) {
            rerun_if_folder_content_changed(&child.path());
        }
    }
}

fn append_share_folder(path: &str) -> Option<String> {
    Path::new(path).join("share").to_str().map(String::from)
}

fn append_src_folder(path: &str) -> Option<String> {
    Path::new(path)
        .join("..")
        .join("src")
        .to_str()
        .map(String::from)
}

fn find_all_messages_and_services(root: &Path) -> Vec<(String, String)> {
    if !root.is_dir() {
        return identify_message_or_service(root).into_iter().collect();
    }
    let mut items = vec![];
    if let Ok(children) = fs::read_dir(root) {
        for child in children.filter_map(|v| v.ok()) {
            items.append(&mut find_all_messages_and_services(&child.path()));
        }
    }
    items
}

fn identify_message_or_service(filename: &Path) -> Option<(String, String)> {
    let extension = filename.extension()?;
    let message = filename.file_stem()?;
    let parent = filename.parent()?;
    let grandparent = parent.parent()?;
    let package = grandparent.file_name()?;
    if Some(extension) != parent.file_name() {
        return None;
    }
    match extension.to_str() {
        Some("msg") => {}
        Some("srv") => {}
        _ => return None,
    }
    Some((package.to_str()?.into(), message.to_str()?.into()))
}
<commit_msg>panic if there are no message definitions during build.rs<commit_after>use std::ffi::OsStr;
use std::path::Path;
use std::{env, fs};

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();

    rerun_if_env_changed("OUT_DIR");
    rerun_if_env_changed("CMAKE_PREFIX_PATH");
    rerun_if_env_changed("ROSRUST_MSG_PATH");

    let cmake_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or_default()
        .split(':')
        .filter_map(append_share_folder)
        .collect::<Vec<String>>();
    let cmake_alt_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or_default()
        .split(':')
        .filter_map(append_src_folder)
        .collect::<Vec<String>>();
    let extra_paths = env::var("ROSRUST_MSG_PATH")
        .unwrap_or_default()
        .split(':')
        .map(String::from)
        .collect::<Vec<String>>();
    let paths = cmake_paths
        .iter()
        .chain(cmake_alt_paths.iter())
        .chain(extra_paths.iter())
        .collect::<Vec<_>>();
    for path in &paths {
        rerun_if_folder_content_changed(Path::new(path));
    }

    let messages = paths
        .iter()
        .flat_map(|path| find_all_messages_and_services(Path::new(path)))
        .collect::<Vec<(String, String)>>();

    let file_name = format!("{}/{}", out_dir, "messages.rs");

    let package_names = messages
        .iter()
        .map(|(pkg, msg)| format!("{}/{}", pkg, msg))
        .collect::<Vec<String>>()
        .join(",");
    let package_tuples = messages
        .iter()
        .map(|(pkg, msg)| format!("(\"{}\",\"{}\")", pkg, msg))
        .collect::<Vec<String>>()
        .join(",");

    // Panic on an empty message list: there is no use for this, and it avoids
    // a cryptic error in the proc macro invocation later on
    if package_names.is_empty() {
        panic!("empty package_names: are any of CMAKE_PREFIX_PATH and ROSRUST_MSG_PATH defined? is /opt/ros/<VERSION>/env sourced?");
    }

    let file_content = format!(
        r#"
rosrust::rosmsg_include!({},IGNORE_BAD);
pub static MESSAGES: &[(&str, &str)]=&[{}];
        "#,
        package_names, package_tuples
    );

    fs::write(&file_name, &file_content).unwrap();
}

fn rerun_if_file_changed(key: &str) {
    println!("cargo:rerun-if-changed={}", key);
}

fn rerun_if_env_changed(key: &str) {
    println!("cargo:rerun-if-env-changed={}", key);
}

pub fn rerun_if_folder_content_changed(folder: &Path) {
    if !folder.is_dir() {
        if folder.extension() == Some(OsStr::new("msg"))
            || folder.extension() == Some(OsStr::new("srv"))
        {
            if let Some(name) = folder.to_str() {
                rerun_if_file_changed(name);
            }
        }
        return;
    }
    if let Some(name) = folder.to_str() {
        rerun_if_file_changed(name);
    }
    if let Ok(children) = fs::read_dir(folder) {
        for child in children.filter_map(Result::ok) {
            rerun_if_folder_content_changed(&child.path());
        }
    }
}

fn append_share_folder(path: &str) -> Option<String> {
    Path::new(path).join("share").to_str().map(String::from)
}

fn append_src_folder(path: &str) -> Option<String> {
    Path::new(path)
        .join("..")
        .join("src")
        .to_str()
        .map(String::from)
}

fn find_all_messages_and_services(root: &Path) -> Vec<(String, String)> {
    if !root.is_dir() {
        return identify_message_or_service(root).into_iter().collect();
    }
    let mut items = vec![];
    if let Ok(children) = fs::read_dir(root) {
        for child in children.filter_map(|v| v.ok()) {
            items.append(&mut find_all_messages_and_services(&child.path()));
        }
    }
    items
}

fn identify_message_or_service(filename: &Path) -> Option<(String, String)> {
    let extension = filename.extension()?;
    let message = filename.file_stem()?;
    let parent = filename.parent()?;
    let grandparent = parent.parent()?;
    let package = grandparent.file_name()?;
    if Some(extension) != parent.file_name() {
        return None;
    }
    match extension.to_str() {
        Some("msg") => {}
        Some("srv") => {}
        _ => return None,
    }
    Some((package.to_str()?.into(), message.to_str()?.into()))
}
<|endoftext|>


<commit_before>extern crate rand;

use std::io;
use std::collections::HashMap;
use rand::Rng;

fn main() {
	// `answers` needs to be mutable, since the structure must be able to be changed with insert etc.
	// We type hint to avoid repeating below u8 for each number. Looks prettier this way.
	let mut answers: HashMap<String, u8> = HashMap::new();
	// We put string literals with to_owned() so we can use collections::string::String instead of &str
	// This will be helpful later when we have to use a dynamic key on the hash map gotten from the stdin.
	answers.insert("rock".to_owned(), 0);
	answers.insert("paper".to_owned(), 1);
	answers.insert("scissors".to_owned(), 2);
	// We indicate the type so we don't make it think it's of _ type. Signed integer, 8 bits is more than enough.
	let multi: [[i8;3];3] = [[0, -1, 1], [1, 0, -1], [-1, -1, 0]];
	let cpu_names = ["rock", "paper", "scissors"];

	// Let's get started.
	println!("Rock, paper, scissors; best of five!");
	let mut wins: u8 = 0;
	let mut losses: u8 = 0;

	loop {
		println!("Choose an action[rock, paper, scissors].");

		let mut input = String::new();
		io::stdin().read_line(&mut input)
			.expect("Failed to read line.");
		input = input.trim().to_owned();

		// Check if the answer is correct. If it isn't, stop this iteration and go onto the next.
		if !answers.contains_key(&input) {
			println!("Wrong action!");
			continue;
		}

		// Choose random action.
		let cpu_action = rand::thread_rng().gen_range(0, 3) as usize;
		let player_action = answers.get(&input).unwrap().to_owned() as usize;
		let result = multi[player_action][cpu_action];
		println!("The CPU chose {}", cpu_names[cpu_action]);

		// Check what happens and show game status.
		match result {
			-1 => {
				losses += 1;
				println!("You lose! ({} - {})", wins, losses);
			},
			1 => {
				wins += 1;
				println!("You win! ({} - {})", wins, losses);
			},
			_ => {
				println!("It's a tie! ({} - {})", wins, losses);
			}
		}

		// Check if the game is over.
		if wins > 2 || losses > 2 {
			if wins > losses {
				println!("You won the game!");
			} else {
				println!("You lost the game...");
			}
			break;
		} else {
			println!("Choose a new action.");
		}
	}
}
<commit_msg>Rust RPS: Prefer String::from over .to_owned<commit_after>extern crate rand;

use std::io;
use std::collections::HashMap;
use rand::Rng;

fn main() {
	// `answers` needs to be mutable, since the structure must be able to be changed with insert etc.
	// We type hint to avoid repeating below u8 for each number. Looks prettier this way.
	let mut answers: HashMap<String, u8> = HashMap::new();
	// We put string literals with String::from so we can use collections::string::String instead of &str
	// This will be helpful later when we have to use a dynamic key on the hash map gotten from the stdin.
	answers.insert(String::from("rock"), 0);
	answers.insert(String::from("paper"), 1);
	answers.insert(String::from("scissors"), 2);
	// We indicate the type so we don't make it think it's of _ type. Signed integer, 8 bits is more than enough.
	let multi: [[i8;3];3] = [[0, -1, 1], [1, 0, -1], [-1, -1, 0]];
	let cpu_names = ["rock", "paper", "scissors"];

	// Let's get started.
	println!("Rock, paper, scissors; best of five!");
	let mut wins: u8 = 0;
	let mut losses: u8 = 0;

	loop {
		println!("Choose an action[rock, paper, scissors].");

		let mut input = String::new();
		io::stdin().read_line(&mut input)
			.expect("Failed to read line.");
		input = String::from(input.trim());

		// Check if the answer is correct. If it isn't, stop this iteration and go onto the next.
		if !answers.contains_key(&input) {
			println!("Wrong action!");
			continue;
		}

		// Choose random action.
		let cpu_action = rand::thread_rng().gen_range(0, 3) as usize;
		let player_action = answers.get(&input).unwrap().to_owned() as usize;
		let result = multi[player_action][cpu_action];
		println!("The CPU chose {}", cpu_names[cpu_action]);

		// Check what happens and show game status.
		match result {
			-1 => {
				losses += 1;
				println!("You lose! ({} - {})", wins, losses);
			},
			1 => {
				wins += 1;
				println!("You win! ({} - {})", wins, losses);
			},
			_ => {
				println!("It's a tie! ({} - {})", wins, losses);
			}
		}

		// Check if the game is over.
		if wins > 2 || losses > 2 {
			if wins > losses {
				println!("You won the game!");
			} else {
				println!("You lost the game...");
			}
			break;
		} else {
			println!("Choose a new action.");
		}
	}
}
<|endoftext|>