<commit_before>use glib::object::Cast;
use gtk::{self, BoxExt, ButtonExt, ContainerExt, DialogExt, LabelExt, ScrolledWindowExt};
use gtk::{WidgetExt, GtkWindowExt};
use pango;
use sysinfo::{self, Pid, ProcessExt};

use utils::format_number;

pub struct ProcDialog {
    working_directory: gtk::Label,
    memory_usage: gtk::Label,
    cpu_usage: gtk::Label,
    run_time: gtk::Label,
    pub popup: gtk::Window,
    pub pid: Pid,
}

impl ProcDialog {
    pub fn update(&self, process: &sysinfo::Process, running_since: u64, start_time: u64) {
        self.working_directory.set_text(&format!("current working directory: {}",
                                                 process.cwd().display()));
        self.memory_usage.set_text(&format!("memory usage: {}",
                                            format_number(process.memory() << 10))); // * 1_024
        self.cpu_usage.set_text(&format!("cpu usage: {:.1}%", process.cpu_usage()));
        let running_since = compute_running_since(process, start_time, running_since);
        self.run_time.set_text(&format!("Running since: {}", format_time(running_since)));
    }
}

fn format_time(t: u64) -> String {
    format!("{}{}{}{}s",
            {
                let days = t / 86_400;
                if days > 0 {
                    format!("{}d ", days)
                } else {
                    "".to_owned()
                }
            },
            {
                let hours = t / 3_600 % 24;
                if hours > 0 {
                    format!("{}h ", hours)
                } else {
                    "".to_owned()
                }
            },
            {
                let minutes = t / 60 % 60;
                if minutes > 0 {
                    format!("{}m ", minutes)
                } else {
                    "".to_owned()
                }
            },
            t % 60)
}

fn create_and_add_new_label(scroll: &gtk::Box, text: &str) -> gtk::Label {
    let label = gtk::Label::new(text);
    label.set_selectable(true);
    label.set_justify(gtk::Justification::Left);
    label.set_line_wrap(true);
    label.set_line_wrap_mode(pango::WrapMode::Char);
    scroll.add(&label);
    label
}

fn compute_running_since(
    process: &sysinfo::Process,
    start_time: u64,
    running_since: u64,
) -> u64 {
    if start_time > process.start_time() {
        start_time - process.start_time() + running_since
    } else {
        start_time + running_since - process.start_time()
    }
}

pub fn create_process_dialog(
    process: &sysinfo::Process,
    window: &gtk::ApplicationWindow,
    running_since: u64,
    start_time: u64
) -> ProcDialog {
    let scroll = gtk::ScrolledWindow::new(None, None);
    let close_button = gtk::Button::new_with_label("Close");
    let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
    scroll.set_policy(gtk::PolicyType::Automatic, gtk::PolicyType::Automatic);

    let flags = gtk::DialogFlags::DESTROY_WITH_PARENT | gtk::DialogFlags::USE_HEADER_BAR;
    let popup = gtk::Dialog::new_with_buttons(
                    Some(&format!("Information about {}", process.name())),
                    Some(window),
                    flags,
                    &[]);
    let running_since = compute_running_since(process, start_time, running_since);
    let area = popup.get_content_area();

    let labels = gtk::Box::new(gtk::Orientation::Vertical, 0);

    create_and_add_new_label(&labels, &format!("name: {}", process.name()));
    create_and_add_new_label(&labels, &format!("pid: {}", process.pid()));
    let memory_usage = create_and_add_new_label(&labels,
                                                &format!("memory usage: {}",
                                                         format_number(process.memory() << 10)));
    let cpu_usage = create_and_add_new_label(&labels,
                                             &format!("cpu usage: {:.1}%", process.cpu_usage()));
    let run_time = create_and_add_new_label(&labels,
                                            &format!("Running since: {}",
                                                     format_time(running_since)));
    create_and_add_new_label(&labels, &format!("command: {:?}", process.cmd()));
    create_and_add_new_label(&labels, &format!("executable path: {}", process.exe().display()));
    let working_directory = create_and_add_new_label(&labels,
                                                     &format!("current working directory: {}",
                                                              process.cwd().display()));
    create_and_add_new_label(&labels, &format!("root directory: {}", process.root().display()));
    let mut text = format!("environment:");
    for env in process.environ() {
        text.push_str(&format!("\n{:?}", env));
    }
    create_and_add_new_label(&labels, &text);

    scroll.add(&labels);
    vertical_layout.pack_start(&scroll, true, true, 0);
    vertical_layout.pack_start(&close_button, false, true, 0);
    vertical_layout.set_spacing(10);
    area.pack_start(&vertical_layout, true, true, 0);
    // To silence the annoying warning:
    // "(.:2257): Gtk-WARNING **: Allocating size to GtkWindow 0x7f8a31038290 without
    // calling gtk_widget_get_preferred_width/height(). How does the code know the size to
    // allocate?"
    popup.get_preferred_width();
    popup.set_size_request(500, 700);

    let popup = popup.upcast::<gtk::Window>();
    popup.set_resizable(false);
    popup.show_all();
    let pop = popup.clone();
    close_button.connect_clicked(move |_| {
        pop.destroy();
    });
    ProcDialog {
        working_directory,
        memory_usage,
        cpu_usage,
        run_time,
        popup,
        pid: process.pid(),
    }
}
<commit_msg>Improve dialog again<commit_after>use glib::object::Cast;
use gtk::{
    self, AdjustmentExt, BoxExt, ButtonExt, ContainerExt, DialogExt, LabelExt, ScrolledWindowExt
};
use gtk::{WidgetExt, GtkWindowExt};
use pango;
use sysinfo::{self, Pid, ProcessExt};

use utils::format_number;

pub struct ProcDialog {
    working_directory: gtk::Label,
    memory_usage: gtk::Label,
    cpu_usage: gtk::Label,
    run_time: gtk::Label,
    pub popup: gtk::Window,
    pub pid: Pid,
}

impl ProcDialog {
    pub fn update(&self, process: &sysinfo::Process, running_since: u64, start_time: u64) {
        self.working_directory.set_text(&process.cwd().display().to_string());
        self.memory_usage.set_text(&format_number(process.memory() << 10)); // * 1_024
        self.cpu_usage.set_text(&format!("{:.1}%", process.cpu_usage()));
        let running_since = compute_running_since(process, start_time, running_since);
        self.run_time.set_text(&format_time(running_since));
    }
}

fn format_time(t: u64) -> String {
    format!("{}{}{}{}s",
            {
                let days = t / 86_400;
                if days > 0 {
                    format!("{}d ", days)
                } else {
                    "".to_owned()
                }
            },
            {
                let hours = t / 3_600 % 24;
                if hours > 0 {
                    format!("{}h ", hours)
                } else {
                    "".to_owned()
                }
            },
            {
                let minutes = t / 60 % 60;
                if minutes > 0 {
                    format!("{}m ", minutes)
                } else {
                    "".to_owned()
                }
            },
            t % 60)
}

fn create_and_add_new_label(scroll: &gtk::Box, title: &str, text: &str) -> gtk::Label {
    let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0);

    horizontal_layout.set_margin_top(5);
    horizontal_layout.set_margin_bottom(5);
    horizontal_layout.set_margin_right(5);
    horizontal_layout.set_margin_left(5);

    let label = gtk::Label::new(None);
    label.set_justify(gtk::Justification::Left);
    label.set_markup(&format!("<b>{}:</b>", title));

    let text = gtk::Label::new(text);
    text.set_selectable(true);
    text.set_justify(gtk::Justification::Left);
    text.set_line_wrap(true);
    text.set_line_wrap_mode(pango::WrapMode::Char);

    horizontal_layout.add(&label);
    horizontal_layout.add(&text);
    scroll.add(&horizontal_layout);
    text
}

fn compute_running_since(
    process: &sysinfo::Process,
    start_time: u64,
    running_since: u64,
) -> u64 {
    if start_time > process.start_time() {
        start_time - process.start_time() + running_since
    } else {
        start_time + running_since - process.start_time()
    }
}

pub fn create_process_dialog(
    process: &sysinfo::Process,
    window: &gtk::ApplicationWindow,
    running_since: u64,
    start_time: u64
) -> ProcDialog {
    let scroll = gtk::ScrolledWindow::new(None, None);
    let close_button = gtk::Button::new_with_label("Close");
    let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
    scroll.set_policy(gtk::PolicyType::Automatic, gtk::PolicyType::Automatic);

    let flags = gtk::DialogFlags::DESTROY_WITH_PARENT | gtk::DialogFlags::USE_HEADER_BAR;
    let popup = gtk::Dialog::new_with_buttons(
                    Some(&format!("Information about {}", process.name())),
                    Some(window),
                    flags,
                    &[]);
    let running_since = compute_running_since(process, start_time, running_since);
    let area = popup.get_content_area();

    let labels = gtk::Box::new(gtk::Orientation::Vertical, 0);

    create_and_add_new_label(&labels, "name", process.name());
    create_and_add_new_label(&labels, "pid", &process.pid().to_string());
    let memory_usage = create_and_add_new_label(&labels,
                                                "memory usage",
                                                &format_number(process.memory() << 10));
    let cpu_usage = create_and_add_new_label(&labels,
                                             "cpu usage",
                                             &format!("{:.1}%", process.cpu_usage()));
    let run_time = create_and_add_new_label(&labels,
                                            "Running since",
                                            &format_time(running_since));
    create_and_add_new_label(&labels, "command", &format!("{:?}", process.cmd()));
    create_and_add_new_label(&labels, "executable path", &process.exe().display().to_string());
    let working_directory = create_and_add_new_label(&labels, "current working directory",
                                                     &process.cwd().display().to_string());
    create_and_add_new_label(&labels, "root directory", &process.root().display().to_string());
    let mut text = String::with_capacity(100);
    for env in process.environ() {
        text.push_str(&format!("\n{:?}", env));
    }
    create_and_add_new_label(&labels, "environment", &text);

    scroll.add(&labels);
    vertical_layout.pack_start(&scroll, true, true, 0);
    vertical_layout.pack_start(&close_button, false, true, 0);
    area.pack_start(&vertical_layout, true, true, 0);
    // To silence the annoying warning:
    // "(.:2257): Gtk-WARNING **: Allocating size to GtkWindow 0x7f8a31038290 without
    // calling gtk_widget_get_preferred_width/height(). How does the code know the size to
    // allocate?"
    popup.get_preferred_width();
    popup.set_size_request(500, 500);

    let popup = popup.upcast::<gtk::Window>();
    popup.set_resizable(true);
    popup.show_all();
    let pop = popup.clone();
    close_button.connect_clicked(move |_| {
        pop.destroy();
    });

    if let Some(adjust) = scroll.get_vadjustment() {
        adjust.set_value(0.);
        scroll.set_vadjustment(&adjust);
    }
    ProcDialog {
        working_directory,
        memory_usage,
        cpu_usage,
        run_time,
        popup,
        pid: process.pid(),
    }
}
<|endoftext|>


<commit_before>//! A simple allocator that never frees, for testing
//! Some code borrowed from [Phil Opp's Blog](http://os.phil-opp.com/kernel-heap.html)

#![feature(allocator)]
#![feature(const_fn)]
#![allocator]
#![no_std]

use spin::Mutex;

extern crate spin;

pub const HEAP_START: usize = 0o_000_001_000_000_0000;
pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB

static BUMP_ALLOCATOR: Mutex<BumpAllocator> = Mutex::new(BumpAllocator::new(HEAP_START, HEAP_SIZE));

