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

// This is a regression test for exonum configuration.
#[macro_use]
extern crate pretty_assertions;
extern crate toml;
extern crate exonum;

use std::ffi::OsString;
use std::fs::File;
use std::fs;
use std::panic;
use std::io::Read;

use exonum::helpers::fabric::NodeBuilder;

const CONFIG_TMP_FOLDER: &str = "/tmp/";
const CONFIG_TESTDATA_FOLDER: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/testdata/config/");

const GENERATED_TEMPLATE: &str = "template.toml";

const SEC_CONFIG: [&str; 4] =
    ["config0_sec.toml", "config1_sec.toml", "config2_sec.toml", "config3_sec.toml"];

const PUB_CONFIG: [&str; 4] =
    ["config0_pub.toml", "config1_pub.toml", "config2_pub.toml", "config3_pub.toml"];

fn full_tmp_folder(folder: &str) -> String {
    format!("{}exonum-test-{}/", CONFIG_TMP_FOLDER, folder)
}

fn full_tmp_name(filename: &str, folder: &str) -> String {
    format!("{}{}", full_tmp_folder(folder), filename)
}

fn full_testdata_name(filename: &str) -> String {
    format!("{}{}", CONFIG_TESTDATA_FOLDER, filename)
}

fn compare_files(filename: &str, folder: &str) {
    let source = full_testdata_name(filename);
    let destination = full_tmp_name(filename, folder);

    let mut source = File::open(source).unwrap();
    let mut destination = File::open(destination).unwrap();

    let mut source_buffer = String::new();
    let mut destination_buffer = String::new();

    let len = source.read_to_string(&mut source_buffer).unwrap();
    destination.read_to_string(&mut destination_buffer).unwrap();

    assert!(len > 0);
    let source_toml: toml::Value = toml::de::from_str(&source_buffer).unwrap();
    let destination_toml: toml::Value = toml::de::from_str(&destination_buffer).unwrap();
    assert_eq!(source_toml, destination_toml);
}

fn default_run_with_matches<I, T>(iter: I) -> bool
where
    I: IntoIterator<Item = T>,
    T: Into<OsString> + Clone,
{
    let builder = NodeBuilder::new();
    builder.parse_cmd_string(iter)
}

fn generate_template(folder: &str) {
    assert!(!default_run_with_matches(vec![
        "exonum-config-test",
        "generate-template",
        &full_tmp_name(GENERATED_TEMPLATE, folder),
    ]));

}

fn generate_config(folder: &str, i: usize) {
    assert!(!default_run_with_matches(vec![
        "exonum-config-test",
        "generate-config",
        &full_testdata_name(GENERATED_TEMPLATE),
        &full_tmp_name(PUB_CONFIG[i], folder),
        &full_tmp_name(SEC_CONFIG[i], folder),
        "-a",
        "127.0.0.1",
    ]));
}

#[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))]
fn finalize_config(folder: &str, config: &str, i: usize, count: usize) {

    let mut variables = vec![
        "exonum-config-test".to_owned(),
        "finalize".to_owned(),
        full_testdata_name(SEC_CONFIG[i]),
        full_tmp_name(config, folder),
        "-p".to_owned(),
    ];
    for n in 0..count {
        variables.push(full_testdata_name(PUB_CONFIG[n]));
    }
    println!("{:?}", variables);
    assert!(!default_run_with_matches(variables));
}

fn run_node(config: &str, folder: &str) {
    assert!(default_run_with_matches(vec![
        "exonum-config-test",
        "run",
        "-c",
        &full_testdata_name(config),
        "-d",
        &full_tmp_folder(folder),
    ]));
}

#[test]
fn test_generate_template() {
    let command = "generate-template";

    let result = panic::catch_unwind(|| {
        generate_template(command);
        compare_files(GENERATED_TEMPLATE, command);
    });

    fs::remove_dir_all(full_tmp_folder(command)).unwrap();

    if let Err(err) = result {
        panic::resume_unwind(err);
    }
}

#[test]
#[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))]
fn test_generate_config() {
    let command = "generate-config";

    let result = panic::catch_unwind(|| for i in 0..PUB_CONFIG.len() {
        generate_config(command, i);
    });

    fs::remove_dir_all(full_tmp_folder(command)).unwrap();

    if let Err(err) = result {
        panic::resume_unwind(err);
    }
}

#[test]
#[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))]
fn test_generate_full_config_run() {
    let command = "finalize";
    let result = panic::catch_unwind(|| {
        for i in 0..PUB_CONFIG.len() {
            for n in 0..PUB_CONFIG.len() + 1 {
                println!("{} {}", i, n);
                let config = format!("config{}{}.toml", i, n);
                let result = panic::catch_unwind(|| {
                    finalize_config(command, &config, i, n);
                    compare_files(&config, command);
                    run_node(&config, command);
                });

                // if we trying to create config,
                // without our config, this is a problem
                if n <= i || n == 0 {
                    assert!(result.is_err());
                } else {
                    assert!(result.is_ok());
                }
            }

        }
    });

    fs::remove_dir_all(full_tmp_folder(command)).unwrap();

    if let Err(err) = result {
        panic::resume_unwind(err);
    }
}
<commit_msg>Add tests for RunDev command<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This is a regression test for exonum configuration.
#[macro_use]
extern crate pretty_assertions;
extern crate toml;
extern crate exonum;

use std::ffi::OsString;
use std::fs::{File, OpenOptions};
use std::fs;
use std::path::Path;
use std::panic;
use std::io::Read;

use exonum::helpers::fabric::NodeBuilder;

const CONFIG_TMP_FOLDER: &str = "/tmp/";
const CONFIG_TESTDATA_FOLDER: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/testdata/config/");

const GENERATED_TEMPLATE: &str = "template.toml";

const SEC_CONFIG: [&str; 4] =
    ["config0_sec.toml", "config1_sec.toml", "config2_sec.toml", "config3_sec.toml"];

const PUB_CONFIG: [&str; 4] =
    ["config0_pub.toml", "config1_pub.toml", "config2_pub.toml", "config3_pub.toml"];

fn full_tmp_folder(folder: &str) -> String {
    format!("{}exonum-test-{}/", CONFIG_TMP_FOLDER, folder)
}

fn full_tmp_name(filename: &str, folder: &str) -> String {
    format!("{}{}", full_tmp_folder(folder), filename)
}

fn full_testdata_name(filename: &str) -> String {
    format!("{}{}", CONFIG_TESTDATA_FOLDER, filename)
}

fn touch(path: &str) {
    OpenOptions::new()
        .create(true)
        .write(true)
        .open(path)
        .unwrap();
}

fn compare_files(filename: &str, folder: &str) {
    let source = full_testdata_name(filename);
    let destination = full_tmp_name(filename, folder);

    let mut source = File::open(source).unwrap();
    let mut destination = File::open(destination).unwrap();

    let mut source_buffer = String::new();
    let mut destination_buffer = String::new();

    let len = source.read_to_string(&mut source_buffer).unwrap();
    destination.read_to_string(&mut destination_buffer).unwrap();

    assert!(len > 0);
    let source_toml: toml::Value = toml::de::from_str(&source_buffer).unwrap();
    let destination_toml: toml::Value = toml::de::from_str(&destination_buffer).unwrap();
    assert_eq!(source_toml, destination_toml);
}

fn default_run_with_matches<I, T>(iter: I) -> bool
where
    I: IntoIterator<Item = T>,
    T: Into<OsString> + Clone,
{
    let builder = NodeBuilder::new();
    builder.parse_cmd_string(iter)
}

fn generate_template(folder: &str) {
    assert!(!default_run_with_matches(vec![
        "exonum-config-test",
        "generate-template",
        &full_tmp_name(GENERATED_TEMPLATE, folder),
    ]));

}

fn generate_config(folder: &str, i: usize) {
    assert!(!default_run_with_matches(vec![
        "exonum-config-test",
        "generate-config",
        &full_testdata_name(GENERATED_TEMPLATE),
        &full_tmp_name(PUB_CONFIG[i], folder),
        &full_tmp_name(SEC_CONFIG[i], folder),
        "-a",
        "127.0.0.1",
    ]));
}

#[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))]
fn finalize_config(folder: &str, config: &str, i: usize, count: usize) {

    let mut variables = vec![
        "exonum-config-test".to_owned(),
        "finalize".to_owned(),
        full_testdata_name(SEC_CONFIG[i]),
        full_tmp_name(config, folder),
        "-p".to_owned(),
    ];
    for n in 0..count {
        variables.push(full_testdata_name(PUB_CONFIG[n]));
    }
    println!("{:?}", variables);
    assert!(!default_run_with_matches(variables));
}

fn run_node(config: &str, folder: &str) {
    assert!(default_run_with_matches(vec![
        "exonum-config-test",
        "run",
        "-c",
        &full_testdata_name(config),
        "-d",
        &full_tmp_folder(folder),
    ]));
}

fn run_dev(folder: &str) {
    assert!(default_run_with_matches(vec![
        "exonum-config-test",
        "run-dev",
        "-a",
        &full_tmp_folder(folder),
    ]));
}

#[test]
fn test_generate_template() {
    let command = "generate-template";

    let result = panic::catch_unwind(|| {
        generate_template(command);
        compare_files(GENERATED_TEMPLATE, command);
    });

    fs::remove_dir_all(full_tmp_folder(command)).unwrap();

    if let Err(err) = result {
        panic::resume_unwind(err);
    }
}

#[test]
#[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))]
fn test_generate_config() {
    let command = "generate-config";

    let result = panic::catch_unwind(|| for i in 0..PUB_CONFIG.len() {
        generate_config(command, i);
    });

    fs::remove_dir_all(full_tmp_folder(command)).unwrap();

    if let Err(err) = result {
        panic::resume_unwind(err);
    }
}

