<commit_before>// Copyright 2020-2021 The Propverify authors
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::{collections::HashMap, ffi::OsString, fs, path::Path, process::Command};

use lazy_static::lazy_static;
use log::{info, warn};
use regex::Regex;

use crate::{utils::Append, *};

/// Check if Klee is avilable.
pub fn check_install() -> bool {
    let output = Command::new("which").arg("klee").output().ok();

    match output {
        Some(output) => output.status.success(),
        None => false,
    }
}

/// Run Klee and replay
pub fn verify(opt: &Opt, name: &str, entry: &str, bcfile: &Path) -> CVResult<Status> {
    let out_dir = opt.cargo_toml.with_file_name("kleeout").append(name);

    // Ignoring result. We don't care if it fails because the path doesn't
    // exist.
    fs::remove_dir_all(&out_dir).unwrap_or_default();
    if out_dir.exists() {
        Err(format!(
            "Directory or file '{}' already exists, and can't be removed",
            out_dir.to_string_lossy()
        ))?
    }

    info!("     Running KLEE to verify {}", name);
    info!("      file: {}", bcfile.to_string_lossy());
    info!("      entry: {}", entry);
    info!("      results: {}", out_dir.to_string_lossy());

    let (status, stats) = run(&opt, &name, &entry, &bcfile, &out_dir)?;
    if !stats.is_empty() {
        match stats.get("completed paths") {
            Some(n) => info!("     {}: {} paths", name, n),
            None => (),
        }
        info!("     {}: {:?}", name, stats);
    }

    // {out_dir}/test*.err
    let mut failures =
        glob(&glob::Pattern::escape(out_dir.to_str().ok_or("not UTF-8")?).append("/test*.err"))?
            .filter_map(Result::ok)
            .collect::<Vec<_>>();
    failures.sort_unstable();
    info!("      Failing test: {:?}", failures);

    if opt.replay > 0 {
        // use -r -r to see all tests, not just failing tests
        let mut ktests = if opt.replay > 1 {
            // {out_dir}/test*.ktest
            glob(
                &glob::Pattern::escape(out_dir.to_str().ok_or("not UTF-8")?).append("/test*.ktest"),
            )?
            .filter_map(Result::ok)
            .collect::<Vec<_>>()
        } else {
            // Remove the '.err' extension and replace the '.*' ('.abort' or
            // '.ptr') with '.ktest'.
            failures
                .iter()
                .map(|p| {
                    p.with_extension("") // Remove '.err'
                        .with_extension("ktest") // Replace '.*' with '.ktest'
                })
                .collect::<Vec<_>>()
        };
        ktests.sort_unstable();

        for ktest in ktests {
            println!("    Test input {}", ktest.to_str().unwrap_or("???"));
            match replay_klee(&opt, &name, &ktest) {
                Ok(()) => (),
                Err(err) => warn!("Failed to replay: {}", err),
            }
        }
    }

    Ok(status)
}

/// Return an int indicating importance of a line from KLEE's output
/// Low numbers are most important, high numbers least important
///
/// -1: script error (always shown)
/// 1: brief description of error
/// 2: long details about an error
/// 3: warnings
/// 4: non-KLEE output
/// 5: any other KLEE output
fn importance(line: &str, expect: &Option<&str>, name: &str) -> i8 {
    if line.starts_with("VERIFIER_EXPECT:") {
        4
    } else if backends_common::is_expected_panic(&line, &expect, &name) {
        // low priority because we report it directly
        5
    } else if line.contains("assertion failed") {
        1
    } else if line.contains("verification failed") {
        1
    } else if line.contains("with overflow") {
        1
    } else if line.starts_with("KLEE: ERROR: Could not link") {
        -1
    } else if line.starts_with("KLEE: ERROR: Unable to load symbol") {
        -1
    } else if line.starts_with("KLEE: ERROR:") {
        2
    } else if line.starts_with("warning: Linking two modules of different data layouts") {
        4
    } else if line.contains("KLEE: WARNING:") {
        4
    } else if line.contains("KLEE: WARNING ONCE:") {
        4
    } else if line.starts_with("KLEE: output directory") {
        5
    } else if line.starts_with("KLEE: Using") {
        5
    } else if line.starts_with("KLEE: NOTE: Using POSIX model") {
        5
    } else if line.starts_with("KLEE: done:") {
        5
    } else if line.starts_with("KLEE: HaltTimer invoked") {
        5
    } else if line.starts_with("KLEE: halting execution, dumping remaining states") {
        5
    } else if line.starts_with("KLEE: NOTE: now ignoring this error at this location") {
        5
    } else if line.starts_with("KLEE:") {
        // Really high priority to force me to categorize it
        0
    } else {
        // Remaining output is probably output from the application, stack dumps, etc.
        3
    }
}

/// Run Klee and analyse its output.
fn run(
    opt: &Opt,
    name: &str,
    entry: &str,
    bcfile: &Path,
    out_dir: &Path,
) -> CVResult<(Status, HashMap<String, isize>)> {
    let (_, stderr, _) = Command::new("klee")
        .args(&[
            "--exit-on-error",
            "--entry-point",
            entry,
            // "--posix-runtime",
            // "--libcxx",
            "--libc=klee",
            "--silent-klee-assume",
            "--disable-verify", // workaround https://github.com/klee/klee/issues/937
        ])
        .arg("--output-dir")
        .arg(out_dir)
        .args(&opt.backend_flags)
        .arg(bcfile)
        .args(&opt.args)
        // .current_dir(&opt.crate_dir);
        .latin1_output_info_ignore_exit()?;

    // We scan stderr for:
    // 1. Indications of the expected output (eg from #[should_panic])
    // 2. Indications of success/failure
    // 3. Information relevant at the current level of verbosity
    // 4. Statistics

    // Scan for expectation message
    let mut expect = None;
    for l in stderr.lines() {
        if l == "VERIFIER_EXPECT: should_panic" {
            expect = Some("");
        } else if let Some(e) = l
            .strip_prefix("VERIFIER_EXPECT: should_panic(expected = \"")
            .and_then(|l| l.strip_suffix("\")"))
        {
            info!("Expecting '{}'", e);
            expect = Some(e);
        }
    }

    // Scan for first message that indicates result
    let status = stderr
        .lines()
        .find_map(|l| {
            if l.starts_with("KLEE: HaltTimer invoked") {
                Some(Status::Timeout)
            } else if l.starts_with("KLEE: halting execution, dumping remaining states") {
                Some(Status::Timeout)
            } else if l.starts_with("KLEE: ERROR: Could not link") {
                Some(Status::Unknown)
            } else if l.starts_with("KLEE: ERROR: Unable to load symbol") {
                Some(Status::Unknown)
            } else if l.starts_with("KLEE: ERROR:") && l.contains("unreachable") {
                Some(Status::Reachable)
            } else if l.starts_with("KLEE: ERROR:") && l.contains("overflow") {
                Some(Status::Overflow)
            } else if l.starts_with("KLEE: ERROR:") {
                Some(Status::Error)
            } else if l.starts_with("VERIFIER_EXPECT:") {
                // don't confuse this line with an error!
                None
            } else if backends_common::is_expected_panic(&l, &expect, &name) {
                Some(Status::Verified)
            } else if l.contains("assertion failed") {
                Some(Status::Error)
            } else if l.contains("verification failed") {
                Some(Status::Error)
            } else if l.contains("with overflow") {
                Some(Status::Overflow)
            } else if l.contains("note: run with `RUST_BACKTRACE=1`") {
                Some(Status::Error)
            } else if l.contains("KLEE: done:") {
                match expect {
                    None => Some(Status::Verified),
                    _ => Some(Status::Error),
                }
            } else {
                None
            }
        })
        .unwrap_or_else(|| {
            warn!("Unable to determine status of {}", name);
            Status::Unknown
        });

    info!(
        "Status: '{}' expected: '{:?}'",
        status,
        expect
    );

    // Scan for statistics
    lazy_static! {
        static ref KLEE_DONE: Regex = Regex::new(r"^KLEE: done:\s+(.*)= (\d+)").unwrap();
    }

    let stats: HashMap<String, isize> = stderr
        .lines()
        // .filter(|l| l.starts_with("KLEE: done:"))
        .filter_map(|l| {
            KLEE_DONE.captures(l).and_then(|caps| {
                // If the value doesn't parse we throw the line.
                caps.get(2)
                    .unwrap()
                    .as_str()
                    .parse::<isize>()
                    .ok()
                    .map(|v| (caps.get(1).unwrap().as_str().trim().to_string(), v))
            })
        })
        .collect();

    for l in stderr.lines() {
        if importance(&l, &expect, &name) < opt.verbose as i8 {
            println!("{}", l);
        }
    }

    Ok((status, stats))
}

/// Replay a KLEE "ktest" file
fn replay_klee(opt: &Opt, name: &str, ktest: &Path) -> CVResult<()> {
    let mut cmd = Command::new("cargo");

    if opt.tests || !opt.test.is_empty() {
        cmd.arg("test")
            .arg("--manifest-path").arg(&opt.cargo_toml);

        if !opt.features.is_empty() {
            cmd.arg("--features").arg(opt.features.join(","));
        }

        cmd.arg(&name).args(&["--", "--nocapture"]);
    } else {
        cmd.arg("run")
            .arg("--manifest-path").arg(&opt.cargo_toml);

        if !opt.features.is_empty() {
            cmd.arg("--features").arg(opt.features.join(","));
        }

        if !opt.args.is_empty() {
            cmd.arg("--").args(opt.args.iter());
        }
    }

    let rustflags = match std::env::var_os("RUSTFLAGS") {
        Some(env_rustflags) => env_rustflags.append(" --cfg=verify"),
        None => OsString::from("--cfg=verify"),
    };
    cmd.env("RUSTFLAGS", rustflags).env("KTEST_FILE", ktest);

    // Note that we do not treat this as an error, because
    // the interesting case for replay is when KLEE had found an error.
    let (stdout, stderr, _success) = cmd.output_info_ignore_exit()?;

    for line in stdout.lines().chain(stderr.lines()) {
        println!("{}", line);
    }

    Ok(())
}
<commit_msg>Cargo-verify: create kleeout directory if needed<commit_after>// Copyright 2020-2021 The Propverify authors
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::{collections::HashMap, ffi::OsString, fs, path::Path, process::Command};

use lazy_static::lazy_static;
use log::{info, warn};
use regex::Regex;

use crate::{utils::Append, *};

/// Check if Klee is avilable.
pub fn check_install() -> bool {
    let output = Command::new("which").arg("klee").output().ok();

    match output {
        Some(output) => output.status.success(),
        None => false,
    }
}