#[no_mangle]
pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    BUMP_ALLOCATOR.lock().allocate(size, align).expect("out of memory")
}

#[no_mangle]
pub extern fn __rust_usable_size(size: usize, align: usize) -> usize {
    size
}

#[no_mangle]
pub extern fn __rust_deallocate(ptr: *mut u8, size: usize, align: usize) {

}

#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, size: usize, new_size: usize, align: usize) -> *mut u8 {
    use core::{ptr, cmp};

    let new_ptr = __rust_allocate(new_size, align);
    unsafe { ptr::copy(ptr, new_ptr, cmp::min(size, new_size)) };
    __rust_deallocate(ptr, size, align);
    new_ptr
}

#[no_mangle]
pub extern fn __rust_reallocate_inplace(ptr: *mut u8, size: usize, new_size: usize, align: usize) -> usize {
    size
}

/// Align downwards. Returns the greatest x with alignment `align`
/// so that x <= addr. The alignment must be a power of 2.
pub fn align_down(addr: usize, align: usize) -> usize {
    if align.is_power_of_two() {
        addr & !(align - 1)
    } else if align == 0 {
        addr
    } else {
        panic!("`align` must be a power of 2");
    }
}

/// Align upwards. Returns the smallest x with alignment `align`
/// so that x >= addr. The alignment must be a power of 2.
pub fn align_up(addr: usize, align: usize) -> usize {
    align_down(addr + align - 1, align)
}

#[derive(Debug)]
struct BumpAllocator {
    heap_start: usize,
    heap_size: usize,
    next: usize,
}

impl BumpAllocator {
    /// Create a new allocator, which uses the memory in the
    /// range [heap_start, heap_start + heap_size).
    const fn new(heap_start: usize, heap_size: usize) -> BumpAllocator {
        BumpAllocator {
            heap_start: heap_start,
            heap_size: heap_size,
            next: heap_start,
        }
    }

    /// Allocates a block of memory with the given size and alignment.
    fn allocate(&mut self, size: usize, align: usize) -> Option<*mut u8> {
    	let alloc_start = align_up(self.next, align);
        let alloc_end = alloc_start + size;

        if alloc_end <= self.heap_start + self.heap_size {
            self.next = alloc_end;
            Some(alloc_start as *mut u8)
        } else {
            None
        }
    }
}
<commit_msg>Move heap, make it larger<commit_after>//! A simple allocator that never frees, for testing
//! Some code borrowed from [Phil Opp's Blog](http://os.phil-opp.com/kernel-heap.html)

#![feature(allocator)]
#![feature(const_fn)]
#![allocator]
#![no_std]

use spin::Mutex;

extern crate spin;

pub const HEAP_START: usize = 0x1_0000_0000; // Put at end of 4GB
pub const HEAP_SIZE: usize = 16 * 1024 * 1024; // 16 MB

static BUMP_ALLOCATOR: Mutex<BumpAllocator> = Mutex::new(BumpAllocator::new(HEAP_START, HEAP_SIZE));

#[no_mangle]
pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    BUMP_ALLOCATOR.lock().allocate(size, align).expect("out of memory")
}

#[no_mangle]
pub extern fn __rust_usable_size(size: usize, align: usize) -> usize {
    size
}

#[no_mangle]
pub extern fn __rust_deallocate(ptr: *mut u8, size: usize, align: usize) {

}

#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, size: usize, new_size: usize, align: usize) -> *mut u8 {
    use core::{ptr, cmp};

    let new_ptr = __rust_allocate(new_size, align);
    unsafe { ptr::copy(ptr, new_ptr, cmp::min(size, new_size)) };
    __rust_deallocate(ptr, size, align);
    new_ptr
}

#[no_mangle]
pub extern fn __rust_reallocate_inplace(ptr: *mut u8, size: usize, new_size: usize, align: usize) -> usize {
    size
}

/// Align downwards. Returns the greatest x with alignment `align`
/// so that x <= addr. The alignment must be a power of 2.
pub fn align_down(addr: usize, align: usize) -> usize {
    if align.is_power_of_two() {
        addr & !(align - 1)
    } else if align == 0 {
        addr
    } else {
        panic!("`align` must be a power of 2");
    }
}

/// Align upwards. Returns the smallest x with alignment `align`
/// so that x >= addr. The alignment must be a power of 2.
pub fn align_up(addr: usize, align: usize) -> usize {
    align_down(addr + align - 1, align)
}

#[derive(Debug)]
struct BumpAllocator {
    heap_start: usize,
    heap_size: usize,
    next: usize,
}

impl BumpAllocator {
    /// Create a new allocator, which uses the memory in the
    /// range [heap_start, heap_start + heap_size).
    const fn new(heap_start: usize, heap_size: usize) -> BumpAllocator {
        BumpAllocator {
            heap_start: heap_start,
            heap_size: heap_size,
            next: heap_start,
        }
    }

    /// Allocates a block of memory with the given size and alignment.
    fn allocate(&mut self, size: usize, align: usize) -> Option<*mut u8> {
    	let alloc_start = align_up(self.next, align);
        let alloc_end = alloc_start + size;

        if alloc_end <= self.heap_start + self.heap_size {
            self.next = alloc_end;
            Some(alloc_start as *mut u8)
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use common::util::*;
use std::os::unix::fs::PermissionsExt;

#[test]
fn test_install_help() {
    let (_, mut ucmd) = at_and_ucmd!();

    assert!(
        ucmd.arg("--help").succeeds().no_stderr().stdout.contains("Options:"));
}

#[test]
fn test_install_basic() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_a";
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";

    at.touch(file1);
    at.touch(file2);
    at.mkdir(dir);
    ucmd.arg(file1).arg(file2).arg(dir).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
    assert!(at.file_exists(&format!("{}/{}", dir, file1)));
    assert!(at.file_exists(&format!("{}/{}", dir, file2)));
}

#[test]
fn test_install_unimplemented_arg() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_b";
    let file = "test_install_target_dir_file_b";
    let context_arg = "--context";

    at.touch(file);
    at.mkdir(dir);
    assert!(ucmd.arg(context_arg).arg(file).arg(dir)
            .fails().stderr.contains("Unimplemented"));

    assert!(!at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_component_directories() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component1 = "test_install_target_dir_component_c1";
    let component2 = "test_install_target_dir_component_c2";
    let component3 = "test_install_target_dir_component_c3";
    let directories_arg = "-d";

    ucmd.args(&[directories_arg, component1, component2, component3])
        .succeeds().no_stderr();

    assert!(at.dir_exists(component1));
    assert!(at.dir_exists(component2));
    assert!(at.dir_exists(component3));
}

#[test]
fn test_install_component_directories_failing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component = "test_install_target_dir_component_d1";
    let directories_arg = "-d";

    at.mkdir(component);
    assert!(ucmd.arg(directories_arg).arg(component)
            .fails().stderr.contains("File exists"));
}

#[test]
fn test_install_mode_numeric() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_e";
    let file = "test_install_target_dir_file_e";
    let mode_arg = "--mode=333";

    at.touch(file);
    at.mkdir(dir);
    ucmd.arg(file).arg(dir).arg(mode_arg).succeeds().no_stderr();

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o333 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_mode_symbolic() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_f";
    let file = "test_install_target_dir_file_f";
    let mode_arg = "--mode=o+wx";

    at.touch(file);
    at.mkdir(dir);
    ucmd.arg(file).arg(dir).arg(mode_arg).succeeds().no_stderr();

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o003 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_mode_failing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_g";
    let file = "test_install_target_dir_file_g";
    let mode_arg = "--mode=999";

    at.touch(file);
    at.mkdir(dir);
    assert!(ucmd.arg(file).arg(dir).arg(mode_arg)
            .fails().stderr.contains("Invalid mode string: numeric parsing error"));

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(!at.file_exists(dest_file));
}

#[test]
fn test_install_mode_directories() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component = "test_install_target_dir_component_h";
    let directories_arg = "-d";
    let mode_arg = "--mode=333";

    ucmd.arg(directories_arg).arg(component).arg(mode_arg).succeeds().no_stderr();

    assert!(at.dir_exists(component));
    let permissions = at.metadata(component).permissions();
    assert_eq!(0o333 as u32, PermissionsExt::mode(&permissions));
}
<commit_msg>install: add high bits to file permissions in tests<commit_after>use common::util::*;
use std::os::unix::fs::PermissionsExt;

#[test]
fn test_install_help() {
    let (_, mut ucmd) = at_and_ucmd!();

    assert!(
        ucmd.arg("--help").succeeds().no_stderr().stdout.contains("Options:"));
}

#[test]
fn test_install_basic() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_a";
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";

    at.touch(file1);
    at.touch(file2);
    at.mkdir(dir);
    ucmd.arg(file1).arg(file2).arg(dir).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
    assert!(at.file_exists(&format!("{}/{}", dir, file1)));
    assert!(at.file_exists(&format!("{}/{}", dir, file2)));
}

#[test]
fn test_install_unimplemented_arg() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_b";
    let file = "test_install_target_dir_file_b";
    let context_arg = "--context";

    at.touch(file);
    at.mkdir(dir);
    assert!(ucmd.arg(context_arg).arg(file).arg(dir)
            .fails().stderr.contains("Unimplemented"));

    assert!(!at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_component_directories() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component1 = "test_install_target_dir_component_c1";
    let component2 = "test_install_target_dir_component_c2";
    let component3 = "test_install_target_dir_component_c3";
    let directories_arg = "-d";

    ucmd.args(&[directories_arg, component1, component2, component3])
        .succeeds().no_stderr();

    assert!(at.dir_exists(component1));
    assert!(at.dir_exists(component2));
    assert!(at.dir_exists(component3));
}

#[test]
fn test_install_component_directories_failing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component = "test_install_target_dir_component_d1";
    let directories_arg = "-d";

    at.mkdir(component);
    assert!(ucmd.arg(directories_arg).arg(component)
            .fails().stderr.contains("File exists"));
}

#[test]
fn test_install_mode_numeric() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_e";
    let file = "test_install_target_dir_file_e";
    let mode_arg = "--mode=333";

    at.touch(file);
    at.mkdir(dir);
    ucmd.arg(file).arg(dir).arg(mode_arg).succeeds().no_stderr();

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_mode_symbolic() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_f";
    let file = "test_install_target_dir_file_f";
    let mode_arg = "--mode=o+wx";

    at.touch(file);
    at.mkdir(dir);
    ucmd.arg(file).arg(dir).arg(mode_arg).succeeds().no_stderr();

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100003 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_mode_failing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_g";
    let file = "test_install_target_dir_file_g";
    let mode_arg = "--mode=999";

    at.touch(file);
    at.mkdir(dir);
    assert!(ucmd.arg(file).arg(dir).arg(mode_arg)
            .fails().stderr.contains("Invalid mode string: numeric parsing error"));

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(!at.file_exists(dest_file));
}

#[test]
fn test_install_mode_directories() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component = "test_install_target_dir_component_h";
    let directories_arg = "-d";
    let mode_arg = "--mode=333";

    ucmd.arg(directories_arg).arg(component).arg(mode_arg).succeeds().no_stderr();

    assert!(at.dir_exists(component));
    let permissions = at.metadata(component).permissions();
    assert_eq!(0o040333 as u32, PermissionsExt::mode(&permissions));
}
<|endoftext|>


<commit_before>extern crate clang;
use self::clang::*;

extern crate regex;
use self::regex::Regex;

use log;
use std::collections::HashSet;
use std::path::PathBuf;
// use std::ffi::OsStr;

