<commit_before>//! A small GPU compute shader demonstration.
//!
//! Here we use a compute shader to calculate the amplitude of `OSCILLATOR_COUNT` number of
//! oscillators. The oscillator amplitudes are then laid out across the screen using rectangles
//! with a gray value equal to the amplitude. Real-time interaction is demonstrated by providing
//! access to time, frequency (mouse `x`) and the number of oscillators via uniform data.

use nannou::prelude::*;
use std::sync::{Arc, Mutex};

struct Model {
    compute: Compute,
    oscillators: Arc<Mutex<Vec<f32>>>,
    threadpool: futures::executor::ThreadPool,
}

struct Compute {
    oscillator_buffer: wgpu::Buffer,
    oscillator_buffer_size: wgpu::BufferAddress,
    uniform_buffer: wgpu::Buffer,
    bind_group: wgpu::BindGroup,
    pipeline: wgpu::ComputePipeline,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct Uniforms {
    time: f32,
    freq: f32,
    oscillator_count: u32,
}

const OSCILLATOR_COUNT: u32 = 128;

fn main() {
    nannou::app(model).update(update).run();
}

fn model(app: &App) -> Model {
    let w_id = app.new_window().size(1440, 512).view(view).build().unwrap();
    let window = app.window(w_id).unwrap();
    let device = window.swap_chain_device();

    // Create the compute shader module.
    let cs_mod = wgpu::shader_from_spirv_bytes(device, include_bytes!("shaders/comp.spv"));

    // Create the buffer that will store the result of our compute operation.
    let oscillator_buffer_size =
        (OSCILLATOR_COUNT as usize * std::mem::size_of::<f32>()) as wgpu::BufferAddress;
    let oscillator_buffer = device.create_buffer(&wgpu::BufferDescriptor {
        label: Some("oscillators"),
        size: oscillator_buffer_size,
        usage: wgpu::BufferUsage::STORAGE
            | wgpu::BufferUsage::COPY_DST
            | wgpu::BufferUsage::COPY_SRC,
    });

    // Create the buffer that will store time.
    let uniforms = create_uniforms(app.time, app.mouse.x, window.rect());
    let uniforms_bytes = uniforms_as_bytes(&uniforms);
    let usage = wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST;
    let uniform_buffer = device.create_buffer_with_data(uniforms_bytes, usage);

    // Create the bind group and pipeline.
    let bind_group_layout = create_bind_group_layout(device);
    let bind_group = create_bind_group(
        device,
        &bind_group_layout,
        &oscillator_buffer,
        oscillator_buffer_size,
        &uniform_buffer,
    );
    let pipeline_layout = create_pipeline_layout(device, &bind_group_layout);
    let pipeline = create_compute_pipeline(device, &pipeline_layout, &cs_mod);

    let compute = Compute {
        oscillator_buffer,
        oscillator_buffer_size,
        uniform_buffer,
        bind_group,
        pipeline,
    };

    // The vector that we will write oscillator values to.
    let oscillators = Arc::new(Mutex::new(vec![0.0; OSCILLATOR_COUNT as usize]));

    // Create a thread pool capable of running our GPU buffer read futures.
    let threadpool = futures::executor::ThreadPool::new().unwrap();

    Model {
        compute,
        oscillators,
        threadpool,
    }
}

fn update(app: &App, model: &mut Model, _update: Update) {
    let window = app.main_window();
    let device = window.swap_chain_device();
    let win_rect = window.rect();
    let compute = &mut model.compute;

    // The buffer into which we'll read some data.
    let read_buffer = device.create_buffer(&wgpu::BufferDescriptor {
        label: Some("read_oscillators"),
        size: compute.oscillator_buffer_size,
        usage: wgpu::BufferUsage::MAP_READ
            | wgpu::BufferUsage::COPY_DST
            | wgpu::BufferUsage::COPY_SRC,
    });

    // An update for the uniform buffer with the current time.
    let uniforms = create_uniforms(app.time, app.mouse.x, win_rect);
    let uniforms_size = std::mem::size_of::<Uniforms>() as wgpu::BufferAddress;
    let uniforms_bytes = uniforms_as_bytes(&uniforms);
    let usage = wgpu::BufferUsage::COPY_SRC;
    let new_uniform_buffer = device.create_buffer_with_data(uniforms_bytes, usage);

    // The encoder we'll use to encode the compute pass.
    let desc = wgpu::CommandEncoderDescriptor {
        label: Some("oscillator_compute"),
    };
    let mut encoder = device.create_command_encoder(&desc);
    encoder.copy_buffer_to_buffer(
        &new_uniform_buffer,
        0,
        &compute.uniform_buffer,
        0,
        uniforms_size,
    );
    {
        let mut cpass = encoder.begin_compute_pass();
        cpass.set_pipeline(&compute.pipeline);
        cpass.set_bind_group(0, &compute.bind_group, &[]);
        cpass.dispatch(OSCILLATOR_COUNT as u32, 1, 1);
    }
    encoder.copy_buffer_to_buffer(
        &compute.oscillator_buffer,
        0,
        &read_buffer,
        0,
        compute.oscillator_buffer_size,
    );

    // Submit the compute pass to the device's queue.
    window.swap_chain_queue().submit(&[encoder.finish()]);

    // Spawn a future that reads the result of the compute pass.
    let oscillators = model.oscillators.clone();
    let oscillator_buffer_size = compute.oscillator_buffer_size;
    let future = async move {
        let result = read_buffer.map_read(0, oscillator_buffer_size).await;
        if let Ok(mapping) = result {
            if let Ok(mut oscillators) = oscillators.lock() {
                let bytes = mapping.as_slice();
                // "Cast" the slice of bytes to a slice of floats as required.
                let floats = {
                    let len = bytes.len() / std::mem::size_of::<f32>();
                    let ptr = bytes.as_ptr() as *const f32;
                    unsafe { std::slice::from_raw_parts(ptr, len) }
                };
                oscillators.copy_from_slice(floats);
            }
        }
    };
    model.threadpool.spawn_ok(future);

    // Check for resource cleanups and mapping callbacks.
    //
    // Note that this line is not necessary in our case, as the device we are using already gets
    // polled when nannou submits the command buffer for drawing and presentation after `view`
    // completes. If we were to use a standalone device to create our buffer and perform our
    // compute (rather than the device requested during window creation), calling `poll` regularly
    // would be a must.
    //
    // device.poll(false);
}

fn view(app: &App, model: &Model, frame: Frame) {
    frame.clear(BLACK);
    let draw = app.draw();
    let window = app.window(frame.window_id()).unwrap();
    let rect = window.rect();

    if let Ok(oscillators) = model.oscillators.lock() {
        let w = rect.w() / OSCILLATOR_COUNT as f32;
        let h = rect.h();
        let half_w = w * 0.5;
        for (i, &osc) in oscillators.iter().enumerate() {
            let x = half_w + map_range(i as u32, 0, OSCILLATOR_COUNT, rect.left(), rect.right());
            draw.rect().w_h(w, h).x(x).color(gray(osc));
        }
    }

    draw.to_frame(app, &frame).unwrap();
}

fn create_uniforms(time: f32, mouse_x: f32, win_rect: geom::Rect) -> Uniforms {
    let freq = map_range(
        mouse_x,
        win_rect.left(),
        win_rect.right(),
        0.0,
        win_rect.w(),
    );
    let oscillator_count = OSCILLATOR_COUNT;
    Uniforms {
        time,
        freq,
        oscillator_count,
    }
}

fn create_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
    let storage_dynamic = false;
    let storage_readonly = false;
    let uniform_dynamic = false;
    wgpu::BindGroupLayoutBuilder::new()
        .storage_buffer(
            wgpu::ShaderStage::COMPUTE,
            storage_dynamic,
            storage_readonly,
        )
        .uniform_buffer(wgpu::ShaderStage::COMPUTE, uniform_dynamic)
        .build(device)
}

fn create_bind_group(
    device: &wgpu::Device,
    layout: &wgpu::BindGroupLayout,
    oscillator_buffer: &wgpu::Buffer,
    oscillator_buffer_size: wgpu::BufferAddress,
    uniform_buffer: &wgpu::Buffer,
) -> wgpu::BindGroup {
    wgpu::BindGroupBuilder::new()
        .buffer_bytes(oscillator_buffer, 0..oscillator_buffer_size)
        .buffer::<Uniforms>(uniform_buffer, 0..1)
        .build(device, layout)
}

fn create_pipeline_layout(
    device: &wgpu::Device,
    bind_group_layout: &wgpu::BindGroupLayout,
) -> wgpu::PipelineLayout {
    device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
        bind_group_layouts: &[&bind_group_layout],
    })
}

fn create_compute_pipeline(
    device: &wgpu::Device,
    layout: &wgpu::PipelineLayout,
    cs_mod: &wgpu::ShaderModule,
) -> wgpu::ComputePipeline {
    let compute_stage = wgpu::ProgrammableStageDescriptor {
        module: &cs_mod,
        entry_point: "main",
    };
    let desc = wgpu::ComputePipelineDescriptor {
        layout,
        compute_stage,
    };
    device.create_compute_pipeline(&desc)
}

// See `nannou::wgpu::bytes` docs for why these are necessary.

fn uniforms_as_bytes(uniforms: &Uniforms) -> &[u8] {
    unsafe { wgpu::bytes::from(uniforms) }
}
<commit_msg>wgpu 0.5-0.6: change buffer init<commit_after>//! A small GPU compute shader demonstration.
//!
//! Here we use a compute shader to calculate the amplitude of `OSCILLATOR_COUNT` number of
//! oscillators. The oscillator amplitudes are then laid out across the screen using rectangles
//! with a gray value equal to the amplitude. Real-time interaction is demonstrated by providing
//! access to time, frequency (mouse `x`) and the number of oscillators via uniform data.

use nannou::prelude::*;
use std::sync::{Arc, Mutex};

struct Model {
    compute: Compute,
    oscillators: Arc<Mutex<Vec<f32>>>,
    threadpool: futures::executor::ThreadPool,
}

