<commit_before>
/// PCAP Header
///
/// * magic number (0xA1B23C4D)
/// * major version number
/// * minor version number
/// * GMT to local correction
/// * accuracy of timestamps (typically ignored as 0)
/// * max length of captured packets, in octets
/// * data link type
///
#[derive(Debug)]
pub struct Header {
    pub magic_number: u32,
    pub version_major: u16,
    pub version_minor: u16,
    pub thiszone: i32,
    pub sigfigs: u32,
    pub snaplen: u32,
    pub network: Link,
}

/// Link types as defined in http://www.tcpdump.org/linktypes.html
#[derive(Debug)]
pub enum Link {
    Null,
    Ethernet,
    Unknown(u32),
}

impl From<u32> for Link {
    fn from(link: u32) -> Self {
        match link {
            0 => Link::Null,
            1 => Link::Ethernet,
            otherwise => Link::Unknown(otherwise),
        }
    }
}

/// Record entry in a packet capture
///
/// * timestamp seconds
/// * timestamp nanoseconds
/// * number of octets of packet saved in file
/// * actual length of packet
#[derive(Debug)]
pub struct Record {
    pub ts_sec: u32,
    pub ts_usec: u32,
    pub incl_len: u32,
    pub orig_len: u32,
    pub payload: Vec<u8>,
}

use std::io;
use std::io::{Read, BufReader, Cursor};

struct Buffer<R>(BufReader<R>);

impl<R: Read> Buffer<R> {
    fn new(buffer: R) -> Self {
        Buffer(BufReader::new(buffer))
    }

    fn take(&mut self, length: usize) -> io::Result<Vec<u8>> {
        let mut buffer = vec![0; length];
        self.0.read_exact(&mut buffer)?;
        Ok(buffer)
    }

    fn take_i32(&mut self) -> io::Result<i32> {
        let buffer = self.take(4)?;
        Ok((buffer[0] as i32) + ((buffer[1] as i32) << 8) + ((buffer[2] as i32) << 16) +
           ((buffer[3] as i32) << 24))
    }

    fn take_u32(&mut self) -> io::Result<u32> {
        let buffer = self.take(4)?;
        Ok((buffer[0] as u32) + ((buffer[1] as u32) << 8) + ((buffer[2] as u32) << 16) +
           ((buffer[3] as u32) << 24))
    }

    fn take_u16(&mut self) -> io::Result<u16> {
        let buffer = self.take(2)?;
        Ok((buffer[0] as u16) + ((buffer[1] as u16) << 8))
    }
}

/// PacketCapture: container for pcap byte-stream
pub struct PacketCapture<R> {
    capture: Buffer<R>,
}

impl<R: Read> PacketCapture<R> {
    pub fn new(capture: R) -> PacketCapture<R> {
        PacketCapture { capture: Buffer::new(capture) }
    }
}

impl From<Vec<u8>> for PacketCapture<Cursor<Vec<u8>>> {
    fn from(buffer: Vec<u8>) -> Self {
        PacketCapture { capture: Buffer::new(Cursor::new(buffer)) }
    }
}

impl Header {
    fn parse<R: Read>(data: &mut Buffer<R>) -> io::Result<Header> {
        Ok(Header {
               magic_number: data.take_u32()?,
               version_major: data.take_u16()?,
               version_minor: data.take_u16()?,
               thiszone: data.take_i32()?,
               sigfigs: data.take_u32()?,
               snaplen: data.take_u32()?,
               network: Link::from(data.take_u32()?),
           })
    }
}

impl Record {
    fn parse<R: Read>(data: &mut Buffer<R>) -> io::Result<Record> {
        let ts_sec = data.take_u32()?;
        let ts_usec = data.take_u32()?;
        let incl_len = data.take_u32()?;
        let orig_len = data.take_u32()?;
        let payload = data.take(incl_len as usize)?;

        Ok(Record {
               ts_sec: ts_sec,
               ts_usec: ts_usec,
               incl_len: incl_len,
               orig_len: orig_len,
               payload: payload,
           })
    }
}

impl<R: Read> PacketCapture<R> {
    pub fn parse(mut self) -> io::Result<(Header, Records<R>)> {
        Ok((Header::parse(&mut self.capture)?, Records { capture: self.capture }))
    }
}

pub struct Records<R> {
    capture: Buffer<R>,
}

impl<R: Read> Iterator for Records<R> {
    type Item = Record;

    fn next(&mut self) -> Option<Self::Item> {
        Record::parse(&mut self.capture).ok()
    }
}
<commit_msg>Optimize byte parsing.<commit_after>
use std::mem;

/// PCAP Header
///
/// * magic number (0xA1B23C4D)
/// * major version number
/// * minor version number
/// * GMT to local correction
/// * accuracy of timestamps (typically ignored as 0)
/// * max length of captured packets, in octets
/// * data link type
///
#[derive(Debug)]
pub struct Header {
    pub magic_number: u32,
    pub version_major: u16,
    pub version_minor: u16,
    pub thiszone: i32,
    pub sigfigs: u32,
    pub snaplen: u32,
    pub network: Link,
}

/// Link types as defined in http://www.tcpdump.org/linktypes.html
#[derive(Debug)]
pub enum Link {
    Null,
    Ethernet,
    Unknown(u32),
}

impl From<u32> for Link {
    fn from(link: u32) -> Self {
        match link {
            0 => Link::Null,
            1 => Link::Ethernet,
            otherwise => Link::Unknown(otherwise),
        }
    }
}

/// Record entry in a packet capture
///
/// * timestamp seconds
/// * timestamp nanoseconds
/// * number of octets of packet saved in file
/// * actual length of packet
#[derive(Debug)]
pub struct Record {
    pub ts_sec: u32,
    pub ts_usec: u32,
    pub incl_len: u32,
    pub orig_len: u32,
    pub payload: Vec<u8>,
}

use std::io;
use std::io::{Read, BufReader, Cursor};

struct Buffer<R> {
    cache: Vec<u8>,
    reader: BufReader<R>,
}

impl<R: Read> Buffer<R> {
    fn new(buffer: R) -> Self {
        Buffer {
            cache: vec![],
            reader: BufReader::new(buffer),
        }
    }

    fn take(&mut self, length: usize) -> io::Result<&[u8]> {
        if self.cache.len() < length {
            let additional = length - self.cache.len();
            self.cache.reserve(additional);
            unsafe { self.cache.set_len(length) };
        }

        self.reader.read_exact(&mut self.cache[..length])?;
        Ok(&self.cache[..length])
    }

    fn take_i32(&mut self) -> io::Result<i32> {
        let buffer = self.take(4)?;
        let buffer = unsafe { mem::transmute::<&[u8], &[i32]>(buffer) };
        Ok(buffer[0])
    }

    fn take_u32(&mut self) -> io::Result<u32> {
        let buffer = self.take(4)?;
        let buffer = unsafe { mem::transmute::<&[u8], &[u32]>(buffer) };
        Ok(buffer[0])
    }

    fn take_u16(&mut self) -> io::Result<u16> {
        let buffer = self.take(2)?;
        let buffer = unsafe { mem::transmute::<&[u8], &[u16]>(buffer) };
        Ok(buffer[0])
    }
}

/// PacketCapture: container for pcap byte-stream
pub struct PacketCapture<R> {
    capture: Buffer<R>,
}

impl<R: Read> PacketCapture<R> {
    pub fn new(capture: R) -> PacketCapture<R> {
        PacketCapture { capture: Buffer::new(capture) }
    }
}

impl From<Vec<u8>> for PacketCapture<Cursor<Vec<u8>>> {
    fn from(buffer: Vec<u8>) -> Self {
        PacketCapture { capture: Buffer::new(Cursor::new(buffer)) }
    }
}

impl Header {
    fn parse<R: Read>(data: &mut Buffer<R>) -> io::Result<Header> {
        Ok(Header {
               magic_number: data.take_u32()?,
               version_major: data.take_u16()?,
               version_minor: data.take_u16()?,
               thiszone: data.take_i32()?,
               sigfigs: data.take_u32()?,
               snaplen: data.take_u32()?,
               network: Link::from(data.take_u32()?),
           })
    }
}

impl Record {
    fn parse<R: Read>(data: &mut Buffer<R>) -> io::Result<Record> {
        let ts_sec = data.take_u32()?;
        let ts_usec = data.take_u32()?;
        let incl_len = data.take_u32()?;
        let orig_len = data.take_u32()?;
        let payload = data.take(incl_len as usize)?;

        Ok(Record {
               ts_sec: ts_sec,
               ts_usec: ts_usec,
               incl_len: incl_len,
               orig_len: orig_len,
               payload: payload.into(),
           })
    }
}

impl<R: Read> PacketCapture<R> {
    pub fn parse(mut self) -> io::Result<(Header, Records<R>)> {
        Ok((Header::parse(&mut self.capture)?, Records { capture: self.capture }))
    }
}

pub struct Records<R> {
    capture: Buffer<R>,
}

impl<R: Read> Iterator for Records<R> {
    type Item = Record;

    fn next(&mut self) -> Option<Self::Item> {
        Record::parse(&mut self.capture).ok()
    }
}
<|endoftext|>


<commit_before>#![crate_type = "bin"]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait, ButtonSignals, BoxTrait};
use gtk::{Orientation};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::{WidgetSignals, TreeViewSignals};
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::{RefCell};

struct NoteBook {
    notebook: gtk::NoteBook,
    tabs: Vec<gtk::Box>
}

impl NoteBook {
    fn new() -> NoteBook {
        NoteBook {
            notebook: gtk::NoteBook::new().unwrap(),
            tabs: Vec::new()
        }
    }

    fn create_tab<'a, Widget: gtk::WidgetTrait>(&mut self, title: &'a str, widget: &Widget) -> Option<u32> {
        let label = gtk::Label::new(title).unwrap();
        let tab = gtk::Box::new(Orientation::Horizontal, 0).unwrap();

        tab.pack_start(&label, false, false, 0);
        tab.show_all();

        let index = match self.notebook.append_page(widget, Some(&tab)) {
            Some(index) => index,
            _ => return None
        };

        self.tabs.push(tab);

        Some(index)
    }
}

struct Procs {
    left_tree: gtk::TreeView,
    scroll: gtk::ScrolledWindow,
    current_pid: Rc<RefCell<Option<i64>>>,
    kill_button: Rc<RefCell<gtk::Button>>,
    vertical_layout: gtk::Box,
    list_store: gtk::ListStore
}