use clang_cpp_data::CLangCppData;
use cpp_type_map::CppTypeInfo;
use cpp_method::CppMethod;
use enums::{CppMethodScope, CppTypeOrigin, CppTypeIndirection};
use cpp_type::CppType;

#[derive(Default)]
pub struct CppParserStats {
  pub total_methods: i32,
  pub failed_methods: i32,
  pub success_methods: i32,
}

pub struct CppParser {
  library_include_dir: PathBuf,
  entity_kinds: HashSet<EntityKind>,
  files: HashSet<String>,
  data: CLangCppData,
  stats: CppParserStats
}

fn inspect_method(entity: Entity) {
  println!("{:?}", entity.get_display_name());
  //  println!("children:");
  //  for c in entity.get_children() {
  //    println!("child {:?}", c);
  //  }
  println!("type: {:?}", entity.get_type());
  println!("return type: {:?}",
           entity.get_type().unwrap().get_result_type());
  println!("args:");
  for c in entity.get_arguments().unwrap() {
    // println!("arg: {:?}", c);
    println!("arg: name={} type={:?}",
             c.get_name().unwrap_or("[no name]".to_string()),
             c.get_type());
  }
}

fn dump_entity(entity: &Entity, level: i32) {
  for _ in 0..level {
    print!(". ");
  }
  println!("{:?}", entity);
  for child in entity.get_children() {
    dump_entity(&child, level + 1);
  }
}

fn get_full_name(entity: Entity) -> Result<String, String> {
  let mut current_entity = entity;
  if let Some(mut s) = entity.get_name() {
    loop {
      if let Some(p) = current_entity.get_semantic_parent() {
        if p.get_kind() == EntityKind::ClassDecl || p.get_kind() == EntityKind::ClassTemplate ||
           p.get_kind() == EntityKind::StructDecl ||
           p.get_kind() == EntityKind::Namespace ||
           p.get_kind() == EntityKind::EnumDecl || p.get_kind() == EntityKind::Method ||
           p.get_kind() == EntityKind::ClassTemplatePartialSpecialization {
          match p.get_name() {
            Some(p_name) => s = format!("{}::{}", p_name, s),
            None => return Err(format!("Anonymous nested type")),
          }
          current_entity = p;
        } else {
          break;
        }
      }
    }
    Ok(s)
  } else {
    Err(format!("Anonymous type"))
  }
}

#[derive(Clone)]
struct EntityContext {
  includes: Vec<String>,
  level: i32,
}

impl EntityContext {
  fn new() -> Self {
    EntityContext {
      level: 0,
      includes: Vec::new(),
    }
  }
}

impl CppParser {
  pub fn new() -> Self {
    CppParser {
      library_include_dir: PathBuf::from("/home/ri/bin/Qt/5.5/gcc_64/include/QtCore"),
      entity_kinds: HashSet::new(),
      files: HashSet::new(),
      data: CLangCppData {
        methods: Vec::new(),
        types: Vec::new(),
      },
      stats: Default::default()
    }
  }

  fn parse_type(&mut self, type1: Type) -> Result<CppType, String> {
    match type1.get_kind() {
      TypeKind::Void |
      TypeKind::Bool |
      TypeKind::CharS |
      TypeKind::CharU |
      TypeKind::SChar |
      TypeKind::UChar |
      TypeKind::WChar |
      TypeKind::Char16 |
      TypeKind::Char32 |
      TypeKind::Short |
      TypeKind::UShort |
      TypeKind::Int |
      TypeKind::UInt |
      TypeKind::Long |
      TypeKind::ULong |
      TypeKind::LongLong |
      TypeKind::ULongLong |
      TypeKind::Int128 |
      TypeKind::UInt128 |
      TypeKind::Float |
      TypeKind::Double |
      TypeKind::LongDouble |
      TypeKind::Enum |
      TypeKind::Record |
      TypeKind::Typedef => {
        Ok(CppType {
          base: type1.get_display_name(),
          is_const: type1.is_const_qualified(),
          indirection: CppTypeIndirection::None,
          template_arguments: None, // TODO: get template arguments
        })
      }
      TypeKind::Pointer |
      TypeKind::LValueReference |
      TypeKind::RValueReference => {
        match type1.get_pointee_type() {
          Some(pointee) => {
            match self.parse_type(pointee.get_canonical_type()) {
              Ok(result) => {
                let new_indirection = match type1.get_kind() {
                  TypeKind::Pointer => {
                    match result.indirection {
                      CppTypeIndirection::None => Ok(CppTypeIndirection::Ptr),
                      CppTypeIndirection::Ptr => Ok(CppTypeIndirection::PtrPtr),
                      CppTypeIndirection::Ref => Ok(CppTypeIndirection::PtrRef),
                      _ => {
                        Err(format!("Unsupported level of indirection: pointer to {:?}",
                                    result.indirection))
                      }
                    }
                  }
                  TypeKind::LValueReference => {
                    if result.indirection == CppTypeIndirection::None {
                      Ok(CppTypeIndirection::Ref)
                    } else {
                      Err(format!("Unsupported level of indirection: reference to {:?}",
                                  result.indirection))
                    }
                  }
                  TypeKind::RValueReference => {
                    if result.indirection == CppTypeIndirection::None {
                      Ok(CppTypeIndirection::Ref)
                    } else {
                      Err(format!("Unsupported level of indirection: r-value reference to {:?}",
                                  result.indirection))
                    }
                  }
                  _ => unreachable!(),
                };
                match new_indirection {
                  Ok(new_indirection) => Ok(CppType { indirection: new_indirection, ..result }),
                  Err(msg) => Err(msg),
                }
              }
              Err(msg) => Err(msg),
            }
          }
          None => Err("can't get pointee type".to_string()),
        }
      }
      _ => {
        if type1.get_kind() == TypeKind::Unexposed {
          if let Some(declaration) = type1.get_declaration() {
            if declaration.get_kind() == EntityKind::ClassDecl {
              return Ok(CppType {
                base: declaration.get_display_name().unwrap(),
                is_const: type1.is_const_qualified(),
                indirection: CppTypeIndirection::None,
                template_arguments: None, /* TODO: get template arguments
                                           * TODO: (well, that's probably not gonna happen) */
              });
            }
          }
          let name = type1.get_display_name();
          let re = Regex::new(r"^(const ){0,1}(type-parameter-0-(\d+))$").unwrap();
          if let Some(matches) = re.captures(name.as_ref()) {
            // TODO: capture and use type parameter index
            return Ok(CppType {
              base: matches.at(2).unwrap().to_string(),
              is_const: type1.is_const_qualified(),
              indirection: CppTypeIndirection::None,
              template_arguments: None,
            });
          }
        }
        println!("unsupported kind of type: {:?}", type1);
        println!("canonical: {:?}", type1.get_canonical_type());
        println!("declaration: {:?}", type1.get_declaration());
        println!("template arguments: {:?}",
                 type1.get_template_argument_types());
        Err(format!("Unsupported kind of type: {:?}", type1.get_kind()))
      }
    }
  }

  fn parse_function(&mut self,
                    entity: Entity,
                    include_file: &Option<String>)
                    -> Result<CppMethod, String> {
    log::noisy(format!("Parsing function: {:?}", get_full_name(entity)));
    let scope = if let Some(p) = entity.get_semantic_parent() {
      match p.get_kind() {
        EntityKind::ClassDecl |
        EntityKind::ClassTemplate |
        EntityKind::StructDecl |
        EntityKind::ClassTemplatePartialSpecialization => {
          match get_full_name(p) {
            Ok(class_name) => CppMethodScope::Class(class_name),
            Err(msg) => {
              panic!("function parent is a class but it doesn't have a name: {}",
                     msg)
            }
          }
        }
        _ => CppMethodScope::Global,
      }
    } else {
      CppMethodScope::Global
    };
    if let CppMethodScope::Class(..) = scope {
      if let Some(accessibility) = entity.get_accessibility() {
        if accessibility == Accessibility::Private {
          return Err("Private method".to_string());
        }
      } else {
        panic!("class method without accessibility");
      }
    }
    let return_type = entity.get_type()
                            .unwrap_or_else(|| panic!("failed to get function type"))
                            .get_result_type()
                            .unwrap_or_else(|| panic!("failed to get function return type"));
    let return_type_parsed = match self.parse_type(return_type.get_canonical_type()) {
      Ok(x) => x,
      Err(msg) => {
        return Err(format!("Can't parse return type: {:?}: {}", return_type, msg));
      }
    };

    for c in entity.get_arguments().unwrap() {
      //c.get_name().unwrap_or("[no name]".to_string()),
      //c.get_type()
    }

    Ok(CppMethod {
      name: get_full_name(entity).unwrap_or_else(|_| panic!("failed to get function name")),
      scope: scope,
      is_virtual: entity.is_virtual_method(),
      is_pure_virtual: entity.is_pure_virtual_method(),
      is_const: entity.is_const_method(),
      is_static: entity.is_static_method(),
      is_protected: entity.get_accessibility().unwrap_or(Accessibility::Public) ==
                    Accessibility::Protected,
      is_signal: false, // TODO: somehow get this information
      arguments: vec![], // TODO: arguments
      allows_variable_arguments: entity.is_variadic(),
      return_type: Some(return_type_parsed),
      is_constructor: entity.get_kind() == EntityKind::Constructor,
      is_destructor: entity.get_kind() == EntityKind::Destructor,
      operator: None, // TODO: operator
      is_variable: false, // TODO: move variables into CppTypeInfo
      original_index: -1,
      origin: match include_file {
        &Some(ref include_file) => CppTypeOrigin::CLang { include_file: include_file.clone() },
        &None => CppTypeOrigin::Unknown,
      },
    })
  }

  fn process_entity(&mut self, entity: Entity, context: &EntityContext) {
    let mut child_context = context.clone();
    child_context.level = child_context.level + 1;
    self.entity_kinds.insert(entity.get_kind());
    if let Some(accessibility) = entity.get_accessibility() {
      if accessibility == Accessibility::Private {
        return; // skipping private stuff
      }
    }

    let include_file = if let Some(location) = entity.get_location() {
      let file_path = location.get_presumed_location().0;
      if file_path.is_empty() {
        println!("empty file path: {:?}", entity.get_kind());
        None
      } else {
        let file_path_buf = PathBuf::from(file_path.clone());
        // println!("file path {}", file_path);
        if !file_path_buf.starts_with(&self.library_include_dir) {
          log::noisy(format!("skipping entities from {}", file_path));
          return;
        }
        //        let file_name = PathBuf::from(file_path.clone())
        //                          .file_name()
        //                          .unwrap_or(OsStr::new(&file_path))
        //                          .to_str()
        //                          .unwrap()
        //                          .to_string();
        let file_name = file_path_buf.strip_prefix(&self.library_include_dir)
                                     .unwrap()
                                     .to_str()
                                     .unwrap()
                                     .to_string();
        self.files.insert(file_name.clone());
        Some(file_name)
      }
    } else {
      None
    };
    // else if entity.get_kind() != EntityKind::TranslationUnit {
    // log::warning(format!("skipped: {:?} (no source file detected)", entity));
    // return;
    // }
    //    if entity.get_kind() == EntityKind::InclusionDirective {
    //      println!("include: {:?}", entity);
    //      child_context.includes.push(entity.get_display_name().unwrap_or(String::new()));
    //    }
    //    if entity.get_kind() == EntityKind::ClassDecl {
    //      println!("class: {} (from {:?})",
    //               entity.get_display_name().unwrap_or(String::new()),
    //               context.includes);
    //    }
    match entity.get_kind() {
      EntityKind::FunctionDecl |
      EntityKind::Method |
      EntityKind::Constructor |
      EntityKind::Destructor => {
        self.stats.total_methods = self.stats.total_methods + 1;
        match self.parse_function(entity, &include_file) {
          Ok(r) => {
            self.stats.success_methods = self.stats.success_methods + 1;
            self.data.methods.push(r);
          }
          Err(msg) => {
            self.stats.failed_methods = self.stats.failed_methods + 1;
            log::warning(format!("Failed to parse method: {}\nentity: {:?}\nerror: {}",
                                 get_full_name(entity).unwrap(),
                                 entity,
                                 msg));
            dump_entity(&entity, 0);
          }
        }
      }
      _ => {}
    }
    for c in entity.get_children() {
      self.process_entity(c, &child_context);
    }
  }