/// Run Klee and replay
pub fn verify(opt: &Opt, name: &str, entry: &str, bcfile: &Path) -> CVResult<Status> {
    // KLEE output files are put in kleeout directory with filename `name`
    let klee_dir = opt.cargo_toml.with_file_name("kleeout");
    fs::create_dir_all(&klee_dir)?;

    let out_dir = klee_dir.append(name);
    // Ignoring result. We don't care if it fails because the path doesn't
    // exist.
    fs::remove_dir_all(&out_dir).unwrap_or_default();
    if out_dir.exists() {
        Err(format!(
            "Directory or file '{}' already exists, and can't be removed",
            out_dir.to_string_lossy()
        ))?
    }

    info!("     Running KLEE to verify {}", name);
    info!("      file: {}", bcfile.to_string_lossy());
    info!("      entry: {}", entry);
    info!("      results: {}", out_dir.to_string_lossy());

    let (status, stats) = run(&opt, &name, &entry, &bcfile, &out_dir)?;
    if !stats.is_empty() {
        match stats.get("completed paths") {
            Some(n) => info!("     {}: {} paths", name, n),
            None => (),
        }
        info!("     {}: {:?}", name, stats);
    }

    // {out_dir}/test*.err
    let mut failures =
        glob(&glob::Pattern::escape(out_dir.to_str().ok_or("not UTF-8")?).append("/test*.err"))?
            .filter_map(Result::ok)
            .collect::<Vec<_>>();
    failures.sort_unstable();
    info!("      Failing test: {:?}", failures);

    if opt.replay > 0 {
        // use -r -r to see all tests, not just failing tests
        let mut ktests = if opt.replay > 1 {
            // {out_dir}/test*.ktest
            glob(
                &glob::Pattern::escape(out_dir.to_str().ok_or("not UTF-8")?).append("/test*.ktest"),
            )?
            .filter_map(Result::ok)
            .collect::<Vec<_>>()
        } else {
            // Remove the '.err' extension and replace the '.*' ('.abort' or
            // '.ptr') with '.ktest'.
            failures
                .iter()
                .map(|p| {
                    p.with_extension("") // Remove '.err'
                        .with_extension("ktest") // Replace '.*' with '.ktest'
                })
                .collect::<Vec<_>>()
        };
        ktests.sort_unstable();

        for ktest in ktests {
            println!("    Test input {}", ktest.to_str().unwrap_or("???"));
            match replay_klee(&opt, &name, &ktest) {
                Ok(()) => (),
                Err(err) => warn!("Failed to replay: {}", err),
            }
        }
    }

    Ok(status)
}

/// Return an int indicating importance of a line from KLEE's output
/// Low numbers are most important, high numbers least important
///
/// -1: script error (always shown)
/// 1: brief description of error
/// 2: long details about an error
/// 3: warnings
/// 4: non-KLEE output
/// 5: any other KLEE output
fn importance(line: &str, expect: &Option<&str>, name: &str) -> i8 {
    if line.starts_with("VERIFIER_EXPECT:") {
        4
    } else if backends_common::is_expected_panic(&line, &expect, &name) {
        // low priority because we report it directly
        5
    } else if line.contains("assertion failed") {
        1
    } else if line.contains("verification failed") {
        1
    } else if line.contains("with overflow") {
        1
    } else if line.starts_with("KLEE: ERROR: Could not link") {
        -1
    } else if line.starts_with("KLEE: ERROR: Unable to load symbol") {
        -1
    } else if line.starts_with("KLEE: ERROR:") {
        2
    } else if line.starts_with("warning: Linking two modules of different data layouts") {
        4
    } else if line.contains("KLEE: WARNING:") {
        4
    } else if line.contains("KLEE: WARNING ONCE:") {
        4
    } else if line.starts_with("KLEE: output directory") {
        5
    } else if line.starts_with("KLEE: Using") {
        5
    } else if line.starts_with("KLEE: NOTE: Using POSIX model") {
        5
    } else if line.starts_with("KLEE: done:") {
        5
    } else if line.starts_with("KLEE: HaltTimer invoked") {
        5
    } else if line.starts_with("KLEE: halting execution, dumping remaining states") {
        5
    } else if line.starts_with("KLEE: NOTE: now ignoring this error at this location") {
        5
    } else if line.starts_with("KLEE:") {
        // Really high priority to force me to categorize it
        0
    } else {
        // Remaining output is probably output from the application, stack dumps, etc.
        3
    }
}

/// Run Klee and analyse its output.
fn run(
    opt: &Opt,
    name: &str,
    entry: &str,
    bcfile: &Path,
    out_dir: &Path,
) -> CVResult<(Status, HashMap<String, isize>)> {
    let (_, stderr, _) = Command::new("klee")
        .args(&[
            "--exit-on-error",
            "--entry-point",
            entry,
            // "--posix-runtime",
            // "--libcxx",
            "--libc=klee",
            "--silent-klee-assume",
            "--disable-verify", // workaround https://github.com/klee/klee/issues/937
        ])
        .arg("--output-dir")
        .arg(out_dir)
        .args(&opt.backend_flags)
        .arg(bcfile)
        .args(&opt.args)
        // .current_dir(&opt.crate_dir);
        .latin1_output_info_ignore_exit()?;

    // We scan stderr for:
    // 1. Indications of the expected output (eg from #[should_panic])
    // 2. Indications of success/failure
    // 3. Information relevant at the current level of verbosity
    // 4. Statistics

    // Scan for expectation message
    let mut expect = None;
    for l in stderr.lines() {
        if l == "VERIFIER_EXPECT: should_panic" {
            expect = Some("");
        } else if let Some(e) = l
            .strip_prefix("VERIFIER_EXPECT: should_panic(expected = \"")
            .and_then(|l| l.strip_suffix("\")"))
        {
            info!("Expecting '{}'", e);
            expect = Some(e);
        }
    }

    // Scan for first message that indicates result
    let status = stderr
        .lines()
        .find_map(|l| {
            if l.starts_with("KLEE: HaltTimer invoked") {
                Some(Status::Timeout)
            } else if l.starts_with("KLEE: halting execution, dumping remaining states") {
                Some(Status::Timeout)
            } else if l.starts_with("KLEE: ERROR: Could not link") {
                Some(Status::Unknown)
            } else if l.starts_with("KLEE: ERROR: Unable to load symbol") {
                Some(Status::Unknown)
            } else if l.starts_with("KLEE: ERROR:") && l.contains("unreachable") {
                Some(Status::Reachable)
            } else if l.starts_with("KLEE: ERROR:") && l.contains("overflow") {
                Some(Status::Overflow)
            } else if l.starts_with("KLEE: ERROR:") {
                Some(Status::Error)
            } else if l.starts_with("VERIFIER_EXPECT:") {
                // don't confuse this line with an error!
                None
            } else if backends_common::is_expected_panic(&l, &expect, &name) {
                Some(Status::Verified)
            } else if l.contains("assertion failed") {
                Some(Status::Error)
            } else if l.contains("verification failed") {
                Some(Status::Error)
            } else if l.contains("with overflow") {
                Some(Status::Overflow)
            } else if l.contains("note: run with `RUST_BACKTRACE=1`") {
                Some(Status::Error)
            } else if l.contains("KLEE: done:") {
                match expect {
                    None => Some(Status::Verified),
                    _ => Some(Status::Error),
                }
            } else {
                None
            }
        })
        .unwrap_or_else(|| {
            warn!("Unable to determine status of {}", name);
            Status::Unknown
        });

    info!(
        "Status: '{}' expected: '{:?}'",
        status,
        expect
    );

    // Scan for statistics
    lazy_static! {
        static ref KLEE_DONE: Regex = Regex::new(r"^KLEE: done:\s+(.*)= (\d+)").unwrap();
    }

    let stats: HashMap<String, isize> = stderr
        .lines()
        // .filter(|l| l.starts_with("KLEE: done:"))
        .filter_map(|l| {
            KLEE_DONE.captures(l).and_then(|caps| {
                // If the value doesn't parse we throw the line.
                caps.get(2)
                    .unwrap()
                    .as_str()
                    .parse::<isize>()
                    .ok()
                    .map(|v| (caps.get(1).unwrap().as_str().trim().to_string(), v))
            })
        })
        .collect();

    for l in stderr.lines() {
        if importance(&l, &expect, &name) < opt.verbose as i8 {
            println!("{}", l);
        }
    }

    Ok((status, stats))
}