struct Compute {
    oscillator_buffer: wgpu::Buffer,
    oscillator_buffer_size: wgpu::BufferAddress,
    uniform_buffer: wgpu::Buffer,
    bind_group: wgpu::BindGroup,
    pipeline: wgpu::ComputePipeline,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct Uniforms {
    time: f32,
    freq: f32,
    oscillator_count: u32,
}

const OSCILLATOR_COUNT: u32 = 128;

fn main() {
    nannou::app(model).update(update).run();
}

fn model(app: &App) -> Model {
    let w_id = app.new_window().size(1440, 512).view(view).build().unwrap();
    let window = app.window(w_id).unwrap();
    let device = window.swap_chain_device();

    // Create the compute shader module.
    let cs_mod = wgpu::shader_from_spirv_bytes(device, include_bytes!("shaders/comp.spv"));

    // Create the buffer that will store the result of our compute operation.
    let oscillator_buffer_size =
        (OSCILLATOR_COUNT as usize * std::mem::size_of::<f32>()) as wgpu::BufferAddress;
    let oscillator_buffer = device.create_buffer(&wgpu::BufferDescriptor {
        label: Some("oscillators"),
        size: oscillator_buffer_size,
        usage: wgpu::BufferUsage::STORAGE
            | wgpu::BufferUsage::COPY_DST
            | wgpu::BufferUsage::COPY_SRC,
        mapped_at_creation: true,
    });

    // Create the buffer that will store time.
    let uniforms = create_uniforms(app.time, app.mouse.x, window.rect());
    let uniforms_bytes = uniforms_as_bytes(&uniforms);
    let usage = wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST;
    let uniform_buffer = device.create_buffer_init(uniforms_bytes, usage);

    // Create the bind group and pipeline.
    let bind_group_layout = create_bind_group_layout(device);
    let bind_group = create_bind_group(
        device,
        &bind_group_layout,
        &oscillator_buffer,
        oscillator_buffer_size,
        &uniform_buffer,
    );
    let pipeline_layout = create_pipeline_layout(device, &bind_group_layout);
    let pipeline = create_compute_pipeline(device, &pipeline_layout, &cs_mod);

    let compute = Compute {
        oscillator_buffer,
        oscillator_buffer_size,
        uniform_buffer,
        bind_group,
        pipeline,
    };

    // The vector that we will write oscillator values to.
    let oscillators = Arc::new(Mutex::new(vec![0.0; OSCILLATOR_COUNT as usize]));

    // Create a thread pool capable of running our GPU buffer read futures.
    let threadpool = futures::executor::ThreadPool::new().unwrap();

    Model {
        compute,
        oscillators,
        threadpool,
    }
}

fn update(app: &App, model: &mut Model, _update: Update) {
    let window = app.main_window();
    let device = window.swap_chain_device();
    let win_rect = window.rect();
    let compute = &mut model.compute;

    // The buffer into which we'll read some data.
    let read_buffer = device.create_buffer_init(&wgpu::BufferDescriptor {
        label: Some("read_oscillators"),
        size: compute.oscillator_buffer_size,
        usage: wgpu::BufferUsage::MAP_READ
            | wgpu::BufferUsage::COPY_DST
            | wgpu::BufferUsage::COPY_SRC,
        mapped_at_creation: true,
    });

    // An update for the uniform buffer with the current time.
    let uniforms = create_uniforms(app.time, app.mouse.x, win_rect);
    let uniforms_size = std::mem::size_of::<Uniforms>() as wgpu::BufferAddress;
    let uniforms_bytes = uniforms_as_bytes(&uniforms);
    let usage = wgpu::BufferUsage::COPY_SRC;
    let new_uniform_buffer = device.create_buffer_init(uniforms_bytes, usage);

    // The encoder we'll use to encode the compute pass.
    let desc = wgpu::CommandEncoderDescriptor {
        label: Some("oscillator_compute"),
    };
    let mut encoder = device.create_command_encoder(&desc);
    encoder.copy_buffer_to_buffer(
        &new_uniform_buffer,
        0,
        &compute.uniform_buffer,
        0,
        uniforms_size,
    );
    {
        let mut cpass = encoder.begin_compute_pass();
        cpass.set_pipeline(&compute.pipeline);
        cpass.set_bind_group(0, &compute.bind_group, &[]);
        cpass.dispatch(OSCILLATOR_COUNT as u32, 1, 1);
    }
    encoder.copy_buffer_to_buffer(
        &compute.oscillator_buffer,
        0,
        &read_buffer,
        0,
        compute.oscillator_buffer_size,
    );

    // Submit the compute pass to the device's queue.
    window.swap_chain_queue().submit(&[encoder.finish()]);

    // Spawn a future that reads the result of the compute pass.
    let oscillators = model.oscillators.clone();
    let oscillator_buffer_size = compute.oscillator_buffer_size;
    let future = async move {
        let result = read_buffer.map_read(0, oscillator_buffer_size).await;
        if let Ok(mapping) = result {
            if let Ok(mut oscillators) = oscillators.lock() {
                let bytes = mapping.as_slice();
                // "Cast" the slice of bytes to a slice of floats as required.
                let floats = {
                    let len = bytes.len() / std::mem::size_of::<f32>();
                    let ptr = bytes.as_ptr() as *const f32;
                    unsafe { std::slice::from_raw_parts(ptr, len) }
                };
                oscillators.copy_from_slice(floats);
            }
        }
    };
    model.threadpool.spawn_ok(future);

    // Check for resource cleanups and mapping callbacks.
    //
    // Note that this line is not necessary in our case, as the device we are using already gets
    // polled when nannou submits the command buffer for drawing and presentation after `view`
    // completes. If we were to use a standalone device to create our buffer and perform our
    // compute (rather than the device requested during window creation), calling `poll` regularly
    // would be a must.
    //
    // device.poll(false);
}

fn view(app: &App, model: &Model, frame: Frame) {
    frame.clear(BLACK);
    let draw = app.draw();
    let window = app.window(frame.window_id()).unwrap();
    let rect = window.rect();

    if let Ok(oscillators) = model.oscillators.lock() {
        let w = rect.w() / OSCILLATOR_COUNT as f32;
        let h = rect.h();
        let half_w = w * 0.5;
        for (i, &osc) in oscillators.iter().enumerate() {
            let x = half_w + map_range(i as u32, 0, OSCILLATOR_COUNT, rect.left(), rect.right());
            draw.rect().w_h(w, h).x(x).color(gray(osc));
        }
    }

    draw.to_frame(app, &frame).unwrap();
}

fn create_uniforms(time: f32, mouse_x: f32, win_rect: geom::Rect) -> Uniforms {
    let freq = map_range(
        mouse_x,
        win_rect.left(),
        win_rect.right(),
        0.0,
        win_rect.w(),
    );
    let oscillator_count = OSCILLATOR_COUNT;
    Uniforms {
        time,
        freq,
        oscillator_count,
    }
}

fn create_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
    let storage_dynamic = false;
    let storage_readonly = false;
    let uniform_dynamic = false;
    wgpu::BindGroupLayoutBuilder::new()
        .storage_buffer(
            wgpu::ShaderStage::COMPUTE,
            storage_dynamic,
            storage_readonly,
        )
        .uniform_buffer(wgpu::ShaderStage::COMPUTE, uniform_dynamic)
        .build(device)
}

fn create_bind_group(
    device: &wgpu::Device,
    layout: &wgpu::BindGroupLayout,
    oscillator_buffer: &wgpu::Buffer,
    oscillator_buffer_size: wgpu::BufferAddress,
    uniform_buffer: &wgpu::Buffer,
) -> wgpu::BindGroup {
    wgpu::BindGroupBuilder::new()
        .buffer_bytes(oscillator_buffer, 0..oscillator_buffer_size)
        .buffer::<Uniforms>(uniform_buffer, 0..1)
        .build(device, layout)
}

fn create_pipeline_layout(
    device: &wgpu::Device,
    bind_group_layout: &wgpu::BindGroupLayout,
) -> wgpu::PipelineLayout {
    device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
        label: "nannou",
        bind_group_layouts: &[&bind_group_layout],
        push_constant_ranges: &[],
    })
}

fn create_compute_pipeline(
    device: &wgpu::Device,
    layout: &wgpu::PipelineLayout,
    cs_mod: &wgpu::ShaderModule,
) -> wgpu::ComputePipeline {
    let compute_stage = wgpu::ProgrammableStageDescriptor {
        module: &cs_mod,
        entry_point: "main",
    };
    let desc = wgpu::ComputePipelineDescriptor {
        label: "nannou",
        layout,
        compute_stage,
    };
    device.create_compute_pipeline(&desc)
}

// See `nannou::wgpu::bytes` docs for why these are necessary.

fn uniforms_as_bytes(uniforms: &Uniforms) -> &[u8] {
    unsafe { wgpu::bytes::from(uniforms) }
}
<|endoftext|>


<commit_before>use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintPass};
use rustc::{declare_tool_lint, lint_array};
use syntax::ast;
use syntax::ptr::P;

declare_clippy_lint! {
    /// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
    /// operators.
    ///
    /// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
    /// confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
    /// ```
    pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
    style,
    "suspicious formatting of `*=`, `-=` or `!=`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for formatting of `else`. It lints if the `else`
    /// is followed immediately by a newline or the `else` seems to be missing.
    ///
    /// **Why is this bad?** This is probably some refactoring remnant, even if the
    /// code is correct, it might look confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// if foo {
    /// } { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } if bar { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// { // this is the `else` block of the previous `if`, but should it be?
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// if bar { // this is the `else` block of the previous `if`, but should it be?
    /// }
    /// ```
    pub SUSPICIOUS_ELSE_FORMATTING,
    style,
    "suspicious formatting of `else`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for possible missing comma in an array. It lints if
    /// an array element is a binary operator expression and it lies on two lines.
    ///
    /// **Why is this bad?** This could lead to unexpected results.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// let a = &[
    ///     -1, -2, -3 // <= no comma here
    ///     -4, -5, -6
    /// ];
    /// ```
    pub POSSIBLE_MISSING_COMMA,
    correctness,
    "possible missing comma in array"
}