  pub fn run(&mut self) {
    log::info(format!("clang version: {}", get_version()));
    log::info("Initializing clang...");
    let clang = Clang::new().unwrap_or_else(|err| panic!("clang init failed: {:?}", err));
    let index = Index::new(&clang, false, false);
    let tu = index.parser("/home/ri/tmp/1.cpp")
                  .arguments(&["-fPIC",
                               "-I",
                               "/home/ri/bin/Qt/5.5/gcc_64/include",
                               "-I",
                               "/home/ri/bin/Qt/5.5/gcc_64/include/QtCore/",
                               "-Xclang",
                               "-detailed-preprocessing-record"])
                  .parse()
                  .unwrap_or_else(|err| panic!("clang parse failed: {:?}", err));
    let translation_unit = tu.get_entity();
    assert!(translation_unit.get_kind() == EntityKind::TranslationUnit);
    if !tu.get_diagnostics().is_empty() {
      log::warning("Diagnostics:");
      for diag in tu.get_diagnostics() {
        log::warning(format!("{}", diag));
      }
    }
    log::info("Found entities:");
    self.process_entity(translation_unit, &EntityContext::new());
    println!("Entity kinds: {:?}", self.entity_kinds);
    println!("Files: {:?}", self.files);
    println!("{}/{} METHODS UNHARMED", self.stats.success_methods, self.stats.total_methods);
    println!("{}/{} METHODS DESTROYED", self.stats.failed_methods, self.stats.total_methods);
  }
}
<commit_msg>parse function arguments<commit_after>extern crate clang;
use self::clang::*;

extern crate regex;
use self::regex::Regex;

use log;
use std::collections::HashSet;
use std::path::PathBuf;
// use std::ffi::OsStr;

use clang_cpp_data::CLangCppData;
use cpp_type_map::CppTypeInfo;
use cpp_method::{CppMethod, CppFunctionArgument};
use enums::{CppMethodScope, CppTypeOrigin, CppTypeIndirection};
use cpp_type::CppType;

#[derive(Default)]
pub struct CppParserStats {
  pub total_methods: i32,
  pub failed_methods: i32,
  pub success_methods: i32,
}

pub struct CppParser {
  library_include_dir: PathBuf,
  entity_kinds: HashSet<EntityKind>,
  files: HashSet<String>,
  data: CLangCppData,
  stats: CppParserStats,
}

fn inspect_method(entity: Entity) {
  println!("{:?}", entity.get_display_name());
  //  println!("children:");
  //  for c in entity.get_children() {
  //    println!("child {:?}", c);
  //  }
  println!("type: {:?}", entity.get_type());
  println!("return type: {:?}",
           entity.get_type().unwrap().get_result_type());
  println!("args:");
  for c in entity.get_arguments().unwrap() {
    // println!("arg: {:?}", c);
    println!("arg: name={} type={:?}",
             c.get_name().unwrap_or("[no name]".to_string()),
             c.get_type());
  }
}

fn dump_entity(entity: &Entity, level: i32) {
  for _ in 0..level {
    print!(". ");
  }
  println!("{:?}", entity);
  for child in entity.get_children() {
    dump_entity(&child, level + 1);
  }
}

fn get_full_name(entity: Entity) -> Result<String, String> {
  let mut current_entity = entity;
  if let Some(mut s) = entity.get_name() {
    loop {
      if let Some(p) = current_entity.get_semantic_parent() {
        if p.get_kind() == EntityKind::ClassDecl || p.get_kind() == EntityKind::ClassTemplate ||
           p.get_kind() == EntityKind::StructDecl ||
           p.get_kind() == EntityKind::Namespace ||
           p.get_kind() == EntityKind::EnumDecl || p.get_kind() == EntityKind::Method ||
           p.get_kind() == EntityKind::ClassTemplatePartialSpecialization {
          match p.get_name() {
            Some(p_name) => s = format!("{}::{}", p_name, s),
            None => return Err(format!("Anonymous nested type")),
          }
          current_entity = p;
        } else {
          break;
        }
      }
    }
    Ok(s)
  } else {
    Err(format!("Anonymous type"))
  }
}

#[derive(Clone)]
struct EntityContext {
  includes: Vec<String>,
  level: i32,
}

impl EntityContext {
  fn new() -> Self {
    EntityContext {
      level: 0,
      includes: Vec::new(),
    }
  }
}

impl CppParser {
  pub fn new() -> Self {
    CppParser {
      library_include_dir: PathBuf::from("/home/ri/bin/Qt/5.5/gcc_64/include/QtCore"),
      entity_kinds: HashSet::new(),
      files: HashSet::new(),
      data: CLangCppData {
        methods: Vec::new(),
        types: Vec::new(),
      },
      stats: Default::default(),
    }
  }

  fn parse_type(&mut self, type1: Type) -> Result<CppType, String> {
    match type1.get_kind() {
      TypeKind::Void |
      TypeKind::Bool |
      TypeKind::CharS |
      TypeKind::CharU |
      TypeKind::SChar |
      TypeKind::UChar |
      TypeKind::WChar |
      TypeKind::Char16 |
      TypeKind::Char32 |
      TypeKind::Short |
      TypeKind::UShort |
      TypeKind::Int |
      TypeKind::UInt |
      TypeKind::Long |
      TypeKind::ULong |
      TypeKind::LongLong |
      TypeKind::ULongLong |
      TypeKind::Int128 |
      TypeKind::UInt128 |
      TypeKind::Float |
      TypeKind::Double |
      TypeKind::LongDouble => {
        Ok(CppType {
          base: type1.get_display_name(), // TODO: remove const
          is_const: type1.is_const_qualified(),
          indirection: CppTypeIndirection::None,
          template_arguments: None,
        })
      }
      TypeKind::Enum |
      TypeKind::Record => {
        Ok(CppType {
          base: get_full_name(type1.get_declaration().unwrap()).unwrap(),
          is_const: type1.is_const_qualified(),
          indirection: CppTypeIndirection::None,
          template_arguments: None, // TODO: get template arguments
        })
      }
      TypeKind::Pointer |
      TypeKind::LValueReference |
      TypeKind::RValueReference => {
        match type1.get_pointee_type() {
          Some(pointee) => {
            match self.parse_type(pointee.get_canonical_type()) {
              Ok(result) => {
                let new_indirection = match type1.get_kind() {
                  TypeKind::Pointer => {
                    match result.indirection {
                      CppTypeIndirection::None => Ok(CppTypeIndirection::Ptr),
                      CppTypeIndirection::Ptr => Ok(CppTypeIndirection::PtrPtr),
                      _ => {
                        Err(format!("Unsupported level of indirection: pointer to {:?}",
                                    result.indirection))
                      }
                    }
                  }
                  TypeKind::LValueReference => {
                    match result.indirection {
                      CppTypeIndirection::None => Ok(CppTypeIndirection::Ref),
                      CppTypeIndirection::Ptr => Ok(CppTypeIndirection::PtrRef),
                      _ => {
                        Err(format!("Unsupported level of indirection: reference to {:?}",
                                    result.indirection))
                      }
                    }
                  }
                  TypeKind::RValueReference => {
                    if result.indirection == CppTypeIndirection::None {
                      Ok(CppTypeIndirection::Ref)
                    } else {
                      Err(format!("Unsupported level of indirection: r-value reference to {:?}",
                                  result.indirection))
                    }
                  }
                  _ => unreachable!(),
                };
                match new_indirection {
                  Ok(new_indirection) => Ok(CppType { indirection: new_indirection, ..result }),
                  Err(msg) => Err(msg),
                }
              }
              Err(msg) => Err(msg),
            }
          }
          None => Err("can't get pointee type".to_string()),
        }
      }
      _ => {
        if type1.get_kind() == TypeKind::Unexposed {
          if let Some(declaration) = type1.get_declaration() {
            if declaration.get_kind() == EntityKind::ClassDecl {
              return Ok(CppType {
                base: declaration.get_display_name().unwrap(),
                is_const: type1.is_const_qualified(),
                indirection: CppTypeIndirection::None,
                template_arguments: None, /* TODO: get template arguments
                                           * TODO: (well, that's probably not gonna happen) */
              });
            }
          }
          let name = type1.get_display_name();
          let re = Regex::new(r"^(const ){0,1}(type-parameter-0-(\d+))$").unwrap();
          if let Some(matches) = re.captures(name.as_ref()) {
            // TODO: capture and use type parameter index
            return Ok(CppType {
              base: matches.at(2).unwrap().to_string(),
              is_const: type1.is_const_qualified(),
              indirection: CppTypeIndirection::None,
              template_arguments: None,
            });
          }
        }
        println!("unsupported kind of type: {:?}", type1);
        println!("canonical: {:?}", type1.get_canonical_type());
        println!("declaration: {:?}", type1.get_declaration());
        println!("template arguments: {:?}",
                 type1.get_template_argument_types());
        Err(format!("Unsupported kind of type: {:?}", type1.get_kind()))
      }
    }
  }