impl Procs {
    pub fn new<'a>(proc_list: &HashMap<usize, Process>) -> Procs {
        let left_tree = gtk::TreeView::new().unwrap();
        let scroll = gtk::ScrolledWindow::new(None, None).unwrap();
        let current_pid = Rc::new(RefCell::new(None));
        let kill_button = Rc::new(RefCell::new(gtk::Button::new_with_label("End task").unwrap()));
        let current_pid1 = current_pid.clone();
        let current_pid2 = current_pid.clone();
        let kill_button1 = kill_button.clone();

        scroll.set_min_content_height(800);
        scroll.set_min_content_width(600);

        let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

        append_column("pid", &mut columns);
        append_column("process name", &mut columns);
        append_column("cpu usage", &mut columns);
        append_column("memory usage (in kB)", &mut columns);

        for i in columns {
            left_tree.append_column(&i);
        }

        let mut list_store = gtk::ListStore::new(&[glib::Type::ISize, glib::Type::String, glib::Type::String, glib::Type::USize]).unwrap();
        for (_, pro) in proc_list {
            create_and_fill_model(&mut list_store, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
        }

        left_tree.set_model(&list_store.get_model().unwrap());
        left_tree.set_headers_visible(true);
        scroll.add(&left_tree);
        let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();

        left_tree.connect_cursor_changed(move |tree_view| {
            match tree_view.get_selection() {
                Some(selection) => {
                    if let Some((model, iter)) = selection.get_selected() {
                        let pid = Some(model.get_value(&iter, 0).get_long());
                        let mut tmp = current_pid1.borrow_mut();
                        *tmp = pid;
                    }
                    (*kill_button1.borrow_mut()).set_sensitive((*current_pid.borrow()).is_some());
                }
                None => {
                    let mut tmp = current_pid1.borrow_mut();
                    *tmp = None;
                }
            }
        });
        (*kill_button.borrow_mut()).set_sensitive(false);

        vertical_layout.add(&scroll);
        vertical_layout.add(&(*kill_button.borrow_mut()));
        Procs {
            left_tree: left_tree,
            scroll: scroll,
            current_pid: current_pid2.clone(),
            kill_button: kill_button,
            vertical_layout: vertical_layout,
            list_store: list_store
        }
    }
}

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.set_resizable(true);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, cmdline: &str, name: &str, cpu: f32, memory: u64) {
    if cmdline.len() < 1 {
        return;
    }

    let mut val1 = glib::Value::new();
    val1.init(glib::Type::ISize);
    val1.set_long(pid);
    let mut val2 = glib::Value::new();
    val2.init(glib::Type::USize);
    val2.set_ulong(memory);
    let top_level = list_store.append();
    list_store.set_value(&top_level, 0, &val1);
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{:.1}", cpu));
    list_store.set_value(&top_level, 3, &val2);
}

fn update_window(list: &mut gtk::ListStore, system: Rc<RefCell<sysinfo::System>>, info: Rc<RefCell<DisplaySysInfo>>) {
    let model = list.get_model().unwrap();

    (*system.borrow_mut()).refresh_all();
    let mut entries : HashMap<usize, Process> = ((*system.borrow()).get_process_list()).clone();
    let mut nb = model.iter_n_children(None);

    let sys = system.clone();
    (*info.borrow_mut()).update_ram_display(sys.clone());
    (*info.borrow_mut()).update_process_display(sys);

    let mut i = 0;
    while i < nb {
        if let Some(mut iter) = model.iter_nth_child(None, i) {
            let pid : i64 = model.get_value(&iter, 0).get_long();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    let mut val2 = glib::Value::new();
                    val2.init(glib::Type::USize);
                    val2.set_ulong(p.memory);
                    list.set_string(&iter, 2, &format!("{:.1}", p.cpu_usage));
                    list.set_value(&iter, 3, &val2);
                    to_delete = true;
                }
                None => {
                    list.remove(&mut iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(list, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
    }
}

struct DisplaySysInfo {
    procs : Rc<RefCell<Vec<gtk::ProgressBar>>>,
    ram : Rc<RefCell<gtk::ProgressBar>>,
    swap : Rc<RefCell<gtk::ProgressBar>>,
    vertical_layout : gtk::Box
}

impl DisplaySysInfo {
    pub fn new(sys1: Rc<RefCell<sysinfo::System>>) -> DisplaySysInfo {
        let mut tmp = DisplaySysInfo {
            procs: Rc::new(RefCell::new(Vec::new())),
            ram: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            swap: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            vertical_layout: gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap()
        };

        let sys2 = sys1.clone();
        let v = tmp.procs.clone();

        (*tmp.ram.borrow_mut()).set_show_text(true);
        (*tmp.swap.borrow_mut()).set_show_text(true);

        tmp.vertical_layout.set_spacing(5);
        let mut i = 0;
        let mut total = false;

        tmp.vertical_layout.pack_start(&gtk::Label::new("Memory usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.ram.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Swap usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.swap.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Total CPU usage").unwrap(), false, false, 15);
        for pro in (*sys1.borrow()).get_processor_list() {
            if total {
                (*v.borrow_mut()).push(gtk::ProgressBar::new().unwrap());
                let p : &gtk::ProgressBar = &(*v.borrow())[i];
                let l = gtk::Label::new(&format!("{}", i)).unwrap();
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();

                p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);
                horizontal_layout.pack_start(&l, false, false, 5);
                horizontal_layout.pack_start(p, true, true, 5);
                tmp.vertical_layout.add(&horizontal_layout);
            } else {
                (*v.borrow_mut()).push(gtk::ProgressBar::new().unwrap());
                let p : &gtk::ProgressBar = &(*v.borrow())[i];

                p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);

                tmp.vertical_layout.add(p);
                tmp.vertical_layout.pack_start(&gtk::Label::new("Process usage").unwrap(), false, false, 15);
                total = true;
            }
            i += 1;
        }
        tmp.update_ram_display(sys2);
        tmp
    }

    pub fn update_ram_display(&mut self, sys: Rc<RefCell<sysinfo::System>>) {
        let total = (*sys.borrow()).get_total_memory();
        let used = (*sys.borrow()).get_used_memory();
        let disp = if total < 100000 {
            format!("{} / {}KB", used, total)
        } else if total < 10000000 {
            format!("{} / {}MB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}GB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}TB", used / 1000000000, total / 1000000000)
        };

        (*self.ram.borrow_mut()).set_text(&disp);
        (*self.ram.borrow_mut()).set_fraction(used as f64 / total as f64);

        let total = (*sys.borrow()).get_total_swap();
        let used = total - (*sys.borrow()).get_used_swap();
        let disp = if total < 100000 {
            format!("{} / {}KB", used, total)
        } else if total < 10000000 {
            format!("{} / {}MB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}GB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}TB", used / 1000000000, total / 1000000000)
        };

        (*self.swap.borrow_mut()).set_text(&disp);
        (*self.swap.borrow_mut()).set_fraction(used as f64 / total as f64);
    }

    pub fn update_process_display(&mut self, sys: Rc<RefCell<sysinfo::System>>) {
        let v = &*self.procs.borrow_mut();
        let mut i = 0;

        for pro in (*sys.borrow()).get_processor_list() {
            v[i].set_text(&format!("{:.1} %", pro.get_cpu_usage() * 100.));
            v[i].set_show_text(true);
            v[i].set_fraction(pro.get_cpu_usage() as f64);
            i += 1;
        }
    }
}

fn main() {
    gtk::init();

    let window = gtk::Window::new(gtk::WindowType::Toplevel).unwrap();
    let sys : Rc<RefCell<sysinfo::System>> = Rc::new(RefCell::new(sysinfo::System::new()));
    let mut note = NoteBook::new();
    let mut procs = Procs::new((*sys.borrow()).get_process_list());
    let current_pid2 = procs.current_pid.clone();
    let sys1 = sys.clone();
    let sys2 = sys.clone();

    window.set_title("Process viewer");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    (*sys.borrow_mut()).refresh_all();
    (*procs.kill_button.borrow_mut()).connect_clicked(move |_| {
        let tmp = (*current_pid2.borrow_mut()).is_some() ;

        if tmp {
            let s = (*current_pid2.borrow()).clone();
            match (*sys.borrow_mut()).get_process(s.unwrap()) {
                Some(p) => {
                    p.kill(Signal::Kill);
                },
                None => {}
            };
        }
    });

    let display_tab = Rc::new(RefCell::new(DisplaySysInfo::new(sys2)));

    //window.add(&vertical_layout);
    note.create_tab("Process list", &procs.vertical_layout);
    //let t = gtk::Button::new_with_label("test").unwrap();
    note.create_tab("System usage", &(*display_tab.borrow()).vertical_layout);

    glib::timeout_add(1500, move || {
        update_window(&mut procs.list_store, sys1.clone(), display_tab.clone());
        glib::Continue(true)
    });

    window.add(&note.notebook);
    window.show_all();
    gtk::main();
}
<commit_msg>Update to last gtk-rs version<commit_after>#![crate_type = "bin"]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait, ButtonSignals, BoxTrait};
use gtk::{Orientation};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::{WidgetSignals, TreeViewSignals};
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;
use std::sync::{Arc, Mutex};

struct NoteBook {
    notebook: gtk::NoteBook,
    tabs: Vec<gtk::Box>
}

impl NoteBook {
    fn new() -> NoteBook {
        NoteBook {
            notebook: gtk::NoteBook::new().unwrap(),
            tabs: Vec::new()
        }
    }

    fn create_tab<'a, Widget: gtk::WidgetTrait>(&mut self, title: &'a str, widget: &Widget) -> Option<u32> {
        let label = gtk::Label::new(title).unwrap();
        let tab = gtk::Box::new(Orientation::Horizontal, 0).unwrap();

        tab.pack_start(&label, false, false, 0);
        tab.show_all();

        let index = match self.notebook.append_page(widget, Some(&tab)) {
            Some(index) => index,
            _ => return None
        };

        self.tabs.push(tab);

        Some(index)
    }
}

struct Procs {
    left_tree: gtk::TreeView,
    scroll: gtk::ScrolledWindow,
    current_pid: Rc<RefCell<Option<i64>>>,
    kill_button: Rc<RefCell<gtk::Button>>,
    vertical_layout: gtk::Box,
    list_store: gtk::ListStore
}

unsafe impl Send for Procs {}