/// Replay a KLEE "ktest" file
fn replay_klee(opt: &Opt, name: &str, ktest: &Path) -> CVResult<()> {
    let mut cmd = Command::new("cargo");

    if opt.tests || !opt.test.is_empty() {
        cmd.arg("test")
            .arg("--manifest-path").arg(&opt.cargo_toml);

        if !opt.features.is_empty() {
            cmd.arg("--features").arg(opt.features.join(","));
        }

        cmd.arg(&name).args(&["--", "--nocapture"]);
    } else {
        cmd.arg("run")
            .arg("--manifest-path").arg(&opt.cargo_toml);

        if !opt.features.is_empty() {
            cmd.arg("--features").arg(opt.features.join(","));
        }

        if !opt.args.is_empty() {
            cmd.arg("--").args(opt.args.iter());
        }
    }

    let rustflags = match std::env::var_os("RUSTFLAGS") {
        Some(env_rustflags) => env_rustflags.append(" --cfg=verify"),
        None => OsString::from("--cfg=verify"),
    };
    cmd.env("RUSTFLAGS", rustflags).env("KTEST_FILE", ktest);

    // Note that we do not treat this as an error, because
    // the interesting case for replay is when KLEE had found an error.
    let (stdout, stderr, _success) = cmd.output_info_ignore_exit()?;

    for line in stdout.lines().chain(stderr.lines()) {
        println!("{}", line);
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! Event callbacks.

use cairo::Context;
use gdk::{EventButton, EventMotion, EventScroll, ScrollDirection, EventKey, keyval_from_name};
use gtk::{DrawingArea, Inhibit, WidgetExt};

use super::sounding_context;
use super::super::data_context;

mod drawing;

/// Draws the sounding, connected to the on-draw event signal.
pub fn draw_sounding(
    sounding_area: &DrawingArea,
    cr: &Context,
    sc: &sounding_context::SoundingContextPointer,
    dc: &data_context::DataContextPointer,
) -> Inhibit {
    use self::drawing::TemperatureType::{DryBulb, WetBulb, DewPoint};

    let mut sc = sc.borrow_mut();
    let dc = dc.borrow();

    drawing::prepare_to_draw(sounding_area, cr, &mut sc);

    // Draw isentrops, isotherms, isobars, ...
    drawing::draw_background_lines(&cr, &sc);

    // Draw temperature profiles
    drawing::draw_temperature_profile(DryBulb, &cr, &sc, &dc);
    drawing::draw_temperature_profile(WetBulb, &cr, &sc, &dc);
    drawing::draw_temperature_profile(DewPoint, &cr, &sc, &dc);

    Inhibit(false)
}

/// Handles zooming from the mouse whell. Connected to the scroll-event signal.
pub fn scroll_event(
    sounding_area: &DrawingArea,
    event: &EventScroll,
    sc: &sounding_context::SoundingContextPointer,
) -> Inhibit {

    const DELTA_SCALE: f32 = 1.05;
    const MIN_ZOOM: f32 = 1.0;
    const MAX_ZOOM: f32 = 10.0;

    let mut sc = sc.borrow_mut();

    let pos = sc.convert_device_to_xy(event.get_position());
    let dir = event.get_direction();

    let old_zoom = sc.zoom_factor;

    match dir {
        ScrollDirection::Up => {
            sc.zoom_factor *= DELTA_SCALE;
        }
        ScrollDirection::Down => {
            sc.zoom_factor /= DELTA_SCALE;
        }
        _ => {}
    }

    if sc.zoom_factor < MIN_ZOOM {
        sc.zoom_factor = MIN_ZOOM;
    } else if sc.zoom_factor > MAX_ZOOM {
        sc.zoom_factor = MAX_ZOOM;
    }

    sc.translate_x = pos.0 - old_zoom / sc.zoom_factor * (pos.0 - sc.translate_x);
    sc.translate_y = pos.1 - old_zoom / sc.zoom_factor * (pos.1 - sc.translate_y);

    sounding_area.queue_draw();

    Inhibit(true)
}

/// Handles button press events
pub fn button_press_event(
    _sounding_area: &DrawingArea,
    event: &EventButton,
    sc: &sounding_context::SoundingContextPointer,
) -> Inhibit {

    // Left mouse button
    if event.get_button() == 1 {
        let mut sc = sc.borrow_mut();
        sc.left_button_press_start = event.get_position();
        sc.left_button_pressed = true;
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}

/// Handles button release events
pub fn button_release_event(
    _sounding_area: &DrawingArea,
    event: &EventButton,
    sc: &sounding_context::SoundingContextPointer,
) -> Inhibit {
    if event.get_button() == 1 {
        let mut sc = sc.borrow_mut();
        sc.left_button_press_start = (0.0, 0.0);
        sc.left_button_pressed = false;
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}

/// Handles motion events
pub fn mouse_motion_event(
    sounding_area: &DrawingArea,
    event: &EventMotion,
    sc: &sounding_context::SoundingContextPointer,
) -> Inhibit {

    let mut sc = sc.borrow_mut();
    if sc.left_button_pressed {
        let old_position = sc.convert_device_to_xy(sc.left_button_press_start);
        sc.left_button_press_start = event.get_position();
        let new_position = sc.convert_device_to_xy(sc.left_button_press_start);
        let delta = (
            new_position.0 - old_position.0,
            new_position.1 - old_position.1,
        );
        sc.translate_x -= delta.0;
        sc.translate_y -= delta.1;

        sounding_area.queue_draw();
        Inhibit(true)
    } else {

        Inhibit(false)
    }
}

/// Handles key-release events, display next or previous sounding in a series.
pub fn key_release_event(
    _sounding_area: &DrawingArea,
    event: &EventKey,
    dc: &data_context::DataContextPointer,
) -> Inhibit {

    let keyval = event.get_keyval();
    if keyval == keyval_from_name("Right") || keyval == keyval_from_name("KP_Right") {
        let mut dc = dc.borrow_mut();
        dc.display_next();
        Inhibit(true)
    } else if keyval == keyval_from_name("Left") || keyval == keyval_from_name("KP_Left") {
        let mut dc = dc.borrow_mut();
        dc.display_previous();
        Inhibit(true)
    } else {
        Inhibit(false)
    }

}
<commit_msg>Change order of drawing.<commit_after>//! Event callbacks.

use cairo::Context;
use gdk::{EventButton, EventMotion, EventScroll, ScrollDirection, EventKey, keyval_from_name};
use gtk::{DrawingArea, Inhibit, WidgetExt};

use super::sounding_context;
use super::super::data_context;

mod drawing;

/// Draws the sounding, connected to the on-draw event signal.
pub fn draw_sounding(
    sounding_area: &DrawingArea,
    cr: &Context,
    sc: &sounding_context::SoundingContextPointer,
    dc: &data_context::DataContextPointer,
) -> Inhibit {
    use self::drawing::TemperatureType::{DryBulb, WetBulb, DewPoint};

    let mut sc = sc.borrow_mut();
    let dc = dc.borrow();

    drawing::prepare_to_draw(sounding_area, cr, &mut sc);

    // Draw isentrops, isotherms, isobars, ...
    drawing::draw_background_lines(&cr, &sc);

    // Draw temperature profiles
    drawing::draw_temperature_profile(WetBulb, &cr, &sc, &dc);
    drawing::draw_temperature_profile(DewPoint, &cr, &sc, &dc);
    drawing::draw_temperature_profile(DryBulb, &cr, &sc, &dc);

    Inhibit(false)
}

/// Handles zooming from the mouse whell. Connected to the scroll-event signal.
pub fn scroll_event(
    sounding_area: &DrawingArea,
    event: &EventScroll,
    sc: &sounding_context::SoundingContextPointer,
) -> Inhibit {

    const DELTA_SCALE: f32 = 1.05;
    const MIN_ZOOM: f32 = 1.0;
    const MAX_ZOOM: f32 = 10.0;

    let mut sc = sc.borrow_mut();

    let pos = sc.convert_device_to_xy(event.get_position());
    let dir = event.get_direction();

    let old_zoom = sc.zoom_factor;

    match dir {
        ScrollDirection::Up => {
            sc.zoom_factor *= DELTA_SCALE;
        }
        ScrollDirection::Down => {
            sc.zoom_factor /= DELTA_SCALE;
        }
        _ => {}
    }

    if sc.zoom_factor < MIN_ZOOM {
        sc.zoom_factor = MIN_ZOOM;
    } else if sc.zoom_factor > MAX_ZOOM {
        sc.zoom_factor = MAX_ZOOM;
    }

    sc.translate_x = pos.0 - old_zoom / sc.zoom_factor * (pos.0 - sc.translate_x);
    sc.translate_y = pos.1 - old_zoom / sc.zoom_factor * (pos.1 - sc.translate_y);

    sounding_area.queue_draw();

    Inhibit(true)
}

/// Handles button press events
pub fn button_press_event(
    _sounding_area: &DrawingArea,
    event: &EventButton,
    sc: &sounding_context::SoundingContextPointer,
) -> Inhibit {

    // Left mouse button
    if event.get_button() == 1 {
        let mut sc = sc.borrow_mut();
        sc.left_button_press_start = event.get_position();
        sc.left_button_pressed = true;
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}

/// Handles button release events
pub fn button_release_event(
    _sounding_area: &DrawingArea,
    event: &EventButton,
    sc: &sounding_context::SoundingContextPointer,
) -> Inhibit {
    if event.get_button() == 1 {
        let mut sc = sc.borrow_mut();
        sc.left_button_press_start = (0.0, 0.0);
        sc.left_button_pressed = false;
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}

/// Handles motion events
pub fn mouse_motion_event(
    sounding_area: &DrawingArea,
    event: &EventMotion,
    sc: &sounding_context::SoundingContextPointer,
) -> Inhibit {

    let mut sc = sc.borrow_mut();
    if sc.left_button_pressed {
        let old_position = sc.convert_device_to_xy(sc.left_button_press_start);
        sc.left_button_press_start = event.get_position();
        let new_position = sc.convert_device_to_xy(sc.left_button_press_start);
        let delta = (
            new_position.0 - old_position.0,
            new_position.1 - old_position.1,
        );
        sc.translate_x -= delta.0;
        sc.translate_y -= delta.1;

        sounding_area.queue_draw();
        Inhibit(true)
    } else {

        Inhibit(false)
    }
}

/// Handles key-release events, display next or previous sounding in a series.
pub fn key_release_event(
    _sounding_area: &DrawingArea,
    event: &EventKey,
    dc: &data_context::DataContextPointer,
) -> Inhibit {

    let keyval = event.get_keyval();
    if keyval == keyval_from_name("Right") || keyval == keyval_from_name("KP_Right") {
        let mut dc = dc.borrow_mut();
        dc.display_next();
        Inhibit(true)
    } else if keyval == keyval_from_name("Left") || keyval == keyval_from_name("KP_Left") {
        let mut dc = dc.borrow_mut();
        dc.display_previous();
        Inhibit(true)
    } else {
        Inhibit(false)
    }

}
<|endoftext|>


<commit_before>use cogset::{Euclid, KmeansBuilder};

use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::collections::HashMap;

pub fn aunt_sue_1(file: &str) -> i32 {
    process(file)
}

pub fn aunt_sue_2(file: &str) -> i32 {
    process(file)
}

fn process(file: &str) -> i32 {
    let input = File::open(file).expect("File open fail.");
    let reader = BufReader::new(input);

    let lines = reader.lines()
        .filter_map(Result::ok)
        .collect::<Vec<String>>();

    let mut sues = HashMap::new();
    for line in lines.iter() {
        let mut words = line.split_whitespace()
            .map(|w| w.trim_matches(|c| c == ':' || c == ','));
        if let Some(id) = words.nth(1) {
            if let Ok(id) = id.parse::<u32>() {
                loop {
                    if let Some(name) = words.next() {
                        if let Some(value) = words.next() {
                            if let Ok(value) = value.parse::<f64>() {
                                let sue_info = sues.entry(id).or_insert(HashMap::new());
                                sue_info.insert(name, value);
                            }
                        }
                    } else {
                        break
                    }
                }
            }
        }
    }
    println!("{:?}", sues);

    let mut sue_data = Vec::new();
    for (id, sue) in sues.iter() {
        sue_data.push(Euclid([
                         id.clone() as f64,
            sue.get("children")
                .unwrap_or(&0.).clone(),
            sue.get("cats")
                .unwrap_or(&0.).clone(),
            sue.get("samoyeds")
                .unwrap_or(&0.).clone(),
            sue.get("pomeranians")
                .unwrap_or(&0.).clone(),
            sue.get("akitas")
                .unwrap_or(&0.).clone(),
            sue.get("vizslas")
                .unwrap_or(&0.).clone(),
            sue.get("goldfish")
                .unwrap_or(&0.).clone(),
            sue.get("trees")
                .unwrap_or(&0.).clone(),
            sue.get("cars")
                .unwrap_or(&0.).clone(),
            sue.get("perfumes")
                .unwrap_or(&0.).clone(),
            ]));
    }

    println!("{:?}", sue_data);

    // TODO Probably perform some sort of clustering/classification here
    let k = 3;
    let tolerance = 1e-12;
    let kmeans = KmeansBuilder::new().tolerance(tolerance)
        .kmeans(&sue_data, k);
    println!("{:?}", kmeans.clusters());
    42
}
<commit_msg>Update to run clustering multiple times.<commit_after>use cogset::{Euclid, KmeansBuilder};
use rand::{thread_rng, Rng};

use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::collections::HashMap;
use std::str;

pub fn aunt_sue_1(file: &str) -> i32 {
    process(file)
}

pub fn aunt_sue_2(file: &str) -> i32 {
    process(file)
}

fn process(file: &str) -> i32 {
    let input = File::open(file).expect("File open fail.");
    let reader = BufReader::new(input);

    let lines = reader.lines()
        .filter_map(Result::ok)
        .collect::<Vec<String>>();

    let mut sues = HashMap::new();
    let mut sue_ids = Vec::new();
    for line in lines.iter() {
        let mut words = line.split_whitespace()
            .map(|w| w.trim_matches(|c| c == ':' || c == ','));
        if let Some(id) = words.nth(1) {
            if let Ok(id) = id.parse::<usize>() {
                sue_ids.push(id);
                loop {
                    if let Some(name) = words.next() {
                        if let Some(value) = words.next() {
                            if let Ok(value) = value.parse::<f64>() {
                                let sue_info = sues.entry(id).or_insert(HashMap::new());
                                sue_info.insert(name, value);
                            }
                        }
                    } else {
                        break
                    }
                }
            }
        }
    }
    //println!("{:?}", sues);

    let mut sue_analysis = HashMap::new();
    sue_analysis.insert("children", 3.);
    sue_analysis.insert("cats", 7.);
    sue_analysis.insert("samoyeds", 2.);
    sue_analysis.insert("pomeranians", 3.);
    sue_analysis.insert("akitas", 0.);
    sue_analysis.insert("vizslas", 0.);
    sue_analysis.insert("goldfish", 5.);
    sue_analysis.insert("trees", 3.);
    sue_analysis.insert("cars", 2.);
    sue_analysis.insert("perfumes", 1.);
    sues.insert(0, sue_analysis);
    sue_ids.push(0);

    //println!("{:?}", sue_data);

    // TODO Probably perform some sort of clustering/classification here
    let mut sue_data = Vec::new();
    let k = 3;
    let tolerance = 1e-12;
    let mut rng = thread_rng();
    for _ in 0..20 {
        sue_data.clear();
        for id in sue_ids.iter() {
            if let Some(sue) = sues.get(&id) {
                println!("Sue {}: {:?} ", id, sue);
                sue_data.push(Euclid([
                                 id.clone() as f64,
                    sue.get("children")
                        .unwrap_or(&(rng.gen_range(0., 10.))).clone(),
                    sue.get("cats")
                        .unwrap_or(&(rng.gen_range(0., 10.))).clone(),
                    sue.get("samoyeds")
                        .unwrap_or(&(rng.gen_range(0., 10.))).clone(),
                    sue.get("pomeranians")
                        .unwrap_or(&(rng.gen_range(0., 10.))).clone(),
                    sue.get("akitas")
                        .unwrap_or(&(rng.gen_range(0., 10.))).clone(),
                    sue.get("vizslas")
                        .unwrap_or(&(rng.gen_range(0., 10.))).clone(),
                    sue.get("goldfish")
                        .unwrap_or(&(rng.gen_range(0., 10.))).clone(),
                    sue.get("trees")
                        .unwrap_or(&(rng.gen_range(0., 10.))).clone(),
                    sue.get("cars")
                        .unwrap_or(&(rng.gen_range(0., 10.))).clone(),
                    sue.get("perfumes")
                        .unwrap_or(&(rng.gen_range(0., 10.))).clone(),
                    ]));
            }
        }
        let kmeans = KmeansBuilder::new().tolerance(tolerance)
            .kmeans(&sue_data, k);
        for (c, &(e, ref v)) in kmeans.clusters().iter().enumerate() {
            println!("");
            println!("Cluster: {}", c);
            println!("{:?}", e);
            if v.contains(&0) {
                println!("Next cluster to process: {}", c);
                sue_ids = v.clone();
            }
        }
        if let Ok(steps) = kmeans.converged() {
            println!("{:?}", steps);
        } else {
            break
        }
        if sue_ids.len() < 4 { break }
    }
    for id in sue_ids.iter() {
        if let Some(sue) = sues.get(&id) {
            println!("Sue {}: {:?} ", id, sue);
        }
    }
    42
}
<|endoftext|>


<commit_before>use crate::alloc::vec::Vec;
#[cfg(feature = "wasm")]
use parity_wasm::elements::{self, Deserialize};
use std::borrow::Cow;
use std::slice;
use std::u64;

use crate::{
    Machine, Object, ObjectSection, ObjectSegment, Relocation, SectionKind, Symbol, SymbolMap,
};

/// A WebAssembly object file.
#[derive(Debug)]
pub struct WasmFile {
    module: elements::Module,
}

impl<'data> WasmFile {
    /// Parse the raw wasm data.
    pub fn parse(mut data: &'data [u8]) -> Result<Self, &'static str> {
        let module =
            elements::Module::deserialize(&mut data).map_err(|_| "failed to parse wasm")?;
        Ok(WasmFile { module })
    }
}

/// An iterator over the segments of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSegmentIterator<'file> {
    file: &'file WasmFile,
}

/// A segment of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSegment<'file> {
    file: &'file WasmFile,
}

/// An iterator over the sections of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSectionIterator<'file> {
    sections: slice::Iter<'file, elements::Section>,
}

/// A section of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSection<'file> {
    section: &'file elements::Section,
}

/// An iterator over the symbols of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSymbolIterator<'file> {
    file: &'file WasmFile,
}

/// An iterator over the relocations in an `WasmSection`.
#[derive(Debug)]
pub struct WasmRelocationIterator;

fn serialize_to_cow<'a, S>(s: S) -> Option<Cow<'a, [u8]>>
where
    S: elements::Serialize,
{
    let mut buf = Vec::new();
    s.serialize(&mut buf).ok()?;
    Some(Cow::from(buf))
}

impl<'file> Object<'static, 'file> for WasmFile {
    type Segment = WasmSegment<'file>;
    type SegmentIterator = WasmSegmentIterator<'file>;
    type Section = WasmSection<'file>;
    type SectionIterator = WasmSectionIterator<'file>;
    type SymbolIterator = WasmSymbolIterator<'file>;

    fn machine(&self) -> Machine {
        Machine::Other
    }

    fn segments(&'file self) -> Self::SegmentIterator {
        WasmSegmentIterator { file: self }
    }

    fn entry(&'file self) -> u64 {
        self.module.start_section().map_or(u64::MAX, u64::from)
    }

    fn section_by_name(&'file self, section_name: &str) -> Option<WasmSection<'file>> {
        for s in self.module.sections() {
            let section = WasmSection { section: s };
            if section.name() == Some(section_name) {
                return Some(section);
            }
        }
        None
    }

    fn sections(&'file self) -> Self::SectionIterator {
        WasmSectionIterator {
            sections: self.module.sections().iter(),
        }
    }

    fn symbol_by_index(&self, _index: u64) -> Option<Symbol<'static>> {
        unimplemented!()
    }

    fn symbols(&'file self) -> Self::SymbolIterator {
        WasmSymbolIterator { file: self }
    }

    fn dynamic_symbols(&'file self) -> Self::SymbolIterator {
        WasmSymbolIterator { file: self }
    }

    fn symbol_map(&self) -> SymbolMap<'static> {
        SymbolMap {
            symbols: Vec::new(),
        }
    }

    fn is_little_endian(&self) -> bool {
        true
    }

    fn has_debug_symbols(&self) -> bool {
        // We ignore the "name" section, and use this to mean whether the wasm
        // has DWARF.
        self.module.sections().iter().any(|s| match *s {
            elements::Section::Custom(ref c) => c.name().starts_with(".debug_"),
            _ => false,
        })
    }
}