  fn parse_function(&mut self,
                    entity: Entity,
                    include_file: &Option<String>)
                    -> Result<CppMethod, String> {
//    log::debug(format!("Parsing function: {:?}", get_full_name(entity).unwrap()));
    //    let allow_debug_print = get_full_name(entity).unwrap().find("QString::").is_some();
    //    if allow_debug_print {
    //    }
    let scope = if let Some(p) = entity.get_semantic_parent() {
      match p.get_kind() {
        EntityKind::ClassDecl |
        EntityKind::ClassTemplate |
        EntityKind::StructDecl |
        EntityKind::ClassTemplatePartialSpecialization => {
          match get_full_name(p) {
            Ok(class_name) => CppMethodScope::Class(class_name),
            Err(msg) => {
              panic!("function parent is a class but it doesn't have a name: {}",
                     msg)
            }
          }
        }
        _ => CppMethodScope::Global,
      }
    } else {
      CppMethodScope::Global
    };
    if let CppMethodScope::Class(..) = scope {
      if let Some(accessibility) = entity.get_accessibility() {
        if accessibility == Accessibility::Private {
          return Err("Private method".to_string());
        }
      } else {
        panic!("class method without accessibility");
      }
    }
    let return_type = entity.get_type()
                            .unwrap_or_else(|| panic!("failed to get function type"))
                            .get_result_type()
                            .unwrap_or_else(|| panic!("failed to get function return type"));
    let return_type_parsed = match self.parse_type(return_type.get_canonical_type()) {
      Ok(x) => x,
      Err(msg) => {
        return Err(format!("Can't parse return type: {:?}: {}", return_type, msg));
      }
    };

    let mut arguments = Vec::new();
    for (argument_number, argument_entity) in entity.get_arguments()
                                                    .unwrap()
                                                    .into_iter()
                                                    .enumerate() {
      //println!("argument {:?}", argument_entity);
      let name = argument_entity.get_name().unwrap_or(format!("arg{}", argument_number + 1));
      let type1 = self.parse_type(argument_entity.get_type().unwrap().get_canonical_type());

      match type1 {
        Ok(argument_type) => {
          arguments.push(CppFunctionArgument {
            name: name,
            argument_type: argument_type,
            default_value: if argument_entity.get_range()
                                             .unwrap()
                                             .tokenize()
                                             .iter()
                                             .find(|t| t.get_spelling() == "=")
                                             .is_some() {
              Some("?".to_string())
            } else {
              None
            },
          });
        }
        Err(msg) => {
          return Err(format!("Can't parse argument type: {}: {:?}: {}",
                             name,
                             argument_entity.get_type().unwrap(),
                             msg));
        }
      }
    }

    Ok(CppMethod {
      name: get_full_name(entity).unwrap_or_else(|_| panic!("failed to get function name")),
      scope: scope,
      is_virtual: entity.is_virtual_method(),
      is_pure_virtual: entity.is_pure_virtual_method(),
      is_const: entity.is_const_method(),
      is_static: entity.is_static_method(),
      is_protected: entity.get_accessibility().unwrap_or(Accessibility::Public) ==
                    Accessibility::Protected,
      is_signal: false, // TODO: somehow get this information
      arguments: arguments,
      allows_variable_arguments: entity.is_variadic(),
      return_type: Some(return_type_parsed),
      is_constructor: entity.get_kind() == EntityKind::Constructor,
      is_destructor: entity.get_kind() == EntityKind::Destructor,
      operator: None, // TODO: operator
      is_variable: false, // TODO: move variables into CppTypeInfo
      original_index: -1,
      origin: match include_file {
        &Some(ref include_file) => CppTypeOrigin::CLang { include_file: include_file.clone() },
        &None => CppTypeOrigin::Unknown,
      },
    })
  }

  fn process_entity(&mut self, entity: Entity, context: &EntityContext) {
    let mut child_context = context.clone();
    child_context.level = child_context.level + 1;
    self.entity_kinds.insert(entity.get_kind());
    if let Some(accessibility) = entity.get_accessibility() {
      if accessibility == Accessibility::Private {
        return; // skipping private stuff
      }
    }

    let include_file = if let Some(location) = entity.get_location() {
      let file_path = location.get_presumed_location().0;
      if file_path.is_empty() {
        println!("empty file path: {:?}", entity.get_kind());
        None
      } else {
        let file_path_buf = PathBuf::from(file_path.clone());
        // println!("file path {}", file_path);
        if !file_path_buf.starts_with(&self.library_include_dir) {
          log::noisy(format!("skipping entities from {}", file_path));
          return;
        }
        //        let file_name = PathBuf::from(file_path.clone())
        //                          .file_name()
        //                          .unwrap_or(OsStr::new(&file_path))
        //                          .to_str()
        //                          .unwrap()
        //                          .to_string();
        let file_name = file_path_buf.strip_prefix(&self.library_include_dir)
                                     .unwrap()
                                     .to_str()
                                     .unwrap()
                                     .to_string();
        self.files.insert(file_name.clone());
        Some(file_name)
      }
    } else {
      None
    };
    // else if entity.get_kind() != EntityKind::TranslationUnit {
    // log::warning(format!("skipped: {:?} (no source file detected)", entity));
    // return;
    // }
    //    if entity.get_kind() == EntityKind::InclusionDirective {
    //      println!("include: {:?}", entity);
    //      child_context.includes.push(entity.get_display_name().unwrap_or(String::new()));
    //    }
    //    if entity.get_kind() == EntityKind::ClassDecl {
    //      println!("class: {} (from {:?})",
    //               entity.get_display_name().unwrap_or(String::new()),
    //               context.includes);
    //    }
    match entity.get_kind() {
      EntityKind::FunctionDecl |
      EntityKind::Method |
      EntityKind::Constructor |
      EntityKind::Destructor => {
        self.stats.total_methods = self.stats.total_methods + 1;
        match self.parse_function(entity, &include_file) {
          Ok(r) => {
            self.stats.success_methods = self.stats.success_methods + 1;
            self.data.methods.push(r);
          }
          Err(msg) => {
            self.stats.failed_methods = self.stats.failed_methods + 1;
            log::warning(format!("Failed to parse method: {}\nentity: {:?}\nerror: {}",
                                 get_full_name(entity).unwrap(),
                                 entity,
                                 msg));
            //dump_entity(&entity, 0);
          }
        }
      }
      _ => {}
    }
    for c in entity.get_children() {
      self.process_entity(c, &child_context);
    }
  }

  pub fn run(&mut self) {
    log::info(format!("clang version: {}", get_version()));
    log::info("Initializing clang...");
    let clang = Clang::new().unwrap_or_else(|err| panic!("clang init failed: {:?}", err));
    let index = Index::new(&clang, false, false);
    let tu = index.parser("/home/ri/tmp/1.cpp")
                  .arguments(&["-fPIC",
                               "-I",
                               "/home/ri/bin/Qt/5.5/gcc_64/include",
                               "-I",
                               "/home/ri/bin/Qt/5.5/gcc_64/include/QtCore/",
                               "-Xclang",
                               "-detailed-preprocessing-record"])
                  .parse()
                  .unwrap_or_else(|err| panic!("clang parse failed: {:?}", err));
    let translation_unit = tu.get_entity();
    assert!(translation_unit.get_kind() == EntityKind::TranslationUnit);
    if !tu.get_diagnostics().is_empty() {
      log::warning("Diagnostics:");
      for diag in tu.get_diagnostics() {
        log::warning(format!("{}", diag));
      }
    }
    log::info("Found entities:");
    self.process_entity(translation_unit, &EntityContext::new());
    println!("Entity kinds: {:?}", self.entity_kinds);
    println!("Files: {:?}", self.files);
    println!("{}/{} METHODS UNHARMED",
             self.stats.success_methods,
             self.stats.total_methods);
    println!("{}/{} METHODS DESTROYED",
             self.stats.failed_methods,
             self.stats.total_methods);
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// 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.

#![allow(bad_style)]
#![unstable]

extern crate netmap_sys;
extern crate libc;

use self::netmap_sys::netmap_user::{NETMAP_BUF, NETMAP_FD, NETMAP_TXRING, nm_close, nm_desc,
                                    nm_nextpkt, nm_open, nm_pkthdr, nm_ring_next};
use self::netmap_sys::netmap::{netmap_slot, nm_ring_empty};

use std::ffi::CString;
use std::path::Path;
use std::fs::File;
use std::io;
use std::io::Read;
use std::mem;
use std::num;
use std::ptr;
use std::raw;
use std::sync::Arc;

use datalink::{DataLinkChannelIterator, DataLinkChannelType, DataLinkReceiver, DataLinkSender};
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use util::NetworkInterface;

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
#[repr(C)]
struct pollfd {
    fd: libc::c_int,
    events: libc::c_short,
    revents: libc::c_short,
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
const POLLIN: libc::c_short = 0x0001;
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
const POLLOUT: libc::c_short = 0x0004;

#[cfg(target_os = "freebsd")]
type nfds_t = libc::c_uint;
#[cfg(target_os = "linux")]
type nfds_t = libc::c_ulong;

extern {
    fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: libc::c_int) -> libc::c_int;
}

struct NmDesc {
    desc: *mut nm_desc,
    buf_size: libc::c_uint,
}

impl NmDesc {
    fn new(iface: &NetworkInterface) -> io::Result<NmDesc> {
        let ifname = CString::new(("netmap:".to_string() + &iface.name[..]).as_bytes());
        let desc = unsafe { nm_open(ifname.unwrap().as_ptr(), ptr::null(), 0, ptr::null()) };

        if desc.is_null() {
            Err(io::Error::last_os_error())
        } else {
            let mut f = try!(File::open(&Path::new("/sys/module/netmap/parameters/buf_size")));
            let mut num_str = String::new();
            try!(f.read_to_string(&mut num_str));
            let buf_size = num_str.trim_right().parse().unwrap();

            Ok(NmDesc {
                desc: desc,
                buf_size: buf_size,
            })
        }
    }
}

impl Drop for NmDesc {
    fn drop(&mut self) {
        unsafe {
            nm_close(self.desc);
        }
    }
}

#[inline]
pub fn datalink_channel(network_interface: &NetworkInterface,
                        _write_buffer_size: usize,
                        _read_buffer_size: usize,
                        _channel_type: DataLinkChannelType)
    -> io::Result<(Box<DataLinkSenderImpl>, Box<DataLinkReceiverImpl>)> {
    // FIXME probably want one for each of send/recv
    let desc = NmDesc::new(network_interface);
    match desc {
        Ok(desc) => {
            let arc = Arc::new(desc);

            Ok((Box::new(DataLinkSenderImpl { desc: arc.clone() }),
                Box::new(DataLinkReceiverImpl { desc: arc })))
        }
        Err(e) => Err(e),
    }
}

pub struct DataLinkSenderImpl {
    desc: Arc<NmDesc>,
}

impl DataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(MutableEthernetPacket))
        -> Option<io::Result<()>> {
        assert!(num::cast::<usize, u16>(packet_size).unwrap() as libc::c_uint <=
                self.desc.buf_size);
        let desc = self.desc.desc;
        let mut fds = pollfd {
            fd: unsafe { NETMAP_FD(desc) },
            events: POLLOUT,
            revents: 0,
        };
        let mut packet_idx = 0usize;
        while packet_idx < num_packets {
            unsafe {
                if poll(&mut fds, 1, -1) < 0 {
                    return Some(Err(io::Error::last_os_error()));
                }
                let ring = NETMAP_TXRING((*desc).nifp, 0);
                while !nm_ring_empty(ring) && packet_idx < num_packets {
                    let i = (*ring).cur;
                    let slot_ptr: *mut netmap_slot = mem::transmute(&mut (*ring).slot);
                    let buf = NETMAP_BUF(ring, (*slot_ptr.offset(i as isize)).buf_idx as isize);
                    let slice = raw::Slice {
                        data: buf,
                        len: packet_size,
                    };
                    let meh = MutableEthernetPacket::new(mem::transmute(slice));
                    (*slot_ptr.offset(i as isize)).len = packet_size as u16;
                    func(meh);
                    let next = nm_ring_next(ring, i);
                    (*ring).head = next;
                    (*ring).cur = next;
                    packet_idx += 1;
                }
            }
        }

        Some(Ok(()))
    }

    #[inline]
    fn send_to(&mut self,
               packet: &EthernetPacket,
               _dst: Option<NetworkInterface>)
        -> Option<io::Result<()>> {
        use packet::MutablePacket;
        self.build_and_send(1,
                            packet.packet().len(),
                            &mut |mut eh: MutableEthernetPacket| {
                                eh.clone_from(packet);
                            })
    }
}

pub struct DataLinkReceiverImpl {
    desc: Arc<NmDesc>,
}

impl DataLinkReceiver for DataLinkReceiverImpl {
    // FIXME Layer 3
    fn iter<'a>(&'a mut self) -> Box<DataLinkChannelIterator + 'a> {
        Box::new(DataLinkChannelIteratorImpl { pc: self })
    }
}

pub struct DataLinkChannelIteratorImpl<'a> {
    pc: &'a mut DataLinkReceiverImpl,
}