impl Procs {
    pub fn new<'a>(proc_list: &HashMap<usize, Process>) -> Procs {
        let left_tree = gtk::TreeView::new().unwrap();
        let scroll = gtk::ScrolledWindow::new(None, None).unwrap();
        let current_pid = Rc::new(RefCell::new(None));
        let kill_button = Rc::new(RefCell::new(gtk::Button::new_with_label("End task").unwrap()));
        let current_pid1 = current_pid.clone();
        let current_pid2 = current_pid.clone();
        let kill_button1 = kill_button.clone();

        scroll.set_min_content_height(800);
        scroll.set_min_content_width(600);

        let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

        append_column("pid", &mut columns);
        append_column("process name", &mut columns);
        append_column("cpu usage", &mut columns);
        append_column("memory usage (in kB)", &mut columns);

        for i in columns {
            left_tree.append_column(&i);
        }

        let mut list_store = gtk::ListStore::new(&[glib::Type::ISize, glib::Type::String, glib::Type::String, glib::Type::USize]).unwrap();
        for (_, pro) in proc_list {
            create_and_fill_model(&mut list_store, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
        }

        left_tree.set_model(&list_store.get_model().unwrap());
        left_tree.set_headers_visible(true);
        scroll.add(&left_tree);
        let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();

        left_tree.connect_cursor_changed(move |tree_view| {
            match tree_view.get_selection() {
                Some(selection) => {
                    if let Some((model, iter)) = selection.get_selected() {
                        let pid = unsafe { Some(model.get_value(&iter, 0).get_long()) };
                        let mut tmp = current_pid1.borrow_mut();
                        *tmp = pid;
                    }
                    (*kill_button1.borrow_mut()).set_sensitive((*current_pid.borrow()).is_some());
                }
                None => {
                    let mut tmp = current_pid1.borrow_mut();
                    *tmp = None;
                }
            }
        });
        (*kill_button.borrow_mut()).set_sensitive(false);

        vertical_layout.add(&scroll);
        vertical_layout.add(&(*kill_button.borrow_mut()));
        Procs {
            left_tree: left_tree,
            scroll: scroll,
            current_pid: current_pid2.clone(),
            kill_button: kill_button,
            vertical_layout: vertical_layout,
            list_store: list_store
        }
    }
}

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.set_resizable(true);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, cmdline: &str, name: &str, cpu: f32, memory: u64) {
    if cmdline.len() < 1 {
        return;
    }

    unsafe {
        let mut val1 = glib::Value::new();
        val1.init(glib::Type::ISize);
        val1.set_long(pid);
        let mut val2 = glib::Value::new();
        val2.init(glib::Type::USize);
        val2.set_ulong(memory);
        let top_level = list_store.append();
        list_store.set_value(&top_level, 0, &val1);
        list_store.set_string(&top_level, 1, name);
        list_store.set_string(&top_level, 2, &format!("{:.1}", cpu));
        list_store.set_value(&top_level, 3, &val2);
    }
}

fn update_window(list: &mut gtk::ListStore, system: Arc<Mutex<sysinfo::System>>, info: Arc<Mutex<DisplaySysInfo>>) {
    let model = list.get_model().unwrap();
    let system = &mut system.lock().unwrap();
    let info = &mut info.lock().unwrap();

    system.refresh_all();
    let mut entries : HashMap<usize, Process> = system.get_process_list().clone();
    let mut nb = model.iter_n_children(None);

    info.update_ram_display(&system);
    info.update_process_display(&system);

    let mut i = 0;
    while i < nb {
        if let Some(mut iter) = model.iter_nth_child(None, i) {
            let pid : i64 = unsafe { model.get_value(&iter, 0).get_long() };
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    let mut val2 = unsafe { glib::Value::new() };
                    val2.init(glib::Type::USize);
                    unsafe { val2.set_ulong(p.memory) };
                    list.set_string(&iter, 2, &format!("{:.1}", p.cpu_usage));
                    list.set_value(&iter, 3, &val2);
                    to_delete = true;
                }
                None => {
                    list.remove(&mut iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(list, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
    }
}

struct DisplaySysInfo {
    procs : Rc<RefCell<Vec<gtk::ProgressBar>>>,
    ram : Rc<RefCell<gtk::ProgressBar>>,
    swap : Rc<RefCell<gtk::ProgressBar>>,
    vertical_layout : gtk::Box
}

unsafe impl Send for DisplaySysInfo {}

impl DisplaySysInfo {
    pub fn new(sys1: Arc<Mutex<sysinfo::System>>) -> DisplaySysInfo {
        let mut tmp = DisplaySysInfo {
            procs: Rc::new(RefCell::new(Vec::new())),
            ram: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            swap: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            vertical_layout: gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap()
        };

        let sys2 = sys1.clone();
        let v = tmp.procs.clone();

        (*tmp.ram.borrow_mut()).set_show_text(true);
        (*tmp.swap.borrow_mut()).set_show_text(true);

        tmp.vertical_layout.set_spacing(5);
        let mut i = 0;
        let mut total = false;

        tmp.vertical_layout.pack_start(&gtk::Label::new("Memory usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.ram.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Swap usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.swap.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Total CPU usage").unwrap(), false, false, 15);
        for pro in sys1.lock().unwrap().get_processor_list() {
            if total {
                (*v.borrow_mut()).push(gtk::ProgressBar::new().unwrap());
                let p : &gtk::ProgressBar = &(*v.borrow())[i];
                let l = gtk::Label::new(&format!("{}", i)).unwrap();
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();

                p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);
                horizontal_layout.pack_start(&l, false, false, 5);
                horizontal_layout.pack_start(p, true, true, 5);
                tmp.vertical_layout.add(&horizontal_layout);
            } else {
                (*v.borrow_mut()).push(gtk::ProgressBar::new().unwrap());
                let p : &gtk::ProgressBar = &(*v.borrow())[i];

                p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);

                tmp.vertical_layout.add(p);
                tmp.vertical_layout.pack_start(&gtk::Label::new("Process usage").unwrap(), false, false, 15);
                total = true;
            }
            i += 1;
        }
        tmp.update_ram_display(&sys2.lock().unwrap());
        tmp
    }

    pub fn update_ram_display(&mut self, sys: &sysinfo::System) {
        let total = sys.get_total_memory();
        let used = sys.get_used_memory();
        let disp = if total < 100000 {
            format!("{} / {}KB", used, total)
        } else if total < 10000000 {
            format!("{} / {}MB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}GB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}TB", used / 1000000000, total / 1000000000)
        };

        (*self.ram.borrow_mut()).set_text(&disp);
        (*self.ram.borrow_mut()).set_fraction(used as f64 / total as f64);

        let total = sys.get_total_swap();
        let used = total - sys.get_used_swap();
        let disp = if total < 100000 {
            format!("{} / {}KB", used, total)
        } else if total < 10000000 {
            format!("{} / {}MB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}GB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}TB", used / 1000000000, total / 1000000000)
        };

        (*self.swap.borrow_mut()).set_text(&disp);
        (*self.swap.borrow_mut()).set_fraction(used as f64 / total as f64);
    }

    pub fn update_process_display(&mut self, sys: &sysinfo::System) {
        let v = &*self.procs.borrow_mut();
        let mut i = 0;

        for pro in sys.get_processor_list() {
            v[i].set_text(&format!("{:.1} %", pro.get_cpu_usage() * 100.));
            v[i].set_show_text(true);
            v[i].set_fraction(pro.get_cpu_usage() as f64);
            i += 1;
        }
    }
}

fn main() {
    gtk::init();

    let window = gtk::Window::new(gtk::WindowType::Toplevel).unwrap();
    let sys : Arc<Mutex<sysinfo::System>> = Arc::new(Mutex::new(sysinfo::System::new()));
    let mut note = NoteBook::new();
    let mut procs = Procs::new(sys.lock().unwrap().get_process_list());
    let current_pid2 = procs.current_pid.clone();
    let sys1 = sys.clone();
    let sys2 = sys.clone();

    window.set_title("Process viewer");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    { sys.lock().unwrap().refresh_all(); }
    (*procs.kill_button.borrow_mut()).connect_clicked(move |_| {
        let tmp = (*current_pid2.borrow_mut()).is_some() ;

        if tmp {
            let s = (*current_pid2.borrow()).clone();
            match sys.lock().unwrap().get_process(s.unwrap()) {
                Some(p) => {
                    p.kill(Signal::Kill);
                },
                None => {}
            };
        }
    });

    let display_tab = DisplaySysInfo::new(sys2);

    //window.add(&vertical_layout);
    note.create_tab("Process list", &procs.vertical_layout);
    //let t = gtk::Button::new_with_label("test").unwrap();
    note.create_tab("System usage", &display_tab.vertical_layout);
    let m_display_tab = Arc::new(Mutex::new(display_tab));

    glib::timeout_add(1500, move || {
        update_window(&mut procs.list_store, sys1.clone(), m_display_tab.clone());
        glib::Continue(true)
    });

    window.add(&note.notebook);
    window.show_all();
    gtk::main();
}
<|endoftext|>


<commit_before>//! This module contains shareable mutable containers designed for triggering
//! and detecting race conditions in thread synchronization testing code.
//!
//! # Motivation
//!
//! The main purpose of a thread synchronization protocol is to ensure that
//! some operations which are not atomic in hardware, such as writing to two
//! unrelated memory locations, appear to occur as atomic transactions from the
//! point of view of other threads: at any point of time, either a given
//! operation appears to be done, or it appears not to have started.
//!
//! Testing a thread synchronization primitive involves showing that
//! inconsistent states (where an operation appears to be half-performed) have a
//! negligible probability of being exposed to the outside world in all expected
//! usage scenarios. It is done by showing that a given non-atomic operation is
//! properly encapsulated by the transactional semantics of the synchronization
//! protocol, and will never appear to be half-done to observers.
//!
//! Non-atomic operations are easier said than done, however, when the set of
//! operations which can be atomic in hardware is larger than most people think
//! (at the time of writing, current Intel CPUs can access memory in blocks of
//! 128 bits, and current NVidia GPUs can do so in blocks of 1024 bits), not
//! well-defined by the architecture (and thus subjected to change in future
//! hardware), and dependent on the compiler's optimization choices in a
//! high-level programming language such as Rust.
//!
//! # Functionality
//!
//! This module provides the RaceCell type, which can hold a value of a
//! certain type U like a Cell<U> would, but is guaranteed *not* to be read
//! or written to in a single atomic operation even if the corresponding type U
//! can be atomically read or written to in hardware.
//!
//! In addition, a RaceCell can detect scenarios where it is read at the same
//! time as it is being written (which constitutes a read-after-write race
//! condition) and report them to the reader thread.
//!
//! Such "controlled data races" can, in turn, be used to detect failures in
//! thread synchronization protocols, manifesting as inconsistent shared state
//! being exposed to the outside world.
//!
//! # Requirements on T
//!
//! In principle, any Clone + Eq type U whose equality operator and clone()
//! implementation work even if the inner data is in a inconsistent state
//! (e.g. filled with random bits) could work, and this is true of all integer
//! types and combinations thereof. However, in practice, unsynchronized
//! concurrent read/write access to such data from multiple threads constitutes
//! a data race, which is undefined behaviour in Rust, even if the data is
//! wrapped into an UnsafeCell.
//!
//! The net result of this behaviour being undefined is that rustc's optimizer
//! allows itself to generate code under the assumption that it won't happen,
//! which leads to breakages when code which is built under the knowledge that
//! it will actually happen is compiled in release mode.
//!
//! For this reason, we currently only support some specific types T which have
//! atomic load and store operations. Note that although individual loads and
//! stores to T are atomic, loads and stores to RaceCell<T> are still
//! guaranteed not to be atomic.

#![deny(missing_docs)]

use std::boxed::Box;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize};
use std::sync::atomic::Ordering;