#[test]
#[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))]
fn test_generate_full_config_run() {
    let command = "finalize";
    let result = panic::catch_unwind(|| {
        for i in 0..PUB_CONFIG.len() {
            for n in 0..PUB_CONFIG.len() + 1 {
                println!("{} {}", i, n);
                let config = format!("config{}{}.toml", i, n);
                let result = panic::catch_unwind(|| {
                    finalize_config(command, &config, i, n);
                    compare_files(&config, command);
                    run_node(&config, command);
                });

                // if we trying to create config,
                // without our config, this is a problem
                if n <= i || n == 0 {
                    assert!(result.is_err());
                } else {
                    assert!(result.is_ok());
                }
            }

        }
    });

    fs::remove_dir_all(full_tmp_folder(command)).unwrap();

    if let Err(err) = result {
        panic::resume_unwind(err);
    }
}

#[test]
fn test_run_dev() {
    let artifacts_dir = ".exonum";
    let db_dir = format!("{}/{}", artifacts_dir, "db");
    let full_db_dir = full_tmp_folder(&db_dir);

    fs::create_dir_all(Path::new(&full_db_dir)).expect("Expected db temp folder to be created.");
    let old_db_file = full_tmp_name("1", &db_dir);
    touch(&old_db_file);

    let result = panic::catch_unwind(|| { run_dev(artifacts_dir); });

    if let Err(err) = result {
        panic::resume_unwind(err);
    }

    // Test cleaning up.
    assert!(!Path::new(&old_db_file).exists());
    fs::remove_dir_all(full_tmp_folder(artifacts_dir)).unwrap();
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate futures;
extern crate rayon;
extern crate tokio_core;
extern crate test;

use futures::Future;
use rayon::iter::ParallelIterator;
use rayon::iter::IntoParallelIterator;

fn main() {
    let noprogress = rayon::spawn_future_async(futures::future::lazy(move || {
        Ok((0..(0u64).wrapping_sub(1)).into_par_iter().reduce(|| 0u64, |x, y|
            // without black_box, LLVM optimizes away the parallel iterator and returns 9223372036854775809
            test::black_box(x.wrapping_add(y))))
    })).map_err(|()| /* type inference hack */ ());
    let progress = futures::future::ok(42);
    let mut core = tokio_core::reactor::Core::new().unwrap();
    println!("{:?}", core.run(noprogress.select(progress).map(|(res, _selectnext)| res).map_err(|(err, _selectnext)| err)).unwrap());
    // Expected: 100% chance of instant "42", barring pathological custom schedulers
    // Actual: 50% chance of instant "42", 50% chance of 100% CPU usage across all cores doing number crunching
}
<commit_msg>Updated rayon_test with workaround / more insight.<commit_after>#![feature(test)]
extern crate futures;
extern crate rayon;
extern crate tokio_core;
extern crate test;

use futures::{Future, Stream, Sink};
use rayon::iter::ParallelIterator;
use rayon::iter::IntoParallelIterator;

fn buggy() {
    let noprogress = rayon::spawn_future_async(futures::future::lazy(move || {
     Ok((0..(0u64).wrapping_sub(1)).into_par_iter().reduce(|| 0u64, |x, y|
         // without black_box, LLVM optimizes away the parallel iterator and returns 9223372036854775809
         test::black_box(x.wrapping_add(y))))
    })).map_err(|()| /* type inference hack */ ());
    let progress = futures::future::ok(42);
    let mut core = tokio_core::reactor::Core::new().unwrap();
    println!("{:?}", core.run(noprogress.select(progress).map(|(res, _selectnext)| res).map_err(|(err, _selectnext)| err)).unwrap());
    // Expected: 100% chance of instant "42", barring pathological custom schedulers
    // Actual: 50% chance of instant "42", 50% chance of 100% CPU usage across all cores doing number crunching
}

fn working() {
    let (send, recv) = futures::sync::mpsc::channel(10);
    let noprogress = rayon::spawn_future_async(futures::future::lazy(move || {
        Ok((0..(0u64).wrapping_sub(1)).into_par_iter().reduce(|| 0u64, |x, y|
            // without black_box, LLVM optimizes away the parallel iterator and returns 9223372036854775809
            test::black_box(x.wrapping_add(y))))
    }).and_then(|res| send.send(res)));
    let progress = futures::future::ok(42);
    rayon::spawn_async(move || { let _ = noprogress.rayon_wait(); }); // this feels kind of hacky_redundant
    let mut core = tokio_core::reactor::Core::new().unwrap();
    println!("{:?}", core.run(recv.into_future().map(|(a, _)| a.unwrap()).select(progress).map(|(res, _selectnext)| res).map_err(|(err, _selectnext)| err)).unwrap());
}

fn main() {
    // strangely, "buggy" seems to work correctly if "working" is run first, but has the 50% behavior if "working" is commented out, or if the order is swapped. maybe it's an initialization thing?
    working();
    println!("-----");
    buggy();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate image;

#[allow(unused_imports)]
use glium::{glutin, Surface};
use glium::index::PrimitiveType;

fn main() {
    // building the display, ie. the main object
    let event_loop = glutin::event_loop::EventLoop::new();
    let wb = glutin::window::WindowBuilder::new().with_visible(false);
    let cb = glutin::ContextBuilder::new();
    let display = glium::Display::new(wb, cb, &event_loop).unwrap();

    // building the vertex buffer, which contains all the vertices that we will draw
    let vertex_buffer = {
        #[derive(Copy, Clone)]
        struct Vertex {
            position: [f32; 2],
            color: [f32; 3],
        }

        implement_vertex!(Vertex, position, color);

        glium::VertexBuffer::new(&display,
            &[
                Vertex { position: [-0.5, -0.5], color: [0.0, 1.0, 0.0] },
                Vertex { position: [ 0.0,  0.5], color: [0.0, 0.0, 1.0] },
                Vertex { position: [ 0.5, -0.5], color: [1.0, 0.0, 0.0] },
            ]
        ).unwrap()
    };

    // building the index buffer
    let index_buffer = glium::IndexBuffer::new(&display, PrimitiveType::TrianglesList,
                                               &[0u16, 1, 2]).unwrap();

    // compiling shaders and linking them together
    let program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 matrix;

                in vec2 position;
                in vec3 color;

                out vec3 vColor;

                void main() {
                    gl_Position = vec4(position, 0.0, 1.0) * matrix;
                    vColor = color;
                }
            ",

            fragment: "
                #version 140
                in vec3 vColor;
                out vec4 f_color;

                void main() {
                    f_color = vec4(vColor, 1.0);
                }
            "
        },

        110 => {
            vertex: "
                #version 110

                uniform mat4 matrix;

                attribute vec2 position;
                attribute vec3 color;

                varying vec3 vColor;

                void main() {
                    gl_Position = vec4(position, 0.0, 1.0) * matrix;
                    vColor = color;
                }
            ",

            fragment: "
                #version 110
                varying vec3 vColor;

                void main() {
                    gl_FragColor = vec4(vColor, 1.0);
                }
            ",
        },
    ).unwrap();

    // drawing once

    // building the uniforms
    let uniforms = uniform! {
        matrix: [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0, 1.0f32]
        ]
    };

    // drawing a frame
    let mut target = display.draw();
    target.clear_color(0.0, 0.0, 0.0, 0.0);
    target.draw(&vertex_buffer, &index_buffer, &program, &uniforms, &Default::default()).unwrap();
    target.finish().unwrap();

    // reading the front buffer into an image
    let image: glium::texture::RawImage2d<u8> = display.read_front_buffer().unwrap();
    let image = image::ImageBuffer::from_raw(image.width, image.height, image.data.into_owned()).unwrap();
    let image = image::DynamicImage::ImageRgba8(image).flipv();
    image.save("glium-example-screenshot.png").unwrap();
}
<commit_msg>Make window used for screenshot visible<commit_after>#[macro_use]
extern crate glium;
extern crate image;

#[allow(unused_imports)]
use glium::{glutin, Surface};
use glium::index::PrimitiveType;

fn main() {
    // building the display, ie. the main object
    let event_loop = glutin::event_loop::EventLoop::new();
    let wb = glutin::window::WindowBuilder::new().with_visible(true);
    let cb = glutin::ContextBuilder::new();
    let display = glium::Display::new(wb, cb, &event_loop).unwrap();

    // building the vertex buffer, which contains all the vertices that we will draw
    let vertex_buffer = {
        #[derive(Copy, Clone)]
        struct Vertex {
            position: [f32; 2],
            color: [f32; 3],
        }

        implement_vertex!(Vertex, position, color);

        glium::VertexBuffer::new(&display,
            &[
                Vertex { position: [-0.5, -0.5], color: [0.0, 1.0, 0.0] },
                Vertex { position: [ 0.0,  0.5], color: [0.0, 0.0, 1.0] },
                Vertex { position: [ 0.5, -0.5], color: [1.0, 0.0, 0.0] },
            ]
        ).unwrap()
    };

    // building the index buffer
    let index_buffer = glium::IndexBuffer::new(&display, PrimitiveType::TrianglesList,
                                               &[0u16, 1, 2]).unwrap();

    // compiling shaders and linking them together
    let program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 matrix;

                in vec2 position;
                in vec3 color;

                out vec3 vColor;

                void main() {
                    gl_Position = vec4(position, 0.0, 1.0) * matrix;
                    vColor = color;
                }
            ",

            fragment: "
                #version 140
                in vec3 vColor;
                out vec4 f_color;

                void main() {
                    f_color = vec4(vColor, 1.0);
                }
            "
        },

        110 => {
            vertex: "
                #version 110

                uniform mat4 matrix;

                attribute vec2 position;
                attribute vec3 color;

                varying vec3 vColor;

                void main() {
                    gl_Position = vec4(position, 0.0, 1.0) * matrix;
                    vColor = color;
                }
            ",

            fragment: "
                #version 110
                varying vec3 vColor;

                void main() {
                    gl_FragColor = vec4(vColor, 1.0);
                }
            ",
        },
    ).unwrap();

    // drawing once

    // building the uniforms
    let uniforms = uniform! {
        matrix: [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0, 1.0f32]
        ]
    };

    // drawing a frame
    let mut target = display.draw();
    target.clear_color(0.0, 0.0, 0.0, 0.0);
    target.draw(&vertex_buffer, &index_buffer, &program, &uniforms, &Default::default()).unwrap();
    target.finish().unwrap();

    // reading the front buffer into an image
    let image: glium::texture::RawImage2d<u8> = display.read_front_buffer().unwrap();
    let image = image::ImageBuffer::from_raw(image.width, image.height, image.data.into_owned()).unwrap();
    let image = image::DynamicImage::ImageRgba8(image).flipv();
    image.save("glium-example-screenshot.png").unwrap();
}
<|endoftext|>