impl<'a> DataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
    fn next<'c>(&'c mut self) -> io::Result<EthernetPacket<'c>> {
        let desc = self.pc.desc.desc;
        let mut h: nm_pkthdr = unsafe { mem::uninitialized() };
        let mut buf = unsafe { nm_nextpkt(desc, &mut h) };
        if buf.is_null() {
            let mut fds = pollfd {
                fd: unsafe { NETMAP_FD(desc) },
                events: POLLIN,
                revents: 0,
            };
            if unsafe { poll(&mut fds, 1, -1) } < 0 {
                return Err(io::Error::last_os_error());
            }
            buf = unsafe { nm_nextpkt(desc, &mut h) };
        }
        Ok(EthernetPacket::new(unsafe {
            mem::transmute(raw::Slice {
                data: buf,
                len: h.len as usize,
            })
        }))
    }
}
<commit_msg>Auto merge of #151 - mrmonday:fix-netmap-build, r=mrmonday<commit_after>// Copyright (c) 2015, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// 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.

#![allow(bad_style)]

extern crate netmap_sys;
extern crate libc;

use self::netmap_sys::netmap_user::{NETMAP_BUF, NETMAP_FD, NETMAP_TXRING, nm_close, nm_desc,
                                    nm_nextpkt, nm_open, nm_pkthdr, nm_ring_next};
use self::netmap_sys::netmap::{netmap_slot, nm_ring_empty};

use std::ffi::CString;
use std::path::Path;
use std::fs::File;
use std::io;
use std::io::Read;
use std::mem;
use std::num;
use std::ptr;
use std::raw;
use std::sync::Arc;

use datalink::{DataLinkChannelIterator, DataLinkChannelType, DataLinkReceiver, DataLinkSender};
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use util::NetworkInterface;

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
#[repr(C)]
struct pollfd {
    fd: libc::c_int,
    events: libc::c_short,
    revents: libc::c_short,
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
const POLLIN: libc::c_short = 0x0001;
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
const POLLOUT: libc::c_short = 0x0004;

#[cfg(target_os = "freebsd")]
type nfds_t = libc::c_uint;
#[cfg(target_os = "linux")]
type nfds_t = libc::c_ulong;

extern {
    fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: libc::c_int) -> libc::c_int;
}

struct NmDesc {
    desc: *mut nm_desc,
    buf_size: libc::c_uint,
}

unsafe impl Send for NmDesc {}
unsafe impl Sync for NmDesc {}

impl NmDesc {
    fn new(iface: &NetworkInterface) -> io::Result<NmDesc> {
        let ifname = CString::new(("netmap:".to_string() + &iface.name[..]).as_bytes());
        let desc = unsafe { nm_open(ifname.unwrap().as_ptr(), ptr::null(), 0, ptr::null()) };

        if desc.is_null() {
            Err(io::Error::last_os_error())
        } else {
            let mut f = try!(File::open(&Path::new("/sys/module/netmap/parameters/buf_size")));
            let mut num_str = String::new();
            try!(f.read_to_string(&mut num_str));
            let buf_size = num_str.trim_right().parse().unwrap();

            Ok(NmDesc {
                desc: desc,
                buf_size: buf_size,
            })
        }
    }
}

impl Drop for NmDesc {
    fn drop(&mut self) {
        unsafe {
            nm_close(self.desc);
        }
    }
}

#[inline]
pub fn datalink_channel(network_interface: &NetworkInterface,
                        _write_buffer_size: usize,
                        _read_buffer_size: usize,
                        _channel_type: DataLinkChannelType)
    -> io::Result<(Box<DataLinkSender>, Box<DataLinkReceiver>)> {
    // FIXME probably want one for each of send/recv
    let desc = NmDesc::new(network_interface);
    match desc {
        Ok(desc) => {
            let arc = Arc::new(desc);

            Ok((Box::new(DataLinkSenderImpl { desc: arc.clone() }),
                Box::new(DataLinkReceiverImpl { desc: arc })))
        }
        Err(e) => Err(e),
    }
}

pub struct DataLinkSenderImpl {
    desc: Arc<NmDesc>,
}

impl DataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(MutableEthernetPacket))
        -> Option<io::Result<()>> {
        assert!(packet_size <= self.desc.buf_size as usize);
        let desc = self.desc.desc;
        let mut fds = pollfd {
            fd: unsafe { NETMAP_FD(desc) },
            events: POLLOUT,
            revents: 0,
        };
        let mut packet_idx = 0usize;
        while packet_idx < num_packets {
            unsafe {
                if poll(&mut fds, 1, -1) < 0 {
                    return Some(Err(io::Error::last_os_error()));
                }
                let ring = NETMAP_TXRING((*desc).nifp, 0);
                while !nm_ring_empty(ring) && packet_idx < num_packets {
                    let i = (*ring).cur;
                    let slot_ptr: *mut netmap_slot = mem::transmute(&mut (*ring).slot);
                    let buf = NETMAP_BUF(ring, (*slot_ptr.offset(i as isize)).buf_idx as isize);
                    let slice = raw::Slice {
                        data: buf,
                        len: packet_size,
                    };
                    let meh = MutableEthernetPacket::new(mem::transmute(slice)).unwrap();
                    (*slot_ptr.offset(i as isize)).len = packet_size as u16;
                    func(meh);
                    let next = nm_ring_next(ring, i);
                    (*ring).head = next;
                    (*ring).cur = next;
                    packet_idx += 1;
                }
            }
        }

        Some(Ok(()))
    }

    #[inline]
    fn send_to(&mut self,
               packet: &EthernetPacket,
               _dst: Option<NetworkInterface>)
        -> Option<io::Result<()>> {
        use packet::MutablePacket;
        self.build_and_send(1,
                            packet.packet().len(),
                            &mut |mut eh: MutableEthernetPacket| {
                                eh.clone_from(packet);
                            })
    }
}

pub struct DataLinkReceiverImpl {
    desc: Arc<NmDesc>,
}

impl DataLinkReceiver for DataLinkReceiverImpl {
    // FIXME Layer 3
    fn iter<'a>(&'a mut self) -> Box<DataLinkChannelIterator + 'a> {
        Box::new(DataLinkChannelIteratorImpl { pc: self })
    }
}

pub struct DataLinkChannelIteratorImpl<'a> {
    pc: &'a mut DataLinkReceiverImpl,
}

impl<'a> DataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
    fn next<'c>(&'c mut self) -> io::Result<EthernetPacket<'c>> {
        let desc = self.pc.desc.desc;
        let mut h: nm_pkthdr = unsafe { mem::uninitialized() };
        let mut buf = unsafe { nm_nextpkt(desc, &mut h) };
        if buf.is_null() {
            let mut fds = pollfd {
                fd: unsafe { NETMAP_FD(desc) },
                events: POLLIN,
                revents: 0,
            };
            if unsafe { poll(&mut fds, 1, -1) } < 0 {
                return Err(io::Error::last_os_error());
            }
            buf = unsafe { nm_nextpkt(desc, &mut h) };
        }
        Ok(EthernetPacket::new(unsafe {
            mem::transmute(raw::Slice {
                data: buf,
                len: h.len as usize,
            })
        }).unwrap())
    }
}
<|endoftext|>


<commit_before>use bt_messages::Message;
use buffered_reader::BufferedReader;
use std::net::TcpStream;
use std::sync::mpsc::Sender;
use std::io::Write;

const BLOCK_LENGTH:usize = 16384; //block length in bytes

/// Handles messages. This is a cheap way to force reactive style
pub trait Handler {
    type MessageType;
    fn handle(&mut self, message: Self::MessageType, peer: &mut Peer);
}

pub struct DefaultHandler {
    //the global piece count
    gpc: Vec<u16>,
    //pieces owned by self. (as a bitfield)
    owned: Vec<u8>,
    //outgoing requests
    request_map: Vec<u8>
}

impl DefaultHandler {
    pub fn new () -> DefaultHandler {
        DefaultHandler {
            gpc: vec![],
            owned: vec![],
            request_map: vec![]
        }
    }

    /// returns a complete bitfield of pieces that aren't owned or being requested
    /// this is done almost as strictly as possible - and might be a little of a waste as it isn't
    /// really necessary to get a complete picture to get a request chunk
    /// additionally the definitions of owned and request_map are not strict yet - currently they
    /// are growable, and impelementers should take note of that
    pub fn unclaimed_field (&self) -> Vec<u8> {
        if self.owned.len() == self.request_map.len() {
            DefaultHandler::nand_slice(&self.owned, &self.request_map)
        } else {
            if self.owned.len() < self.request_map.len() {
                let mut vec = DefaultHandler::nand_slice(&self.request_map[..self.owned.len()], &self.owned);
                vec.extend((0..self.request_map.len()-self.owned.len()).map(|_| 0));
                vec
            } else {
                let mut vec = DefaultHandler::nand_slice(&self.request_map, &self.owned[..self.request_map.len()]);
                vec.extend((0..self.owned.len()-self.request_map.len()).map(|_| 0));
                vec
            }
        }
    }

    #[inline]
    pub fn nand_slice (lhs: &[u8], rhs: &[u8]) -> Vec<u8> {
        assert!(lhs.len() == rhs.len());
        lhs.iter().zip(rhs)
                  .map(|(a, b)| !a & !b)
                  .collect::<Vec<u8>>()
    }
}

/// The default algorithm
impl Handler for DefaultHandler {
    type MessageType = Message;
    #[inline]
    fn handle (&mut self, message: Message, peer: &mut Peer) {
        println!("{:?}", message);
        match message {
            Message::Have{piece_index: index} => {
                peer.state.set_have(index as usize);
            }
            Message::Bitfield(bitfield) => {
                peer.state.set_bitfield(bitfield);
            },
            Message::Choke => {
                peer.state.set_us_choked(true);
            },
            Message::Unchoke => {
                peer.state.set_us_choked(false);
            },
            Message::Interested => {
                peer.state.set_us_interested(true);
            },
            _ => {
            }
        };
    }
}

pub struct Peer {
    pub id: String,
    stream: TcpStream,
    pub state: State
}

impl Peer {
    pub fn new (id:String, stream: TcpStream) -> Peer {
        Peer {
            id: id,
            stream: stream,
            state: State::new()
        }
    }

    pub fn send_message (&mut self, message: Message) {
        let as_bytes = message.to_byte_array();
        self.stream.write_all(&as_bytes);
    }
}

#[derive(Debug)]
pub struct State {
    //are we choked by them?
    us_choked: bool,
    //are we interested in them?
    us_interested: bool,
    //are they choked by us?
    is_choked: bool,
    //are they interested in us?
    is_interested: bool,
    //the intention is that eventually we will support growable files. so going with vector
    bitfield: Vec<u8>
}

impl State {
    fn new () -> State {
        State {
            us_choked: true,
            us_interested: false,
            is_choked: true,
            is_interested: false,
            bitfield: vec![]
        }
    }

    pub fn set_us_interested (&mut self, us_interested: bool) {
        self.us_interested = us_interested;
    }

    fn set_bitfield (&mut self, bitfield: Vec<u8>) {
        self.bitfield = bitfield;
    }

    fn set_have (&mut self, index: usize) {
        set_have_bitfield(&mut self.bitfield, index);
    }

    fn set_us_choked (&mut self, us_choked: bool) {
        self.us_choked = us_choked;
    }
}