/// RaceCell is a container for triggering and detecting write-after-read
/// data races in a well-controlled fashion.
pub struct RaceCell<T, U> where T: AtomicLoadStore<U>,
                                U: Clone + Debug + Eq {
    /// Two copies of a value of type T are made. One is stored on the stack...
    local_contents: T,

    /// ...and one is stored on the heap, which in all popular OSs is too far
    /// away from the stack to allow any significant probability of the hardware
    /// writing both copies in a single atomic transactions.
    ///
    /// Of course, a malicious optimizer could still use hardware transactional
    /// memory or a software emulation thereof to achieve this effect, but there
    /// are no performance benefits in doing so, and in fact it has an averse
    /// effect on performance, so a realistic optimizer won't do it.
    ///
    remote_version: Box<T>,

    /// Rust really dislikes unused generic struct parameters, even if they are
    /// used in the implementation, so a PhantomData marker must be added for U
    unused: PhantomData<U>,
}
//
impl<T, U> RaceCell<T, U> where T: AtomicLoadStore<U>,
                                U: Clone + Debug + Eq {
    /// Create a new RaceCell with a certain initial content
    pub fn new(value: U) -> Self {
        RaceCell {
            local_contents: T::new(value.clone()),
            remote_version: Box::new(T::new(value)),
            unused: PhantomData,
        }
    }

    /// Update the internal contents of the RaceCell in a non-atomic fashion
    pub fn set(&self, value: U) {
        self.local_contents.store(value.clone(), Ordering::Relaxed);
        self.remote_version.store(value, Ordering::Relaxed);
    }

    /// Read the current contents of the RaceCell, detecting any data race
    /// caused by a concurrently occurring write along the way.
    pub fn get(&self) -> Racey<U> {
        let local_data = self.local_contents.load(Ordering::Relaxed);
        let remote_data = self.remote_version.load(Ordering::Relaxed);
        if local_data == remote_data {
            Racey::Consistent(local_data)
        } else {
            Racey::Inconsistent
        }
    }
}

/// This is the result of a RaceCell read
#[derive(Debug, Eq, PartialEq)]
pub enum Racey<U: Debug + Eq> {
    /// The RaceCell was internally consistent, and its content was copied
    Consistent(U),

    /// The RaceCell was internally inconsistent, so a data race has occurred
    Inconsistent,
}

/// For the implementation of RaceCell not to be considered as undefined
/// behaviour and trashed by the Rust compiler in release mode, the underlying
/// type T's load and store operations must be atomic. In practice, this is true
/// of all std::sync::atomic::AtomicXyz types.
///
pub trait AtomicLoadStore<U> {
    /// Create an atomic value
    fn new(v: U) -> Self;

    /// Atomically load the contents
    fn load(&self, order: Ordering) -> U;

    /// Atomically store new contents
    fn store(&self, val: U, order: Ordering);
}
///
/// This macro implements support for one non-generic atomic type
///
macro_rules! impl_load_store {
    ($($U:ty, $T:ty);*) => ($(
        impl AtomicLoadStore<$U> for $T {
            fn new(v: $U) -> $T {
                <$T>::new(v)
            }

            fn load(&self, order: Ordering) -> $U {
                <$T>::load(self, order)
            }

            fn store(&self, val: $U, order: Ordering) {
                <$T>::store(self, val, order)
            }
        }
    )*)
}
///
impl_load_store!{ bool,  AtomicBool;
                  isize, AtomicIsize;
                  usize, AtomicUsize }
///
/// Atomic pointers are a bit special as they are generic, so for now we
/// will just treat them as a special case.
///
impl<V> AtomicLoadStore<*mut V> for AtomicPtr<V> {
    fn new(v: *mut V) -> AtomicPtr<V> {
        <AtomicPtr<V>>::new(v)
    }

    fn load(&self, order: Ordering) -> *mut V {
        <AtomicPtr<V>>::load(self, order)
    }

    fn store(&self, val: *mut V, order: Ordering) {
        <AtomicPtr<V>>::store(self, val, order)
    }
}

// Here are implementations of RaceCell for all supported data types

/// Implementation of RaceCell for bool
pub type BoolRaceCell = RaceCell<AtomicBool, bool>;
/// Implementation of RaceCell for isize
pub type IsizeRaceCell = RaceCell<AtomicIsize, isize>;
/// Implementation of RaceCell for pointers
pub type PtrRaceCell<V> = RaceCell<AtomicPtr<V>, *mut V>;
/// Implementation of RaceCell for usize
pub type UsizeRaceCell = RaceCell<AtomicUsize, usize>;

/// Here are some RaceCell tests
#[cfg(test)]
mod tests {
    use std::sync::{Arc, Mutex};
    use std::sync::atomic::Ordering;
    use super::{BoolRaceCell, IsizeRaceCell, UsizeRaceCell, Racey};

    /// A RaceCell should be created in a consistent and correct state
    #[test]
    fn initial_state() {
        let cell = BoolRaceCell::new(true);
        assert_eq!(cell.local_contents.load(Ordering::Relaxed), true);
        assert_eq!(cell.remote_version.load(Ordering::Relaxed), true);
    }

    /// Reading a consistent RaceCell should work as expected
    #[test]
    fn consistent_read() {
        let cell = IsizeRaceCell::new(-42);
        assert_eq!(cell.get(), Racey::Consistent(-42));
    }

    /// Reading an inconsistent RaceCell should work as expected
    #[test]
    fn inconsistent_read() {
        let cell = UsizeRaceCell::new(0xbad);
        cell.local_contents.store(0xdead, Ordering::Relaxed);
        assert_eq!(cell.get(), Racey::Inconsistent);
    }

    /// Unprotected concurrent reads and writes to a RaceCell should trigger
    /// detectable race conditions, illustrating its non-atomic nature.
    #[test]
    fn unprotected_race() {
        // Amount of writes to carry out
        const WRITES_COUNT: usize = 100_000_000;

        // RaceCell in which the writes will be carried out
        let initial_value = 0;
        let cell1 = Arc::new(UsizeRaceCell::new(initial_value));
        let cell2 = cell1.clone();

        // Make sure that RaceCell does expose existing data races :)
        ::concurrent_test_2(
            move || {
                for i in 1..(WRITES_COUNT+1) {
                    cell1.set(i);
                }
            },
            move || {
                let mut last_value = 0;
                let mut data_race_count = 0usize;
                while last_value != WRITES_COUNT {
                    match cell2.get() {
                        Racey::Consistent(value) => last_value = value,
                        Racey::Inconsistent => data_race_count += 1,
                    }
                }
                print!("{} races detected, ", data_race_count);
                assert!(data_race_count > 0);
            }
        );
    }

    /// Appropriately protected concurrent reads and writes to a RaceCell should
    /// not yield any detectable race conditions.
    #[test]
    fn protected_transaction() {
        // Amount of writes to carry out
        const WRITES_COUNT: usize = 10_000_000;

        // Mutex-protected RaceCell in which the writes will be carried out
        let initial_value = 0;
        let cell1 = Arc::new(Mutex::new(UsizeRaceCell::new(initial_value)));
        let cell2 = cell1.clone();

        // Make sure that RaceCell does not incorrectly detect race conditions
        ::concurrent_test_2(
            move || {
                for i in 1..(WRITES_COUNT+1) {
                    cell1.lock().unwrap().set(i);
                }
            },
            move || {
                let mut last_value = 0;
                let mut data_race_count = 0usize;
                while last_value != WRITES_COUNT {
                    match cell2.lock().unwrap().get() {
                        Racey::Consistent(value) => last_value = value,
                        Racey::Inconsistent => data_race_count += 1,
                    }
                }
                assert_eq!(data_race_count, 0);
            }
        );
    }
}
<commit_msg>Cleaned up documentation, test, and atomic wrappers<commit_after>//! This module contains shareable mutable containers designed for enabling
//! and detecting race conditions in thread synchronization testing code.
//!
//! # Motivation
//!
//! The main purpose of a thread synchronization protocol is to ensure that
//! some operations which are not atomic in hardware, such as writing to two
//! unrelated memory locations, appear to occur as atomic transactions from the
//! point of view of other threads: at any point of time, either a given
//! operation appears to be done, or it appears not to have started.
//!
//! Testing a thread synchronization primitive involves showing that
//! inconsistent states (where an operation appears to be half-performed) have a
//! negligible probability of being exposed to the outside world in all expected
//! usage scenarios. It is typically done by showing that a given non-atomic
//! operation is properly encapsulated by the transactional semantics of the
//! synchronization protocol, and will never appear as half-done to observers.
//!
//! Non-atomic operations are easier said than done, however, when the set of
//! operations which can be atomic in hardware is larger than most people think
//! (at the time of writing, current Intel CPUs can access memory in blocks of
//! 128 bits, and current NVidia GPUs can do so in blocks of 1024 bits), not
//! well-defined by the architecture (and thus subjected to increase in future
//! hardware), and highly dependent on the compiler's optimization choices in a
//! high-level programming language such as Rust.
//!
//! Which is why I think we need some types whose operations are guaranteed to
//! be non-atomic under a set of reasonable assumptions, and which can easily be
//! observed to be in an inconsistent state.
//!
//! # Functionality
//!
//! This module provides the RaceCell type, which can hold a value of a
//! certain type U like a `Cell<U>` would, but is guaranteed **not** to be read
//! or written to in a single atomic operation, even if the corresponding type U
//! can be atomically read or written to in hardware.
//!
//! In addition, a RaceCell can detect scenarios where it is read at the same
//! time as it is being written (which constitutes a read-after-write race
//! condition) and report them to the reader thread.
//!
//! Such "controlled data races" can, in turn, be used to detect failures in
//! thread synchronization protocols, manifesting as inconsistent shared states
//! being exposed to the outside world.
//!
//! # Requirements on U
//!
//! In principle, any Clone + Eq type U whose equality operator and clone()
//! implementation behave well even if the inner data is in a inconsistent state
//! (e.g. filled with random bits) could be used. This is true of all primitive
//! integral types and aggregates thereof, for example.
//!
//! However, in practice, unsynchronized concurrent read/write access to
//! arbitrary data from multiple threads constitutes a data race, which is
//! undefined behaviour in Rust even when it occurs inside an UnsafeCell. This
//! is problematic because rustc's optimizer allows itself to transform code
//! which relies on undefined behaviour however it likes, leading to breakages
//! in release builds such as infinite loops appearing out of nowhere.
//!
//! For this reason, we currently only support some specific types U which have
//! atomic load and store operations, implemented as part of an atomic wrapper
//! T. Note that although individual loads and stores to U are atomic, loads and
//! stores to RaceCell<T> are still guaranteed not to be atomic.