<commit_before>extern crate emu;
extern crate spc;
extern crate snes_apu;

use std::iter;
use std::env;
use std::io::{Result, Error, ErrorKind, Write, stdout, stdin};
use std::thread;
use std::sync::{Arc, Mutex};

use emu::audio_driver::AudioDriver;
use emu::audio_driver_factory;

use spc::spc::{Spc, Emulator};
use snes_apu::apu::Apu;
use snes_apu::dsp::dsp::{SAMPLE_RATE, BUFFER_LEN};

fn main() {
    if let Err(e) = play_spc_files() {
        println!("ERROR: {}", e);
        std::process::exit(1);
    }
}

fn play_spc_files() -> Result<()> {
    for file_name in try!(get_file_names()) {
        try!(play_spc_file(&file_name));
    }
    Ok(())
}

fn get_file_names() -> Result<iter::Skip<env::Args>> {
    let args = env::args();
    match args.len() {
        1 => Err(Error::new(ErrorKind::Other, "No file(s) specified")),
        _ => Ok(args.skip(1))
    }
}

struct SpcEndState {
    sample_pos: i32,
    fade_out_sample: i32,
    end_sample: i32
}

fn play_spc_file(file_name: &String) -> Result<()> {
    let spc = try!(Spc::load(file_name));

    println!("SPC: {}", file_name);
    println!(" Version Minor: {}", spc.version_minor);
    println!(" PC: {}", spc.pc);
    println!(" A: {}", spc.a);
    println!(" X: {}", spc.x);
    println!(" Y: {}", spc.y);
    println!(" PSW: {}", spc.psw);
    println!(" SP: {}", spc.sp);

    if let Some(ref id666_tag) = spc.id666_tag {
        println!(" ID666 tag present:");
        println!("  Song title: {}", id666_tag.song_title);
        println!("  Game title: {}", id666_tag.game_title);
        println!("  Dumper name: {}", id666_tag.dumper_name);
        println!("  Comments: {}", id666_tag.comments);
        println!("  Date dumped (MM/DD/YYYY): {}", id666_tag.date_dumped);
        println!("  Seconds to play before fading out: {}", id666_tag.seconds_to_play_before_fading_out);
        println!("  Fade out length: {}ms", id666_tag.fade_out_length);
        println!("  Artist name: {}", id666_tag.artist_name);
        println!("  Default channel disables: {}", id666_tag.default_channel_disables);
        println!("  Dumping emulator: {}", match id666_tag.dumping_emulator {
            Emulator::Unknown => "Unknown",
            Emulator::ZSnes => "ZSnes",
            Emulator::Snes9x => "Snes9x"
        });
    } else {
        println!(" No ID666 tag present.");
    };

    let mut apu = Apu::new();
    apu.set_state(&spc);
    // Most SPC's have crap in the echo buffer on startup, so while it's not technically correct, we'll clear that.
    // The example for blargg's APU emulator (which is known to be the most accurate there is) also does this, so I
    //  think we're OK to do it too :)
    apu.clear_echo_buffer();

    let mut driver = audio_driver_factory::create_default();
    driver.set_sample_rate(SAMPLE_RATE as i32);
    let mut left = Box::new([0; BUFFER_LEN]);
    let mut right = Box::new([0; BUFFER_LEN]);
    let end_state = if let Some(ref id666_tag) = spc.id666_tag {
        let fade_out_sample = id666_tag.seconds_to_play_before_fading_out * (SAMPLE_RATE as i32);
        let end_sample = fade_out_sample + id666_tag.fade_out_length * (SAMPLE_RATE as i32) / 1000;
        Some(Arc::new(Mutex::new(SpcEndState {
            sample_pos: 0,
            fade_out_sample: fade_out_sample,
            end_sample: end_sample
        })))
    } else {
        None
    };
    let driver_end_state = end_state.clone();
    driver.set_render_callback(Some(Box::new(move |buffer, num_frames| {
        apu.render(&mut *left, &mut *right, num_frames as i32);
        match driver_end_state {
            Some(ref state_mutex) => {
                let state = &mut *state_mutex.lock().unwrap();
                for i in 0..num_frames {
                    let j = i * 2;
                    let sample_index = state.sample_pos + (i as i32);
                    let f = if sample_index >= state.end_sample {
                        0.0
                    } else if sample_index >= state.fade_out_sample {
                        1.0 - ((sample_index - state.fade_out_sample) as f32) / ((state.end_sample - state.fade_out_sample) as f32)
                    } else {
                        1.0
                    };
                    buffer[j + 0] = left[i] as f32 * f / 32768.0;
                    buffer[j + 1] = right[i] as f32 * f / 32768.0;
                }
                state.sample_pos += num_frames as i32;
            },
            _ => {
                for i in 0..num_frames {
                    let j = i * 2;
                    buffer[j + 0] = left[i] as f32 / 32768.0;
                    buffer[j + 1] = right[i] as f32 / 32768.0;
                }
            }
        }
    })));

    match end_state {
        Some(ref state_mutex) => {
            loop {
                {
                    let state = &*state_mutex.lock().unwrap();
                    if state.sample_pos >= state.end_sample {
                        break;
                    }
                }

                thread::sleep_ms(5);
            }
        },
        _ => {
            println!("Return stops song.");
            try!(wait_for_key_press_with_busy_icon());
        }
    }

    Ok(())
}

// TODO: This function is super thread-safe but can panic XD
fn wait_for_key_press_with_busy_icon() -> Result<()> {
    let is_done = Arc::new(Mutex::new(false));

    let thread_is_done = is_done.clone();
    let handle = thread::spawn(move || {
        let chars = ['-', '/', '|', '\\'];
        let mut char_index = 0;
        while !*thread_is_done.lock().unwrap() {
            print!("\r[{}]", chars[char_index]);
            stdout().flush().unwrap();
            char_index = (char_index + 1) % chars.len();

            thread::sleep_ms(5);
        }
        print!("\r   \r");
    });

    let mut s = String::new();
    try!(stdin().read_line(&mut s));
    *is_done.lock().unwrap() = true;
    handle.join().unwrap();

    Ok(())
}
<commit_msg>Quit on song end and keypress both work<commit_after>extern crate emu;
extern crate spc;
extern crate snes_apu;

use std::iter;
use std::env;
use std::io::{Result, Error, ErrorKind, Write, stdout, stdin};
use std::thread;
use std::sync::mpsc::{channel, Sender, Receiver};

use emu::audio_driver::AudioDriver;
use emu::audio_driver_factory;

use spc::spc::{Spc, Emulator};
use snes_apu::apu::Apu;
use snes_apu::dsp::dsp::{SAMPLE_RATE, BUFFER_LEN};

fn main() {
    if let Err(e) = play_spc_files() {
        println!("ERROR: {}", e);
        std::process::exit(1);
    }
}

fn play_spc_files() -> Result<()> {
    for file_name in try!(get_file_names()) {
        try!(play_spc_file(&file_name));
    }
    Ok(())
}

fn get_file_names() -> Result<iter::Skip<env::Args>> {
    let args = env::args();
    match args.len() {
        1 => Err(Error::new(ErrorKind::Other, "No file(s) specified")),
        _ => Ok(args.skip(1))
    }
}

struct SpcEndState {
    sample_pos: i32,
    fade_out_sample: i32,
    end_sample: i32,
    is_done_send: Sender<()>
}

fn play_spc_file(file_name: &String) -> Result<()> {
    let spc = try!(Spc::load(file_name));

    println!("SPC: {}", file_name);
    println!(" Version Minor: {}", spc.version_minor);
    println!(" PC: {}", spc.pc);
    println!(" A: {}", spc.a);
    println!(" X: {}", spc.x);
    println!(" Y: {}", spc.y);
    println!(" PSW: {}", spc.psw);
    println!(" SP: {}", spc.sp);

    if let Some(ref id666_tag) = spc.id666_tag {
        println!(" ID666 tag present:");
        println!("  Song title: {}", id666_tag.song_title);
        println!("  Game title: {}", id666_tag.game_title);
        println!("  Dumper name: {}", id666_tag.dumper_name);
        println!("  Comments: {}", id666_tag.comments);
        println!("  Date dumped (MM/DD/YYYY): {}", id666_tag.date_dumped);
        println!("  Seconds to play before fading out: {}", id666_tag.seconds_to_play_before_fading_out);
        println!("  Fade out length: {}ms", id666_tag.fade_out_length);
        println!("  Artist name: {}", id666_tag.artist_name);
        println!("  Default channel disables: {}", id666_tag.default_channel_disables);
        println!("  Dumping emulator: {}", match id666_tag.dumping_emulator {
            Emulator::Unknown => "Unknown",
            Emulator::ZSnes => "ZSnes",
            Emulator::Snes9x => "Snes9x"
        });
    } else {
        println!(" No ID666 tag present.");
    };

    let mut apu = Apu::new();
    apu.set_state(&spc);
    // Most SPC's have crap in the echo buffer on startup, so while it's not technically correct, we'll clear that.
    // The example for blargg's APU emulator (which is known to be the most accurate there is) also does this, so I
    //  think we're OK to do it too :)
    apu.clear_echo_buffer();

    let (is_done_send, is_done_recv) = channel();

    let mut driver = audio_driver_factory::create_default();
    driver.set_sample_rate(SAMPLE_RATE as i32);
    let mut left = Box::new([0; BUFFER_LEN]);
    let mut right = Box::new([0; BUFFER_LEN]);
    let mut end_state = if let Some(ref id666_tag) = spc.id666_tag {
        let fade_out_sample = id666_tag.seconds_to_play_before_fading_out * (SAMPLE_RATE as i32);
        let end_sample = fade_out_sample + id666_tag.fade_out_length * (SAMPLE_RATE as i32) / 1000;
        Some(SpcEndState {
            sample_pos: 0,
            fade_out_sample: fade_out_sample,
            end_sample: end_sample,
            is_done_send: is_done_send.clone()
        })
    } else {
        None
    };
    driver.set_render_callback(Some(Box::new(move |buffer, num_frames| {
        apu.render(&mut *left, &mut *right, num_frames as i32);
        match end_state {
            Some(ref mut state) => {
                for i in 0..num_frames {
                    let j = i * 2;
                    let sample_index = state.sample_pos + (i as i32);
                    let f = if sample_index >= state.end_sample {
                        0.0
                    } else if sample_index >= state.fade_out_sample {
                        1.0 - ((sample_index - state.fade_out_sample) as f32) / ((state.end_sample - state.fade_out_sample) as f32)
                    } else {
                        1.0
                    };
                    buffer[j + 0] = left[i] as f32 * f / 32768.0;
                    buffer[j + 1] = right[i] as f32 * f / 32768.0;
                }
                state.sample_pos += num_frames as i32;
                if state.sample_pos >= state.end_sample {
                    state.is_done_send.send(()).unwrap();
                }
            },
            _ => {
                for i in 0..num_frames {
                    let j = i * 2;
                    buffer[j + 0] = left[i] as f32 / 32768.0;
                    buffer[j + 1] = right[i] as f32 / 32768.0;
                }
            }
        }
    })));

    wait_for_key_press_with_busy_icon(is_done_send, is_done_recv)
}