fn set_have_bitfield (bitfield: &mut Vec<u8>, index: usize) {
    //lets say i have index 500 -> how do i bitwise over a u8 array?
    let chunk_index = index/8;
    let chunk_posit = index % 8;
    let chunk_mask = 128 >> chunk_posit;

    //bounds check needs to be here because the bitfield is a variable size - which we want in
    //the future
    if chunk_index+1 > bitfield.len() {
        bitfield.extend((0..chunk_index).map(|_| 0 as u8));
    }

    bitfield[chunk_index] = bitfield[chunk_index] | chunk_mask;
}

#[test]
fn test_set_have_singleton_bitfield() {
    let mut state = State::new();

    state.set_bitfield(vec![0]);
    state.set_have(2);

    assert_eq!(state.bitfield[0], 32);
}

#[test]
fn test_set_have_longer_bitfiled() {
    let mut state = State::new();

    state.set_bitfield(vec![0, 0, 0, 0]);
    state.set_have(23);

    assert_eq!(state.bitfield[0], 0);
    assert_eq!(state.bitfield[1], 0);
    assert_eq!(state.bitfield[2], 1);
    assert_eq!(state.bitfield[3], 0);
}

#[test]
fn test_set_have_out_of_bounds() {
    let mut state = State::new();

    state.set_bitfield(vec![0, 1]);
    state.set_have(31);

    assert_eq!(state.bitfield[0], 0);
    assert_eq!(state.bitfield[1], 1);
    assert_eq!(state.bitfield[2], 0);
    assert_eq!(state.bitfield[3], 1);
}
<commit_msg>added tests for unclaimed_fields, fixed mistake<commit_after>use bt_messages::Message;
use buffered_reader::BufferedReader;
use std::net::TcpStream;
use std::sync::mpsc::Sender;
use std::io::Write;

const BLOCK_LENGTH:usize = 16384; //block length in bytes

/// Handles messages. This is a cheap way to force reactive style
pub trait Handler {
    type MessageType;
    fn handle(&mut self, message: Self::MessageType, peer: &mut Peer);
}

pub struct DefaultHandler {
    //the global piece count
    gpc: Vec<u16>,
    //pieces owned by self. (as a bitfield)
    owned: Vec<u8>,
    //outgoing requests
    request_map: Vec<u8>
}

impl DefaultHandler {
    pub fn new () -> DefaultHandler {
        DefaultHandler {
            gpc: vec![],
            owned: vec![],
            request_map: vec![]
        }
    }

    /// returns a complete bitfield of pieces that aren't owned or being requested
    /// this is done almost as strictly as possible - and might be a little of a waste as it isn't
    /// really necessary to get a complete picture to get a request chunk
    /// additionally the definitions of owned and request_map are not strict yet - currently they
    /// are growable, and impelementers should take note of that
    pub fn unclaimed_fields (&self) -> Vec<u8> {
        if self.owned.len() == self.request_map.len() {
            DefaultHandler::nand_slice(&self.owned, &self.request_map)
        } else {
            if self.owned.len() < self.request_map.len() {
                let mut vec = DefaultHandler::nand_slice(&self.request_map[..self.owned.len()], &self.owned);
                vec.extend((0..self.request_map.len()-self.owned.len()).map(|_| 255));
                vec
            } else {
                let mut vec = DefaultHandler::nand_slice(&self.request_map, &self.owned[..self.request_map.len()]);
                vec.extend((0..self.owned.len()-self.request_map.len()).map(|_| 255));
                vec
            }
        }
    }

    #[inline]
    pub fn nand_slice (lhs: &[u8], rhs: &[u8]) -> Vec<u8> {
        assert!(lhs.len() == rhs.len());
        lhs.iter().zip(rhs)
                  .map(|(a, b)| !a & !b)
                  .collect::<Vec<u8>>()
    }
}

/// The default algorithm
impl Handler for DefaultHandler {
    type MessageType = Message;
    #[inline]
    fn handle (&mut self, message: Message, peer: &mut Peer) {
        println!("{:?}", message);
        match message {
            Message::Have{piece_index: index} => {
                peer.state.set_have(index as usize);
            }
            Message::Bitfield(bitfield) => {
                peer.state.set_bitfield(bitfield);
            },
            Message::Choke => {
                peer.state.set_us_choked(true);
            },
            Message::Unchoke => {
                peer.state.set_us_choked(false);
            },
            Message::Interested => {
                peer.state.set_us_interested(true);
            },
            _ => {
            }
        };
    }
}

pub struct Peer {
    pub id: String,
    stream: TcpStream,
    pub state: State
}

impl Peer {
    pub fn new (id:String, stream: TcpStream) -> Peer {
        Peer {
            id: id,
            stream: stream,
            state: State::new()
        }
    }

    pub fn send_message (&mut self, message: Message) {
        let as_bytes = message.to_byte_array();
        self.stream.write_all(&as_bytes);
    }
}

#[derive(Debug)]
pub struct State {
    //are we choked by them?
    us_choked: bool,
    //are we interested in them?
    us_interested: bool,
    //are they choked by us?
    is_choked: bool,
    //are they interested in us?
    is_interested: bool,
    //the intention is that eventually we will support growable files. so going with vector
    bitfield: Vec<u8>
}

impl State {
    fn new () -> State {
        State {
            us_choked: true,
            us_interested: false,
            is_choked: true,
            is_interested: false,
            bitfield: vec![]
        }
    }

    pub fn set_us_interested (&mut self, us_interested: bool) {
        self.us_interested = us_interested;
    }

    fn set_bitfield (&mut self, bitfield: Vec<u8>) {
        self.bitfield = bitfield;
    }

    fn set_have (&mut self, index: usize) {
        set_have_bitfield(&mut self.bitfield, index);
    }

    fn set_us_choked (&mut self, us_choked: bool) {
        self.us_choked = us_choked;
    }
}

fn set_have_bitfield (bitfield: &mut Vec<u8>, index: usize) {
    //lets say i have index 500 -> how do i bitwise over a u8 array?
    let chunk_index = index/8;
    let chunk_posit = index % 8;
    let chunk_mask = 128 >> chunk_posit;

    //bounds check needs to be here because the bitfield is a variable size - which we want in
    //the future
    if chunk_index+1 > bitfield.len() {
        bitfield.extend((0..chunk_index).map(|_| 0));
    }

    bitfield[chunk_index] = bitfield[chunk_index] | chunk_mask;
}

#[test]
fn test_nand_slice() {
    let a = vec![0, 0];
    let b = vec![0, 1];
    let c = DefaultHandler::nand_slice(&a, &b);

    assert_eq!(c, vec![255, 254]);
}

#[test]
fn test_unclaimed_fields() {
    let mut handler = DefaultHandler::new();

    handler.owned = vec![0, 0, 0];
    handler.request_map = vec![1, 0];

    let c = handler.unclaimed_fields();
    assert_eq!(c, vec![254, 255, 255]);
}

#[test]
fn test_set_have_singleton_bitfield() {
    let mut state = State::new();

    state.set_bitfield(vec![0]);
    state.set_have(2);

    assert_eq!(state.bitfield[0], 32);
}

#[test]
fn test_set_have_longer_bitfiled() {
    let mut state = State::new();

    state.set_bitfield(vec![0, 0, 0, 0]);
    state.set_have(23);

    assert_eq!(state.bitfield[0], 0);
    assert_eq!(state.bitfield[1], 0);
    assert_eq!(state.bitfield[2], 1);
    assert_eq!(state.bitfield[3], 0);
}

#[test]
fn test_set_have_out_of_bounds() {
    let mut state = State::new();

    state.set_bitfield(vec![0, 1]);
    state.set_have(31);

    assert_eq!(state.bitfield[0], 0);
    assert_eq!(state.bitfield[1], 1);
    assert_eq!(state.bitfield[2], 0);
    assert_eq!(state.bitfield[3], 1);
}
<|endoftext|>


<commit_before>use core::mem;
use core::ptr::Unique;

use memory::{allocate_frames, deallocate_frames, Frame};

use super::{ActivePageTable, Page, PAGE_SIZE, PhysicalAddress, VirtualAddress};
use super::entry::{self, EntryFlags};
use super::table::{self, Table, Level4};

/// In order to enforce correct paging operations in the kernel, these types
/// are returned on any mapping operation to get the code involved to specify
/// how it intends to flush changes to a page table
#[must_use = "The page table must be flushed, or the changes unsafely ignored"]
pub struct MapperFlush(Page);

impl MapperFlush {
    /// Create a new page flush promise
    pub fn new(page: Page) -> MapperFlush {
        MapperFlush(page)
    }

    /// Flush this page in the active table
    pub fn flush(self, table: &mut ActivePageTable) {
        table.flush(self.0);
        mem::forget(self);
    }

    /// Ignore the flush. This is unsafe, and a reason should be provided for use
    pub unsafe fn ignore(self) {
        mem::forget(self);
    }
}

/// A flush cannot be dropped, it must be consumed
impl Drop for MapperFlush {
    fn drop(&mut self) {
        panic!("Mapper flush was not utilized");
    }
}

/// To allow for combining multiple flushes into one, we have a way of flushing
/// the active table, which can consume MapperFlush structs
#[must_use = "The page table must be flushed, or the changes unsafely ignored"]
pub struct MapperFlushAll(bool);

impl MapperFlushAll {
    /// Create a new promise to flush all mappings
    pub fn new() -> MapperFlushAll {
        MapperFlushAll(false)
    }

    /// Consume a single page flush
    pub fn consume(&mut self, flush: MapperFlush) {
        self.0 = true;
        mem::forget(flush);
    }

    /// Flush the active page table
    pub fn flush(self, table: &mut ActivePageTable) {
        if self.0 {
            table.flush_all();
        }
        mem::forget(self);
    }

    /// Ignore the flush. This is unsafe, and a reason should be provided for use
    pub unsafe fn ignore(self) {
        mem::forget(self);
    }
}

/// A flush cannot be dropped, it must be consumed
impl Drop for MapperFlushAll {
    fn drop(&mut self) {
        panic!("Mapper flush all was not utilized");
    }
}

pub struct Mapper {
    p4: Unique<Table<Level4>>,
}

impl Mapper {
    /// Create a new page table
    pub unsafe fn new() -> Mapper {
        Mapper {
            p4: Unique::new(table::P4),
        }
    }

    pub fn p4(&self) -> &Table<Level4> {
        unsafe { self.p4.get() }
    }

    pub fn p4_mut(&mut self) -> &mut Table<Level4> {
        unsafe { self.p4.get_mut() }
    }

    /// Map a page to a frame
    pub fn map_to(&mut self, page: Page, frame: Frame, flags: EntryFlags) -> MapperFlush {
        let mut p3 = self.p4_mut().next_table_create(page.p4_index());
        let mut p2 = p3.next_table_create(page.p3_index());
        let mut p1 = p2.next_table_create(page.p2_index());

        assert!(p1[page.p1_index()].is_unused(),
            "{:X}: Set to {:X}: {:?}, requesting {:X}: {:?}",
            page.start_address().get(),
            p1[page.p1_index()].address().get(), p1[page.p1_index()].flags(),
            frame.start_address().get(), flags);
        p1[page.p1_index()].set(frame, flags | entry::PRESENT);
        MapperFlush::new(page)
    }

    /// Map a page to the next free frame
    pub fn map(&mut self, page: Page, flags: EntryFlags) -> MapperFlush {
        let frame = allocate_frames(1).expect("out of frames");
        self.map_to(page, frame, flags)
    }