impl<'file> Iterator for WasmSegmentIterator<'file> {
    type Item = WasmSegment<'file>;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

impl<'file> ObjectSegment<'static> for WasmSegment<'file> {
    #[inline]
    fn address(&self) -> u64 {
        unreachable!()
    }

    #[inline]
    fn size(&self) -> u64 {
        unreachable!()
    }

    fn data(&self) -> &'static [u8] {
        unreachable!()
    }

    #[inline]
    fn name(&self) -> Option<&str> {
        unreachable!()
    }
}

impl<'file> Iterator for WasmSectionIterator<'file> {
    type Item = WasmSection<'file>;

    fn next(&mut self) -> Option<Self::Item> {
        self.sections.next().map(|s| WasmSection { section: s })
    }
}

impl<'file> ObjectSection<'static> for WasmSection<'file> {
    type RelocationIterator = WasmRelocationIterator;

    #[inline]
    fn address(&self) -> u64 {
        1
    }

    #[inline]
    fn size(&self) -> u64 {
        serialize_to_cow(self.section.clone()).map_or(0, |b| b.len() as u64)
    }

    fn data(&self) -> Cow<'static, [u8]> {
        match *self.section {
            elements::Section::Start(section) => {
                serialize_to_cow(elements::VarUint32::from(section))
            }
            _ => serialize_to_cow(self.section.clone()),
        }
        .unwrap_or_else(|| Cow::from(&[][..]))
    }

    #[inline]
    fn uncompressed_data(&self) -> Cow<'static, [u8]> {
        // TODO: does wasm support compression?
        self.data()
    }

    fn name(&self) -> Option<&str> {
        match *self.section {
            elements::Section::Unparsed { .. } => None,
            elements::Section::Custom(ref c) => Some(c.name()),
            elements::Section::Type(_) => Some("Type"),
            elements::Section::Import(_) => Some("Import"),
            elements::Section::Function(_) => Some("Function"),
            elements::Section::Table(_) => Some("Table"),
            elements::Section::Memory(_) => Some("Memory"),
            elements::Section::Global(_) => Some("Global"),
            elements::Section::Export(_) => Some("Export"),
            elements::Section::Start(_) => Some("Start"),
            elements::Section::Element(_) => Some("Element"),
            elements::Section::Code(_) => Some("Code"),
            elements::Section::DataCount(_) => Some("DataCount"),
            elements::Section::Data(_) => Some("Data"),
            elements::Section::Name(_) => Some("Name"),
            elements::Section::Reloc(_) => Some("Reloc"),
        }
    }

    #[inline]
    fn segment_name(&self) -> Option<&str> {
        None
    }

    fn kind(&self) -> SectionKind {
        match *self.section {
            elements::Section::Unparsed { .. } => SectionKind::Unknown,
            elements::Section::Custom(_) => SectionKind::Unknown,
            elements::Section::Type(_) => SectionKind::Other,
            elements::Section::Import(_) => SectionKind::Other,
            elements::Section::Function(_) => SectionKind::Other,
            elements::Section::Table(_) => SectionKind::Other,
            elements::Section::Memory(_) => SectionKind::Other,
            elements::Section::Global(_) => SectionKind::Other,
            elements::Section::Export(_) => SectionKind::Other,
            elements::Section::Start(_) => SectionKind::Other,
            elements::Section::Element(_) => SectionKind::Other,
            elements::Section::Code(_) => SectionKind::Text,
            elements::Section::DataCount(_) => SectionKind::Other,
            elements::Section::Data(_) => SectionKind::Data,
            elements::Section::Name(_) => SectionKind::Other,
            elements::Section::Reloc(_) => SectionKind::Other,
        }
    }

    fn relocations(&self) -> WasmRelocationIterator {
        WasmRelocationIterator
    }
}

impl<'file> Iterator for WasmSymbolIterator<'file> {
    type Item = Symbol<'static>;

    fn next(&mut self) -> Option<Self::Item> {
        unimplemented!()
    }
}

impl Iterator for WasmRelocationIterator {
    type Item = (u64, Relocation);

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}
<commit_msg>Remove unneeded line test for `wasm` feature<commit_after>use crate::alloc::vec::Vec;
use parity_wasm::elements::{self, Deserialize};
use std::borrow::Cow;
use std::slice;
use std::u64;

use crate::{
    Machine, Object, ObjectSection, ObjectSegment, Relocation, SectionKind, Symbol, SymbolMap,
};

/// A WebAssembly object file.
#[derive(Debug)]
pub struct WasmFile {
    module: elements::Module,
}

impl<'data> WasmFile {
    /// Parse the raw wasm data.
    pub fn parse(mut data: &'data [u8]) -> Result<Self, &'static str> {
        let module =
            elements::Module::deserialize(&mut data).map_err(|_| "failed to parse wasm")?;
        Ok(WasmFile { module })
    }
}

/// An iterator over the segments of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSegmentIterator<'file> {
    file: &'file WasmFile,
}

/// A segment of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSegment<'file> {
    file: &'file WasmFile,
}

/// An iterator over the sections of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSectionIterator<'file> {
    sections: slice::Iter<'file, elements::Section>,
}

/// A section of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSection<'file> {
    section: &'file elements::Section,
}

/// An iterator over the symbols of an `WasmFile`.
#[derive(Debug)]
pub struct WasmSymbolIterator<'file> {
    file: &'file WasmFile,
}

/// An iterator over the relocations in an `WasmSection`.
#[derive(Debug)]
pub struct WasmRelocationIterator;

fn serialize_to_cow<'a, S>(s: S) -> Option<Cow<'a, [u8]>>
where
    S: elements::Serialize,
{
    let mut buf = Vec::new();
    s.serialize(&mut buf).ok()?;
    Some(Cow::from(buf))
}