fn wait_for_key_press_with_busy_icon(is_done_send: Sender<()>, is_done_recv: Receiver<()>) -> Result<()> {
    thread::spawn(move || {
        let mut s = String::new();
        stdin().read_line(&mut s).unwrap();
        is_done_send.send(()).unwrap();
    });

    println!("Return stops song.");
    let chars = ['-', '/', '|', '\\'];
    let mut char_index = 0;
    loop {
        if let Ok(()) = is_done_recv.try_recv() {
            break;
        }

        print!("\r[{}]", chars[char_index]);
        stdout().flush().unwrap();
        char_index = (char_index + 1) % chars.len();

        thread::sleep_ms(5);
    }
    print!("\r   \r");

    Ok(())
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

#![crate_type = "bin"]
#![allow(unused_must_use, non_upper_case_globals)]

extern crate sysinfo;

use std::io::{self, BufRead, Write};
use std::str::FromStr;
use sysinfo::Signal::*;
use sysinfo::{
    NetworkExt, NetworksExt, Pid, ProcessExt, ProcessorExt, Signal, System, SystemExt, UserExt,
};

const signals: [Signal; 31] = [
    Hangup,
    Interrupt,
    Quit,
    Illegal,
    Trap,
    Abort,
    Bus,
    FloatingPointException,
    Kill,
    User1,
    Segv,
    User2,
    Pipe,
    Alarm,
    Term,
    Stklft,
    Child,
    Continue,
    Stop,
    TSTP,
    TTIN,
    TTOU,
    Urgent,
    XCPU,
    XFSZ,
    VirtualAlarm,
    Profiling,
    Winch,
    IO,
    Power,
    Sys,
];

fn print_help() {
    writeln!(&mut io::stdout(), "== Help menu ==");
    writeln!(&mut io::stdout(), "help               : show this menu");
    writeln!(
        &mut io::stdout(),
        "signals            : show the available signals"
    );
    writeln!(
        &mut io::stdout(),
        "refresh            : reloads all processes' information"
    );
    writeln!(
        &mut io::stdout(),
        "refresh [pid]      : reloads corresponding process' information"
    );
    writeln!(
        &mut io::stdout(),
        "refresh_disks      : reloads only disks' information"
    );
    writeln!(
        &mut io::stdout(),
        "refresh_users      : reloads only users' information"
    );
    writeln!(
        &mut io::stdout(),
        "show [pid | name]  : show information of the given process \
         corresponding to [pid | name]"
    );
    writeln!(
        &mut io::stdout(),
        "kill [pid] [signal]: send [signal] to the process with this \
         [pid]. 0 < [signal] < 32"
    );
    writeln!(
        &mut io::stdout(),
        "processors         : Displays processors state"
    );
    writeln!(
        &mut io::stdout(),
        "memory             : Displays memory state"
    );
    writeln!(
        &mut io::stdout(),
        "temperature        : Displays components' temperature"
    );
    writeln!(
        &mut io::stdout(),
        "disks              : Displays disks' information"
    );
    writeln!(
        &mut io::stdout(),
        "network            : Displays network' information"
    );
    writeln!(
        &mut io::stdout(),
        "all                : Displays all process name and pid"
    );
    writeln!(
        &mut io::stdout(),
        "uptime             : Displays system uptime"
    );
    writeln!(
        &mut io::stdout(),
        "boot_time          : Displays system boot time"
    );
    writeln!(
        &mut io::stdout(),
        "vendor_id          : Displays processor vendor id"
    );
    writeln!(
        &mut io::stdout(),
        "brand              : Displays processor brand"
    );
    writeln!(
        &mut io::stdout(),
        "load_avg           : Displays system load average"
    );
    writeln!(
        &mut io::stdout(),
        "frequency          : Displays processor frequency"
    );
    writeln!(&mut io::stdout(), "users              : Displays all users");
    writeln!(&mut io::stdout(), "quit               : exit the program");
}

fn interpret_input(input: &str, sys: &mut System) -> bool {
    match input.trim() {
        "help" => print_help(),
        "refresh_disks" => {
            writeln!(&mut io::stdout(), "Refreshing disk list...");
            sys.refresh_disks_list();
            writeln!(&mut io::stdout(), "Done.");
        }
        "refresh_users" => {
            writeln!(&mut io::stdout(), "Refreshing user list...");
            sys.refresh_users_list();
            writeln!(&mut io::stdout(), "Done.");
        }
        "signals" => {
            let mut nb = 1i32;

            for sig in &signals {
                writeln!(&mut io::stdout(), "{:2}:{:?}", nb, sig);
                nb += 1;
            }
        }
        "processors" => {
            // Note: you should refresh a few times before using this, so that usage statistics
            // can be ascertained
            writeln!(
                &mut io::stdout(),
                "total process usage: {}%",
                sys.get_global_processor_info().get_cpu_usage()
            );
            for proc_ in sys.get_processors() {
                writeln!(&mut io::stdout(), "{:?}", proc_);
            }
        }
        "memory" => {
            writeln!(
                &mut io::stdout(),
                "total memory: {} KB",
                sys.get_total_memory()
            );
            writeln!(
                &mut io::stdout(),
                "used memory : {} KB",
                sys.get_used_memory()
            );
            writeln!(
                &mut io::stdout(),
                "total swap  : {} KB",
                sys.get_total_swap()
            );
            writeln!(
                &mut io::stdout(),
                "used swap   : {} KB",
                sys.get_used_swap()
            );
        }
        "quit" | "exit" => return true,
        "all" => {
            for (pid, proc_) in sys.get_processes() {
                writeln!(
                    &mut io::stdout(),
                    "{}:{} status={:?}",
                    pid,
                    proc_.name(),
                    proc_.status()
                );
            }
        }
        "frequency" => {
            writeln!(
                &mut io::stdout(),
                "{} MHz",
                sys.get_processors()[0].get_frequency()
            );
        }
        "vendor_id" => {
            writeln!(
                &mut io::stdout(),
                "vendor ID: {}",
                sys.get_processors()[0].get_vendor_id()
            );
        }
        "brand" => {
            writeln!(
                &mut io::stdout(),
                "brand: {}",
                sys.get_processors()[0].get_brand()
            );
        }
        "load_avg" => {
            let load_avg = sys.get_load_average();
            writeln!(&mut io::stdout(), "one minute     : {}%", load_avg.one);
            writeln!(&mut io::stdout(), "five minutes   : {}%", load_avg.five);
            writeln!(&mut io::stdout(), "fifteen minutes: {}%", load_avg.fifteen);
        }
        e if e.starts_with("show ") => {
            let tmp: Vec<&str> = e.split(' ').collect();

            if tmp.len() != 2 {
                writeln!(
                    &mut io::stdout(),
                    "show command takes a pid or a name in parameter!"
                );
                writeln!(&mut io::stdout(), "example: show 1254");
            } else if let Ok(pid) = Pid::from_str(tmp[1]) {
                match sys.get_process(pid) {
                    Some(p) => writeln!(&mut io::stdout(), "{:?}", *p),
                    None => writeln!(&mut io::stdout(), "pid \"{:?}\" not found", pid),
                };
            } else {
                let proc_name = tmp[1];
                for proc_ in sys.get_process_by_name(proc_name) {
                    writeln!(&mut io::stdout(), "==== {} ====", proc_.name());
                    writeln!(&mut io::stdout(), "{:?}", proc_);
                }
            }
        }
        "temperature" => {
            for component in sys.get_components() {
                writeln!(&mut io::stdout(), "{:?}", component);
            }
        }
        "network" => {
            for (interface_name, data) in sys.get_networks().iter() {
                writeln!(
                    &mut io::stdout(),
                    "{}:\n  input data  (new / total): {} / {} B\n  output data (new / total): {} / {} B",
                    interface_name,
                    data.get_received(),
                    data.get_total_received(),
                    data.get_transmitted(),
                    data.get_total_transmitted(),
                );
            }
        }
        "show" => {
            writeln!(
                &mut io::stdout(),
                "'show' command expects a pid number or a process name"
            );
        }
        e if e.starts_with("kill ") => {
            let tmp: Vec<&str> = e.split(' ').collect();

            if tmp.len() != 3 {
                writeln!(
                    &mut io::stdout(),
                    "kill command takes the pid and a signal number in parameter !"
                );
                writeln!(&mut io::stdout(), "example: kill 1254 9");
            } else {
                let pid = Pid::from_str(tmp[1]).unwrap();
                let signal = i32::from_str(tmp[2]).unwrap();

                if signal < 1 || signal > 31 {
                    writeln!(
                        &mut io::stdout(),
                        "Signal must be between 0 and 32 ! See the signals list with the \
                         signals command"
                    );
                } else {
                    match sys.get_process(pid) {
                        Some(p) => {
                            writeln!(
                                &mut io::stdout(),
                                "kill: {}",
                                p.kill(*signals.get(signal as usize - 1).unwrap())
                            );
                        }
                        None => {
                            writeln!(&mut io::stdout(), "pid not found");
                        }
                    };
                }
            }
        }
        "disks" => {
            for disk in sys.get_disks() {
                writeln!(&mut io::stdout(), "{:?}", disk);
            }
        }
        "users" => {
            for user in sys.get_users() {
                writeln!(&mut io::stdout(), "{:?}", user.get_name());
            }
        }
        "boot_time" => {
            writeln!(&mut io::stdout(), "{} seconds", sys.get_boot_time());
        }
        "uptime" => {
            let up = sys.get_uptime();
            let mut uptime = sys.get_uptime();
            let days = uptime / 86400;
            uptime -= days * 86400;
            let hours = uptime / 3600;
            uptime -= hours * 3600;
            let minutes = uptime / 60;
            writeln!(
                &mut io::stdout(),
                "{} days {} hours {} minutes ({} seconds in total)",
                days,
                hours,
                minutes,
                up,
            );
        }
        x if x.starts_with("refresh") => {
            if x == "refresh" {
                writeln!(&mut io::stdout(), "Getting processes' information...");
                sys.refresh_all();
                writeln!(&mut io::stdout(), "Done.");
            } else if x.starts_with("refresh ") {
                writeln!(&mut io::stdout(), "Getting process' information...");
                if let Some(pid) = x
                    .split(' ')
                    .filter_map(|pid| pid.parse().ok())
                    .take(1)
                    .next()
                {
                    if sys.refresh_process(pid) {
                        writeln!(&mut io::stdout(), "Process `{}` updated successfully", pid);
                    } else {
                        writeln!(
                            &mut io::stdout(),
                            "Process `{}` couldn't be updated...",
                            pid
                        );
                    }
                } else {
                    writeln!(&mut io::stdout(), "Invalid [pid] received...");
                }
            } else {
                writeln!(
                    &mut io::stdout(),
                    "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                     list.",
                    x
                );
            }
        }
        e => {
            writeln!(
                &mut io::stdout(),
                "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                 list.",
                e
            );
        }
    }
    false
}

fn main() {
    println!("Getting processes' information...");
    let mut t = System::new_all();
    println!("Done.");
    let t_stin = io::stdin();
    let mut stin = t_stin.lock();
    let mut done = false;

    println!("To get the commands' list, enter 'help'.");
    while !done {
        let mut input = String::new();
        write!(&mut io::stdout(), "> ");
        io::stdout().flush();

        stin.read_line(&mut input);
        if input.is_empty() {
            // The string is empty, meaning there is no '\n', meaning
            // that the user used CTRL+D so we can just quit!
            println!("\nLeaving, bye!");
            break;
        }
        if (&input as &str).ends_with('\n') {
            input.pop();
        }
        done = interpret_input(input.as_ref(), &mut t);
    }
}
<commit_msg>Add more subcommands in example<commit_after>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

#![crate_type = "bin"]
#![allow(unused_must_use, non_upper_case_globals)]

extern crate sysinfo;

use std::io::{self, BufRead, Write};
use std::str::FromStr;
use sysinfo::Signal::*;
use sysinfo::{
    NetworkExt, NetworksExt, Pid, ProcessExt, ProcessorExt, Signal, System, SystemExt, UserExt,
};

const signals: [Signal; 31] = [
    Hangup,
    Interrupt,
    Quit,
    Illegal,
    Trap,
    Abort,
    Bus,
    FloatingPointException,
    Kill,
    User1,
    Segv,
    User2,
    Pipe,
    Alarm,
    Term,
    Stklft,
    Child,
    Continue,
    Stop,
    TSTP,
    TTIN,
    TTOU,
    Urgent,
    XCPU,
    XFSZ,
    VirtualAlarm,
    Profiling,
    Winch,
    IO,
    Power,
    Sys,
];

fn print_help() {
    writeln!(&mut io::stdout(), "== Help menu ==");
    writeln!(&mut io::stdout(), "help               : show this menu");
    writeln!(
        &mut io::stdout(),
        "signals            : show the available signals"
    );
    writeln!(
        &mut io::stdout(),
        "refresh            : reloads all processes' information"
    );
    writeln!(
        &mut io::stdout(),
        "refresh [pid]      : reloads corresponding process' information"
    );
    writeln!(
        &mut io::stdout(),
        "refresh_disks      : reloads only disks' information"
    );
    writeln!(
        &mut io::stdout(),
        "refresh_users      : reloads only users' information"
    );
    writeln!(
        &mut io::stdout(),
        "show [pid | name]  : show information of the given process \
         corresponding to [pid | name]"
    );
    writeln!(
        &mut io::stdout(),
        "kill [pid] [signal]: send [signal] to the process with this \
         [pid]. 0 < [signal] < 32"
    );
    writeln!(
        &mut io::stdout(),
        "processors         : Displays processors state"
    );
    writeln!(
        &mut io::stdout(),
        "memory             : Displays memory state"
    );
    writeln!(
        &mut io::stdout(),
        "temperature        : Displays components' temperature"
    );
    writeln!(
        &mut io::stdout(),
        "disks              : Displays disks' information"
    );
    writeln!(
        &mut io::stdout(),
        "network            : Displays network' information"
    );
    writeln!(
        &mut io::stdout(),
        "all                : Displays all process name and pid"
    );
    writeln!(
        &mut io::stdout(),
        "uptime             : Displays system uptime"
    );
    writeln!(
        &mut io::stdout(),
        "boot_time          : Displays system boot time"
    );
    writeln!(
        &mut io::stdout(),
        "vendor_id          : Displays processor vendor id"
    );
    writeln!(
        &mut io::stdout(),
        "brand              : Displays processor brand"
    );
    writeln!(
        &mut io::stdout(),
        "load_avg           : Displays system load average"
    );
    writeln!(
        &mut io::stdout(),
        "frequency          : Displays processor frequency"
    );
    writeln!(&mut io::stdout(), "users              : Displays all users");
    writeln!(
        &mut io::stdout(),
        "system             : Displays system information (such as name, version and hostname)"
    );
    writeln!(&mut io::stdout(), "quit               : exit the program");
}

fn interpret_input(input: &str, sys: &mut System) -> bool {
    match input.trim() {
        "help" => print_help(),
        "refresh_disks" => {
            writeln!(&mut io::stdout(), "Refreshing disk list...");
            sys.refresh_disks_list();
            writeln!(&mut io::stdout(), "Done.");
        }
        "refresh_users" => {
            writeln!(&mut io::stdout(), "Refreshing user list...");
            sys.refresh_users_list();
            writeln!(&mut io::stdout(), "Done.");
        }
        "signals" => {
            let mut nb = 1i32;

            for sig in &signals {
                writeln!(&mut io::stdout(), "{:2}:{:?}", nb, sig);
                nb += 1;
            }
        }
        "processors" => {
            // Note: you should refresh a few times before using this, so that usage statistics
            // can be ascertained
            writeln!(
                &mut io::stdout(),
                "total process usage: {}%",
                sys.get_global_processor_info().get_cpu_usage()
            );
            for proc_ in sys.get_processors() {
                writeln!(&mut io::stdout(), "{:?}", proc_);
            }
        }
        "memory" => {
            writeln!(
                &mut io::stdout(),
                "total memory: {} KB",
                sys.get_total_memory()
            );
            writeln!(
                &mut io::stdout(),
                "used memory : {} KB",
                sys.get_used_memory()
            );
            writeln!(
                &mut io::stdout(),
                "total swap  : {} KB",
                sys.get_total_swap()
            );
            writeln!(
                &mut io::stdout(),
                "used swap   : {} KB",
                sys.get_used_swap()
            );
        }
        "quit" | "exit" => return true,
        "all" => {
            for (pid, proc_) in sys.get_processes() {
                writeln!(
                    &mut io::stdout(),
                    "{}:{} status={:?}",
                    pid,
                    proc_.name(),
                    proc_.status()
                );
            }
        }
        "frequency" => {
            writeln!(
                &mut io::stdout(),
                "{} MHz",
                sys.get_processors()[0].get_frequency()
            );
        }
        "vendor_id" => {
            writeln!(
                &mut io::stdout(),
                "vendor ID: {}",
                sys.get_processors()[0].get_vendor_id()
            );
        }
        "brand" => {
            writeln!(
                &mut io::stdout(),
                "brand: {}",
                sys.get_processors()[0].get_brand()
            );
        }
        "load_avg" => {
            let load_avg = sys.get_load_average();
            writeln!(&mut io::stdout(), "one minute     : {}%", load_avg.one);
            writeln!(&mut io::stdout(), "five minutes   : {}%", load_avg.five);
            writeln!(&mut io::stdout(), "fifteen minutes: {}%", load_avg.fifteen);
        }
        e if e.starts_with("show ") => {
            let tmp: Vec<&str> = e.split(' ').collect();

            if tmp.len() != 2 {
                writeln!(
                    &mut io::stdout(),
                    "show command takes a pid or a name in parameter!"
                );
                writeln!(&mut io::stdout(), "example: show 1254");
            } else if let Ok(pid) = Pid::from_str(tmp[1]) {
                match sys.get_process(pid) {
                    Some(p) => writeln!(&mut io::stdout(), "{:?}", *p),
                    None => writeln!(&mut io::stdout(), "pid \"{:?}\" not found", pid),
                };
            } else {
                let proc_name = tmp[1];
                for proc_ in sys.get_process_by_name(proc_name) {
                    writeln!(&mut io::stdout(), "==== {} ====", proc_.name());
                    writeln!(&mut io::stdout(), "{:?}", proc_);
                }
            }
        }
        "temperature" => {
            for component in sys.get_components() {
                writeln!(&mut io::stdout(), "{:?}", component);
            }
        }
        "network" => {
            for (interface_name, data) in sys.get_networks().iter() {
                writeln!(
                    &mut io::stdout(),
                    "{}:\n  input data  (new / total): {} / {} B\n  output data (new / total): {} / {} B",
                    interface_name,
                    data.get_received(),
                    data.get_total_received(),
                    data.get_transmitted(),
                    data.get_total_transmitted(),
                );
            }
        }
        "show" => {
            writeln!(
                &mut io::stdout(),
                "'show' command expects a pid number or a process name"
            );
        }
        e if e.starts_with("kill ") => {
            let tmp: Vec<&str> = e.split(' ').collect();

            if tmp.len() != 3 {
                writeln!(
                    &mut io::stdout(),
                    "kill command takes the pid and a signal number in parameter !"
                );
                writeln!(&mut io::stdout(), "example: kill 1254 9");
            } else {
                let pid = Pid::from_str(tmp[1]).unwrap();
                let signal = i32::from_str(tmp[2]).unwrap();

                if signal < 1 || signal > 31 {
                    writeln!(
                        &mut io::stdout(),
                        "Signal must be between 0 and 32 ! See the signals list with the \
                         signals command"
                    );
                } else {
                    match sys.get_process(pid) {
                        Some(p) => {
                            writeln!(
                                &mut io::stdout(),
                                "kill: {}",
                                p.kill(*signals.get(signal as usize - 1).unwrap())
                            );
                        }
                        None => {
                            writeln!(&mut io::stdout(), "pid not found");
                        }
                    };
                }
            }
        }
        "disks" => {
            for disk in sys.get_disks() {
                writeln!(&mut io::stdout(), "{:?}", disk);
            }
        }
        "users" => {
            for user in sys.get_users() {
                writeln!(&mut io::stdout(), "{:?}", user.get_name());
            }
        }
        "boot_time" => {
            writeln!(&mut io::stdout(), "{} seconds", sys.get_boot_time());
        }
        "uptime" => {
            let up = sys.get_uptime();
            let mut uptime = sys.get_uptime();
            let days = uptime / 86400;
            uptime -= days * 86400;
            let hours = uptime / 3600;
            uptime -= hours * 3600;
            let minutes = uptime / 60;
            writeln!(
                &mut io::stdout(),
                "{} days {} hours {} minutes ({} seconds in total)",
                days,
                hours,
                minutes,
                up,
            );
        }
        x if x.starts_with("refresh") => {
            if x == "refresh" {
                writeln!(&mut io::stdout(), "Getting processes' information...");
                sys.refresh_all();
                writeln!(&mut io::stdout(), "Done.");
            } else if x.starts_with("refresh ") {
                writeln!(&mut io::stdout(), "Getting process' information...");
                if let Some(pid) = x
                    .split(' ')
                    .filter_map(|pid| pid.parse().ok())
                    .take(1)
                    .next()
                {
                    if sys.refresh_process(pid) {
                        writeln!(&mut io::stdout(), "Process `{}` updated successfully", pid);
                    } else {
                        writeln!(
                            &mut io::stdout(),
                            "Process `{}` couldn't be updated...",
                            pid
                        );
                    }
                } else {
                    writeln!(&mut io::stdout(), "Invalid [pid] received...");
                }
            } else {
                writeln!(
                    &mut io::stdout(),
                    "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                     list.",
                    x
                );
            }
        }
        "system" => {
            writeln!(
                &mut io::stdout(),
                "System name:      {}",
                sys.get_name().unwrap_or_else(|| "<unknown>".to_owned())
            );
            writeln!(
                &mut io::stdout(),
                "System version:   {}",
                sys.get_version().unwrap_or_else(|| "<unknown>".to_owned())
            );
            writeln!(
                &mut io::stdout(),
                "System host name: {}",
                sys.get_host_name()
                    .unwrap_or_else(|| "<unknown>".to_owned())
            );
        }
        e => {
            writeln!(
                &mut io::stdout(),
                "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                 list.",
                e
            );
        }
    }
    false
}

fn main() {
    println!("Getting processes' information...");
    let mut t = System::new_all();
    println!("Done.");
    let t_stin = io::stdin();
    let mut stin = t_stin.lock();
    let mut done = false;

    println!("To get the commands' list, enter 'help'.");
    while !done {
        let mut input = String::new();
        write!(&mut io::stdout(), "> ");
        io::stdout().flush();

        stin.read_line(&mut input);
        if input.is_empty() {
            // The string is empty, meaning there is no '\n', meaning
            // that the user used CTRL+D so we can just quit!
            println!("\nLeaving, bye!");
            break;
        }
        if (&input as &str).ends_with('\n') {
            input.pop();
        }
        done = interpret_input(input.as_ref(), &mut t);
    }
}
<|endoftext|>


<commit_before>use petgraph::Direction;
use petgraph::graph::{Graph, NodeIndex};
use petgraph::visit::EdgeRef;
use std::cell::Cell;
use std::collections::HashMap;

use parser::ast::Identifier;

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Symbol {
    pub name: Identifier,
    pub type_: SymbolType,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SymbolType {
    Argument,
    Callback,
    CallbackInterface,
    Const,
    Enum,
    ExtendedAttributeArgumentList,
    Iterable,
    Maplike,
    NonPartialDictionary,
    NonPartialInterface,
    NonPartialNamespace,
    PartialDictionary,
    PartialNamespace,
    PartialInterface,
    RegularAttribute,
    RegularOperation,
    Setlike,
    SpecialOperation,
    StaticAttribute,
    StaticOperation,
    StringifierAttribute,
    StringifierOperation,
    Typedef,
}

type SymbolNode = HashMap<Identifier, Symbol>;

#[derive(Clone, Debug)]
pub struct SymbolTable {
    current_scope: Cell<NodeIndex>,
    scope_tree: Graph<SymbolNode, Identifier>,
}

impl SymbolTable {
    pub fn new() -> Self {
        let mut scope_tree = Graph::<SymbolNode, Identifier>::new();
        let current_scope = Cell::new(scope_tree.add_node(HashMap::new()));

        SymbolTable {
            current_scope,
            scope_tree,
        }
    }

    pub fn create_scope(&mut self, name: Identifier) {
        assert!(!self.does_child_scope_exist(&*name),
                "Cannot create scope that already exists");

        let new_scope = self.scope_tree.add_node(HashMap::new());
        self.scope_tree
            .add_edge(self.current_scope.get(), new_scope, name);
    }

    pub fn does_child_scope_exist(&self, name: &str) -> bool {
        self.find_child_scope(name, self.current_scope.get())
            .is_some()
    }

    pub fn enter_scope(&self, name: &str) {
        let child_scope = self.find_child_scope(name, self.current_scope.get())
            .expect("Cannot enter scope that does not exist");
        self.current_scope.set(child_scope);
    }

    pub fn exit_scope(&self) {
        let parent_scope = self.get_parent_scope(self.current_scope.get())
            .expect("Cannot exit out of global scope");
        self.current_scope.set(parent_scope);
    }

    pub fn lookup_local_symbol(&self, name: &str) -> Option<&Symbol> {
        self.get_symbol_node(self.current_scope.get()).get(name)
    }

    pub fn lookup_symbol(&self, name: &str) -> Option<&Symbol> {
        let mut current_scope = self.current_scope.get();

        loop {
            let symbol_node = self.get_symbol_node(current_scope);

            if let Some(symbol) = symbol_node.get(name) {
                return Some(symbol);
            }

            match self.get_parent_scope(current_scope) {
                Some(parent_scope) => current_scope = parent_scope,
                None => return None,
            }
        }
    }

    pub fn insert_symbol(&mut self, name: Identifier, symbol: Symbol) -> Option<Symbol> {
        let current_scope = self.current_scope.get();
        let symbol_node = self.get_symbol_node_mut(current_scope);
        symbol_node.insert(name, symbol)
    }

    fn find_child_scope(&self, name: &str, scope: NodeIndex) -> Option<NodeIndex> {
        let edge = self.scope_tree
            .edges_directed(scope, Direction::Outgoing)
            .find(|edge| edge.weight() == name);

        edge.map(|edge| edge.target())
    }

    fn get_parent_scope(&self, scope: NodeIndex) -> Option<NodeIndex> {
        let edge = self.scope_tree
            .edges_directed(scope, Direction::Incoming)
            .nth(0);

        edge.map(|edge| edge.target())
    }

    fn get_symbol_node(&self, scope: NodeIndex) -> &SymbolNode {
        self.scope_tree
            .node_weight(scope)
            .expect("\"scope\" must reference an existing symbol node")
    }

    fn get_symbol_node_mut(&mut self, scope: NodeIndex) -> &mut SymbolNode {
        self.scope_tree
            .node_weight_mut(scope)
            .expect("\"scope\" must reference an existing symbol node")
    }
}
<commit_msg>add error handling for symbol table<commit_after>use petgraph::Direction;
use petgraph::graph::{Graph, NodeIndex};
use petgraph::visit::EdgeRef;
use std::cell::Cell;
use std::collections::HashMap;

use parser::ast::Identifier;

pub mod errors {
    use super::Symbol;

    error_chain! {
        errors {
            CannotExitGlobalScope {
                description("cannot exit global scope")
            }
            ScopeAlreadyExists(scope: String) {
                description("scope already exists")
                display("scope already exists: `{}`", scope)
            }
            ScopeDoesNotExist(scope: String) {
                description("scope does not exist")
                display("scope does not exist: `{}`", scope)
            }
            SymbolAlreadyExists(symbol: Symbol) {
                description("symbol already exists")
                display("symbol already exists: `{:?}`", symbol)
            }
        }
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Symbol {
    pub name: Identifier,
    pub type_: SymbolType,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SymbolType {
    Argument,
    Callback,
    CallbackInterface,
    Const,
    Enum,
    ExtendedAttributeArgumentList,
    Iterable,
    Maplike,
    NonPartialDictionary,
    NonPartialInterface,
    NonPartialNamespace,
    PartialDictionary,
    PartialNamespace,
    PartialInterface,
    RegularAttribute,
    RegularOperation,
    Setlike,
    SpecialOperation,
    StaticAttribute,
    StaticOperation,
    StringifierAttribute,
    StringifierOperation,
    Typedef,
}

type SymbolNode = HashMap<Identifier, Symbol>;

#[derive(Clone, Debug)]
pub struct SymbolTable {
    current_scope: Cell<NodeIndex>,
    scope_tree: Graph<SymbolNode, Identifier>,
}

impl SymbolTable {
    pub fn new() -> Self {
        let mut scope_tree = Graph::<SymbolNode, Identifier>::new();
        let current_scope = Cell::new(scope_tree.add_node(HashMap::new()));

        SymbolTable {
            current_scope,
            scope_tree,
        }
    }

    pub fn create_scope(&mut self, name: Identifier) -> errors::Result<()> {
        if !self.does_child_scope_exist(&*name) {
            return Err(errors::ErrorKind::ScopeAlreadyExists(name).into());
        }

        let new_scope = self.scope_tree.add_node(HashMap::new());
        self.scope_tree.add_edge(
            self.current_scope.get(),
            new_scope,
            name,
        );
        Ok(())
    }

    pub fn does_child_scope_exist(&self, name: &str) -> bool {
        self.find_child_scope(name, self.current_scope.get())
            .is_some()
    }

    pub fn enter_scope(&self, name: &str) -> errors::Result<()> {
        match self.find_child_scope(name, self.current_scope.get()) {
            Some(child_scope) => {
                self.current_scope.set(child_scope);
                Ok(())
            }
            None => Err(
                errors::ErrorKind::ScopeDoesNotExist(name.to_string()).into(),
            ),
        }
    }

    pub fn exit_scope(&self) -> errors::Result<()> {
        match self.get_parent_scope(self.current_scope.get()) {
            Some(parent_scope) => {
                self.current_scope.set(parent_scope);
                Ok(())
            }
            None => Err(errors::ErrorKind::CannotExitGlobalScope.into()),
        }
    }

    pub fn insert_symbol(&mut self, name: Identifier, symbol: Symbol) -> errors::Result<()> {
        let current_scope = self.current_scope.get();
        let symbol_node = self.get_symbol_node_mut(current_scope);
        symbol_node.insert(name, symbol).map(|symbol| ()).ok_or(
            errors::ErrorKind::SymbolAlreadyExists(symbol).into(),
        )
    }

    pub fn lookup_local_symbol(&self, name: &str) -> Option<&Symbol> {
        self.get_symbol_node(self.current_scope.get()).get(name)
    }

    pub fn lookup_symbol(&self, name: &str) -> Option<&Symbol> {
        let mut current_scope = self.current_scope.get();

        loop {
            let symbol_node = self.get_symbol_node(current_scope);

            if let Some(symbol) = symbol_node.get(name) {
                return Some(symbol);
            }

            match self.get_parent_scope(current_scope) {
                Some(parent_scope) => current_scope = parent_scope,
                None => return None,
            }
        }
    }

    fn find_child_scope(&self, name: &str, scope: NodeIndex) -> Option<NodeIndex> {
        let edge = self.scope_tree
            .edges_directed(scope, Direction::Outgoing)
            .find(|edge| edge.weight() == name);

        edge.map(|edge| edge.target())
    }

    fn get_parent_scope(&self, scope: NodeIndex) -> Option<NodeIndex> {
        let edge = self.scope_tree
            .edges_directed(scope, Direction::Incoming)
            .nth(0);

        edge.map(|edge| edge.target())
    }

    fn get_symbol_node(&self, scope: NodeIndex) -> &SymbolNode {
        self.scope_tree.node_weight(scope).expect(
            "\"scope\" must reference an existing symbol node",
        )
    }

    fn get_symbol_node_mut(&mut self, scope: NodeIndex) -> &mut SymbolNode {
        self.scope_tree.node_weight_mut(scope).expect(
            "\"scope\" must reference an existing symbol node",
        )
    }
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2018-2019 de4dot@gmail.com

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

use core::hash::{Hash, Hasher};
use pyo3::class::basic::CompareOp;
use pyo3::prelude::*;
use pyo3::PyObjectProtocol;
use std::collections::hash_map::DefaultHasher;

/// Contains the offsets of the displacement and immediate.
///
/// Call :class:`Decoder.get_constant_offsets` or :class:`Encoder.get_constant_offsets` to get the
/// offsets of the constants after the instruction has been decoded/encoded.
#[pyclass(module = "_iced_x86_py")]
#[text_signature = "(/)"]
pub struct ConstantOffsets {
	pub(crate) offsets: iced_x86::ConstantOffsets,
}

#[pymethods]
impl ConstantOffsets {
	/// int: (``usize``) The offset of the displacement, if any
	#[getter]
	fn displacement_offset(&self) -> usize {
		self.offsets.displacement_offset()
	}

	/// int: (``usize``) Size in bytes of the displacement, or 0 if there's no displacement
	#[getter]
	fn displacement_size(&self) -> usize {
		self.offsets.displacement_size()
	}

	/// int: (``usize``) The offset of the first immediate, if any.
	///
	/// This field can be invalid even if the operand has an immediate if it's an immediate that isn't part
	/// of the instruction stream, eg. ``SHL AL,1``.
	#[getter]
	fn immediate_offset(&self) -> usize {
		self.offsets.immediate_offset()
	}

	/// int: (``usize``) Size in bytes of the first immediate, or 0 if there's no immediate
	#[getter]
	fn immediate_size(&self) -> usize {
		self.offsets.immediate_size()
	}

	/// int: (``usize``) The offset of the second immediate, if any.
	#[getter]
	fn immediate_offset2(&self) -> usize {
		self.offsets.immediate_offset2()
	}

	/// int: (``usize``) Size in bytes of the second immediate, or 0 if there's no second immediate
	#[getter]
	fn immediate_size2(&self) -> usize {
		self.offsets.immediate_size2()
	}

	/// bool: ``True`` if :class:`ConstantOffsets.displacement_offset` and :class:`ConstantOffsets.displacement_size` are valid
	#[getter]
	fn has_displacement(&self) -> bool {
		self.offsets.has_displacement()
	}

	/// bool: ``True`` if :class:`ConstantOffsets.immediate_offset` and :class:`ConstantOffsets.immediate_size` are valid
	#[getter]
	fn has_immediate(&self) -> bool {
		self.offsets.has_immediate()
	}

	/// bool: ``True`` if :class:`ConstantOffsets.immediate_offset2` and :class:`ConstantOffsets.immediate_size2` are valid
	#[getter]
	fn has_immediate2(&self) -> bool {
		self.offsets.has_immediate2()
	}
}

#[pyproto]
impl PyObjectProtocol for ConstantOffsets {
	fn __richcmp__(&self, other: PyRef<ConstantOffsets>, op: CompareOp) -> PyObject {
		match op {
			CompareOp::Eq => (self.offsets == other.offsets).into_py(other.py()),
			CompareOp::Ne => (self.offsets != other.offsets).into_py(other.py()),
			_ => other.py().NotImplemented(),
		}
	}

	fn __hash__(&self) -> u64 {
		let mut hasher = DefaultHasher::new();
		self.offsets.hash(&mut hasher);
		hasher.finish()
	}
}
<commit_msg>Change return type from usize to u32<commit_after>/*
Copyright (C) 2018-2019 de4dot@gmail.com

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

use core::hash::{Hash, Hasher};
use pyo3::class::basic::CompareOp;
use pyo3::prelude::*;
use pyo3::PyObjectProtocol;
use std::collections::hash_map::DefaultHasher;

/// Contains the offsets of the displacement and immediate.
///
/// Call :class:`Decoder.get_constant_offsets` or :class:`Encoder.get_constant_offsets` to get the
/// offsets of the constants after the instruction has been decoded/encoded.
#[pyclass(module = "_iced_x86_py")]
#[text_signature = "(/)"]
pub struct ConstantOffsets {
	pub(crate) offsets: iced_x86::ConstantOffsets,
}

#[pymethods]
impl ConstantOffsets {
	/// int: (``u32``) The offset of the displacement, if any
	#[getter]
	fn displacement_offset(&self) -> u32 {
		self.offsets.displacement_offset() as u32
	}

	/// int: (``u32``) Size in bytes of the displacement, or 0 if there's no displacement
	#[getter]
	fn displacement_size(&self) -> u32 {
		self.offsets.displacement_size() as u32
	}

	/// int: (``u32``) The offset of the first immediate, if any.
	///
	/// This field can be invalid even if the operand has an immediate if it's an immediate that isn't part
	/// of the instruction stream, eg. ``SHL AL,1``.
	#[getter]
	fn immediate_offset(&self) -> u32 {
		self.offsets.immediate_offset() as u32
	}

	/// int: (``u32``) Size in bytes of the first immediate, or 0 if there's no immediate
	#[getter]
	fn immediate_size(&self) -> u32 {
		self.offsets.immediate_size() as u32
	}

	/// int: (``u32``) The offset of the second immediate, if any.
	#[getter]
	fn immediate_offset2(&self) -> u32 {
		self.offsets.immediate_offset2() as u32
	}

	/// int: (``u32``) Size in bytes of the second immediate, or 0 if there's no second immediate
	#[getter]
	fn immediate_size2(&self) -> u32 {
		self.offsets.immediate_size2() as u32
	}

	/// bool: ``True`` if :class:`ConstantOffsets.displacement_offset` and :class:`ConstantOffsets.displacement_size` are valid
	#[getter]
	fn has_displacement(&self) -> bool {
		self.offsets.has_displacement()
	}

	/// bool: ``True`` if :class:`ConstantOffsets.immediate_offset` and :class:`ConstantOffsets.immediate_size` are valid
	#[getter]
	fn has_immediate(&self) -> bool {
		self.offsets.has_immediate()
	}

	/// bool: ``True`` if :class:`ConstantOffsets.immediate_offset2` and :class:`ConstantOffsets.immediate_size2` are valid
	#[getter]
	fn has_immediate2(&self) -> bool {
		self.offsets.has_immediate2()
	}
}

#[pyproto]
impl PyObjectProtocol for ConstantOffsets {
	fn __richcmp__(&self, other: PyRef<ConstantOffsets>, op: CompareOp) -> PyObject {
		match op {
			CompareOp::Eq => (self.offsets == other.offsets).into_py(other.py()),
			CompareOp::Ne => (self.offsets != other.offsets).into_py(other.py()),
			_ => other.py().NotImplemented(),
		}
	}

	fn __hash__(&self) -> u64 {
		let mut hasher = DefaultHasher::new();
		self.offsets.hash(&mut hasher);
		hasher.finish()
	}
}
<|endoftext|>


<commit_before>use crate::utils::{is_direct_expn_of, span_lint};
use if_chain::if_chain;
use matches::matches;
use rustc::hir::map::Map;
use rustc::ty;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, StmtKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for function/method calls with a mutable
    /// parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros.
    ///
    /// **Why is this bad?** In release builds `debug_assert!` macros are optimized out by the
    /// compiler.
    /// Therefore mutating something in a `debug_assert!` macro results in different behaviour
    /// between a release and debug build.
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust,ignore
    /// debug_assert_eq!(vec![3].pop(), Some(3));
    /// // or
    /// fn take_a_mut_parameter(_: &mut u32) -> bool { unimplemented!() }
    /// debug_assert!(take_a_mut_parameter(&mut 5));
    /// ```
    pub DEBUG_ASSERT_WITH_MUT_CALL,
    correctness,
    "mutable arguments in `debug_assert{,_ne,_eq}!`"
}

declare_lint_pass!(DebugAssertWithMutCall => [DEBUG_ASSERT_WITH_MUT_CALL]);

const DEBUG_MACRO_NAMES: [&str; 3] = ["debug_assert", "debug_assert_eq", "debug_assert_ne"];

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DebugAssertWithMutCall {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
        for dmn in &DEBUG_MACRO_NAMES {
            if is_direct_expn_of(e.span, dmn).is_some() {
                if let Some(span) = extract_call(cx, e) {
                    span_lint(
                        cx,
                        DEBUG_ASSERT_WITH_MUT_CALL,
                        span,
                        &format!("do not call a function with mutable arguments inside of `{}!`", dmn),
                    );
                }
            }
        }
    }
}

//HACK(hellow554): remove this when #4694 is implemented
#[allow(clippy::cognitive_complexity)]
fn extract_call<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) -> Option<Span> {
    if_chain! {
        if let ExprKind::Block(ref block, _) = e.kind;
        if block.stmts.len() == 1;
        if let StmtKind::Semi(ref matchexpr) = block.stmts[0].kind;
        then {
            if_chain! {
                if let ExprKind::Match(ref ifclause, _, _) = matchexpr.kind;
                if let ExprKind::DropTemps(ref droptmp) = ifclause.kind;
                if let ExprKind::Unary(UnOp::UnNot, ref condition) = droptmp.kind;
                then {
                    // debug_assert
                    let mut visitor = MutArgVisitor::new(cx);
                    visitor.visit_expr(condition);
                    return visitor.expr_span();
                } else {
                    // debug_assert_{eq,ne}
                    if_chain! {
                        if let ExprKind::Block(ref matchblock, _) = matchexpr.kind;
                        if let Some(ref matchheader) = matchblock.expr;
                        if let ExprKind::Match(ref headerexpr, _, _) = matchheader.kind;
                        if let ExprKind::Tup(ref conditions) = headerexpr.kind;
                        if conditions.len() == 2;
                        then {
                            if let ExprKind::AddrOf(BorrowKind::Ref, _, ref lhs) = conditions[0].kind {
                                let mut visitor = MutArgVisitor::new(cx);
                                visitor.visit_expr(lhs);
                                if let Some(span) = visitor.expr_span() {
                                    return Some(span);
                                }
                            }
                            if let ExprKind::AddrOf(BorrowKind::Ref, _, ref rhs) = conditions[1].kind {
                                let mut visitor = MutArgVisitor::new(cx);
                                visitor.visit_expr(rhs);
                                if let Some(span) = visitor.expr_span() {
                                    return Some(span);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    None
}

struct MutArgVisitor<'a, 'tcx> {
    cx: &'a LateContext<'a, 'tcx>,
    expr_span: Option<Span>,
    found: bool,
}

impl<'a, 'tcx> MutArgVisitor<'a, 'tcx> {
    fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
        Self {
            cx,
            expr_span: None,
            found: false,
        }
    }

    fn expr_span(&self) -> Option<Span> {
        if self.found {
            self.expr_span
        } else {
            None
        }
    }
}

impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
        match expr.kind {
            ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) => {
                self.found = true;
                return;
            },
            ExprKind::Path(_) => {
                if let Some(adj) = self.cx.tables.adjustments().get(expr.hir_id) {
                    if adj
                        .iter()
                        .any(|a| matches!(a.target.kind, ty::Ref(_, _, Mutability::Mut)))
                    {
                        self.found = true;
                        return;
                    }
                }
            },
            _ if !self.found => self.expr_span = Some(expr.span),
            _ => return,
        }
        walk_expr(self, expr)
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
        NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir())
    }
}
<commit_msg>Small refactor of mutable_debug_assertions<commit_after>use crate::utils::{is_direct_expn_of, span_lint};
use if_chain::if_chain;
use matches::matches;
use rustc::hir::map::Map;
use rustc::ty;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, StmtKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for function/method calls with a mutable
    /// parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros.
    ///
    /// **Why is this bad?** In release builds `debug_assert!` macros are optimized out by the
    /// compiler.
    /// Therefore mutating something in a `debug_assert!` macro results in different behaviour
    /// between a release and debug build.
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust,ignore
    /// debug_assert_eq!(vec![3].pop(), Some(3));
    /// // or
    /// fn take_a_mut_parameter(_: &mut u32) -> bool { unimplemented!() }
    /// debug_assert!(take_a_mut_parameter(&mut 5));
    /// ```
    pub DEBUG_ASSERT_WITH_MUT_CALL,
    correctness,
    "mutable arguments in `debug_assert{,_ne,_eq}!`"
}

declare_lint_pass!(DebugAssertWithMutCall => [DEBUG_ASSERT_WITH_MUT_CALL]);

const DEBUG_MACRO_NAMES: [&str; 3] = ["debug_assert", "debug_assert_eq", "debug_assert_ne"];

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DebugAssertWithMutCall {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
        for dmn in &DEBUG_MACRO_NAMES {
            if is_direct_expn_of(e.span, dmn).is_some() {
                if let Some(span) = extract_call(cx, e) {
                    span_lint(
                        cx,
                        DEBUG_ASSERT_WITH_MUT_CALL,
                        span,
                        &format!("do not call a function with mutable arguments inside of `{}!`", dmn),
                    );
                }
            }
        }
    }
}

//HACK(hellow554): remove this when #4694 is implemented
#[allow(clippy::cognitive_complexity)]
fn extract_call<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) -> Option<Span> {
    if_chain! {
        if let ExprKind::Block(ref block, _) = e.kind;
        if block.stmts.len() == 1;
        if let StmtKind::Semi(ref matchexpr) = block.stmts[0].kind;
        then {
            // debug_assert
            if_chain! {
                if let ExprKind::Match(ref ifclause, _, _) = matchexpr.kind;
                if let ExprKind::DropTemps(ref droptmp) = ifclause.kind;
                if let ExprKind::Unary(UnOp::UnNot, ref condition) = droptmp.kind;
                then {
                    let mut visitor = MutArgVisitor::new(cx);
                    visitor.visit_expr(condition);
                    return visitor.expr_span();
                }
            }

            // debug_assert_{eq,ne}
            if_chain! {
                if let ExprKind::Block(ref matchblock, _) = matchexpr.kind;
                if let Some(ref matchheader) = matchblock.expr;
                if let ExprKind::Match(ref headerexpr, _, _) = matchheader.kind;
                if let ExprKind::Tup(ref conditions) = headerexpr.kind;
                if conditions.len() == 2;
                then {
                    if let ExprKind::AddrOf(BorrowKind::Ref, _, ref lhs) = conditions[0].kind {
                        let mut visitor = MutArgVisitor::new(cx);
                        visitor.visit_expr(lhs);
                        if let Some(span) = visitor.expr_span() {
                            return Some(span);
                        }
                    }
                    if let ExprKind::AddrOf(BorrowKind::Ref, _, ref rhs) = conditions[1].kind {
                        let mut visitor = MutArgVisitor::new(cx);
                        visitor.visit_expr(rhs);
                        if let Some(span) = visitor.expr_span() {
                            return Some(span);
                        }
                    }
                }
            }
        }
    }

    None
}

struct MutArgVisitor<'a, 'tcx> {
    cx: &'a LateContext<'a, 'tcx>,
    expr_span: Option<Span>,
    found: bool,
}

impl<'a, 'tcx> MutArgVisitor<'a, 'tcx> {
    fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
        Self {
            cx,
            expr_span: None,
            found: false,
        }
    }

    fn expr_span(&self) -> Option<Span> {
        if self.found {
            self.expr_span
        } else {
            None
        }
    }
}

impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
        match expr.kind {
            ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) => {
                self.found = true;
                return;
            },
            ExprKind::Path(_) => {
                if let Some(adj) = self.cx.tables.adjustments().get(expr.hir_id) {
                    if adj
                        .iter()
                        .any(|a| matches!(a.target.kind, ty::Ref(_, _, Mutability::Mut)))
                    {
                        self.found = true;
                        return;
                    }
                }
            },
            _ if !self.found => self.expr_span = Some(expr.span),
            _ => return,
        }
        walk_expr(self, expr)
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
        NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir())
    }
}
<|endoftext|>