    /// Update flags for a page
    pub fn remap(&mut self, page: Page, flags: EntryFlags) -> MapperFlush {
        let mut p3 = self.p4_mut().next_table_mut(page.p4_index()).expect("failed to remap: no p3");
        let mut p2 = p3.next_table_mut(page.p3_index()).expect("failed to remap: no p2");
        let mut p1 = p2.next_table_mut(page.p2_index()).expect("failed to remap: no p1");
        let frame = p1[page.p1_index()].pointed_frame().expect("failed to remap: not mapped");
        p1[page.p1_index()].set(frame, flags | entry::PRESENT);
        MapperFlush::new(page)
    }

    /// Identity map a frame
    pub fn identity_map(&mut self, frame: Frame, flags: EntryFlags) -> MapperFlush {
        let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
        self.map_to(page, frame, flags)
    }

    fn unmap_inner(&mut self, page: &Page, keep_parents: bool) -> Frame {
        let frame;

        let p4 = self.p4_mut();
        {
            let p3 = p4.next_table_mut(page.p4_index()).expect("unmap_inner: p3 not found");
            {
                let p2 = p3.next_table_mut(page.p3_index()).expect("unmap_inner: p2 not found");
                {
                    let p1 = p2.next_table_mut(page.p2_index()).expect("unmap_inner: p1 not found");

                    frame = p1[page.p1_index()].pointed_frame().expect("unmap_inner: frame not found");
                    p1[page.p1_index()].set_unused();

                    if keep_parents || ! p1.is_unused() {
                        return frame;
                    }
                }

                {
                    let p1_frame = p2[page.p2_index()].pointed_frame().expect("unmap_inner: p1 frame not found");
                    //println!("Free p1 {:?}", p1_frame);
                    p2[page.p2_index()].set_unused();
                    deallocate_frames(p1_frame, 1);
                }

                if keep_parents || ! p2.is_unused() {
                    return frame;
                }
            }

            {
                let p2_frame = p3[page.p3_index()].pointed_frame().expect("unmap_inner: p2 frame not found");
                //println!("Free p2 {:?}", p2_frame);
                p3[page.p3_index()].set_unused();
                deallocate_frames(p2_frame, 1);
            }

            if keep_parents || ! p3.is_unused() {
                return frame;
            }
        }

        {
            let p3_frame = p4[page.p4_index()].pointed_frame().expect("unmap_inner: p3 frame not found");
            //println!("Free p3 {:?}", p3_frame);
            p4[page.p4_index()].set_unused();
            deallocate_frames(p3_frame, 1);
        }

        frame
    }

    /// Unmap a page
    pub fn unmap(&mut self, page: Page) -> MapperFlush {
        let frame = self.unmap_inner(&page, false);
        deallocate_frames(frame, 1);
        MapperFlush::new(page)
    }

    /// Unmap a page, return frame without free
    pub fn unmap_return(&mut self, page: Page, keep_parents: bool) -> (MapperFlush, Frame) {
        let frame = self.unmap_inner(&page, keep_parents);
        (MapperFlush::new(page), frame)
    }

    pub fn translate_page(&self, page: Page) -> Option<Frame> {
        self.p4().next_table(page.p4_index())
            .and_then(|p3| p3.next_table(page.p3_index()))
            .and_then(|p2| p2.next_table(page.p2_index()))
            .and_then(|p1| p1[page.p1_index()].pointed_frame())
    }

    pub fn translate_page_flags(&self, page: Page) -> Option<EntryFlags> {
        self.p4().next_table(page.p4_index())
            .and_then(|p3| p3.next_table(page.p3_index()))
            .and_then(|p2| p2.next_table(page.p2_index()))
            .and_then(|p1| Some(p1[page.p1_index()].flags()))
    }

    /// Translate a virtual address to a physical one
    pub fn translate(&self, virtual_address: VirtualAddress) -> Option<PhysicalAddress> {
        let offset = virtual_address.get() % PAGE_SIZE;
        self.translate_page(Page::containing_address(virtual_address))
            .map(|frame| PhysicalAddress::new(frame.start_address().get() + offset))
    }
}
<commit_msg>Update for changes in std::ptr::Unique API<commit_after>use core::mem;
use core::ptr::Unique;

use memory::{allocate_frames, deallocate_frames, Frame};

use super::{ActivePageTable, Page, PAGE_SIZE, PhysicalAddress, VirtualAddress};
use super::entry::{self, EntryFlags};
use super::table::{self, Table, Level4};

/// In order to enforce correct paging operations in the kernel, these types
/// are returned on any mapping operation to get the code involved to specify
/// how it intends to flush changes to a page table
#[must_use = "The page table must be flushed, or the changes unsafely ignored"]
pub struct MapperFlush(Page);

impl MapperFlush {
    /// Create a new page flush promise
    pub fn new(page: Page) -> MapperFlush {
        MapperFlush(page)
    }

    /// Flush this page in the active table
    pub fn flush(self, table: &mut ActivePageTable) {
        table.flush(self.0);
        mem::forget(self);
    }

    /// Ignore the flush. This is unsafe, and a reason should be provided for use
    pub unsafe fn ignore(self) {
        mem::forget(self);
    }
}

/// A flush cannot be dropped, it must be consumed
impl Drop for MapperFlush {
    fn drop(&mut self) {
        panic!("Mapper flush was not utilized");
    }
}

/// To allow for combining multiple flushes into one, we have a way of flushing
/// the active table, which can consume MapperFlush structs
#[must_use = "The page table must be flushed, or the changes unsafely ignored"]
pub struct MapperFlushAll(bool);

impl MapperFlushAll {
    /// Create a new promise to flush all mappings
    pub fn new() -> MapperFlushAll {
        MapperFlushAll(false)
    }

    /// Consume a single page flush
    pub fn consume(&mut self, flush: MapperFlush) {
        self.0 = true;
        mem::forget(flush);
    }

    /// Flush the active page table
    pub fn flush(self, table: &mut ActivePageTable) {
        if self.0 {
            table.flush_all();
        }
        mem::forget(self);
    }

    /// Ignore the flush. This is unsafe, and a reason should be provided for use
    pub unsafe fn ignore(self) {
        mem::forget(self);
    }
}

/// A flush cannot be dropped, it must be consumed
impl Drop for MapperFlushAll {
    fn drop(&mut self) {
        panic!("Mapper flush all was not utilized");
    }
}

pub struct Mapper {
    p4: Unique<Table<Level4>>,
}

impl Mapper {
    /// Create a new page table
    pub unsafe fn new() -> Mapper {
        Mapper {
            p4: Unique::new(table::P4),
        }
    }

    pub fn p4(&self) -> &Table<Level4> {
        unsafe { self.p4.as_ref() }
    }

    pub fn p4_mut(&mut self) -> &mut Table<Level4> {
        unsafe { self.p4.as_mut() }
    }

    /// Map a page to a frame
    pub fn map_to(&mut self, page: Page, frame: Frame, flags: EntryFlags) -> MapperFlush {
        let mut p3 = self.p4_mut().next_table_create(page.p4_index());
        let mut p2 = p3.next_table_create(page.p3_index());
        let mut p1 = p2.next_table_create(page.p2_index());

        assert!(p1[page.p1_index()].is_unused(),
            "{:X}: Set to {:X}: {:?}, requesting {:X}: {:?}",
            page.start_address().get(),
            p1[page.p1_index()].address().get(), p1[page.p1_index()].flags(),
            frame.start_address().get(), flags);
        p1[page.p1_index()].set(frame, flags | entry::PRESENT);
        MapperFlush::new(page)
    }

    /// Map a page to the next free frame
    pub fn map(&mut self, page: Page, flags: EntryFlags) -> MapperFlush {
        let frame = allocate_frames(1).expect("out of frames");
        self.map_to(page, frame, flags)
    }

    /// Update flags for a page
    pub fn remap(&mut self, page: Page, flags: EntryFlags) -> MapperFlush {
        let mut p3 = self.p4_mut().next_table_mut(page.p4_index()).expect("failed to remap: no p3");
        let mut p2 = p3.next_table_mut(page.p3_index()).expect("failed to remap: no p2");
        let mut p1 = p2.next_table_mut(page.p2_index()).expect("failed to remap: no p1");
        let frame = p1[page.p1_index()].pointed_frame().expect("failed to remap: not mapped");
        p1[page.p1_index()].set(frame, flags | entry::PRESENT);
        MapperFlush::new(page)
    }

    /// Identity map a frame
    pub fn identity_map(&mut self, frame: Frame, flags: EntryFlags) -> MapperFlush {
        let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
        self.map_to(page, frame, flags)
    }

    fn unmap_inner(&mut self, page: &Page, keep_parents: bool) -> Frame {
        let frame;

        let p4 = self.p4_mut();
        {
            let p3 = p4.next_table_mut(page.p4_index()).expect("unmap_inner: p3 not found");
            {
                let p2 = p3.next_table_mut(page.p3_index()).expect("unmap_inner: p2 not found");
                {
                    let p1 = p2.next_table_mut(page.p2_index()).expect("unmap_inner: p1 not found");

                    frame = p1[page.p1_index()].pointed_frame().expect("unmap_inner: frame not found");
                    p1[page.p1_index()].set_unused();

                    if keep_parents || ! p1.is_unused() {
                        return frame;
                    }
                }

                {
                    let p1_frame = p2[page.p2_index()].pointed_frame().expect("unmap_inner: p1 frame not found");
                    //println!("Free p1 {:?}", p1_frame);
                    p2[page.p2_index()].set_unused();
                    deallocate_frames(p1_frame, 1);
                }

                if keep_parents || ! p2.is_unused() {
                    return frame;
                }
            }

            {
                let p2_frame = p3[page.p3_index()].pointed_frame().expect("unmap_inner: p2 frame not found");
                //println!("Free p2 {:?}", p2_frame);
                p3[page.p3_index()].set_unused();
                deallocate_frames(p2_frame, 1);
            }

            if keep_parents || ! p3.is_unused() {
                return frame;
            }
        }

        {
            let p3_frame = p4[page.p4_index()].pointed_frame().expect("unmap_inner: p3 frame not found");
            //println!("Free p3 {:?}", p3_frame);
            p4[page.p4_index()].set_unused();
            deallocate_frames(p3_frame, 1);
        }

        frame
    }

    /// Unmap a page
    pub fn unmap(&mut self, page: Page) -> MapperFlush {
        let frame = self.unmap_inner(&page, false);
        deallocate_frames(frame, 1);
        MapperFlush::new(page)
    }

    /// Unmap a page, return frame without free
    pub fn unmap_return(&mut self, page: Page, keep_parents: bool) -> (MapperFlush, Frame) {
        let frame = self.unmap_inner(&page, keep_parents);
        (MapperFlush::new(page), frame)
    }

    pub fn translate_page(&self, page: Page) -> Option<Frame> {
        self.p4().next_table(page.p4_index())
            .and_then(|p3| p3.next_table(page.p3_index()))
            .and_then(|p2| p2.next_table(page.p2_index()))
            .and_then(|p1| p1[page.p1_index()].pointed_frame())
    }

    pub fn translate_page_flags(&self, page: Page) -> Option<EntryFlags> {
        self.p4().next_table(page.p4_index())
            .and_then(|p3| p3.next_table(page.p3_index()))
            .and_then(|p2| p2.next_table(page.p2_index()))
            .and_then(|p1| Some(p1[page.p1_index()].flags()))
    }

    /// Translate a virtual address to a physical one
    pub fn translate(&self, virtual_address: VirtualAddress) -> Option<PhysicalAddress> {
        let offset = virtual_address.get() % PAGE_SIZE;
        self.translate_page(Page::containing_address(virtual_address))
            .map(|frame| PhysicalAddress::new(frame.start_address().get() + offset))
    }
}
<|endoftext|>