impl<'file> Object<'static, 'file> for WasmFile {
    type Segment = WasmSegment<'file>;
    type SegmentIterator = WasmSegmentIterator<'file>;
    type Section = WasmSection<'file>;
    type SectionIterator = WasmSectionIterator<'file>;
    type SymbolIterator = WasmSymbolIterator<'file>;

    fn machine(&self) -> Machine {
        Machine::Other
    }

    fn segments(&'file self) -> Self::SegmentIterator {
        WasmSegmentIterator { file: self }
    }

    fn entry(&'file self) -> u64 {
        self.module.start_section().map_or(u64::MAX, u64::from)
    }

    fn section_by_name(&'file self, section_name: &str) -> Option<WasmSection<'file>> {
        for s in self.module.sections() {
            let section = WasmSection { section: s };
            if section.name() == Some(section_name) {
                return Some(section);
            }
        }
        None
    }

    fn sections(&'file self) -> Self::SectionIterator {
        WasmSectionIterator {
            sections: self.module.sections().iter(),
        }
    }

    fn symbol_by_index(&self, _index: u64) -> Option<Symbol<'static>> {
        unimplemented!()
    }

    fn symbols(&'file self) -> Self::SymbolIterator {
        WasmSymbolIterator { file: self }
    }

    fn dynamic_symbols(&'file self) -> Self::SymbolIterator {
        WasmSymbolIterator { file: self }
    }

    fn symbol_map(&self) -> SymbolMap<'static> {
        SymbolMap {
            symbols: Vec::new(),
        }
    }

    fn is_little_endian(&self) -> bool {
        true
    }

    fn has_debug_symbols(&self) -> bool {
        // We ignore the "name" section, and use this to mean whether the wasm
        // has DWARF.
        self.module.sections().iter().any(|s| match *s {
            elements::Section::Custom(ref c) => c.name().starts_with(".debug_"),
            _ => false,
        })
    }
}

impl<'file> Iterator for WasmSegmentIterator<'file> {
    type Item = WasmSegment<'file>;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

impl<'file> ObjectSegment<'static> for WasmSegment<'file> {
    #[inline]
    fn address(&self) -> u64 {
        unreachable!()
    }

    #[inline]
    fn size(&self) -> u64 {
        unreachable!()
    }

    fn data(&self) -> &'static [u8] {
        unreachable!()
    }

    #[inline]
    fn name(&self) -> Option<&str> {
        unreachable!()
    }
}

impl<'file> Iterator for WasmSectionIterator<'file> {
    type Item = WasmSection<'file>;

    fn next(&mut self) -> Option<Self::Item> {
        self.sections.next().map(|s| WasmSection { section: s })
    }
}

impl<'file> ObjectSection<'static> for WasmSection<'file> {
    type RelocationIterator = WasmRelocationIterator;

    #[inline]
    fn address(&self) -> u64 {
        1
    }

    #[inline]
    fn size(&self) -> u64 {
        serialize_to_cow(self.section.clone()).map_or(0, |b| b.len() as u64)
    }

    fn data(&self) -> Cow<'static, [u8]> {
        match *self.section {
            elements::Section::Start(section) => {
                serialize_to_cow(elements::VarUint32::from(section))
            }
            _ => serialize_to_cow(self.section.clone()),
        }
        .unwrap_or_else(|| Cow::from(&[][..]))
    }

    #[inline]
    fn uncompressed_data(&self) -> Cow<'static, [u8]> {
        // TODO: does wasm support compression?
        self.data()
    }

    fn name(&self) -> Option<&str> {
        match *self.section {
            elements::Section::Unparsed { .. } => None,
            elements::Section::Custom(ref c) => Some(c.name()),
            elements::Section::Type(_) => Some("Type"),
            elements::Section::Import(_) => Some("Import"),
            elements::Section::Function(_) => Some("Function"),
            elements::Section::Table(_) => Some("Table"),
            elements::Section::Memory(_) => Some("Memory"),
            elements::Section::Global(_) => Some("Global"),
            elements::Section::Export(_) => Some("Export"),
            elements::Section::Start(_) => Some("Start"),
            elements::Section::Element(_) => Some("Element"),
            elements::Section::Code(_) => Some("Code"),
            elements::Section::DataCount(_) => Some("DataCount"),
            elements::Section::Data(_) => Some("Data"),
            elements::Section::Name(_) => Some("Name"),
            elements::Section::Reloc(_) => Some("Reloc"),
        }
    }

    #[inline]
    fn segment_name(&self) -> Option<&str> {
        None
    }

    fn kind(&self) -> SectionKind {
        match *self.section {
            elements::Section::Unparsed { .. } => SectionKind::Unknown,
            elements::Section::Custom(_) => SectionKind::Unknown,
            elements::Section::Type(_) => SectionKind::Other,
            elements::Section::Import(_) => SectionKind::Other,
            elements::Section::Function(_) => SectionKind::Other,
            elements::Section::Table(_) => SectionKind::Other,
            elements::Section::Memory(_) => SectionKind::Other,
            elements::Section::Global(_) => SectionKind::Other,
            elements::Section::Export(_) => SectionKind::Other,
            elements::Section::Start(_) => SectionKind::Other,
            elements::Section::Element(_) => SectionKind::Other,
            elements::Section::Code(_) => SectionKind::Text,
            elements::Section::DataCount(_) => SectionKind::Other,
            elements::Section::Data(_) => SectionKind::Data,
            elements::Section::Name(_) => SectionKind::Other,
            elements::Section::Reloc(_) => SectionKind::Other,
        }
    }

    fn relocations(&self) -> WasmRelocationIterator {
        WasmRelocationIterator
    }
}

impl<'file> Iterator for WasmSymbolIterator<'file> {
    type Item = Symbol<'static>;

    fn next(&mut self) -> Option<Self::Item> {
        unimplemented!()
    }
}

impl Iterator for WasmRelocationIterator {
    type Item = (u64, Relocation);

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;

use ra_syntax::{
    ast::{self, HasQuotes, HasStringValue},
    AstToken,
    SyntaxKind::{RAW_STRING, STRING},
    TextSize,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: make_raw_string
//
// Adds `r#` to a plain string literal.
//
// ```
// fn main() {
//     "Hello,<|> World!";
// }
// ```
// ->
// ```
// fn main() {
//     r#"Hello, World!"#;
// }
// ```
pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?;
    let value = token.value()?;
    let target = token.syntax().text_range();
    acc.add(
        AssistId("make_raw_string", AssistKind::RefactorRewrite),
        "Rewrite as raw string",
        target,
        |edit| {
            let max_hash_streak = count_hashes(&value);
            let hashes = "#".repeat(max_hash_streak + 1);
            if matches!(value, Cow::Borrowed(_)) {
                // Avoid replacing the whole string to better position the cursor.
                edit.insert(token.syntax().text_range().start(), format!("r{}", hashes));
                edit.insert(token.syntax().text_range().end(), format!("{}", hashes));
            } else {
                edit.replace(
                    token.syntax().text_range(),
                    format!("r{}\"{}\"{}", hashes, value, hashes),
                );
            }
        },
    )
}

// Assist: make_usual_string
//
// Turns a raw string into a plain string.
//
// ```
// fn main() {
//     r#"Hello,<|> "World!""#;
// }
// ```
// ->
// ```
// fn main() {
//     "Hello, \"World!\"";
// }
// ```
pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?;
    let value = token.value()?;
    let target = token.syntax().text_range();
    acc.add(
        AssistId("make_usual_string", AssistKind::RefactorRewrite),
        "Rewrite as regular string",
        target,
        |edit| {
            // parse inside string to escape `"`
            let escaped = value.escape_default().to_string();
            if let Some(offsets) = token.quote_offsets() {
                if token.text()[offsets.contents - token.syntax().text_range().start()] == escaped {
                    edit.replace(offsets.quotes.0, "\"");
                    edit.replace(offsets.quotes.1, "\"");
                    return;
                }
            }

            edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped));
        },
    )
}

// Assist: add_hash
//
// Adds a hash to a raw string literal.
//
// ```
// fn main() {
//     r#"Hello,<|> World!"#;
// }
// ```
// ->
// ```
// fn main() {
//     r##"Hello, World!"##;
// }
// ```
pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let token = ctx.find_token_at_offset(RAW_STRING)?;
    let target = token.text_range();
    acc.add(AssistId("add_hash", AssistKind::Refactor), "Add # to raw string", target, |edit| {
        edit.insert(token.text_range().start() + TextSize::of('r'), "#");
        edit.insert(token.text_range().end(), "#");
    })
}

// Assist: remove_hash
//
// Removes a hash from a raw string literal.
//
// ```
// fn main() {
//     r#"Hello,<|> World!"#;
// }
// ```
// ->
// ```
// fn main() {
//     r"Hello, World!";
// }
// ```
pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let token = ctx.find_token_at_offset(RAW_STRING)?;
    let text = token.text().as_str();
    if text.starts_with("r\"") {
        // no hash to remove
        return None;
    }
    let target = token.text_range();
    acc.add(
        AssistId("remove_hash", AssistKind::RefactorRewrite),
        "Remove hash from raw string",
        target,
        |edit| {
            let result = &text[2..text.len() - 1];
            let result = if result.starts_with('\"') {
                // FIXME: this logic is wrong, not only the last has has to handled specially
                // no more hash, escape
                let internal_str = &result[1..result.len() - 1];
                format!("\"{}\"", internal_str.escape_default().to_string())
            } else {
                result.to_owned()
            };
            edit.replace(token.text_range(), format!("r{}", result));
        },
    )
}