#[derive(Copy, Clone)]
pub struct Formatting;

impl LintPass for Formatting {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            SUSPICIOUS_ASSIGNMENT_FORMATTING,
            SUSPICIOUS_ELSE_FORMATTING,
            POSSIBLE_MISSING_COMMA
        )
    }

    fn name(&self) -> &'static str {
        "Formatting"
    }
}

impl EarlyLintPass for Formatting {
    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        for w in block.stmts.windows(2) {
            match (&w[0].node, &w[1].node) {
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second))
                | (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
                    check_missing_else(cx, first, second);
                },
                _ => (),
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
        check_assign(cx, expr);
        check_else(cx, expr);
        check_array(cx, expr);
    }
}

/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node {
        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(lhs.span) {
            let eq_span = lhs.span.between(rhs.span);
            if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node {
                if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
                    let op = ast::UnOp::to_string(op);
                    let eqop_span = lhs.span.between(sub_rhs.span);
                    if eq_snippet.ends_with('=') {
                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ASSIGNMENT_FORMATTING,
                            eqop_span,
                            &format!(
                                "this looks like you are trying to use `.. {op}= ..`, but you \
                                 really are doing `.. = ({op} ..)`",
                                op = op
                            ),
                            eqop_span,
                            &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
                        );
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`.
fn check_else(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let Some((then, &Some(ref else_))) = unsugar_if(expr) {
        if (is_block(else_) || unsugar_if(else_).is_some())
            && !differing_macro_contexts(then.span, else_.span)
            && !in_macro(then.span)
            && !in_external_macro(cx.sess, expr.span)
        {
            // workaround for rust-lang/rust#43081
            if expr.span.lo().0 == 0 && expr.span.hi().0 == 0 {
                return;
            }

            // this will be a span from the closing ‘}’ of the “then” block (excluding) to
            // the
            // “if” of the “else if” block (excluding)
            let else_span = then.span.between(else_.span);

            // the snippet should look like " else \n    " with maybe comments anywhere
            // it’s bad when there is a ‘\n’ after the “else”
            if let Some(else_snippet) = snippet_opt(cx, else_span) {
                if let Some(else_pos) = else_snippet.find("else") {
                    if else_snippet[else_pos..].contains('\n') {
                        let else_desc = if unsugar_if(else_).is_some() { "if" } else { "{..}" };

                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ELSE_FORMATTING,
                            else_span,
                            &format!("this is an `else {}` but the formatting might hide it", else_desc),
                            else_span,
                            &format!(
                                "to remove this lint, remove the `else` or remove the new line between \
                                 `else` and `{}`",
                                else_desc,
                            ),
                        );
                    }
                }
            }
        }
    }
}

fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
    // &, *, -
    bin_op == ast::BinOpKind::And || bin_op == ast::BinOpKind::Mul || bin_op == ast::BinOpKind::Sub
}

/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Array(ref array) = expr.node {
        for element in array {
            if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node {
                if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span) {
                    let space_span = lhs.span.between(op.span);
                    if let Some(space_snippet) = snippet_opt(cx, space_span) {
                        let lint_span = lhs.span.with_lo(lhs.span.hi());
                        if space_snippet.contains('\n') {
                            span_note_and_lint(
                                cx,
                                POSSIBLE_MISSING_COMMA,
                                lint_span,
                                "possibly missing a comma here",
                                lint_span,
                                "to remove this lint, add a comma or write the expr in a single line",
                            );
                        }
                    }
                }
            }
        }
    }
}

fn check_missing_else(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
    if !differing_macro_contexts(first.span, second.span)
        && !in_macro(first.span)
        && unsugar_if(first).is_some()
        && (is_block(second) || unsugar_if(second).is_some())
    {
        // where the else would be
        let else_span = first.span.between(second.span);

        if let Some(else_snippet) = snippet_opt(cx, else_span) {
            if !else_snippet.contains('\n') {
                let (looks_like, next_thing) = if unsugar_if(second).is_some() {
                    ("an `else if`", "the second `if`")
                } else {
                    ("an `else {..}`", "the next block")
                };

                span_note_and_lint(
                    cx,
                    SUSPICIOUS_ELSE_FORMATTING,
                    else_span,
                    &format!("this looks like {} but the `else` is missing", looks_like),
                    else_span,
                    &format!(
                        "to remove this lint, add the missing `else` or add a new line before {}",
                        next_thing,
                    ),
                );
            }
        }
    }
}

fn is_block(expr: &ast::Expr) -> bool {
    if let ast::ExprKind::Block(..) = expr.node {
        true
    } else {
        false
    }
}

/// Match `if` or `if let` expressions and return the `then` and `else` block.
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
    match expr.node {
        ast::ExprKind::If(_, ref then, ref else_) | ast::ExprKind::IfLet(_, _, ref then, ref else_) => {
            Some((then, else_))
        },
        _ => None,
    }
}
<commit_msg>Refactor suspicious_else_formatting using if_chain<commit_after>use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintPass};
use rustc::{declare_tool_lint, lint_array};
use syntax::ast;
use syntax::ptr::P;
use if_chain::if_chain;

declare_clippy_lint! {
    /// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
    /// operators.
    ///
    /// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
    /// confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
    /// ```
    pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
    style,
    "suspicious formatting of `*=`, `-=` or `!=`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for formatting of `else`. It lints if the `else`
    /// is followed immediately by a newline or the `else` seems to be missing.
    ///
    /// **Why is this bad?** This is probably some refactoring remnant, even if the
    /// code is correct, it might look confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// if foo {
    /// } { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } if bar { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// { // this is the `else` block of the previous `if`, but should it be?
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// if bar { // this is the `else` block of the previous `if`, but should it be?
    /// }
    /// ```
    pub SUSPICIOUS_ELSE_FORMATTING,
    style,
    "suspicious formatting of `else`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for possible missing comma in an array. It lints if
    /// an array element is a binary operator expression and it lies on two lines.
    ///
    /// **Why is this bad?** This could lead to unexpected results.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// let a = &[
    ///     -1, -2, -3 // <= no comma here
    ///     -4, -5, -6
    /// ];
    /// ```
    pub POSSIBLE_MISSING_COMMA,
    correctness,
    "possible missing comma in array"
}

#[derive(Copy, Clone)]
pub struct Formatting;

impl LintPass for Formatting {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            SUSPICIOUS_ASSIGNMENT_FORMATTING,
            SUSPICIOUS_ELSE_FORMATTING,
            POSSIBLE_MISSING_COMMA
        )
    }

    fn name(&self) -> &'static str {
        "Formatting"
    }
}

impl EarlyLintPass for Formatting {
    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        for w in block.stmts.windows(2) {
            match (&w[0].node, &w[1].node) {
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second))
                | (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
                    check_missing_else(cx, first, second);
                },
                _ => (),
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
        check_assign(cx, expr);
        check_else(cx, expr);
        check_array(cx, expr);
    }
}