#![deny(missing_docs)]

use std::boxed::Box;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize};
use std::sync::atomic::Ordering;

/// Shareable mutable container for triggering and detecting write-after-read
/// data races in a well-controlled fashion. Operates on a type U through an
/// atomic wrapper type T.
pub struct RaceCell<T, U> where T: AtomicLoadStore<U>,
                                U: Clone + Debug + Eq {
    /// Two copies of a value of type U are made. One is stored on the stack...
    local_contents: T,

    /// ...and one is stored on the heap, which in all popular OSs is too far
    /// away from the stack to allow any significant probability of the hardware
    /// writing both copies in a single atomic transactions.
    ///
    /// Of course, a malicious optimizer could still use hardware transactional
    /// memory or a software emulation thereof to achieve this effect, but there
    /// are no performance benefits in doing so, and in fact it will rather have
    /// an averse effect on performance, so a realistic optimizer won't do it.
    ///
    remote_version: Box<T>,

    /// Rust really dislikes unused generic struct parameters, even if they are
    /// used in the implementation, so a PhantomData marker must be added for U
    unused: PhantomData<U>,
}
//
impl<T, U> RaceCell<T, U> where T: AtomicLoadStore<U>,
                                U: Clone + Debug + Eq {
    /// Create a new RaceCell with a certain initial content
    pub fn new(value: U) -> Self {
        RaceCell {
            local_contents: T::new(value.clone()),
            remote_version: Box::new(T::new(value)),
            unused: PhantomData,
        }
    }

    /// Update the internal contents of the RaceCell in a non-atomic fashion
    pub fn set(&self, value: U) {
        self.local_contents.relaxed_store(value.clone());
        self.remote_version.relaxed_store(value);
    }

    /// Read the current contents of the RaceCell, detecting any data race
    /// caused by a concurrently occurring write along the way.
    pub fn get(&self) -> Racey<U> {
        let local_data = self.local_contents.relaxed_load();
        let remote_data = self.remote_version.relaxed_load();
        if local_data == remote_data {
            Racey::Consistent(local_data)
        } else {
            Racey::Inconsistent
        }
    }
}

/// This is the result of a RaceCell read
#[derive(Debug, Eq, PartialEq)]
pub enum Racey<U: Debug + Eq> {
    /// The RaceCell was internally consistent, and its content was copied
    Consistent(U),

    /// The RaceCell was internally inconsistent: a data race has occurred
    Inconsistent,
}

/// Atomic wrapper type for a value of type U
///
/// For the implementation of RaceCell not to be considered as undefined
/// behaviour and trashed by the Rust compiler in release mode, the underlying
/// type U must be loaded and stored atomically. This requires synchronizing
/// accesses to it using things like the std::sync::atomic::AtomicXyz wrappers.
///
/// The only guarantee that we need is that loads and stores are atomic. We do
/// not need any other memory ordering guarantee. This is why we allow for
/// more wrapper type implementation freedom by not specifying memory orderings,
/// and internally relying only on relaxed ordering.
///
pub trait AtomicLoadStore<U> {
    /// Create an atomic wrapper for a value of type U
    fn new(v: U) -> Self;

    /// Atomically load a value from the wrapper
    fn relaxed_load(&self) -> U;

    /// Atomically store a new value into the wrapper
    fn relaxed_store(&self, val: U);
}
///
/// This macro implements support for non-generic standard atomic types
///
macro_rules! impl_load_store {
    ($($U:ty, $T:ty);*) => ($(
        impl AtomicLoadStore<$U> for $T {
            fn new(v: $U) -> $T {
                <$T>::new(v)
            }

            fn relaxed_load(&self) -> $U {
                <$T>::load(self, Ordering::Relaxed)
            }

            fn relaxed_store(&self, val: $U) {
                <$T>::store(self, val, Ordering::Relaxed)
            }
        }
    )*)
}
///
impl_load_store!{ bool,  AtomicBool;
                  isize, AtomicIsize;
                  usize, AtomicUsize }
///
/// Atomic pointers are a bit special as they are generic, for now we will just
/// treat them as a special case.
///
impl<V> AtomicLoadStore<*mut V> for AtomicPtr<V> {
    fn new(v: *mut V) -> AtomicPtr<V> {
        <AtomicPtr<V>>::new(v)
    }

    fn relaxed_load(&self) -> *mut V {
        <AtomicPtr<V>>::load(self, Ordering::Relaxed)
    }

    fn relaxed_store(&self, val: *mut V) {
        <AtomicPtr<V>>::store(self, val, Ordering::Relaxed)
    }
}

// Here are implementations of RaceCell for all stable hardware atomic types

/// Implementation of RaceCell for bool
pub type BoolRaceCell = RaceCell<AtomicBool, bool>;
/// Implementation of RaceCell for isize
pub type IsizeRaceCell = RaceCell<AtomicIsize, isize>;
/// Implementation of RaceCell for pointers
pub type PtrRaceCell<V> = RaceCell<AtomicPtr<V>, *mut V>;
/// Implementation of RaceCell for usize
pub type UsizeRaceCell = RaceCell<AtomicUsize, usize>;

/// Here are some RaceCell tests
#[cfg(test)]
mod tests {
    use std::sync::{Arc, Mutex};
    use super::{AtomicLoadStore, Racey};
    use super::{BoolRaceCell, IsizeRaceCell, UsizeRaceCell};

    /// A RaceCell should be created in a consistent and correct state
    #[test]
    fn initial_state() {
        let cell = BoolRaceCell::new(true);
        assert_eq!(cell.local_contents.relaxed_load(), true);
        assert_eq!(cell.remote_version.relaxed_load(), true);
    }

    /// Reading a consistent RaceCell should work as expected
    #[test]
    fn consistent_read() {
        let cell = IsizeRaceCell::new(-42);
        assert_eq!(cell.get(), Racey::Consistent(-42));
    }

    /// Reading an inconsistent RaceCell should work as expected
    #[test]
    fn inconsistent_read() {
        let cell = UsizeRaceCell::new(0xbad);
        cell.local_contents.relaxed_store(0xdead);
        assert_eq!(cell.get(), Racey::Inconsistent);
    }

    /// Unprotected concurrent reads and writes to a RaceCell should trigger
    /// detectable race conditions, illustrating its non-atomic nature.
    #[test]
    fn unprotected_race() {
        // Amount of writes to carry out
        const WRITES_COUNT: usize = 100_000_000;

        // RaceCell in which the writes will be carried out
        let initial_value = 0;
        let cell1 = Arc::new(UsizeRaceCell::new(initial_value));
        let cell2 = cell1.clone();

        // Make sure that RaceCell does expose existing data races, with a
        // detection probability better than 1% for very obvious ones :)
        ::concurrent_test_2(
            move || {
                for i in 1..(WRITES_COUNT+1) {
                    cell1.set(i);
                }
            },
            move || {
                let mut last_value = 0;
                let mut data_race_count = 0usize;
                while last_value != WRITES_COUNT {
                    match cell2.get() {
                        Racey::Consistent(value) => last_value = value,
                        Racey::Inconsistent => data_race_count += 1,
                    }
                }
                print!("{} races detected: ", data_race_count);
                assert!(data_race_count > WRITES_COUNT/100);
            }
        );
    }