fn count_hashes(s: &str) -> usize {
    let mut max_hash_streak = 0usize;
    for idx in s.match_indices("\"#").map(|(i, _)| i) {
        let (_, sub) = s.split_at(idx + 1);
        let nb_hash = sub.chars().take_while(|c| *c == '#').count();
        if nb_hash > max_hash_streak {
            max_hash_streak = nb_hash;
        }
    }
    max_hash_streak
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    #[test]
    fn make_raw_string_target() {
        check_assist_target(
            make_raw_string,
            r#"
            fn f() {
                let s = <|>"random\nstring";
            }
            "#,
            r#""random\nstring""#,
        );
    }

    #[test]
    fn make_raw_string_works() {
        check_assist(
            make_raw_string,
            r#"
fn f() {
    let s = <|>"random\nstring";
}
"#,
            r##"
fn f() {
    let s = r#"random
string"#;
}
"##,
        )
    }

    #[test]
    fn make_raw_string_works_inside_macros() {
        check_assist(
            make_raw_string,
            r#"
            fn f() {
                format!(<|>"x = {}", 92)
            }
            "#,
            r##"
            fn f() {
                format!(r#"x = {}"#, 92)
            }
            "##,
        )
    }

    #[test]
    fn make_raw_string_hashes_inside_works() {
        check_assist(
            make_raw_string,
            r###"
fn f() {
    let s = <|>"#random##\nstring";
}
"###,
            r####"
fn f() {
    let s = r#"#random##
string"#;
}
"####,
        )
    }

    #[test]
    fn make_raw_string_closing_hashes_inside_works() {
        check_assist(
            make_raw_string,
            r###"
fn f() {
    let s = <|>"#random\"##\nstring";
}
"###,
            r####"
fn f() {
    let s = r###"#random"##
string"###;
}
"####,
        )
    }

    #[test]
    fn make_raw_string_nothing_to_unescape_works() {
        check_assist(
            make_raw_string,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
            r##"
            fn f() {
                let s = r#"random string"#;
            }
            "##,
        )
    }

    #[test]
    fn make_raw_string_not_works_on_partial_string() {
        check_assist_not_applicable(
            make_raw_string,
            r#"
            fn f() {
                let s = "foo<|>
            }
            "#,
        )
    }

    #[test]
    fn make_usual_string_not_works_on_partial_string() {
        check_assist_not_applicable(
            make_usual_string,
            r#"
            fn main() {
                let s = r#"bar<|>
            }
            "#,
        )
    }

    #[test]
    fn add_hash_target() {
        check_assist_target(
            add_hash,
            r#"
            fn f() {
                let s = <|>r"random string";
            }
            "#,
            r#"r"random string""#,
        );
    }

    #[test]
    fn add_hash_works() {
        check_assist(
            add_hash,
            r#"
            fn f() {
                let s = <|>r"random string";
            }
            "#,
            r##"
            fn f() {
                let s = r#"random string"#;
            }
            "##,
        )
    }

    #[test]
    fn add_more_hash_works() {
        check_assist(
            add_hash,
            r##"
            fn f() {
                let s = <|>r#"random"string"#;
            }
            "##,
            r###"
            fn f() {
                let s = r##"random"string"##;
            }
            "###,
        )
    }

    #[test]
    fn add_hash_not_works() {
        check_assist_not_applicable(
            add_hash,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
        );
    }

    #[test]
    fn remove_hash_target() {
        check_assist_target(
            remove_hash,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r##"r#"random string"#"##,
        );
    }

    #[test]
    fn remove_hash_works() {
        check_assist(
            remove_hash,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r#"
            fn f() {
                let s = r"random string";
            }
            "#,
        )
    }

    #[test]
    fn remove_hash_with_quote_works() {
        check_assist(
            remove_hash,
            r##"
            fn f() {
                let s = <|>r#"random"str"ing"#;
            }
            "##,
            r#"
            fn f() {
                let s = r"random\"str\"ing";
            }
            "#,
        )
    }

    #[test]
    fn remove_more_hash_works() {
        check_assist(
            remove_hash,
            r###"
            fn f() {
                let s = <|>r##"random string"##;
            }
            "###,
            r##"
            fn f() {
                let s = r#"random string"#;
            }
            "##,
        )
    }

    #[test]
    fn remove_hash_not_works() {
        check_assist_not_applicable(
            remove_hash,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
        );
    }

    #[test]
    fn remove_hash_no_hash_not_works() {
        check_assist_not_applicable(
            remove_hash,
            r#"
            fn f() {
                let s = <|>r"random string";
            }
            "#,
        );
    }

    #[test]
    fn make_usual_string_target() {
        check_assist_target(
            make_usual_string,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r##"r#"random string"#"##,
        );
    }

    #[test]
    fn make_usual_string_works() {
        check_assist(
            make_usual_string,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r#"
            fn f() {
                let s = "random string";
            }
            "#,
        )
    }

    #[test]
    fn make_usual_string_with_quote_works() {
        check_assist(
            make_usual_string,
            r##"
            fn f() {
                let s = <|>r#"random"str"ing"#;
            }
            "##,
            r#"
            fn f() {
                let s = "random\"str\"ing";
            }
            "#,
        )
    }

    #[test]
    fn make_usual_string_more_hash_works() {
        check_assist(
            make_usual_string,
            r###"
            fn f() {
                let s = <|>r##"random string"##;
            }
            "###,
            r##"
            fn f() {
                let s = "random string";
            }
            "##,
        )
    }

    #[test]
    fn make_usual_string_not_works() {
        check_assist_not_applicable(
            make_usual_string,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
        );
    }

    #[test]
    fn count_hashes_test() {
        assert_eq!(0, count_hashes("abc"));
        assert_eq!(0, count_hashes("###"));
        assert_eq!(1, count_hashes("\"#abc"));
        assert_eq!(0, count_hashes("#abc"));
        assert_eq!(2, count_hashes("#ab\"##c"));
        assert_eq!(4, count_hashes("#ab\"##\"####c"));
    }
}
<commit_msg>More precise ranges in remove hashes assist<commit_after>use std::borrow::Cow;

use ra_syntax::{
    ast::{self, HasQuotes, HasStringValue},
    AstToken,
    SyntaxKind::{RAW_STRING, STRING},
    TextRange, TextSize,
};
use test_utils::mark;

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: make_raw_string
//
// Adds `r#` to a plain string literal.
//
// ```
// fn main() {
//     "Hello,<|> World!";
// }
// ```
// ->
// ```
// fn main() {
//     r#"Hello, World!"#;
// }
// ```
pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?;
    let value = token.value()?;
    let target = token.syntax().text_range();
    acc.add(
        AssistId("make_raw_string", AssistKind::RefactorRewrite),
        "Rewrite as raw string",
        target,
        |edit| {
            let hashes = "#".repeat(required_hashes(&value).max(1));
            if matches!(value, Cow::Borrowed(_)) {
                // Avoid replacing the whole string to better position the cursor.
                edit.insert(token.syntax().text_range().start(), format!("r{}", hashes));
                edit.insert(token.syntax().text_range().end(), format!("{}", hashes));
            } else {
                edit.replace(
                    token.syntax().text_range(),
                    format!("r{}\"{}\"{}", hashes, value, hashes),
                );
            }
        },
    )
}

// Assist: make_usual_string
//
// Turns a raw string into a plain string.
//
// ```
// fn main() {
//     r#"Hello,<|> "World!""#;
// }
// ```
// ->
// ```
// fn main() {
//     "Hello, \"World!\"";
// }
// ```
pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?;
    let value = token.value()?;
    let target = token.syntax().text_range();
    acc.add(
        AssistId("make_usual_string", AssistKind::RefactorRewrite),
        "Rewrite as regular string",
        target,
        |edit| {
            // parse inside string to escape `"`
            let escaped = value.escape_default().to_string();
            if let Some(offsets) = token.quote_offsets() {
                if token.text()[offsets.contents - token.syntax().text_range().start()] == escaped {
                    edit.replace(offsets.quotes.0, "\"");
                    edit.replace(offsets.quotes.1, "\"");
                    return;
                }
            }

            edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped));
        },
    )
}

// Assist: add_hash
//
// Adds a hash to a raw string literal.
//
// ```
// fn main() {
//     r#"Hello,<|> World!"#;
// }
// ```
// ->
// ```
// fn main() {
//     r##"Hello, World!"##;
// }
// ```
pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let token = ctx.find_token_at_offset(RAW_STRING)?;
    let target = token.text_range();
    acc.add(AssistId("add_hash", AssistKind::Refactor), "Add #", target, |edit| {
        edit.insert(token.text_range().start() + TextSize::of('r'), "#");
        edit.insert(token.text_range().end(), "#");
    })
}

// Assist: remove_hash
//
// Removes a hash from a raw string literal.
//
// ```
// fn main() {
//     r#"Hello,<|> World!"#;
// }
// ```
// ->
// ```
// fn main() {
//     r"Hello, World!";
// }
// ```
pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?;

    let text = token.text().as_str();
    if !text.starts_with("r#") && text.ends_with("#") {
        return None;
    }

    let existing_hashes = text.chars().skip(1).take_while(|&it| it == '#').count();

    let text_range = token.syntax().text_range();
    let internal_text = &text[token.text_range_between_quotes()? - text_range.start()];

    if existing_hashes == required_hashes(internal_text) {
        mark::hit!(cant_remove_required_hash);
        return None;
    }

    acc.add(AssistId("remove_hash", AssistKind::RefactorRewrite), "Remove #", text_range, |edit| {
        edit.delete(TextRange::at(text_range.start() + TextSize::of('r'), TextSize::of('#')));
        edit.delete(TextRange::new(text_range.end() - TextSize::of('#'), text_range.end()));
    })
}

fn required_hashes(s: &str) -> usize {
    let mut res = 0usize;
    for idx in s.match_indices('"').map(|(i, _)| i) {
        let (_, sub) = s.split_at(idx + 1);
        let n_hashes = sub.chars().take_while(|c| *c == '#').count();
        res = res.max(n_hashes + 1)
    }
    res
}

#[test]
fn test_required_hashes() {
    assert_eq!(0, required_hashes("abc"));
    assert_eq!(0, required_hashes("###"));
    assert_eq!(1, required_hashes("\""));
    assert_eq!(2, required_hashes("\"#abc"));
    assert_eq!(0, required_hashes("#abc"));
    assert_eq!(3, required_hashes("#ab\"##c"));
    assert_eq!(5, required_hashes("#ab\"##\"####c"));
}

#[cfg(test)]
mod test {
    use test_utils::mark;

    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    use super::*;

    #[test]
    fn make_raw_string_target() {
        check_assist_target(
            make_raw_string,
            r#"
            fn f() {
                let s = <|>"random\nstring";
            }
            "#,
            r#""random\nstring""#,
        );
    }

    #[test]
    fn make_raw_string_works() {
        check_assist(
            make_raw_string,
            r#"
fn f() {
    let s = <|>"random\nstring";
}
"#,
            r##"
fn f() {
    let s = r#"random
string"#;
}
"##,
        )
    }