/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node {
        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(lhs.span) {
            let eq_span = lhs.span.between(rhs.span);
            if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node {
                if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
                    let op = ast::UnOp::to_string(op);
                    let eqop_span = lhs.span.between(sub_rhs.span);
                    if eq_snippet.ends_with('=') {
                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ASSIGNMENT_FORMATTING,
                            eqop_span,
                            &format!(
                                "this looks like you are trying to use `.. {op}= ..`, but you \
                                 really are doing `.. = ({op} ..)`",
                                op = op
                            ),
                            eqop_span,
                            &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
                        );
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`.
fn check_else(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if_chain! {
        if let Some((then, &Some(ref else_))) = unsugar_if(expr);
        if is_block(else_) || unsugar_if(else_).is_some();
        if !differing_macro_contexts(then.span, else_.span);
        if !in_macro(then.span) && !in_external_macro(cx.sess, expr.span);

        // workaround for rust-lang/rust#43081
        if expr.span.lo().0 != 0 && expr.span.hi().0 != 0;

        // this will be a span from the closing ‘}’ of the “then” block (excluding) to
        // the
        // “if” of the “else if” block (excluding)
        let else_span = then.span.between(else_.span);

        // the snippet should look like " else \n    " with maybe comments anywhere
        // it’s bad when there is a ‘\n’ after the “else”
        if let Some(else_snippet) = snippet_opt(cx, else_span);
        if let Some(else_pos) = else_snippet.find("else");
        if else_snippet[else_pos..].contains('\n');
        let else_desc = if unsugar_if(else_).is_some() { "if" } else { "{..}" };

        then {
            span_note_and_lint(
                cx,
                SUSPICIOUS_ELSE_FORMATTING,
                else_span,
                &format!("this is an `else {}` but the formatting might hide it", else_desc),
                else_span,
                &format!(
                    "to remove this lint, remove the `else` or remove the new line between \
                     `else` and `{}`",
                    else_desc,
                ),
            );
        }
    }
}

fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
    // &, *, -
    bin_op == ast::BinOpKind::And || bin_op == ast::BinOpKind::Mul || bin_op == ast::BinOpKind::Sub
}

/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Array(ref array) = expr.node {
        for element in array {
            if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node {
                if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span) {
                    let space_span = lhs.span.between(op.span);
                    if let Some(space_snippet) = snippet_opt(cx, space_span) {
                        let lint_span = lhs.span.with_lo(lhs.span.hi());
                        if space_snippet.contains('\n') {
                            span_note_and_lint(
                                cx,
                                POSSIBLE_MISSING_COMMA,
                                lint_span,
                                "possibly missing a comma here",
                                lint_span,
                                "to remove this lint, add a comma or write the expr in a single line",
                            );
                        }
                    }
                }
            }
        }
    }
}

fn check_missing_else(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
    if !differing_macro_contexts(first.span, second.span)
        && !in_macro(first.span)
        && unsugar_if(first).is_some()
        && (is_block(second) || unsugar_if(second).is_some())
    {
        // where the else would be
        let else_span = first.span.between(second.span);

        if let Some(else_snippet) = snippet_opt(cx, else_span) {
            if !else_snippet.contains('\n') {
                let (looks_like, next_thing) = if unsugar_if(second).is_some() {
                    ("an `else if`", "the second `if`")
                } else {
                    ("an `else {..}`", "the next block")
                };

                span_note_and_lint(
                    cx,
                    SUSPICIOUS_ELSE_FORMATTING,
                    else_span,
                    &format!("this looks like {} but the `else` is missing", looks_like),
                    else_span,
                    &format!(
                        "to remove this lint, add the missing `else` or add a new line before {}",
                        next_thing,
                    ),
                );
            }
        }
    }
}

fn is_block(expr: &ast::Expr) -> bool {
    if let ast::ExprKind::Block(..) = expr.node {
        true
    } else {
        false
    }
}

/// Match `if` or `if let` expressions and return the `then` and `else` block.
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
    match expr.node {
        ast::ExprKind::If(_, ref then, ref else_) | ast::ExprKind::IfLet(_, _, ref then, ref else_) => {
            Some((then, else_))
        },
        _ => None,
    }
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use std::collections::HashMap;
use std::char;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::visit::FnKind;
use utils::{constants, span_lint, span_help_and_lint, snippet, snippet_opt, span_lint_and_then};

/// **What it does:** Checks for structure field patterns bound to wildcards.
///
/// **Why is this bad?** Using `..` instead is shorter and leaves the focus on
/// the fields that are actually bound.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let { a: _, b: ref b, c: _ } = ..
/// ```
declare_lint! {
    pub UNNEEDED_FIELD_PATTERN,
    Warn,
    "struct fields bound to a wildcard instead of using `..`"
}

/// **What it does:** Checks for function arguments having the similar names
/// differing by an underscore.
///
/// **Why is this bad?** It affects code readability.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// fn foo(a: i32, _a: i32) {}
/// ```
declare_lint! {
    pub DUPLICATE_UNDERSCORE_ARGUMENT,
    Warn,
    "function arguments having names which only differ by an underscore"
}

/// **What it does:** Detects closures called in the same expression where they are defined.
///
/// **Why is this bad?** It is unnecessarily adding to the expression's complexity.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// (|| 42)()
/// ```
declare_lint! {
    pub REDUNDANT_CLOSURE_CALL,
    Warn,
    "throwaway closures called in the expression they are defined"
}

/// **What it does:** Detects expressions of the form `--x`.
///
/// **Why is this bad?** It can mislead C/C++ programmers to think `x` was
/// decremented.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// --x;
/// ```
declare_lint! {
    pub DOUBLE_NEG,
    Warn,
    "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++"
}

/// **What it does:** Warns on hexadecimal literals with mixed-case letter digits.
///
/// **Why is this bad?** It looks confusing.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let y = 0x1a9BAcD;
/// ```
declare_lint! {
    pub MIXED_CASE_HEX_LITERALS,
    Warn,
    "hex literals whose letter digits are not consistently upper- or lowercased"
}

/// **What it does:** Warns if literal suffixes are not separated by an underscore.
///
/// **Why is this bad?** It is much less readable.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let y = 123832i32;
/// ```
declare_lint! {
    pub UNSEPARATED_LITERAL_SUFFIX,
    Allow,
    "literals whose suffix is not separated by an underscore"
}

/// **What it does:** Warns if an integral constant literal starts with `0`.
///
/// **Why is this bad?** In some languages (including the infamous C language and most of its
/// familly), this marks an octal constant. In Rust however, this is a decimal constant. This could
/// be confusing for both the writer and a reader of the constant.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// In Rust:
/// ```rust
/// fn main() {
///     let a = 0123;
///     println!("{}", a);
/// }
/// ```
///
/// prints `123`, while in C:
///
/// ```c
/// #include <stdio.h>
///
/// int main() {
///     int a = 0123;
///     printf("%d\n", a);
/// }
/// ```
///
/// prints `83` (as `83 == 0o123` while `123 == 0o173`).
declare_lint! {
    pub ZERO_PREFIXED_LITERAL,
    Warn,
    "integer literals starting with `0`"
}

/// **What it does:** Warns if a generic shadows a built-in type.
///
/// **Why is this bad?** This gives surprising type errors.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// impl<u32> Foo<u32> {
///     fn impl_func(&self) -> u32 {
///         42
///     }
/// }
/// ```
declare_lint! {
    pub BUILTIN_TYPE_SHADOW,
    Warn,
    "shadowing a builtin type"
}

#[derive(Copy, Clone)]
pub struct MiscEarly;

impl LintPass for MiscEarly {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNNEEDED_FIELD_PATTERN,
                    DUPLICATE_UNDERSCORE_ARGUMENT,
                    REDUNDANT_CLOSURE_CALL,
                    DOUBLE_NEG,
                    MIXED_CASE_HEX_LITERALS,
                    UNSEPARATED_LITERAL_SUFFIX,
                    ZERO_PREFIXED_LITERAL,
                    BUILTIN_TYPE_SHADOW)
    }
}

impl EarlyLintPass for MiscEarly {
    fn check_generics(&mut self, cx: &EarlyContext, gen: &Generics) {
        for ty in &gen.ty_params {
            let name = ty.ident.name.as_str();
            if constants::BUILTIN_TYPES.contains(&&*name) {
                span_lint(cx,
                          BUILTIN_TYPE_SHADOW,
                          ty.span,
                          &format!("This generic shadows the built-in type `{}`", name));
            }
        }
    }

    fn check_pat(&mut self, cx: &EarlyContext, pat: &Pat) {
        if let PatKind::Struct(ref npat, ref pfields, _) = pat.node {
            let mut wilds = 0;
            let type_name = npat.segments.last().expect("A path must have at least one segment").identifier.name;

            for field in pfields {
                if field.node.pat.node == PatKind::Wild {
                    wilds += 1;
                }
            }
            if !pfields.is_empty() && wilds == pfields.len() {
                span_help_and_lint(cx,
                                   UNNEEDED_FIELD_PATTERN,
                                   pat.span,
                                   "All the struct fields are matched to a wildcard pattern, consider using `..`.",
                                   &format!("Try with `{} {{ .. }}` instead", type_name));
                return;
            }
            if wilds > 0 {
                let mut normal = vec![];

                for field in pfields {
                    if field.node.pat.node != PatKind::Wild {
                        if let Ok(n) = cx.sess().codemap().span_to_snippet(field.span) {
                            normal.push(n);
                        }
                    }
                }
                for field in pfields {
                    if field.node.pat.node == PatKind::Wild {
                        wilds -= 1;
                        if wilds > 0 {
                            span_lint(cx,
                                      UNNEEDED_FIELD_PATTERN,
                                      field.span,
                                      "You matched a field with a wildcard pattern. Consider using `..` instead");
                        } else {
                            span_help_and_lint(cx,
                                               UNNEEDED_FIELD_PATTERN,
                                               field.span,
                                               "You matched a field with a wildcard pattern. Consider using `..` \
                                                instead",
                                               &format!("Try with `{} {{ {}, .. }}`",
                                                        type_name,
                                                        normal[..].join(", ")));
                        }
                    }
                }
            }
        }
    }

    fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, decl: &FnDecl, _: Span, _: NodeId) {
        let mut registered_names: HashMap<String, Span> = HashMap::new();

        for arg in &decl.inputs {
            if let PatKind::Ident(_, sp_ident, None) = arg.pat.node {
                let arg_name = sp_ident.node.to_string();

                if arg_name.starts_with('_') {
                    if let Some(correspondence) = registered_names.get(&arg_name[1..]) {
                        span_lint(cx,
                                  DUPLICATE_UNDERSCORE_ARGUMENT,
                                  *correspondence,
                                  &format!("`{}` already exists, having another argument having almost the same \
                                            name makes code comprehension and documentation more difficult",
                                           arg_name[1..].to_owned()));;
                    }
                } else {
                    registered_names.insert(arg_name, arg.pat.span);
                }
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        match expr.node {
            ExprKind::Call(ref paren, _) => {
                if let ExprKind::Paren(ref closure) = paren.node {
                    if let ExprKind::Closure(_, ref decl, ref block, _) = closure.node {
                        span_lint_and_then(cx,
                                           REDUNDANT_CLOSURE_CALL,
                                           expr.span,
                                           "Try not to call a closure in the expression where it is declared.",
                                           |db| if decl.inputs.is_empty() {
                                               let hint = snippet(cx, block.span, "..").into_owned();
                                               db.span_suggestion(expr.span, "Try doing something like: ", hint);
                                           });
                    }
                }
            },
            ExprKind::Unary(UnOp::Neg, ref inner) => {
                if let ExprKind::Unary(UnOp::Neg, _) = inner.node {
                    span_lint(cx,
                              DOUBLE_NEG,
                              expr.span,
                              "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op");
                }
            },
            ExprKind::Lit(ref lit) => {
                if_let_chain! {[
                    let LitKind::Int(value, ..) = lit.node,
                    let Some(src) = snippet_opt(cx, lit.span),
                    let Some(firstch) = src.chars().next(),
                    char::to_digit(firstch, 10).is_some()
                ], {
                    let mut prev = '\0';
                    for ch in src.chars() {
                        if ch == 'i' || ch == 'u' {
                            if prev != '_' {
                                span_lint(cx, UNSEPARATED_LITERAL_SUFFIX, lit.span,
                                          "integer type suffix should be separated by an underscore");
                            }
                            break;
                        }
                        prev = ch;
                    }
                    if src.starts_with("0x") {
                        let mut seen = (false, false);
                        for ch in src.chars() {
                            match ch {
                                'a' ... 'f' => seen.0 = true,
                                'A' ... 'F' => seen.1 = true,
                                'i' | 'u'   => break,   // start of suffix already
                                _ => ()
                            }
                        }
                        if seen.0 && seen.1 {
                            span_lint(cx, MIXED_CASE_HEX_LITERALS, lit.span,
                                      "inconsistent casing in hexadecimal literal");
                        }
                    } else if src.starts_with("0b") || src.starts_with("0o") {
                        /* nothing to do */
                    } else if value != 0 && src.starts_with('0') {
                        span_lint_and_then(cx,
                                           ZERO_PREFIXED_LITERAL,
                                           lit.span,
                                           "this is a decimal constant",
                                           |db| {
                            db.span_suggestion(
                                lit.span,
                                "if you mean to use a decimal constant, remove the `0` to remove confusion:",
                                src[1..].to_string(),
                            );
                            /*db.span_suggestion(
                                lit.span,
                                "if you mean to use an octal constant, use `0o`:",
                                format!("0o{}", &src[1..]),
                            ); FIXME: rustc doesn't support multiple suggestions anymore */
                        });
                    }
                }}
                if_let_chain! {[
                    let LitKind::Float(..) = lit.node,
                    let Some(src) = snippet_opt(cx, lit.span),
                    let Some(firstch) = src.chars().next(),
                    char::to_digit(firstch, 10).is_some()
                ], {
                    let mut prev = '\0';
                    for ch in src.chars() {
                        if ch == 'f' {
                            if prev != '_' {
                                span_lint(cx, UNSEPARATED_LITERAL_SUFFIX, lit.span,
                                          "float type suffix should be separated by an underscore");
                            }
                            break;
                        }
                        prev = ch;
                    }
                }}
            },
            _ => (),
        }
    }

    fn check_block(&mut self, cx: &EarlyContext, block: &Block) {
        for w in block.stmts.windows(2) {
            if_let_chain! {[
                let StmtKind::Local(ref local) = w[0].node,
                let Option::Some(ref t) = local.init,
                let ExprKind::Closure(_, _, _, _) = t.node,
                let PatKind::Ident(_, sp_ident, _) = local.pat.node,
                let StmtKind::Semi(ref second) = w[1].node,
                let ExprKind::Assign(_, ref call) = second.node,
                let ExprKind::Call(ref closure, _) = call.node,
                let ExprKind::Path(_, ref path) = closure.node
            ], {
                if sp_ident.node == (&path.segments[0]).identifier {
                    span_lint(
                        cx,
                        REDUNDANT_CLOSURE_CALL,
                        second.span,
                        "Closure called just once immediately after it was declared",
                    );
                }
            }}
        }
    }
}
<commit_msg>Don't trigger some lints inside macros<commit_after>use rustc::lint::*;
use std::collections::HashMap;
use std::char;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::visit::FnKind;
use utils::{constants, span_lint, span_help_and_lint, snippet, snippet_opt, span_lint_and_then};

/// **What it does:** Checks for structure field patterns bound to wildcards.
///
/// **Why is this bad?** Using `..` instead is shorter and leaves the focus on
/// the fields that are actually bound.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let { a: _, b: ref b, c: _ } = ..
/// ```
declare_lint! {
    pub UNNEEDED_FIELD_PATTERN,
    Warn,
    "struct fields bound to a wildcard instead of using `..`"
}

/// **What it does:** Checks for function arguments having the similar names
/// differing by an underscore.
///
/// **Why is this bad?** It affects code readability.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// fn foo(a: i32, _a: i32) {}
/// ```
declare_lint! {
    pub DUPLICATE_UNDERSCORE_ARGUMENT,
    Warn,
    "function arguments having names which only differ by an underscore"
}

/// **What it does:** Detects closures called in the same expression where they are defined.
///
/// **Why is this bad?** It is unnecessarily adding to the expression's complexity.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// (|| 42)()
/// ```
declare_lint! {
    pub REDUNDANT_CLOSURE_CALL,
    Warn,
    "throwaway closures called in the expression they are defined"
}

/// **What it does:** Detects expressions of the form `--x`.
///
/// **Why is this bad?** It can mislead C/C++ programmers to think `x` was
/// decremented.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// --x;
/// ```
declare_lint! {
    pub DOUBLE_NEG,
    Warn,
    "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++"
}

/// **What it does:** Warns on hexadecimal literals with mixed-case letter digits.
///
/// **Why is this bad?** It looks confusing.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let y = 0x1a9BAcD;
/// ```
declare_lint! {
    pub MIXED_CASE_HEX_LITERALS,
    Warn,
    "hex literals whose letter digits are not consistently upper- or lowercased"
}

/// **What it does:** Warns if literal suffixes are not separated by an underscore.
///
/// **Why is this bad?** It is much less readable.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let y = 123832i32;
/// ```
declare_lint! {
    pub UNSEPARATED_LITERAL_SUFFIX,
    Allow,
    "literals whose suffix is not separated by an underscore"
}

/// **What it does:** Warns if an integral constant literal starts with `0`.
///
/// **Why is this bad?** In some languages (including the infamous C language and most of its
/// familly), this marks an octal constant. In Rust however, this is a decimal constant. This could
/// be confusing for both the writer and a reader of the constant.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// In Rust:
/// ```rust
/// fn main() {
///     let a = 0123;
///     println!("{}", a);
/// }
/// ```
///
/// prints `123`, while in C:
///
/// ```c
/// #include <stdio.h>
///
/// int main() {
///     int a = 0123;
///     printf("%d\n", a);
/// }
/// ```
///
/// prints `83` (as `83 == 0o123` while `123 == 0o173`).
declare_lint! {
    pub ZERO_PREFIXED_LITERAL,
    Warn,
    "integer literals starting with `0`"
}

/// **What it does:** Warns if a generic shadows a built-in type.
///
/// **Why is this bad?** This gives surprising type errors.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// impl<u32> Foo<u32> {
///     fn impl_func(&self) -> u32 {
///         42
///     }
/// }
/// ```
declare_lint! {
    pub BUILTIN_TYPE_SHADOW,
    Warn,
    "shadowing a builtin type"
}

#[derive(Copy, Clone)]
pub struct MiscEarly;

impl LintPass for MiscEarly {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNNEEDED_FIELD_PATTERN,
                    DUPLICATE_UNDERSCORE_ARGUMENT,
                    REDUNDANT_CLOSURE_CALL,
                    DOUBLE_NEG,
                    MIXED_CASE_HEX_LITERALS,
                    UNSEPARATED_LITERAL_SUFFIX,
                    ZERO_PREFIXED_LITERAL,
                    BUILTIN_TYPE_SHADOW)
    }
}