    /// Appropriately protected concurrent reads and writes to a RaceCell should
    /// not yield any detectable race conditions.
    #[test]
    fn protected_transaction() {
        // Amount of writes to carry out
        const WRITES_COUNT: usize = 10_000_000;

        // Mutex-protected RaceCell in which the writes will be carried out
        let initial_value = 0;
        let cell1 = Arc::new(Mutex::new(UsizeRaceCell::new(initial_value)));
        let cell2 = cell1.clone();

        // Make sure that RaceCell does not incorrectly detect race conditions
        ::concurrent_test_2(
            move || {
                for i in 1..(WRITES_COUNT+1) {
                    cell1.lock().unwrap().set(i);
                }
            },
            move || {
                let mut last_value = 0;
                let mut data_race_count = 0usize;
                while last_value != WRITES_COUNT {
                    match cell2.lock().unwrap().get() {
                        Racey::Consistent(value) => last_value = value,
                        Racey::Inconsistent => data_race_count += 1,
                    }
                }
                assert_eq!(data_race_count, 0);
            }
        );
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 Fabian Schuiki

//! Object declarations
//!
//! This includes constant, signal, variable, shared variable, and file
//! declarations.

use common::errors::*;
use common::score::Result;
use common::source::Spanned;

use add_ctx::AddContext;
use syntax::ast;
use hir;
use score::*;

impl<'sbc, 'lazy, 'sb, 'ast, 'ctx> AddContext<'sbc, 'lazy, 'sb, 'ast, 'ctx> {
    /// Add a constant declaration.
    pub fn add_const_decl<I>(&self, decl: &'ast ast::ObjDecl) -> Result<Vec<I>>
        where I: From<ConstDeclRef>
    {
        let ty = self.add_subtype_ind(&decl.subtype)?;
        let init = self.add_optional(&decl.init, AddContext::add_expr)?;
        self.ctx.set_type_context_optional(init, TypeCtx::TypeOf(ty.into()));
        if let Some(Spanned{span, ..}) = decl.detail {
            self.emit(
                DiagBuilder2::error("expected `:=` or `;`")
                .span(span)
            );
        }
        decl.names.iter().map(|dn|{
            let (mk, id, scope) = self.make::<ConstDeclRef>(dn.span);
            mk.lower_to_hir(Box::new(move |_sbc|{
                Ok(hir::Decl {
                    parent: scope,
                    span: dn.span,
                    name: (*dn).into(),
                    decl: hir::ConstDecl {
                        ty: ty,
                        init: init,
                    }
                })
            }));
            mk.typeval(Box::new(move |tyc|{
                let hir = tyc.ctx.lazy_hir(id)?;
                // TODO: Check that the type of the init expression matches.
                tyc.ctx.lazy_typeval(hir.decl.ty)
            }));
            Ok(mk.finish().into())
        }).collect()
    }

    /// Add a signal declaration.
    pub fn add_signal_decl<I>(&self, decl: &'ast ast::ObjDecl) -> Result<Vec<I>>
        where I: From<SignalDeclRef>
    {
        let ty = self.add_subtype_ind(&decl.subtype)?;
        let init = self.add_optional(&decl.init, AddContext::add_expr)?;
        self.ctx.set_type_context_optional(init, TypeCtx::TypeOf(ty.into()));
        let kind = match decl.detail {
            Some(Spanned{value: ast::ObjDetail::Register, ..}) => hir::SignalKind::Register,
            Some(Spanned{value: ast::ObjDetail::Bus, ..}) => hir::SignalKind::Bus,
            Some(Spanned{span, ..}) => {
                self.emit(
                    DiagBuilder2::error("expected `:=` or `;`")
                    .span(span)
                );
                hir::SignalKind::Normal
            }
            None => hir::SignalKind::Normal,
        };
        decl.names.iter().map(|dn|{
            let (mk, id, scope) = self.make::<SignalDeclRef>(dn.span);
            mk.lower_to_hir(Box::new(move |_sbc|{
                Ok(hir::Decl {
                    parent: scope,
                    span: dn.span,
                    name: (*dn).into(),
                    decl: hir::SignalDecl {
                        ty: ty,
                        kind: kind,
                        init: init,
                    }
                })
            }));
            mk.typeval(Box::new(move |tyc|{
                let hir = tyc.ctx.lazy_hir(id)?;
                // TODO: Check that the type of the init expression matches.
                tyc.ctx.lazy_typeval(hir.decl.ty)
            }));
            Ok(mk.finish().into())
        }).collect()
    }

    /// Add a variable declaration.
    pub fn add_var_decl<I>(&self, decl: &'ast ast::ObjDecl) -> Result<Vec<I>>
        where I: From<VarDeclRef>
    {
        let ty = self.add_subtype_ind(&decl.subtype)?;
        let init = self.add_optional(&decl.init, AddContext::add_expr)?;
        self.ctx.set_type_context_optional(init, TypeCtx::TypeOf(ty.into()));
        if let Some(Spanned{span, ..}) = decl.detail {
            self.emit(
                DiagBuilder2::error("expected `:=` or `;`")
                .span(span)
            );
        }
        decl.names.iter().map(|dn|{
            let (mk, id, scope) = self.make::<VarDeclRef>(dn.span);
            mk.lower_to_hir(Box::new(move |_sbc|{
                Ok(hir::Decl {
                    parent: scope,
                    span: dn.span,
                    name: (*dn).into(),
                    decl: hir::VarDecl {
                        shared: decl.kind == ast::ObjKind::SharedVar,
                        ty: ty,
                        init: init,
                    }
                })
            }));
            mk.typeval(Box::new(move |tyc|{
                let hir = tyc.ctx.lazy_hir(id)?;
                // TODO: Check that the type of the init expression matches.
                tyc.ctx.lazy_typeval(hir.decl.ty)
            }));
            Ok(mk.finish().into())
        }).collect()
    }

    /// Add a file declaration.
    pub fn add_file_decl<I>(&self, decl: &'ast ast::ObjDecl) -> Result<Vec<I>>
        where I: From<FileDeclRef>
    {
        let ty = self.add_subtype_ind(&decl.subtype)?;
        if let Some(ref init) = decl.init {
            self.emit(
                DiagBuilder2::error("expected `;`, `open`, or `is`")
                .span(init.span)
            );
        }
        decl.names.iter().map(|dn|{
            let (mk, id, scope) = self.make::<FileDeclRef>(dn.span);
            mk.lower_to_hir(Box::new(move |sbc|{
                let ctx = AddContext::new(sbc, scope);
                let (mode, filename) = match decl.detail {
                    Some(Spanned{value: ast::ObjDetail::Open(ref mode, ref filename), ..}) => {
                        let mode = ctx.add_optional(mode, AddContext::add_expr)?;
                        let filename = ctx.add_expr(filename)?;
                        (mode, Some(filename))
                    }
                    Some(Spanned{span, ..}) => {
                        sbc.emit(
                            DiagBuilder2::error("expected `;`, `open`, or `is`")
                            .span(span)
                        );
                        (None, None)
                    }
                    None => (None, None),
                };
                Ok(hir::Decl {
                    parent: scope,
                    span: dn.span,
                    name: (*dn).into(),
                    decl: hir::FileDecl {
                        ty: ty,
                        filename: filename,
                        mode: mode,
                    }
                })
            }));
            mk.typeval(Box::new(move |tyc|{
                let hir = tyc.ctx.lazy_hir(id)?;
                // TODO: Check that the type of expressions are okay.
                tyc.ctx.lazy_typeval(hir.decl.ty)
            }));
            Ok(mk.finish().into())
        }).collect()
    }
}
<commit_msg>vhdl: partial impl of const decl typeval<commit_after>// Copyright (c) 2018 Fabian Schuiki

//! Object declarations
//!
//! This includes constant, signal, variable, shared variable, and file
//! declarations.

use common::errors::*;
use common::score::Result;
use common::source::Spanned;

use add_ctx::AddContext;
use syntax::ast;
use hir;
use score::*;

impl<'sbc, 'lazy, 'sb, 'ast, 'ctx> AddContext<'sbc, 'lazy, 'sb, 'ast, 'ctx> {
    /// Add a constant declaration.
    pub fn add_const_decl<I>(&self, decl: &'ast ast::ObjDecl) -> Result<Vec<I>>
        where I: From<ConstDeclRef>
    {
        let ty = self.add_subtype_ind(&decl.subtype)?;
        let init = self.add_optional(&decl.init, AddContext::add_expr)?;
        self.ctx.set_type_context_optional(init, TypeCtx::TypeOf(ty.into()));
        if let Some(Spanned{span, ..}) = decl.detail {
            self.emit(
                DiagBuilder2::error("expected `:=` or `;`")
                .span(span)
            );
        }
        decl.names.iter().map(|dn|{
            let (mk, id, scope) = self.make::<ConstDeclRef>(dn.span);
            mk.lower_to_hir(Box::new(move |_sbc|{
                Ok(hir::Decl {
                    parent: scope,
                    span: dn.span,
                    name: (*dn).into(),
                    decl: hir::ConstDecl {
                        ty: ty,
                        init: init,
                    }
                })
            }));
            mk.typeval(Box::new(move |tyc|{
                let hir = tyc.ctx.lazy_hir(id)?;
                let ty = tyc.lazy_typeval(hir.decl.ty)?;
                if let Some(init) = hir.decl.init {
                    let init_ty = tyc.lazy_typeval(init)?;
                    // TODO: Check that the type of the init expression matches.
                    tyc.emit(
                        DiagBuilder2::note(format!("const has type `{}`, init has type `{}`", ty, init_ty))
                        .span(hir.span)
                    );
                }
                Ok(ty)
            }));
            Ok(mk.finish().into())
        }).collect()
    }

    /// Add a signal declaration.
    pub fn add_signal_decl<I>(&self, decl: &'ast ast::ObjDecl) -> Result<Vec<I>>
        where I: From<SignalDeclRef>
    {
        let ty = self.add_subtype_ind(&decl.subtype)?;
        let init = self.add_optional(&decl.init, AddContext::add_expr)?;
        self.ctx.set_type_context_optional(init, TypeCtx::TypeOf(ty.into()));
        let kind = match decl.detail {
            Some(Spanned{value: ast::ObjDetail::Register, ..}) => hir::SignalKind::Register,
            Some(Spanned{value: ast::ObjDetail::Bus, ..}) => hir::SignalKind::Bus,
            Some(Spanned{span, ..}) => {
                self.emit(
                    DiagBuilder2::error("expected `:=` or `;`")
                    .span(span)
                );
                hir::SignalKind::Normal
            }
            None => hir::SignalKind::Normal,
        };
        decl.names.iter().map(|dn|{
            let (mk, id, scope) = self.make::<SignalDeclRef>(dn.span);
            mk.lower_to_hir(Box::new(move |_sbc|{
                Ok(hir::Decl {
                    parent: scope,
                    span: dn.span,
                    name: (*dn).into(),
                    decl: hir::SignalDecl {
                        ty: ty,
                        kind: kind,
                        init: init,
                    }
                })
            }));
            mk.typeval(Box::new(move |tyc|{
                let hir = tyc.ctx.lazy_hir(id)?;
                // TODO: Check that the type of the init expression matches.
                tyc.ctx.lazy_typeval(hir.decl.ty)
            }));
            Ok(mk.finish().into())
        }).collect()
    }

    /// Add a variable declaration.
    pub fn add_var_decl<I>(&self, decl: &'ast ast::ObjDecl) -> Result<Vec<I>>
        where I: From<VarDeclRef>
    {
        let ty = self.add_subtype_ind(&decl.subtype)?;
        let init = self.add_optional(&decl.init, AddContext::add_expr)?;
        self.ctx.set_type_context_optional(init, TypeCtx::TypeOf(ty.into()));
        if let Some(Spanned{span, ..}) = decl.detail {
            self.emit(
                DiagBuilder2::error("expected `:=` or `;`")
                .span(span)
            );
        }
        decl.names.iter().map(|dn|{
            let (mk, id, scope) = self.make::<VarDeclRef>(dn.span);
            mk.lower_to_hir(Box::new(move |_sbc|{
                Ok(hir::Decl {
                    parent: scope,
                    span: dn.span,
                    name: (*dn).into(),
                    decl: hir::VarDecl {
                        shared: decl.kind == ast::ObjKind::SharedVar,
                        ty: ty,
                        init: init,
                    }
                })
            }));
            mk.typeval(Box::new(move |tyc|{
                let hir = tyc.ctx.lazy_hir(id)?;
                // TODO: Check that the type of the init expression matches.
                tyc.ctx.lazy_typeval(hir.decl.ty)
            }));
            Ok(mk.finish().into())
        }).collect()
    }

    /// Add a file declaration.
    pub fn add_file_decl<I>(&self, decl: &'ast ast::ObjDecl) -> Result<Vec<I>>
        where I: From<FileDeclRef>
    {
        let ty = self.add_subtype_ind(&decl.subtype)?;
        if let Some(ref init) = decl.init {
            self.emit(
                DiagBuilder2::error("expected `;`, `open`, or `is`")
                .span(init.span)
            );
        }
        decl.names.iter().map(|dn|{
            let (mk, id, scope) = self.make::<FileDeclRef>(dn.span);
            mk.lower_to_hir(Box::new(move |sbc|{
                let ctx = AddContext::new(sbc, scope);
                let (mode, filename) = match decl.detail {
                    Some(Spanned{value: ast::ObjDetail::Open(ref mode, ref filename), ..}) => {
                        let mode = ctx.add_optional(mode, AddContext::add_expr)?;
                        let filename = ctx.add_expr(filename)?;
                        (mode, Some(filename))
                    }
                    Some(Spanned{span, ..}) => {
                        sbc.emit(
                            DiagBuilder2::error("expected `;`, `open`, or `is`")
                            .span(span)
                        );
                        (None, None)
                    }
                    None => (None, None),
                };
                Ok(hir::Decl {
                    parent: scope,
                    span: dn.span,
                    name: (*dn).into(),
                    decl: hir::FileDecl {
                        ty: ty,
                        filename: filename,
                        mode: mode,
                    }
                })
            }));
            mk.typeval(Box::new(move |tyc|{
                let hir = tyc.ctx.lazy_hir(id)?;
                // TODO: Check that the type of expressions are okay.
                tyc.ctx.lazy_typeval(hir.decl.ty)
            }));
            Ok(mk.finish().into())
        }).collect()
    }
}
<|endoftext|>


<commit_before>use na::{MatrixMN, VectorN, Vector1, Vector2, Vector3, Vector4,
         Matrix2, Matrix3, Matrix4,
         Matrix2x3, Matrix3x2, Matrix4x2,
         Matrix2x4, Matrix3x4, Matrix4x3,
         Quaternion};

/// A matrix with components of type `N`. It has `R` rows, and `C` columns.
pub type TMat<N, R, C> = MatrixMN<N, R, C>;
/// A column vector with components of type `N`. It has `D` rows (and one column).
pub type TVec<N, R> = VectorN<N, R>;
/// A quaternion with components of type `N`.
pub type Qua<N> = Quaternion<N>;

/// A 1D vector with components of type `N`.
pub type TVec1<N> = Vector1<N>;
/// A 2D vector with components of type `N`.
pub type TVec2<N> = Vector2<N>;
/// A 3D vector with components of type `N`.
pub type TVec3<N> = Vector3<N>;
/// A 4D vector with components of type `N`.
pub type TVec4<N> = Vector4<N>;
/// A 1D vector with boolean components.
pub type BVec1 = Vector1<bool>;
/// A 2D vector with boolean components.
pub type BVec2 = Vector2<bool>;
/// A 3D vector with boolean components.
pub type BVec3 = Vector3<bool>;
/// A 4D vector with boolean components.
pub type BVec4 = Vector4<bool>;
/// A 1D vector with `f64` components.
pub type DVec1 = Vector1<f64>;
/// A 2D vector with `f64` components.
pub type DVec2 = Vector2<f64>;
/// A 3D vector with `f64` components.
pub type DVec3 = Vector3<f64>;
/// A 4D vector with `f64` components.
pub type DVec4 = Vector4<f64>;
/// A 1D vector with `i32` components.
pub type IVec1 = Vector1<i32>;
/// A 2D vector with `i32` components.
pub type IVec2 = Vector2<i32>;
/// A 3D vector with `i32` components.
pub type IVec3 = Vector3<i32>;
/// A 4D vector with `i32` components.
pub type IVec4 = Vector4<i32>;
/// A 1D vector with `u32` components.
pub type UVec1 = Vector1<u32>;
/// A 2D vector with `u32` components.
pub type UVec2 = Vector2<u32>;
/// A 3D vector with `u32` components.
pub type UVec3 = Vector3<u32>;
/// A 4D vector with `u32` components.
pub type UVec4 = Vector4<u32>;
/// A 1D vector with `f32` components.
pub type Vec1  = Vector1<f32>;
/// A 2D vector with `f32` components.
pub type Vec2  = Vector2<f32>;
/// A 3D vector with `f32` components.
pub type Vec3  = Vector3<f32>;
/// A 4D vector with `f32` components.
pub type Vec4  = Vector4<f32>;

/// A 1D vector with `u64` components.
pub type U64Vec1 = Vector1<u64>;
/// A 2D vector with `u64` components.
pub type U64Vec2 = Vector2<u64>;
/// A 3D vector with `u64` components.
pub type U64Vec3 = Vector3<u64>;
/// A 4D vector with `u64` components.
pub type U64Vec4 = Vector4<u64>;
/// A 1D vector with `i64` components.
pub type I64Vec1 = Vector1<i64>;
/// A 2D vector with `i64` components.
pub type I64Vec2 = Vector2<i64>;
/// A 3D vector with `i64` components.
pub type I64Vec3 = Vector3<i64>;
/// A 4D vector with `i64` components.
pub type I64Vec4 = Vector4<i64>;

/// A 1D vector with `u32` components.
pub type U32Vec1 = Vector1<u32>;
/// A 2D vector with `u32` components.
pub type U32Vec2 = Vector2<u32>;
/// A 3D vector with `u32` components.
pub type U32Vec3 = Vector3<u32>;
/// A 4D vector with `u32` components.
pub type U32Vec4 = Vector4<u32>;
/// A 1D vector with `i32` components.
pub type I32Vec1 = Vector1<i32>;
/// A 2D vector with `i32` components.
pub type I32Vec2 = Vector2<i32>;
/// A 3D vector with `i32` components.
pub type I32Vec3 = Vector3<i32>;
/// A 4D vector with `i32` components.
pub type I32Vec4 = Vector4<i32>;

/// A 1D vector with `u16` components.
pub type U16Vec1 = Vector1<u16>;
/// A 2D vector with `u16` components.
pub type U16Vec2 = Vector2<u16>;
/// A 3D vector with `u16` components.
pub type U16Vec3 = Vector3<u16>;
/// A 4D vector with `u16` components.
pub type U16Vec4 = Vector4<u16>;
/// A 1D vector with `i16` components.
pub type I16Vec1 = Vector1<i16>;
/// A 2D vector with `i16` components.
pub type I16Vec2 = Vector2<i16>;
/// A 3D vector with `i16` components.
pub type I16Vec3 = Vector3<i16>;
/// A 4D vector with `i16` components.
pub type I16Vec4 = Vector4<i16>;

/// A 1D vector with `u8` components.
pub type U8Vec1 = Vector1<u8>;
/// A 2D vector with `u8` components.
pub type U8Vec2 = Vector2<u8>;
/// A 3D vector with `u8` components.
pub type U8Vec3 = Vector3<u8>;
/// A 4D vector with `u8` components.
pub type U8Vec4 = Vector4<u8>;
/// A 1D vector with `i8` components.
pub type I8Vec1 = Vector1<i8>;
/// A 2D vector with `i8` components.
pub type I8Vec2 = Vector2<i8>;
/// A 3D vector with `i8` components.
pub type I8Vec3 = Vector3<i8>;
/// A 4D vector with `i8` components.
pub type I8Vec4 = Vector4<i8>;

/// A 2x2 matrix with components of type `N`.
pub type TMat2<N> = Matrix2<N>;
/// A 2x2 matrix with components of type `N`.
pub type TMat2x2<N> = Matrix2<N>;
/// A 2x3 matrix with components of type `N`.
pub type TMat2x3<N> = Matrix2x3<N>;
/// A 2x4 matrix with components of type `N`.
pub type TMat2x4<N> = Matrix2x4<N>;
/// A 3x3 matrix with components of type `N`.
pub type TMat3<N> = Matrix3<N>;
/// A 3x2 matrix with components of type `N`.
pub type TMat3x2<N> = Matrix3x2<N>;
/// A 3x3 matrix with components of type `N`.
pub type TMat3x3<N> = Matrix3<N>;
/// A 3x4 matrix with components of type `N`.
pub type TMat3x4<N> = Matrix3x4<N>;
/// A 4x4 matrix with components of type `N`.
pub type TMat4<N> = Matrix4<N>;
/// A 4x2 matrix with components of type `N`.
pub type TMat4x2<N> = Matrix4x2<N>;
/// A 4x3 matrix with components of type `N`.
pub type TMat4x3<N> = Matrix4x3<N>;
/// A 4x4 matrix with components of type `N`.
pub type TMat4x4<N> = Matrix4<N>;
/// A 2x2 matrix with components of type `N`.
pub type DMat2 = Matrix2<f64>;
/// A 2x2 matrix with `f64` components.
pub type DMat2x2 = Matrix2<f64>;
/// A 2x3 matrix with `f64` components.
pub type DMat2x3 = Matrix2x3<f64>;
/// A 2x4 matrix with `f64` components.
pub type DMat2x4 = Matrix2x4<f64>;
/// A 3x3 matrix with `f64` components.
pub type DMat3 = Matrix3<f64>;
/// A 3x2 matrix with `f64` components.
pub type DMat3x2 = Matrix3x2<f64>;
/// A 3x3 matrix with `f64` components.
pub type DMat3x3 = Matrix3<f64>;
/// A 3x4 matrix with `f64` components.
pub type DMat3x4 = Matrix3x4<f64>;
/// A 4x4 matrix with `f64` components.
pub type DMat4 = Matrix4<f64>;
/// A 4x2 matrix with `f64` components.
pub type DMat4x2 = Matrix4x2<f64>;
/// A 4x3 matrix with `f64` components.
pub type DMat4x3 = Matrix4x3<f64>;
/// A 4x4 matrix with `f64` components.
pub type DMat4x4 = Matrix4<f64>;
/// A 2x2 matrix with `f32` components.
pub type Mat2 = Matrix2<f32>;
/// A 2x2 matrix with `f32` components.
pub type Mat2x2 = Matrix2<f32>;
/// A 2x2 matrix with `f32` components.
pub type Mat2x3 = Matrix2x3<f32>;
/// A 2x4 matrix with `f32` components.
pub type Mat2x4 = Matrix2x4<f32>;
/// A 3x3 matrix with `f32` components.
pub type Mat3 = Matrix3<f32>;
/// A 3x2 matrix with `f32` components.
pub type Mat3x2 = Matrix3x2<f32>;
/// A 3x3 matrix with `f32` components.
pub type Mat3x3 = Matrix3<f32>;
/// A 3x4 matrix with `f32` components.
pub type Mat3x4 = Matrix3x4<f32>;
/// A 4x2 matrix with `f32` components.
pub type Mat4x2 = Matrix4x2<f32>;
/// A 4x3 matrix with `f32` components.
pub type Mat4x3 = Matrix4x3<f32>;
/// A 4x4 matrix with `f32` components.
pub type Mat4x4 = Matrix4<f32>;
/// A 4x3 matrix with `f32` components.
pub type Mat4 = Matrix4<f32>;

/// A quaternion with f32 components.
pub type Quat = Quaternion<f32>;
/// A quaternion with f64 components.
pub type DQuat = Quaternion<f64>;
<commit_msg>Fix typo in GLM alias docs<commit_after>use na::{MatrixMN, VectorN, Vector1, Vector2, Vector3, Vector4,
         Matrix2, Matrix3, Matrix4,
         Matrix2x3, Matrix3x2, Matrix4x2,
         Matrix2x4, Matrix3x4, Matrix4x3,
         Quaternion};

/// A matrix with components of type `N`. It has `R` rows, and `C` columns.
pub type TMat<N, R, C> = MatrixMN<N, R, C>;
/// A column vector with components of type `N`. It has `D` rows (and one column).
pub type TVec<N, R> = VectorN<N, R>;
/// A quaternion with components of type `N`.
pub type Qua<N> = Quaternion<N>;

/// A 1D vector with components of type `N`.
pub type TVec1<N> = Vector1<N>;
/// A 2D vector with components of type `N`.
pub type TVec2<N> = Vector2<N>;
/// A 3D vector with components of type `N`.
pub type TVec3<N> = Vector3<N>;
/// A 4D vector with components of type `N`.
pub type TVec4<N> = Vector4<N>;
/// A 1D vector with boolean components.
pub type BVec1 = Vector1<bool>;
/// A 2D vector with boolean components.
pub type BVec2 = Vector2<bool>;
/// A 3D vector with boolean components.
pub type BVec3 = Vector3<bool>;
/// A 4D vector with boolean components.
pub type BVec4 = Vector4<bool>;
/// A 1D vector with `f64` components.
pub type DVec1 = Vector1<f64>;
/// A 2D vector with `f64` components.
pub type DVec2 = Vector2<f64>;
/// A 3D vector with `f64` components.
pub type DVec3 = Vector3<f64>;
/// A 4D vector with `f64` components.
pub type DVec4 = Vector4<f64>;
/// A 1D vector with `i32` components.
pub type IVec1 = Vector1<i32>;
/// A 2D vector with `i32` components.
pub type IVec2 = Vector2<i32>;
/// A 3D vector with `i32` components.
pub type IVec3 = Vector3<i32>;
/// A 4D vector with `i32` components.
pub type IVec4 = Vector4<i32>;
/// A 1D vector with `u32` components.
pub type UVec1 = Vector1<u32>;
/// A 2D vector with `u32` components.
pub type UVec2 = Vector2<u32>;
/// A 3D vector with `u32` components.
pub type UVec3 = Vector3<u32>;
/// A 4D vector with `u32` components.
pub type UVec4 = Vector4<u32>;
/// A 1D vector with `f32` components.
pub type Vec1  = Vector1<f32>;
/// A 2D vector with `f32` components.
pub type Vec2  = Vector2<f32>;
/// A 3D vector with `f32` components.
pub type Vec3  = Vector3<f32>;
/// A 4D vector with `f32` components.
pub type Vec4  = Vector4<f32>;

/// A 1D vector with `u64` components.
pub type U64Vec1 = Vector1<u64>;
/// A 2D vector with `u64` components.
pub type U64Vec2 = Vector2<u64>;
/// A 3D vector with `u64` components.
pub type U64Vec3 = Vector3<u64>;
/// A 4D vector with `u64` components.
pub type U64Vec4 = Vector4<u64>;
/// A 1D vector with `i64` components.
pub type I64Vec1 = Vector1<i64>;
/// A 2D vector with `i64` components.
pub type I64Vec2 = Vector2<i64>;
/// A 3D vector with `i64` components.
pub type I64Vec3 = Vector3<i64>;
/// A 4D vector with `i64` components.
pub type I64Vec4 = Vector4<i64>;

/// A 1D vector with `u32` components.
pub type U32Vec1 = Vector1<u32>;
/// A 2D vector with `u32` components.
pub type U32Vec2 = Vector2<u32>;
/// A 3D vector with `u32` components.
pub type U32Vec3 = Vector3<u32>;
/// A 4D vector with `u32` components.
pub type U32Vec4 = Vector4<u32>;
/// A 1D vector with `i32` components.
pub type I32Vec1 = Vector1<i32>;
/// A 2D vector with `i32` components.
pub type I32Vec2 = Vector2<i32>;
/// A 3D vector with `i32` components.
pub type I32Vec3 = Vector3<i32>;
/// A 4D vector with `i32` components.
pub type I32Vec4 = Vector4<i32>;

/// A 1D vector with `u16` components.
pub type U16Vec1 = Vector1<u16>;
/// A 2D vector with `u16` components.
pub type U16Vec2 = Vector2<u16>;
/// A 3D vector with `u16` components.
pub type U16Vec3 = Vector3<u16>;
/// A 4D vector with `u16` components.
pub type U16Vec4 = Vector4<u16>;
/// A 1D vector with `i16` components.
pub type I16Vec1 = Vector1<i16>;
/// A 2D vector with `i16` components.
pub type I16Vec2 = Vector2<i16>;
/// A 3D vector with `i16` components.
pub type I16Vec3 = Vector3<i16>;
/// A 4D vector with `i16` components.
pub type I16Vec4 = Vector4<i16>;

/// A 1D vector with `u8` components.
pub type U8Vec1 = Vector1<u8>;
/// A 2D vector with `u8` components.
pub type U8Vec2 = Vector2<u8>;
/// A 3D vector with `u8` components.
pub type U8Vec3 = Vector3<u8>;
/// A 4D vector with `u8` components.
pub type U8Vec4 = Vector4<u8>;
/// A 1D vector with `i8` components.
pub type I8Vec1 = Vector1<i8>;
/// A 2D vector with `i8` components.
pub type I8Vec2 = Vector2<i8>;
/// A 3D vector with `i8` components.
pub type I8Vec3 = Vector3<i8>;
/// A 4D vector with `i8` components.
pub type I8Vec4 = Vector4<i8>;

/// A 2x2 matrix with components of type `N`.
pub type TMat2<N> = Matrix2<N>;
/// A 2x2 matrix with components of type `N`.
pub type TMat2x2<N> = Matrix2<N>;
/// A 2x3 matrix with components of type `N`.
pub type TMat2x3<N> = Matrix2x3<N>;
/// A 2x4 matrix with components of type `N`.
pub type TMat2x4<N> = Matrix2x4<N>;
/// A 3x3 matrix with components of type `N`.
pub type TMat3<N> = Matrix3<N>;
/// A 3x2 matrix with components of type `N`.
pub type TMat3x2<N> = Matrix3x2<N>;
/// A 3x3 matrix with components of type `N`.
pub type TMat3x3<N> = Matrix3<N>;
/// A 3x4 matrix with components of type `N`.
pub type TMat3x4<N> = Matrix3x4<N>;
/// A 4x4 matrix with components of type `N`.
pub type TMat4<N> = Matrix4<N>;
/// A 4x2 matrix with components of type `N`.
pub type TMat4x2<N> = Matrix4x2<N>;
/// A 4x3 matrix with components of type `N`.
pub type TMat4x3<N> = Matrix4x3<N>;
/// A 4x4 matrix with components of type `N`.
pub type TMat4x4<N> = Matrix4<N>;
/// A 2x2 matrix with components of type `N`.
pub type DMat2 = Matrix2<f64>;
/// A 2x2 matrix with `f64` components.
pub type DMat2x2 = Matrix2<f64>;
/// A 2x3 matrix with `f64` components.
pub type DMat2x3 = Matrix2x3<f64>;
/// A 2x4 matrix with `f64` components.
pub type DMat2x4 = Matrix2x4<f64>;
/// A 3x3 matrix with `f64` components.
pub type DMat3 = Matrix3<f64>;
/// A 3x2 matrix with `f64` components.
pub type DMat3x2 = Matrix3x2<f64>;
/// A 3x3 matrix with `f64` components.
pub type DMat3x3 = Matrix3<f64>;
/// A 3x4 matrix with `f64` components.
pub type DMat3x4 = Matrix3x4<f64>;
/// A 4x4 matrix with `f64` components.
pub type DMat4 = Matrix4<f64>;
/// A 4x2 matrix with `f64` components.
pub type DMat4x2 = Matrix4x2<f64>;
/// A 4x3 matrix with `f64` components.
pub type DMat4x3 = Matrix4x3<f64>;
/// A 4x4 matrix with `f64` components.
pub type DMat4x4 = Matrix4<f64>;
/// A 2x2 matrix with `f32` components.
pub type Mat2 = Matrix2<f32>;
/// A 2x2 matrix with `f32` components.
pub type Mat2x2 = Matrix2<f32>;
/// A 2x2 matrix with `f32` components.
pub type Mat2x3 = Matrix2x3<f32>;
/// A 2x4 matrix with `f32` components.
pub type Mat2x4 = Matrix2x4<f32>;
/// A 3x3 matrix with `f32` components.
pub type Mat3 = Matrix3<f32>;
/// A 3x2 matrix with `f32` components.
pub type Mat3x2 = Matrix3x2<f32>;
/// A 3x3 matrix with `f32` components.
pub type Mat3x3 = Matrix3<f32>;
/// A 3x4 matrix with `f32` components.
pub type Mat3x4 = Matrix3x4<f32>;
/// A 4x2 matrix with `f32` components.
pub type Mat4x2 = Matrix4x2<f32>;
/// A 4x3 matrix with `f32` components.
pub type Mat4x3 = Matrix4x3<f32>;
/// A 4x4 matrix with `f32` components.
pub type Mat4x4 = Matrix4<f32>;
/// A 4x4 matrix with `f32` components.
pub type Mat4 = Matrix4<f32>;

/// A quaternion with f32 components.
pub type Quat = Quaternion<f32>;
/// A quaternion with f64 components.
pub type DQuat = Quaternion<f64>;
<|endoftext|>