    #[test]
    fn make_raw_string_works_inside_macros() {
        check_assist(
            make_raw_string,
            r#"
            fn f() {
                format!(<|>"x = {}", 92)
            }
            "#,
            r##"
            fn f() {
                format!(r#"x = {}"#, 92)
            }
            "##,
        )
    }

    #[test]
    fn make_raw_string_hashes_inside_works() {
        check_assist(
            make_raw_string,
            r###"
fn f() {
    let s = <|>"#random##\nstring";
}
"###,
            r####"
fn f() {
    let s = r#"#random##
string"#;
}
"####,
        )
    }

    #[test]
    fn make_raw_string_closing_hashes_inside_works() {
        check_assist(
            make_raw_string,
            r###"
fn f() {
    let s = <|>"#random\"##\nstring";
}
"###,
            r####"
fn f() {
    let s = r###"#random"##
string"###;
}
"####,
        )
    }

    #[test]
    fn make_raw_string_nothing_to_unescape_works() {
        check_assist(
            make_raw_string,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
            r##"
            fn f() {
                let s = r#"random string"#;
            }
            "##,
        )
    }

    #[test]
    fn make_raw_string_not_works_on_partial_string() {
        check_assist_not_applicable(
            make_raw_string,
            r#"
            fn f() {
                let s = "foo<|>
            }
            "#,
        )
    }

    #[test]
    fn make_usual_string_not_works_on_partial_string() {
        check_assist_not_applicable(
            make_usual_string,
            r#"
            fn main() {
                let s = r#"bar<|>
            }
            "#,
        )
    }

    #[test]
    fn add_hash_target() {
        check_assist_target(
            add_hash,
            r#"
            fn f() {
                let s = <|>r"random string";
            }
            "#,
            r#"r"random string""#,
        );
    }

    #[test]
    fn add_hash_works() {
        check_assist(
            add_hash,
            r#"
            fn f() {
                let s = <|>r"random string";
            }
            "#,
            r##"
            fn f() {
                let s = r#"random string"#;
            }
            "##,
        )
    }

    #[test]
    fn add_more_hash_works() {
        check_assist(
            add_hash,
            r##"
            fn f() {
                let s = <|>r#"random"string"#;
            }
            "##,
            r###"
            fn f() {
                let s = r##"random"string"##;
            }
            "###,
        )
    }

    #[test]
    fn add_hash_not_works() {
        check_assist_not_applicable(
            add_hash,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
        );
    }

    #[test]
    fn remove_hash_target() {
        check_assist_target(
            remove_hash,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r##"r#"random string"#"##,
        );
    }

    #[test]
    fn remove_hash_works() {
        check_assist(
            remove_hash,
            r##"fn f() { let s = <|>r#"random string"#; }"##,
            r#"fn f() { let s = r"random string"; }"#,
        )
    }

    #[test]
    fn cant_remove_required_hash() {
        mark::check!(cant_remove_required_hash);
        check_assist_not_applicable(
            remove_hash,
            r##"
            fn f() {
                let s = <|>r#"random"str"ing"#;
            }
            "##,
        )
    }

    #[test]
    fn remove_more_hash_works() {
        check_assist(
            remove_hash,
            r###"
            fn f() {
                let s = <|>r##"random string"##;
            }
            "###,
            r##"
            fn f() {
                let s = r#"random string"#;
            }
            "##,
        )
    }

    #[test]
    fn remove_hash_doesnt_work() {
        check_assist_not_applicable(remove_hash, r#"fn f() { let s = <|>"random string"; }"#);
    }

    #[test]
    fn remove_hash_no_hash_doesnt_work() {
        check_assist_not_applicable(remove_hash, r#"fn f() { let s = <|>r"random string"; }"#);
    }

    #[test]
    fn make_usual_string_target() {
        check_assist_target(
            make_usual_string,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r##"r#"random string"#"##,
        );
    }

    #[test]
    fn make_usual_string_works() {
        check_assist(
            make_usual_string,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r#"
            fn f() {
                let s = "random string";
            }
            "#,
        )
    }

    #[test]
    fn make_usual_string_with_quote_works() {
        check_assist(
            make_usual_string,
            r##"
            fn f() {
                let s = <|>r#"random"str"ing"#;
            }
            "##,
            r#"
            fn f() {
                let s = "random\"str\"ing";
            }
            "#,
        )
    }

    #[test]
    fn make_usual_string_more_hash_works() {
        check_assist(
            make_usual_string,
            r###"
            fn f() {
                let s = <|>r##"random string"##;
            }
            "###,
            r##"
            fn f() {
                let s = "random string";
            }
            "##,
        )
    }

    #[test]
    fn make_usual_string_not_works() {
        check_assist_not_applicable(
            make_usual_string,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
        );
    }
}
<|endoftext|>


<commit_before>//
// min-llvm-version: 10.0.1
// compile-flags: -O
#![crate_type="lib"]

#[no_mangle]
pub fn alloc_test(data: u32) {
    // CHECK-LABEL: @alloc_test
    // CHECK-NEXT: start:
    // CHECK-NEXT: ret void
    let x = Box::new(data);
    drop(x);
}
<commit_msg>Rollup merge of #89591 - infinity0:master, r=Amanieu<commit_after>//
// no-system-llvm
// min-llvm-version: 10.0.1
// compile-flags: -O
#![crate_type="lib"]

#[no_mangle]
pub fn alloc_test(data: u32) {
    // CHECK-LABEL: @alloc_test
    // CHECK-NEXT: start:
    // CHECK-NEXT: ret void
    let x = Box::new(data);
    drop(x);
}
<|endoftext|>


<commit_before>//! `GET /_matrix/client/*/account/whoami`

pub mod v3 {
    //! `/v3/` ([spec])
    //!
    //! [spec]: https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv3accountwhoami

    use ruma_api::ruma_api;
    use ruma_identifiers::{DeviceId, UserId};

    ruma_api! {
        metadata: {
            description: "Get information about the owner of a given access token.",
            method: GET,
            name: "whoami",
            r0_path: "/_matrix/client/r0/account/whoami",
            stable_path: "/_matrix/client/v3/account/whoami",
            rate_limited: true,
            authentication: AccessToken,
            added: 1.0,
        }

        #[derive(Default)]
        request: {}

        response: {
            /// The id of the user that owns the access token.
            pub user_id: Box<UserId>,

            /// The device ID associated with the access token, if any.
            #[serde(skip_serializing_if = "Option::is_none")]
            pub device_id: Option<Box<DeviceId>>,
        }

        error: crate::Error
    }

    impl Request {
        /// Creates an empty `Request`.
        pub fn new() -> Self {
            Self {}
        }
    }

    impl Response {
        /// Creates a new `Response` with the given user ID.
        pub fn new(user_id: Box<UserId>) -> Self {
            Self { user_id, device_id: None }
        }
    }
}
<commit_msg>client-api: Add is_guest to account::whoami::Response<commit_after>//! `GET /_matrix/client/*/account/whoami`

pub mod v3 {
    //! `/v3/` ([spec])
    //!
    //! [spec]: https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv3accountwhoami

    use ruma_api::ruma_api;
    use ruma_identifiers::{DeviceId, UserId};

    ruma_api! {
        metadata: {
            description: "Get information about the owner of a given access token.",
            method: GET,
            name: "whoami",
            r0_path: "/_matrix/client/r0/account/whoami",
            stable_path: "/_matrix/client/v3/account/whoami",
            rate_limited: true,
            authentication: AccessToken,
            added: 1.0,
        }

        #[derive(Default)]
        request: {}

        response: {
            /// The id of the user that owns the access token.
            pub user_id: Box<UserId>,

            /// The device ID associated with the access token, if any.
            #[serde(skip_serializing_if = "Option::is_none")]
            pub device_id: Option<Box<DeviceId>>,

            /// If `true`, the user is a guest user.
            #[serde(default, skip_serializing_if = "ruma_serde::is_default")]
            pub is_guest: bool,
        }

        error: crate::Error
    }

    impl Request {
        /// Creates an empty `Request`.
        pub fn new() -> Self {
            Self {}
        }
    }

    impl Response {
        /// Creates a new `Response` with the given user ID.
        pub fn new(user_id: Box<UserId>, is_guest: bool) -> Self {
            Self { user_id, device_id: None, is_guest }
        }
    }
}
<|endoftext|>


<commit_before>// error-pattern:3:13:3:14
fn main() -> () {
  auto foo = [];
}
// this checks that span_err gets used
<commit_msg>xfail vector-no-ann.rs.<commit_after>// xfail-stage0
// xfail-stage1
// xfail-stage2
// xfail-stage3

// error-pattern:3:13:3:14
fn main() -> () {
  auto foo = [];
}
// this checks that span_err gets used
<|endoftext|>


<commit_before>#[macro_use] extern crate elfkit;
#[macro_use] extern crate itertools;
extern crate byteorder;

use itertools::Itertools;

use std::env;
use std::fs::OpenOptions;
use elfkit::{
    Elf, types, SegmentHeader, Section, SectionContent,
    SectionHeader, Dynamic, Symbol, Relocation, Strtab};

use elfkit::linker::Linker;

use elfkit::dynamic::DynamicContent;
use elfkit::relocation::RelocationType;
use std::collections::HashMap;

#[derive(Default)]
struct Unit {
    pub data: Vec<u8>,
    pub text: Vec<u8>,
    pub symbols: Vec<Symbol>,
    pub dynrel: Vec<Relocation>,
}

impl Unit {
    pub fn load(in_elf: &Elf) -> Result<Unit, elfkit::Error> {

        let mut r = Unit::default();

        let mut shndx_text = 0;
        let mut shndx_data = 0;

        for (i, sec) in in_elf.sections.iter().enumerate() {
            match (sec.name.as_ref(), &sec.content) {
                (".text", &SectionContent::Raw(ref v)) => {shndx_text = i; r.text.extend(v);},
                (".data", &SectionContent::Raw(ref v)) => {shndx_data = i; r.data.extend(v);},
                (".symtab", &SectionContent::Symbols(ref v)) => {r.symbols.extend(v.iter().cloned());},
                _ => {},
            };
        }

        for sec in in_elf.sections.iter() {
            if sec.header.shtype == types::SectionType::RELA && sec.header.info == shndx_text as u32 {
                let symtab = in_elf.sections[sec.header.link as usize].content.as_symbols().unwrap();
                for reloc in  sec.content.as_relocations().unwrap() {
                    match reloc.rtype {
                        RelocationType::R_X86_64_NONE => {},
                        RelocationType::R_X86_64_64   => {
                            let symbol = &symtab[reloc.sym as usize];
                            if symbol.shndx == shndx_data as u16 {
                                let value = (
                                    r.data.len() as i64 +
                                    symbol.value as i64 +
                                    reloc.addend as i64)
                                    as u64;

                                let (_,mut xd) = r.text.split_at_mut(reloc.addr as usize);
                                elf_write_u64!(&in_elf.header, xd, value)?;

                                r.dynrel.push(Relocation{
                                    rtype:  RelocationType::R_X86_64_RELATIVE,
                                    sym:    0,
                                    addr:   reloc.addr,
                                    addend: value as i64,
                                })
                            } else {
                                panic!(format!("relocation {:?} on symbol {:?} in unknown section",
                                               reloc, symbol));
                            }

                        },
                        _ => panic!(format!("relocation {:?} not implemented",reloc)),
                    }
                }
            }
        }

        Ok(r)
    }
}

fn main() {
    let in_filename  = env::args().nth(1).unwrap();
    let out_filename = env::args().nth(2).unwrap();
    let mut in_file  = OpenOptions::new().read(true).open(in_filename).unwrap();
    let mut out_file = OpenOptions::new().write(true).truncate(true).create(true).open(out_filename).unwrap();

    let mut in_elf  = Elf::from_reader(&mut in_file).unwrap();
    in_elf.load_all().unwrap();

    let mut out_elf = Elf::default();
    out_elf.header.ident_class  = in_elf.header.ident_class.clone();
    out_elf.header.ident_abi    = in_elf.header.ident_abi.clone();

    //NOTE PIEs must be set to DYN, since ld behaves differently.
    //elfkit is not tested for EXEC and is unlikely going to produce a working exe
    out_elf.header.etype        = types::ElfType::DYN;
    out_elf.header.machine      = in_elf.header.machine.clone();

    let mut sc_interp  : Vec<u8> = b"/lib64/ld-linux-x86-64.so.2\0".to_vec();
    //let mut sc_interp  : Vec<u8> = b"/usr/local/musl/lib/libc.so\0".to_vec();
    let mut sc_text    : Vec<u8> = Vec::new();
    let mut sc_data    : Vec<u8> = Vec::new();
    let mut sc_dynsym  : Vec<Symbol>  = Vec::new();
    let mut sc_rela    : Vec<Relocation>  = Vec::new();
    let mut sc_dynamic : Vec<Dynamic> = vec![
        Dynamic{
            dhtype: types::DynamicType::FLAGS_1,
            content: DynamicContent::Flags1(types::DynamicFlags1::PIE),
        },
        //Dynamic{
        //    dhtype: types::DynamicType::NEEDED,
        //    content: DynamicContent::String(String::from("libc.so.6")),
        //},
    ];

    out_elf.sections.insert(0, Section::default());
    out_elf.sections.push(Section::new(".interp", types::SectionType::PROGBITS,
                                       types::SectionFlags::ALLOC,
                                       SectionContent::Raw(sc_interp), 0,0));

    let in_unit = Unit::load(&in_elf).unwrap();
    sc_text = in_unit.text;
    sc_data = in_unit.data;

    let sh_index_mo_ae = out_elf.sections.len();
    out_elf.sections.push(Section::new(".mo1.read", types::SectionType::PROGBITS,
                                       types::SectionFlags::ALLOC | types::SectionFlags::WRITE | types::SectionFlags::EXECINSTR,
                                       SectionContent::Raw(sc_text), 0,0));

    out_elf.sections.push(Section::new(".mo1.write", types::SectionType::PROGBITS,
                                       types::SectionFlags::ALLOC | types::SectionFlags::WRITE,
                                       SectionContent::Raw(sc_data), 0,0));

    out_elf.sync_all().unwrap();
    Linker::relayout(&mut out_elf, 0x300).unwrap();

    for mut rel in in_unit.dynrel {
        rel.addr   += out_elf.sections[sh_index_mo_ae].header.addr;

        //TODO: this only works for X86_64_RELATIVE
        rel.addend += out_elf.sections[sh_index_mo_ae].header.addr as i64;
        sc_rela.push(rel);
    }

    let sh_index_dynstr = out_elf.sections.len();
    out_elf.sections.push(Section::new(".dynstr", types::SectionType::STRTAB,
                                       types::SectionFlags::ALLOC,
                                       SectionContent::Strtab(Strtab::default()), 0,0));

    //TODO should i maybe just make all symbols global? a dynlinker will probably not use local
    //syms anyway
    sc_dynsym.sort_unstable_by(|a,b| a.bind.cmp(&b.bind));
    let first_global_dynsym = sc_dynsym.iter().enumerate()
        .find(|&(_,s)|s.bind == types::SymbolBind::GLOBAL).map(|(i,_)|i).unwrap_or(0);;
    let sh_index_dynsym = out_elf.sections.len();
    out_elf.sections.push(Section::new(".dynsym", types::SectionType::SYMTAB,
                                       types::SectionFlags::ALLOC,
                                       SectionContent::Symbols(sc_dynsym),
                                       sh_index_dynstr as u32, first_global_dynsym as u32));

    out_elf.sections.push(Section::new(".rela.dyn", types::SectionType::RELA,
                                       types::SectionFlags::ALLOC,
                                       SectionContent::Relocations(sc_rela),
                                       sh_index_dynsym as u32, 0));

    out_elf.sections.push(Section::new(".shstrtab", types::SectionType::STRTAB,
                                       types::SectionFlags::from_bits_truncate(0),
                                       SectionContent::Strtab(Strtab::default()),
                                       0,0));

    out_elf.sync_all().unwrap();
    Linker::relayout(&mut out_elf, 0x300).unwrap();

    sc_dynamic.extend(Linker::dynamic(&out_elf).unwrap());
    let sh_index_dynamic = out_elf.sections.len() -1;
    out_elf.sections.insert(sh_index_dynamic, Section::new(".dynamic", types::SectionType::DYNAMIC,
                                                           types::SectionFlags::ALLOC | types::SectionFlags::WRITE,
                                                           SectionContent::Dynamic(sc_dynamic), sh_index_dynstr as u32,0));

    out_elf.sync_all().unwrap();
    Linker::relayout(&mut out_elf, 0x300).unwrap();
    //find the start sym
    for sym in in_unit.symbols {
        if sym.name == "_start" {
            out_elf.header.entry = out_elf.sections[sh_index_mo_ae].header.addr +  sym.value;
        }
    }

    out_elf.segments = Linker::segments(&out_elf).unwrap();

    out_elf.store_all().unwrap();
    out_elf.to_writer(&mut out_file).unwrap();
}

<commit_msg>dont modify .text before reloc<commit_after>#[macro_use] extern crate elfkit;
#[macro_use] extern crate itertools;
extern crate byteorder;

use itertools::Itertools;

use std::env;
use std::fs::OpenOptions;
use elfkit::{
    Elf, types, SegmentHeader, Section, SectionContent,
    SectionHeader, Dynamic, Symbol, Relocation, Strtab};

use elfkit::linker::Linker;

use elfkit::dynamic::DynamicContent;
use elfkit::relocation::RelocationType;
use std::collections::HashMap;

#[derive(Default)]
struct Unit {
    pub data: Vec<u8>,
    pub text: Vec<u8>,
    pub symbols: Vec<Symbol>,
    pub dynrel: Vec<Relocation>,
}

impl Unit {
    pub fn load(in_elf: &Elf) -> Result<Unit, elfkit::Error> {

        let mut r = Unit::default();

        let mut shndx_text = 0;
        let mut shndx_data = 0;

        for (i, sec) in in_elf.sections.iter().enumerate() {
            match (sec.name.as_ref(), &sec.content) {
                (".text", &SectionContent::Raw(ref v)) => {shndx_text = i; r.text.extend(v);},
                (".data", &SectionContent::Raw(ref v)) => {shndx_data = i; r.data.extend(v);},
                (".symtab", &SectionContent::Symbols(ref v)) => {r.symbols.extend(v.iter().cloned());},
                _ => {},
            };
        }

        for sec in in_elf.sections.iter() {
            if sec.header.shtype == types::SectionType::RELA && sec.header.info == shndx_text as u32 {
                let symtab = in_elf.sections[sec.header.link as usize].content.as_symbols().unwrap();
                for reloc in  sec.content.as_relocations().unwrap() {
                    match reloc.rtype {
                        RelocationType::R_X86_64_NONE => {},
                        RelocationType::R_X86_64_64   => {
                            let symbol = &symtab[reloc.sym as usize];
                            if symbol.shndx == shndx_data as u16 {
                                let value = (
                                    r.data.len() as i64 +
                                    symbol.value as i64 +
                                    reloc.addend as i64)
                                    as u64;

                                r.dynrel.push(Relocation{
                                    rtype:  RelocationType::R_X86_64_RELATIVE,
                                    sym:    0,
                                    addr:   reloc.addr,
                                    addend: value as i64,
                                })
                            } else {
                                panic!(format!("relocation {:?} on symbol {:?} in unknown section",
                                               reloc, symbol));
                            }

                        },
                        _ => panic!(format!("relocation {:?} not implemented",reloc)),
                    }
                }
            }
        }

        Ok(r)
    }
}

fn main() {
    let in_filename  = env::args().nth(1).unwrap();
    let out_filename = env::args().nth(2).unwrap();
    let mut in_file  = OpenOptions::new().read(true).open(in_filename).unwrap();
    let mut out_file = OpenOptions::new().write(true).truncate(true).create(true).open(out_filename).unwrap();

    let mut in_elf  = Elf::from_reader(&mut in_file).unwrap();
    in_elf.load_all().unwrap();

    let mut out_elf = Elf::default();
    out_elf.header.ident_class  = in_elf.header.ident_class.clone();
    out_elf.header.ident_abi    = in_elf.header.ident_abi.clone();

    //NOTE PIEs must be set to DYN, since ld behaves differently.
    //elfkit is not tested for EXEC and is unlikely going to produce a working exe
    out_elf.header.etype        = types::ElfType::DYN;
    out_elf.header.machine      = in_elf.header.machine.clone();

    let mut sc_interp  : Vec<u8> = b"/lib64/ld-linux-x86-64.so.2\0".to_vec();
    //let mut sc_interp  : Vec<u8> = b"/usr/local/musl/lib/libc.so\0".to_vec();
    let mut sc_text    : Vec<u8> = Vec::new();
    let mut sc_data    : Vec<u8> = Vec::new();
    let mut sc_dynsym  : Vec<Symbol>  = Vec::new();
    let mut sc_rela    : Vec<Relocation>  = Vec::new();
    let mut sc_dynamic : Vec<Dynamic> = vec![
        Dynamic{
            dhtype: types::DynamicType::FLAGS_1,
            content: DynamicContent::Flags1(types::DynamicFlags1::PIE),
        },
        //Dynamic{
        //    dhtype: types::DynamicType::NEEDED,
        //    content: DynamicContent::String(String::from("libc.so.6")),
        //},
    ];

    out_elf.sections.insert(0, Section::default());
    out_elf.sections.push(Section::new(".interp", types::SectionType::PROGBITS,
                                       types::SectionFlags::ALLOC,
                                       SectionContent::Raw(sc_interp), 0,0));

    let in_unit = Unit::load(&in_elf).unwrap();
    sc_text = in_unit.text;
    sc_data = in_unit.data;

    let sh_index_mo_ae = out_elf.sections.len();
    out_elf.sections.push(Section::new(".mo1.read", types::SectionType::PROGBITS,
                                       types::SectionFlags::ALLOC | types::SectionFlags::WRITE | types::SectionFlags::EXECINSTR,
                                       SectionContent::Raw(sc_text), 0,0));

    out_elf.sections.push(Section::new(".mo1.write", types::SectionType::PROGBITS,
                                       types::SectionFlags::ALLOC | types::SectionFlags::WRITE,
                                       SectionContent::Raw(sc_data), 0,0));

    out_elf.sync_all().unwrap();
    Linker::relayout(&mut out_elf, 0x300).unwrap();

    for mut rel in in_unit.dynrel {
        rel.addr   += out_elf.sections[sh_index_mo_ae].header.addr;

        //TODO: this only works for X86_64_RELATIVE
        rel.addend += out_elf.sections[sh_index_mo_ae].header.addr as i64;
        sc_rela.push(rel);
    }

    let sh_index_dynstr = out_elf.sections.len();
    out_elf.sections.push(Section::new(".dynstr", types::SectionType::STRTAB,
                                       types::SectionFlags::ALLOC,
                                       SectionContent::Strtab(Strtab::default()), 0,0));

    //TODO should i maybe just make all symbols global? a dynlinker will probably not use local
    //syms anyway
    sc_dynsym.sort_unstable_by(|a,b| a.bind.cmp(&b.bind));
    let first_global_dynsym = sc_dynsym.iter().enumerate()
        .find(|&(_,s)|s.bind == types::SymbolBind::GLOBAL).map(|(i,_)|i).unwrap_or(0);;
    let sh_index_dynsym = out_elf.sections.len();
    out_elf.sections.push(Section::new(".dynsym", types::SectionType::SYMTAB,
                                       types::SectionFlags::ALLOC,
                                       SectionContent::Symbols(sc_dynsym),
                                       sh_index_dynstr as u32, first_global_dynsym as u32));

    out_elf.sections.push(Section::new(".rela.dyn", types::SectionType::RELA,
                                       types::SectionFlags::ALLOC,
                                       SectionContent::Relocations(sc_rela),
                                       sh_index_dynsym as u32, 0));

    out_elf.sections.push(Section::new(".shstrtab", types::SectionType::STRTAB,
                                       types::SectionFlags::from_bits_truncate(0),
                                       SectionContent::Strtab(Strtab::default()),
                                       0,0));

    out_elf.sync_all().unwrap();
    Linker::relayout(&mut out_elf, 0x300).unwrap();

    sc_dynamic.extend(Linker::dynamic(&out_elf).unwrap());
    let sh_index_dynamic = out_elf.sections.len() -1;
    out_elf.sections.insert(sh_index_dynamic, Section::new(".dynamic", types::SectionType::DYNAMIC,
                                                           types::SectionFlags::ALLOC | types::SectionFlags::WRITE,
                                                           SectionContent::Dynamic(sc_dynamic), sh_index_dynstr as u32,0));

    out_elf.sync_all().unwrap();
    Linker::relayout(&mut out_elf, 0x300).unwrap();
    //find the start sym
    for sym in in_unit.symbols {
        if sym.name == "_start" {
            out_elf.header.entry = out_elf.sections[sh_index_mo_ae].header.addr +  sym.value;
        }
    }

    out_elf.segments = Linker::segments(&out_elf).unwrap();

    out_elf.store_all().unwrap();
    out_elf.to_writer(&mut out_file).unwrap();
}

<|endoftext|>