impl EarlyLintPass for MiscEarly {
    fn check_generics(&mut self, cx: &EarlyContext, gen: &Generics) {
        for ty in &gen.ty_params {
            let name = ty.ident.name.as_str();
            if constants::BUILTIN_TYPES.contains(&&*name) {
                span_lint(cx,
                          BUILTIN_TYPE_SHADOW,
                          ty.span,
                          &format!("This generic shadows the built-in type `{}`", name));
            }
        }
    }

    fn check_pat(&mut self, cx: &EarlyContext, pat: &Pat) {
        if let PatKind::Struct(ref npat, ref pfields, _) = pat.node {
            let mut wilds = 0;
            let type_name = npat.segments.last().expect("A path must have at least one segment").identifier.name;

            for field in pfields {
                if field.node.pat.node == PatKind::Wild {
                    wilds += 1;
                }
            }
            if !pfields.is_empty() && wilds == pfields.len() {
                span_help_and_lint(cx,
                                   UNNEEDED_FIELD_PATTERN,
                                   pat.span,
                                   "All the struct fields are matched to a wildcard pattern, consider using `..`.",
                                   &format!("Try with `{} {{ .. }}` instead", type_name));
                return;
            }
            if wilds > 0 {
                let mut normal = vec![];

                for field in pfields {
                    if field.node.pat.node != PatKind::Wild {
                        if let Ok(n) = cx.sess().codemap().span_to_snippet(field.span) {
                            normal.push(n);
                        }
                    }
                }
                for field in pfields {
                    if field.node.pat.node == PatKind::Wild {
                        wilds -= 1;
                        if wilds > 0 {
                            span_lint(cx,
                                      UNNEEDED_FIELD_PATTERN,
                                      field.span,
                                      "You matched a field with a wildcard pattern. Consider using `..` instead");
                        } else {
                            span_help_and_lint(cx,
                                               UNNEEDED_FIELD_PATTERN,
                                               field.span,
                                               "You matched a field with a wildcard pattern. Consider using `..` \
                                                instead",
                                               &format!("Try with `{} {{ {}, .. }}`",
                                                        type_name,
                                                        normal[..].join(", ")));
                        }
                    }
                }
            }
        }
    }

    fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, decl: &FnDecl, _: Span, _: NodeId) {
        let mut registered_names: HashMap<String, Span> = HashMap::new();

        for arg in &decl.inputs {
            if let PatKind::Ident(_, sp_ident, None) = arg.pat.node {
                let arg_name = sp_ident.node.to_string();

                if arg_name.starts_with('_') {
                    if let Some(correspondence) = registered_names.get(&arg_name[1..]) {
                        span_lint(cx,
                                  DUPLICATE_UNDERSCORE_ARGUMENT,
                                  *correspondence,
                                  &format!("`{}` already exists, having another argument having almost the same \
                                            name makes code comprehension and documentation more difficult",
                                           arg_name[1..].to_owned()));;
                    }
                } else {
                    registered_names.insert(arg_name, arg.pat.span);
                }
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        if in_external_macro(cx, expr.span) {
            return;
        }
        match expr.node {
            ExprKind::Call(ref paren, _) => {
                if let ExprKind::Paren(ref closure) = paren.node {
                    if let ExprKind::Closure(_, ref decl, ref block, _) = closure.node {
                        span_lint_and_then(cx,
                                           REDUNDANT_CLOSURE_CALL,
                                           expr.span,
                                           "Try not to call a closure in the expression where it is declared.",
                                           |db| if decl.inputs.is_empty() {
                                               let hint = snippet(cx, block.span, "..").into_owned();
                                               db.span_suggestion(expr.span, "Try doing something like: ", hint);
                                           });
                    }
                }
            },
            ExprKind::Unary(UnOp::Neg, ref inner) => {
                if let ExprKind::Unary(UnOp::Neg, _) = inner.node {
                    span_lint(cx,
                              DOUBLE_NEG,
                              expr.span,
                              "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op");
                }
            },
            ExprKind::Lit(ref lit) => {
                if_let_chain! {[
                    let LitKind::Int(value, ..) = lit.node,
                    let Some(src) = snippet_opt(cx, lit.span),
                    let Some(firstch) = src.chars().next(),
                    char::to_digit(firstch, 10).is_some()
                ], {
                    let mut prev = '\0';
                    for ch in src.chars() {
                        if ch == 'i' || ch == 'u' {
                            if prev != '_' {
                                span_lint(cx, UNSEPARATED_LITERAL_SUFFIX, lit.span,
                                          "integer type suffix should be separated by an underscore");
                            }
                            break;
                        }
                        prev = ch;
                    }
                    if src.starts_with("0x") {
                        let mut seen = (false, false);
                        for ch in src.chars() {
                            match ch {
                                'a' ... 'f' => seen.0 = true,
                                'A' ... 'F' => seen.1 = true,
                                'i' | 'u'   => break,   // start of suffix already
                                _ => ()
                            }
                        }
                        if seen.0 && seen.1 {
                            span_lint(cx, MIXED_CASE_HEX_LITERALS, lit.span,
                                      "inconsistent casing in hexadecimal literal");
                        }
                    } else if src.starts_with("0b") || src.starts_with("0o") {
                        /* nothing to do */
                    } else if value != 0 && src.starts_with('0') {
                        span_lint_and_then(cx,
                                           ZERO_PREFIXED_LITERAL,
                                           lit.span,
                                           "this is a decimal constant",
                                           |db| {
                            db.span_suggestion(
                                lit.span,
                                "if you mean to use a decimal constant, remove the `0` to remove confusion:",
                                src[1..].to_string(),
                            );
                            /*db.span_suggestion(
                                lit.span,
                                "if you mean to use an octal constant, use `0o`:",
                                format!("0o{}", &src[1..]),
                            ); FIXME: rustc doesn't support multiple suggestions anymore */
                        });
                    }
                }}
                if_let_chain! {[
                    let LitKind::Float(..) = lit.node,
                    let Some(src) = snippet_opt(cx, lit.span),
                    let Some(firstch) = src.chars().next(),
                    char::to_digit(firstch, 10).is_some()
                ], {
                    let mut prev = '\0';
                    for ch in src.chars() {
                        if ch == 'f' {
                            if prev != '_' {
                                span_lint(cx, UNSEPARATED_LITERAL_SUFFIX, lit.span,
                                          "float type suffix should be separated by an underscore");
                            }
                            break;
                        }
                        prev = ch;
                    }
                }}
            },
            _ => (),
        }
    }

    fn check_block(&mut self, cx: &EarlyContext, block: &Block) {
        for w in block.stmts.windows(2) {
            if_let_chain! {[
                let StmtKind::Local(ref local) = w[0].node,
                let Option::Some(ref t) = local.init,
                let ExprKind::Closure(_, _, _, _) = t.node,
                let PatKind::Ident(_, sp_ident, _) = local.pat.node,
                let StmtKind::Semi(ref second) = w[1].node,
                let ExprKind::Assign(_, ref call) = second.node,
                let ExprKind::Call(ref closure, _) = call.node,
                let ExprKind::Path(_, ref path) = closure.node
            ], {
                if sp_ident.node == (&path.segments[0]).identifier {
                    span_lint(
                        cx,
                        REDUNDANT_CLOSURE_CALL,
                        second.span,
                        "Closure called just once immediately after it was declared",
                    );
                }
            }}
        }
    }
}
<|endoftext|>


<commit_before>use core::num::{IntErrorKind, NonZeroI32, NonZeroI8, NonZeroU32, NonZeroU8};
use core::option::Option::{self, None, Some};
use std::mem::size_of;

#[test]
fn test_create_nonzero_instance() {
    let _a = unsafe { NonZeroU32::new_unchecked(21) };
}

#[test]
fn test_size_nonzero_in_option() {
    assert_eq!(size_of::<NonZeroU32>(), size_of::<Option<NonZeroU32>>());
    assert_eq!(size_of::<NonZeroI32>(), size_of::<Option<NonZeroI32>>());
}

#[test]
fn test_match_on_nonzero_option() {
    let a = Some(unsafe { NonZeroU32::new_unchecked(42) });
    match a {
        Some(val) => assert_eq!(val.get(), 42),
        None => panic!("unexpected None while matching on Some(NonZeroU32(_))"),
    }

    match unsafe { Some(NonZeroU32::new_unchecked(43)) } {
        Some(val) => assert_eq!(val.get(), 43),
        None => panic!("unexpected None while matching on Some(NonZeroU32(_))"),
    }
}

#[test]
fn test_match_option_empty_vec() {
    let a: Option<Vec<isize>> = Some(vec![]);
    match a {
        None => panic!("unexpected None while matching on Some(vec![])"),
        _ => {}
    }
}

#[test]
fn test_match_option_vec() {
    let a = Some(vec![1, 2, 3, 4]);
    match a {
        Some(v) => assert_eq!(v, [1, 2, 3, 4]),
        None => panic!("unexpected None while matching on Some(vec![1, 2, 3, 4])"),
    }
}

#[test]
fn test_match_option_rc() {
    use std::rc::Rc;

    let five = Rc::new(5);
    match Some(five) {
        Some(r) => assert_eq!(*r, 5),
        None => panic!("unexpected None while matching on Some(Rc::new(5))"),
    }
}

#[test]
fn test_match_option_arc() {
    use std::sync::Arc;

    let five = Arc::new(5);
    match Some(five) {
        Some(a) => assert_eq!(*a, 5),
        None => panic!("unexpected None while matching on Some(Arc::new(5))"),
    }
}

#[test]
fn test_match_option_empty_string() {
    let a = Some(String::new());
    match a {
        None => panic!("unexpected None while matching on Some(String::new())"),
        _ => {}
    }
}

#[test]
fn test_match_option_string() {
    let five = "Five".to_string();
    match Some(five) {
        Some(s) => assert_eq!(s, "Five"),
        None => panic!("unexpected None while matching on Some(String { ... })"),
    }
}

mod atom {
    use core::num::NonZeroU32;

    #[derive(PartialEq, Eq)]
    pub struct Atom {
        index: NonZeroU32, // private
    }
    pub const FOO_ATOM: Atom = Atom { index: unsafe { NonZeroU32::new_unchecked(7) } };
}

macro_rules! atom {
    ("foo") => {
        atom::FOO_ATOM
    };
}

#[test]
fn test_match_nonzero_const_pattern() {
    match atom!("foo") {
        // Using as a pattern is supported by the compiler:
        atom!("foo") => {}
        _ => panic!("Expected the const item as a pattern to match."),
    }
}

#[test]
fn test_from_nonzero() {
    let nz = NonZeroU32::new(1).unwrap();
    let num: u32 = nz.into();
    assert_eq!(num, 1u32);
}

#[test]
fn test_from_signed_nonzero() {
    let nz = NonZeroI32::new(1).unwrap();
    let num: i32 = nz.into();
    assert_eq!(num, 1i32);
}

#[test]
fn test_from_str() {
    assert_eq!("123".parse::<NonZeroU8>(), Ok(NonZeroU8::new(123).unwrap()));
    assert_eq!("0".parse::<NonZeroU8>().err().map(|e| e.kind().clone()), Some(IntErrorKind::Zero));
    assert_eq!(
        "-1".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
        Some(IntErrorKind::InvalidDigit)
    );
    assert_eq!(
        "-129".parse::<NonZeroI8>().err().map(|e| e.kind().clone()),
        Some(IntErrorKind::Underflow)
    );
    assert_eq!(
        "257".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
        Some(IntErrorKind::Overflow)
    );
}

#[test]
fn test_nonzero_bitor() {
    let nz_alt = NonZeroU8::new(0b1010_1010).unwrap();
    let nz_low = NonZeroU8::new(0b0000_1111).unwrap();

    let both_nz: NonZeroU8 = nz_alt | nz_low;
    assert_eq!(both_nz.get(), 0b1010_1111);

    let rhs_int: NonZeroU8 = nz_low | 0b1100_0000u8;
    assert_eq!(rhs_int.get(), 0b1100_1111);

    let rhs_zero: NonZeroU8 = nz_alt | 0u8;
    assert_eq!(rhs_zero.get(), 0b1010_1010);

    let lhs_int: NonZeroU8 = 0b0110_0110u8 | nz_alt;
    assert_eq!(lhs_int.get(), 0b1110_1110);

    let lhs_zero: NonZeroU8 = 0u8 | nz_low;
    assert_eq!(lhs_zero.get(), 0b0000_1111);
}

#[test]
fn test_nonzero_bitor_assign() {
    let mut target = NonZeroU8::new(0b1010_1010).unwrap();

    target |= NonZeroU8::new(0b0000_1111).unwrap();
    assert_eq!(target.get(), 0b1010_1111);

    target |= 0b0001_0000;
    assert_eq!(target.get(), 0b1011_1111);

    target |= 0;
    assert_eq!(target.get(), 0b1011_1111);
}
<commit_msg>Added tests for the implementations<commit_after>use core::num::{TryFromIntError, IntErrorKind, NonZeroI32, NonZeroI8, NonZeroU32, NonZeroU8};
use core::option::Option::{self, None, Some};
use std::mem::size_of;

#[test]
fn test_create_nonzero_instance() {
    let _a = unsafe { NonZeroU32::new_unchecked(21) };
}

#[test]
fn test_size_nonzero_in_option() {
    assert_eq!(size_of::<NonZeroU32>(), size_of::<Option<NonZeroU32>>());
    assert_eq!(size_of::<NonZeroI32>(), size_of::<Option<NonZeroI32>>());
}

#[test]
fn test_match_on_nonzero_option() {
    let a = Some(unsafe { NonZeroU32::new_unchecked(42) });
    match a {
        Some(val) => assert_eq!(val.get(), 42),
        None => panic!("unexpected None while matching on Some(NonZeroU32(_))"),
    }

    match unsafe { Some(NonZeroU32::new_unchecked(43)) } {
        Some(val) => assert_eq!(val.get(), 43),
        None => panic!("unexpected None while matching on Some(NonZeroU32(_))"),
    }
}

#[test]
fn test_match_option_empty_vec() {
    let a: Option<Vec<isize>> = Some(vec![]);
    match a {
        None => panic!("unexpected None while matching on Some(vec![])"),
        _ => {}
    }
}

#[test]
fn test_match_option_vec() {
    let a = Some(vec![1, 2, 3, 4]);
    match a {
        Some(v) => assert_eq!(v, [1, 2, 3, 4]),
        None => panic!("unexpected None while matching on Some(vec![1, 2, 3, 4])"),
    }
}

#[test]
fn test_match_option_rc() {
    use std::rc::Rc;

    let five = Rc::new(5);
    match Some(five) {
        Some(r) => assert_eq!(*r, 5),
        None => panic!("unexpected None while matching on Some(Rc::new(5))"),
    }
}

#[test]
fn test_match_option_arc() {
    use std::sync::Arc;

    let five = Arc::new(5);
    match Some(five) {
        Some(a) => assert_eq!(*a, 5),
        None => panic!("unexpected None while matching on Some(Arc::new(5))"),
    }
}

#[test]
fn test_match_option_empty_string() {
    let a = Some(String::new());
    match a {
        None => panic!("unexpected None while matching on Some(String::new())"),
        _ => {}
    }
}

#[test]
fn test_match_option_string() {
    let five = "Five".to_string();
    match Some(five) {
        Some(s) => assert_eq!(s, "Five"),
        None => panic!("unexpected None while matching on Some(String { ... })"),
    }
}

mod atom {
    use core::num::NonZeroU32;

    #[derive(PartialEq, Eq)]
    pub struct Atom {
        index: NonZeroU32, // private
    }
    pub const FOO_ATOM: Atom = Atom { index: unsafe { NonZeroU32::new_unchecked(7) } };
}

macro_rules! atom {
    ("foo") => {
        atom::FOO_ATOM
    };
}

#[test]
fn test_match_nonzero_const_pattern() {
    match atom!("foo") {
        // Using as a pattern is supported by the compiler:
        atom!("foo") => {}
        _ => panic!("Expected the const item as a pattern to match."),
    }
}

#[test]
fn test_from_nonzero() {
    let nz = NonZeroU32::new(1).unwrap();
    let num: u32 = nz.into();
    assert_eq!(num, 1u32);
}

#[test]
fn test_from_signed_nonzero() {
    let nz = NonZeroI32::new(1).unwrap();
    let num: i32 = nz.into();
    assert_eq!(num, 1i32);
}

#[test]
fn test_from_str() {
    assert_eq!("123".parse::<NonZeroU8>(), Ok(NonZeroU8::new(123).unwrap()));
    assert_eq!("0".parse::<NonZeroU8>().err().map(|e| e.kind().clone()), Some(IntErrorKind::Zero));
    assert_eq!(
        "-1".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
        Some(IntErrorKind::InvalidDigit)
    );
    assert_eq!(
        "-129".parse::<NonZeroI8>().err().map(|e| e.kind().clone()),
        Some(IntErrorKind::Underflow)
    );
    assert_eq!(
        "257".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
        Some(IntErrorKind::Overflow)
    );
}

#[test]
fn test_nonzero_bitor() {
    let nz_alt = NonZeroU8::new(0b1010_1010).unwrap();
    let nz_low = NonZeroU8::new(0b0000_1111).unwrap();

    let both_nz: NonZeroU8 = nz_alt | nz_low;
    assert_eq!(both_nz.get(), 0b1010_1111);

    let rhs_int: NonZeroU8 = nz_low | 0b1100_0000u8;
    assert_eq!(rhs_int.get(), 0b1100_1111);

    let rhs_zero: NonZeroU8 = nz_alt | 0u8;
    assert_eq!(rhs_zero.get(), 0b1010_1010);

    let lhs_int: NonZeroU8 = 0b0110_0110u8 | nz_alt;
    assert_eq!(lhs_int.get(), 0b1110_1110);

    let lhs_zero: NonZeroU8 = 0u8 | nz_low;
    assert_eq!(lhs_zero.get(), 0b0000_1111);
}

#[test]
fn test_nonzero_bitor_assign() {
    let mut target = NonZeroU8::new(0b1010_1010).unwrap();

    target |= NonZeroU8::new(0b0000_1111).unwrap();
    assert_eq!(target.get(), 0b1010_1111);

    target |= 0b0001_0000;
    assert_eq!(target.get(), 0b1011_1111);

    target |= 0;
    assert_eq!(target.get(), 0b1011_1111);
}

#[test]
fn test_nonzero_from_int_on_success() {
    assert_eq!(NonZeroU8::try_from(5), Ok(NonZeroU8::new(5)));
    assert_eq!(NonZeroU32::try_from(5), Ok(NonZeroU32::new(5)));

    assert_eq!(NonZeroI8::try_from(-5), Ok(NonZeroI8::new(-5)));
    assert_eq!(NonZeroI32::try_from(-5), Ok(NonZeroI32::new(-5)));
}

#[test]
fn test_nonzero_from_int_on_err() {
    assert_eq!(NonZeroU8::try_from(0), Err(TryFromIntError(())));
    assert_eq!(NonZeroU32::try_from(0), Err(TryFromIntError(())));

    assert_eq!(NonZeroI8::try_from(0), Err(TryFromIntError(())));
    assert_eq!(NonZeroI32::try_from(0), Err(TryFromIntError(())));
}
<|endoftext|>


<commit_before>#![feature(globs)]

extern crate graphics;
extern crate piston;
// extern crate sdl2_game_window;
extern crate glfw_game_window;

// use sdl2_game_window::WindowSDL2;
use glfw_game_window::WindowGLFW;
use piston::input::keyboard;
use piston::input::{
    Focus,
    Keyboard,
    Mouse,
    MouseCursor,
    MouseRelative,
    MouseScroll,
    Move,
    Press,
    Release,
    Resize,
    Text,
};
use piston::{
    Input,
    Render,
    Update
};

pub struct App {
    capture_cursor: bool
}

impl App {
    /// Creates a new application.
    pub fn new() -> App {
        App {
            capture_cursor: false
        }
    }

    fn key_press<W: piston::Window>(
        &mut self,
        window: &mut W,
        key: keyboard::Key
    ) {
        if key == keyboard::C {
            println!("Turned capture cursor on");
            self.capture_cursor = !self.capture_cursor;

            window.capture_cursor(self.capture_cursor);
        }

        println!("Pressed keyboard key '{}'", key);
    }
}

fn main() {
    let mut window = WindowGLFW::new(
        piston::shader_version::opengl::OpenGL_3_2,
        piston::WindowSettings {
            title: "Keycode".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    println!("Press C to turn capture cursor on/off");

    let mut app = App::new();
    let event_settings = piston::EventSettings {
            updates_per_second: 120,
            max_frames_per_second: 60,
        };
    for e in piston::EventIterator::new(&mut window, &event_settings) {
        match e {
            Input(Press(Keyboard(key))) =>
                app.key_press(&mut window, key),
            Input(Release(Keyboard(key))) =>
                println!("Released keyboard key '{}'", key),
            Input(Press(Mouse(button))) =>
                println!("Pressed mouse button '{}'", button),
            Input(Release(Mouse(button))) =>
                println!("Released mouse button '{}'", button),
            Input(Move(MouseCursor(x, y))) =>
                println!("Mouse moved '{} {}'", x, y),
            Input(Move(MouseScroll(dx, dy))) =>
                println!("Scrolled mouse '{}, {}'", dx, dy),
            Input(Move(MouseRelative(dx, dy))) =>
                println!("Relative mouse moved '{} {}'", dx, dy),
            Input(Text(text)) => println!("Typed '{}'", text),
            Input(Resize(w, h)) => println!("Resized '{}, {}'", w, h),
            Input(Focus(true)) => println!("Gained focus"),
            Input(Focus(false)) => println!("Lost focus"),
            Render(_) => {},
            Update(_) => {},
        }
    }
}

<commit_msg>Upgraded to latest Rust<commit_after>#![feature(globs)]

extern crate graphics;
extern crate piston;
// extern crate sdl2_game_window;
extern crate glfw_game_window;

// use sdl2_game_window::WindowSDL2;
use glfw_game_window::WindowGLFW;
use piston::input::keyboard;
use piston::input::{
    Focus,
    Keyboard,
    Mouse,
    MouseCursor,
    MouseRelative,
    MouseScroll,
    Move,
    Press,
    Release,
    Resize,
    Text,
};
use piston::{
    Input,
    Render,
    Update
};

pub struct App {
    capture_cursor: bool
}

impl App {
    /// Creates a new application.
    pub fn new() -> App {
        App {
            capture_cursor: false
        }
    }

    fn key_press<W: piston::Window>(
        &mut self,
        window: &mut W,
        key: keyboard::Key
    ) {
        if key == keyboard::C {
            println!("Turned capture cursor on");
            self.capture_cursor = !self.capture_cursor;

            window.capture_cursor(self.capture_cursor);
        }

        println!("Pressed keyboard key '{}'", key);
    }
}

fn main() {
    let mut window = WindowGLFW::new(
        piston::shader_version::opengl::OpenGL_3_2,
        piston::WindowSettings {
            title: "Keycode".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    println!("Press C to turn capture cursor on/off");

    let mut app = App::new();
    let event_settings = piston::EventSettings {
            updates_per_second: 120,
            max_frames_per_second: 60,
        };
    let mut event_iter = piston::EventIterator::new(&mut window, &event_settings);
    loop {
        let e = match event_iter.next() {
                None => { break; }
                Some(e) => e
            };

        match e {
            Input(Press(Keyboard(key))) =>
                app.key_press(event_iter.window, key),
            Input(Release(Keyboard(key))) =>
                println!("Released keyboard key '{}'", key),
            Input(Press(Mouse(button))) =>
                println!("Pressed mouse button '{}'", button),
            Input(Release(Mouse(button))) =>
                println!("Released mouse button '{}'", button),
            Input(Move(MouseCursor(x, y))) =>
                println!("Mouse moved '{} {}'", x, y),
            Input(Move(MouseScroll(dx, dy))) =>
                println!("Scrolled mouse '{}, {}'", dx, dy),
            Input(Move(MouseRelative(dx, dy))) =>
                println!("Relative mouse moved '{} {}'", dx, dy),
            Input(Text(text)) => println!("Typed '{}'", text),
            Input(Resize(w, h)) => println!("Resized '{}, {}'", w, h),
            Input(Focus(true)) => println!("Gained focus"),
            Input(Focus(false)) => println!("Lost focus"),
            Render(_) => {},
            Update(_) => {},
        }
    }
}

<|endoftext|>


<commit_before>//! The `wasm32-wasi` target is a new and still (as of April 2019) an
//! experimental target. The definition in this file is likely to be tweaked
//! over time and shouldn't be relied on too much.
//!
//! The `wasi` target is a proposal to define a standardized set of syscalls
//! that WebAssembly files can interoperate with. This set of syscalls is
//! intended to empower WebAssembly binaries with native capabilities such as
//! filesystem access, network access, etc.
//!
//! You can see more about the proposal at https://wasi.dev
//!
//! The Rust target definition here is interesting in a few ways. We want to
//! serve two use cases here with this target:
//!
//! * First, we want Rust usage of the target to be as hassle-free as possible,
//!   ideally avoiding the need to configure and install a local wasm32-wasi
//!   toolchain.
//!
//! * Second, one of the primary use cases of LLVM's new wasm backend and the
//!   wasm support in LLD is that any compiled language can interoperate with
//!   any other. To that the `wasm32-wasi` target is the first with a viable C
//!   standard library and sysroot common definition, so we want Rust and C/C++
//!   code to interoperate when compiled to `wasm32-unknown-unknown`.
//!
//! You'll note, however, that the two goals above are somewhat at odds with one
//! another. To attempt to solve both use cases in one go we define a target
//! that (ab)uses the `crt-static` target feature to indicate which one you're
//! in.
//!
//! ## No interop with C required
//!
//! By default the `crt-static` target feature is enabled, and when enabled
//! this means that the the bundled version of `libc.a` found in `liblibc.rlib`
//! is used. This isn't intended really for interoperation with a C because it
//! may be the case that Rust's bundled C library is incompatible with a
//! foreign-compiled C library. In this use case, though, we use `rust-lld` and
//! some copied crt startup object files to ensure that you can download the
//! wasi target for Rust and you're off to the races, no further configuration
//! necessary.
//!
//! All in all, by default, no external dependencies are required. You can
//! compile `wasm32-wasi` binaries straight out of the box. You can't, however,
//! reliably interoperate with C code in this mode (yet).
//!
//! ## Interop with C required
//!
//! For the second goal we repurpose the `target-feature` flag, meaning that
//! you'll need to do a few things to have C/Rust code interoperate.
//!
//! 1. All Rust code needs to be compiled with `-C target-feature=-crt-static`,
//!    indicating that the bundled C standard library in the Rust sysroot will
//!    not be used.
//!
//! 2. If you're using rustc to build a linked artifact then you'll need to
//!    specify `-C linker` to a `clang` binary that supports
//!    `wasm32-wasi` and is configured with the `wasm32-wasi` sysroot. This
//!    will cause Rust code to be linked against the libc.a that the specified
//!    `clang` provides.
//!
//! 3. If you're building a staticlib and integrating Rust code elsewhere, then
//!    compiling with `-C target-feature=-crt-static` is all you need to do.
//!
//! You can configure the linker via Cargo using the
//! `CARGO_TARGET_WASM32_WASI_LINKER` env var. Be sure to also set
//! `CC_wasm32-wasi` if any crates in the dependency graph are using the `cc`
//! crate.
//!
//! ## Remember, this is all in flux
//!
//! The wasi target is **very** new in its specification. It's likely going to
//! be a long effort to get it standardized and stable. We'll be following it as
//! best we can with this target. Don't start relying on too much here unless
//! you know what you're getting in to!

use super::wasm32_base;
use super::{LinkerFlavor, LldFlavor, Target};

pub fn target() -> Result<Target, String> {
    let mut options = wasm32_base::options();

    options
        .pre_link_args
        .entry(LinkerFlavor::Gcc)
        .or_insert(Vec::new())
        .push("--target=wasm32-wasi".to_string());

    // When generating an executable be sure to put the startup object at the
    // front so the main function is correctly hooked up.
    options.pre_link_objects_exe_crt.push("crt1.o".to_string());

    // Right now this is a bit of a workaround but we're currently saying that
    // the target by default has a static crt which we're taking as a signal
    // for "use the bundled crt". If that's turned off then the system's crt
    // will be used, but this means that default usage of this target doesn't
    // need an external compiler but it's still interoperable with an external
    // compiler if configured correctly.
    options.crt_static_default = true;
    options.crt_static_respected = true;

    Ok(Target {
        llvm_target: "wasm32-wasi".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "wasi".to_string(),
        target_env: String::new(),
        target_vendor: String::new(),
        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
        arch: "wasm32".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Wasm),
        options,
    })
}
<commit_msg>rustc: Allow the cdylib crate type with wasm32-wasi<commit_after>//! The `wasm32-wasi` target is a new and still (as of April 2019) an
//! experimental target. The definition in this file is likely to be tweaked
//! over time and shouldn't be relied on too much.
//!
//! The `wasi` target is a proposal to define a standardized set of syscalls
//! that WebAssembly files can interoperate with. This set of syscalls is
//! intended to empower WebAssembly binaries with native capabilities such as
//! filesystem access, network access, etc.
//!
//! You can see more about the proposal at https://wasi.dev
//!
//! The Rust target definition here is interesting in a few ways. We want to
//! serve two use cases here with this target:
//!
//! * First, we want Rust usage of the target to be as hassle-free as possible,
//!   ideally avoiding the need to configure and install a local wasm32-wasi
//!   toolchain.
//!
//! * Second, one of the primary use cases of LLVM's new wasm backend and the
//!   wasm support in LLD is that any compiled language can interoperate with
//!   any other. To that the `wasm32-wasi` target is the first with a viable C
//!   standard library and sysroot common definition, so we want Rust and C/C++
//!   code to interoperate when compiled to `wasm32-unknown-unknown`.
//!
//! You'll note, however, that the two goals above are somewhat at odds with one
//! another. To attempt to solve both use cases in one go we define a target
//! that (ab)uses the `crt-static` target feature to indicate which one you're
//! in.
//!
//! ## No interop with C required
//!
//! By default the `crt-static` target feature is enabled, and when enabled
//! this means that the the bundled version of `libc.a` found in `liblibc.rlib`
//! is used. This isn't intended really for interoperation with a C because it
//! may be the case that Rust's bundled C library is incompatible with a
//! foreign-compiled C library. In this use case, though, we use `rust-lld` and
//! some copied crt startup object files to ensure that you can download the
//! wasi target for Rust and you're off to the races, no further configuration
//! necessary.
//!
//! All in all, by default, no external dependencies are required. You can
//! compile `wasm32-wasi` binaries straight out of the box. You can't, however,
//! reliably interoperate with C code in this mode (yet).
//!
//! ## Interop with C required
//!
//! For the second goal we repurpose the `target-feature` flag, meaning that
//! you'll need to do a few things to have C/Rust code interoperate.
//!
//! 1. All Rust code needs to be compiled with `-C target-feature=-crt-static`,
//!    indicating that the bundled C standard library in the Rust sysroot will
//!    not be used.
//!
//! 2. If you're using rustc to build a linked artifact then you'll need to
//!    specify `-C linker` to a `clang` binary that supports
//!    `wasm32-wasi` and is configured with the `wasm32-wasi` sysroot. This
//!    will cause Rust code to be linked against the libc.a that the specified
//!    `clang` provides.
//!
//! 3. If you're building a staticlib and integrating Rust code elsewhere, then
//!    compiling with `-C target-feature=-crt-static` is all you need to do.
//!
//! You can configure the linker via Cargo using the
//! `CARGO_TARGET_WASM32_WASI_LINKER` env var. Be sure to also set
//! `CC_wasm32-wasi` if any crates in the dependency graph are using the `cc`
//! crate.
//!
//! ## Remember, this is all in flux
//!
//! The wasi target is **very** new in its specification. It's likely going to
//! be a long effort to get it standardized and stable. We'll be following it as
//! best we can with this target. Don't start relying on too much here unless
//! you know what you're getting in to!

use super::wasm32_base;
use super::{LinkerFlavor, LldFlavor, Target};

pub fn target() -> Result<Target, String> {
    let mut options = wasm32_base::options();

    options
        .pre_link_args
        .entry(LinkerFlavor::Gcc)
        .or_insert(Vec::new())
        .push("--target=wasm32-wasi".to_string());

    // When generating an executable be sure to put the startup object at the
    // front so the main function is correctly hooked up.
    options.pre_link_objects_exe_crt.push("crt1.o".to_string());

    // Right now this is a bit of a workaround but we're currently saying that
    // the target by default has a static crt which we're taking as a signal
    // for "use the bundled crt". If that's turned off then the system's crt
    // will be used, but this means that default usage of this target doesn't
    // need an external compiler but it's still interoperable with an external
    // compiler if configured correctly.
    options.crt_static_default = true;
    options.crt_static_respected = true;

    // Allow `+crt-static` to create a "cdylib" output which is just a wasm file
    // without a main function.
    options.crt_static_allows_dylibs = true;

    Ok(Target {
        llvm_target: "wasm32-wasi".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "wasi".to_string(),
        target_env: String::new(),
        target_vendor: String::new(),
        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
        arch: "wasm32".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Wasm),
        options,
    })
}
<|endoftext|>