<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

#[macro_use]
extern crate log;
extern crate fern;
extern crate time;
extern crate libc;
extern crate rand;
extern crate epoll;
extern crate errno;
extern crate openssl;
extern crate rustc_serialize;

use std::sync::Mutex;
use config::Config;

pub use stream::{Stream, HSend};
pub use types::EventHandler;

pub mod stream;
pub mod config;

mod types;
mod stats;
mod server;
mod resources;
mod workerthread;

/// Starts the server binding to the passed address.
/// This is a blocking call for the life of the server.
pub fn begin<T>(config: Config, handler: Box<T>)
    where T: EventHandler + Send + Sync + 'static
{
    initialize_logger();
    let mut data = Mutex::new(stats::Stats::new());
    stats::init(&mut data);
    server::begin(config, handler);
}

/// Initializes the global logger
fn initialize_logger() {
    let _ = fern::init_global_logger(fern::DispatchConfig {
                                         format: Box::new(|msg: &str,
                                                           level: &log::LogLevel,
                                                           _location: &log::LogLocation| {
                                             format!("[{}][{}] {}",
                                                     time::now()
                                                         .strftime("%Y-%m-%d][%H:%M:%S")
                                                         .unwrap(),
                                                     level,
                                                     msg)
                                         }),
                                         output: vec![fern::OutputConfig::stdout(),
                                                      fern::OutputConfig::file("/var/log/hydrogen\
                                                                                .log")],
                                         level: log::LogLevelFilter::Trace,
                                     },
                                     log::LogLevelFilter::Trace);
}
<commit_msg>Remote debugging<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

#[macro_use]
extern crate log;
extern crate fern;
extern crate time;
extern crate libc;
extern crate rand;
extern crate epoll;
extern crate errno;
extern crate openssl;
extern crate num_cpus;
extern crate rustc_serialize;

use std::sync::Mutex;
use config::Config;

pub use stream::{Stream, HSend};
pub use types::EventHandler;

pub mod stream;
pub mod config;

mod types;
mod stats;
mod server;
mod resources;
mod workerthread;

/// Starts the server binding to the passed address.
/// This is a blocking call for the life of the server.
pub fn begin<T>(config: Config, handler: Box<T>)
    where T: EventHandler + Send + Sync + 'static
{
    initialize_logger();
    let mut data = Mutex::new(stats::Stats::new());
    stats::init(&mut data);
    server::begin(config, handler);
}

/// Initializes the global logger
fn initialize_logger() {
    let _ = fern::init_global_logger(fern::DispatchConfig {
                                         format: Box::new(|msg: &str,
                                                           level: &log::LogLevel,
                                                           _location: &log::LogLocation| {
                                             format!("[{}][{}] {}",
                                                     time::now()
                                                         .strftime("%Y-%m-%d][%H:%M:%S")
                                                         .unwrap(),
                                                     level,
                                                     msg)
                                         }),
                                         output: vec![fern::OutputConfig::stdout(),
                                                      fern::OutputConfig::file("/var/log/hydrogen\
                                                                                .log")],
                                         level: log::LogLevelFilter::Trace,
                                     },
                                     log::LogLevelFilter::Trace);
}
<|endoftext|>


<commit_before>extern crate zip;
extern crate quick_xml;

mod error;

use std::path::Path;
use std::fs::File;
use std::io::BufReader;
use std::collections::HashMap;

use error::{ExcelError, ExcelResult};

use zip::read::{ZipFile, ZipArchive};
use quick_xml::{XmlReader, Event, AsStr};

#[derive(Debug, Clone)]
pub enum DataType {
    Int(i64),
    Float(f64),
    String(String),
    Empty,
}

pub struct Excel {
    zip: ZipArchive<File>,
    strings: Vec<String>,
    /// Map of sheet names/sheet path within zip archive
    sheets: HashMap<String, String>,
}

#[derive(Debug, Default)]
pub struct Range {
    position: (u32, u32),
    size: (usize, usize),
    inner: Vec<DataType>,
}

impl Excel {

    /// Opens a new workbook
    pub fn open<P: AsRef<Path>>(path: P) -> ExcelResult<Excel> {
        let f = try!(File::open(path));
        let zip = try!(ZipArchive::new(f));
        let mut xl = Excel { zip: zip, strings: vec![], sheets: HashMap::new() };
        try!(xl.read_shared_strings());
        try!(xl.read_sheets_names());
        Ok(xl)
    }

    /// Get all data from `Worksheet`
    pub fn worksheet_range(&mut self, name: &str) -> ExcelResult<Range> {
        let strings = &self.strings;
        let ws = match self.sheets.get(name) {
            Some(p) => try!(self.zip.by_name(p)),
            None => return Err(ExcelError::Unexpected(format!("Sheet '{}' does not exist", name))),
        };
        Range::from_worksheet(ws, strings)
    }

    /// Loop through all archive files and opens 'xl/worksheets' files
    /// Store sheet name and path into self.sheets
    fn read_sheets_names(&mut self) -> ExcelResult<()> {
        let sheets = {
            let mut sheets = HashMap::new();
            for i in 0..self.zip.len() {
                let f = try!(self.zip.by_index(i));
                let name = f.name().to_string();
                if name.starts_with("xl/worksheets/") {
                    let xml = XmlReader::from_reader(BufReader::new(f))
                        .with_check(false)
                        .trim_text(false);
                    'xml_loop: for res_event in xml {
                        if let Ok(Event::Start(ref e)) = res_event {
                            if e.name() == b"sheetPr" {
                                for a in e.attributes() {
                                    if let Ok((b"codeName", v)) = a {
                                        sheets.insert(try!(v.as_str()).to_string(), name);
                                        break 'xml_loop;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            sheets
        };
        self.sheets = sheets;
        Ok(())
    }

    /// Read shared string list
    fn read_shared_strings(&mut self) -> ExcelResult<()> {
        let strings = {
            let f = try!(self.zip.by_name("xl/sharedStrings.xml"));
            let mut xml = XmlReader::from_reader(BufReader::new(f))
                .with_check(false)
                .trim_text(false);

            let mut strings = Vec::new();
            while let Some(res_event) = xml.next() {
                match res_event {
                    Ok(Event::Start(ref e)) if e.name() == b"t" => {
                        strings.push(try!(xml.read_text(b"t")));
                    }
                    Err(e) => return Err(ExcelError::Xml(e)),
                    _ => (),
                }
            }
            strings
        };
        self.strings = strings;
        Ok(())
    }

}

impl Range {

    /// open a xml `ZipFile` reader and read content of *sheetData* and *dimension* node
    fn from_worksheet(xml: ZipFile, strings: &[String]) -> ExcelResult<Range> {
        let mut xml = XmlReader::from_reader(BufReader::new(xml))
            .with_check(false)
            .trim_text(false);
        let mut data = Range::default();
        while let Some(res_event) = xml.next() {
            match res_event {
                Err(e) => return Err(ExcelError::Xml(e)),
                Ok(Event::Start(ref e)) => {
                    match e.name() {
                        b"dimension" => match e.attributes().filter_map(|a| a.ok())
                                .find(|&(key, _)| key == b"ref") {
                            Some((_, dim)) => {
                                let (position, size) = try!(get_dimension(try!(dim.as_str())));
                                data.position = position;
                                data.size = (size.0 as usize, size.1 as usize);
                                data.inner.reserve_exact(data.size.0 * data.size.1);
                            },
                            None => return Err(ExcelError::Unexpected(
                                    format!("Expecting dimension, got {:?}", e))),
                        },
                        b"sheetData" => {
                            let _ = try!(data.read_sheet_data(&mut xml, strings));
                        }
                        _ => (),
                    }
                },
                _ => (),
            }
        }
        data.inner.shrink_to_fit();
        Ok(data)
    }

    /// get worksheet position (row, column)
    pub fn get_position(&self) -> (u32, u32) {
        self.position
    }

    /// get size
    pub fn get_size(&self) -> (usize, usize) {
        self.size
    }

    /// get cell value
    pub fn get_value(&self, i: usize, j: usize) -> &DataType {
        let idx = i * self.size.0 + j;
        &self.inner[idx]
    }

    /// read sheetData node
    fn read_sheet_data(&mut self, xml: &mut XmlReader<BufReader<ZipFile>>, strings: &[String])
        -> ExcelResult<()>
    {
        while let Some(res_event) = xml.next() {
            match res_event {
                Err(e) => return Err(ExcelError::Xml(e)),
                Ok(Event::Start(ref c_element)) => {
                    if c_element.name() == b"c" {
                        loop {
                            match xml.next() {
                                Some(Err(e)) => return Err(ExcelError::Xml(e)),
                                Some(Ok(Event::Start(ref e))) => {
                                    if e.name() == b"v" {
                                        let v = try!(xml.read_text(b"v"));
                                        let value = match c_element.attributes()
                                            .filter_map(|a| a.ok())
                                            .find(|&(k, _)| k == b"t") {
                                                Some((_, b"s")) => {
                                                    let idx: usize = try!(v.parse());
                                                    DataType::String(strings[idx].clone())
                                                },
                                                // TODO: check in styles to know which type is
                                                // supposed to be used
                                                _ => match v.parse() {
                                                    Ok(i) => DataType::Int(i),
                                                    Err(_) => try!(v.parse()
                                                                   .map(DataType::Float)),
                                                },
                                            };
                                        self.inner.push(value);
                                        break;
                                    } else {
                                        return Err(ExcelError::Unexpected("not v node".to_string()));
                                    }
                                },
                                Some(Ok(Event::End(ref e))) => {
                                    if e.name() == b"c" {
                                        self.inner.push(DataType::Empty);
                                        break;
                                    }
                                }
                                None => {
                                    return Err(ExcelError::Unexpected("End of xml".to_string()));
                                }
                                _ => (),
                            }
                        }
                    }
                },
                Ok(Event::End(ref e)) if e.name() == b"sheetData" => return Ok(()),
                _ => (),
            }
        }
        Err(ExcelError::Unexpected("Could not find </sheetData>".to_string()))
    }

}

/// converts a text representation (e.g. "A6:G67") of a dimension into integers
/// - top left (row, column),
/// - size (width, height)
fn get_dimension(dimension: &str) -> ExcelResult<((u32, u32), (u32, u32))> {
    match dimension.chars().position(|c| c == ':') {
        None => {
            get_row_column(dimension).map(|position| (position, (1, 1)))
        },
        Some(p) => {
            let top_left = try!(get_row_column(&dimension[..p]));
            let bottom_right = try!(get_row_column(&dimension[p + 1..]));
            Ok((top_left, (bottom_right.0 - top_left.0 + 1, bottom_right.1 - top_left.1 + 1)))
        }
    }
}

/// converts a text range name into its position (row, column)
fn get_row_column(range: &str) -> ExcelResult<(u32, u32)> {
    let mut col = 0;
    let mut pow = 1;
    let mut rowpos = range.len();
    let mut readrow = true;
    for c in range.chars().rev() {
        match c {
            '0'...'9' => {
                if readrow {
                    rowpos -= 1;
                } else {
                    return Err(ExcelError::Unexpected(
                        format!("Numeric character are only allowed at the end of the range: {}", c)));
                }
            }
            c @ 'A'...'Z' => {
                readrow = false;
                col += ((c as u8 - b'A') as u32 + 1) * pow;
                pow *= 26;
            },
            c @ 'a'...'z' => {
                readrow = false;
                col += ((c as u8 - b'a') as u32 + 1) * pow;
                pow *= 26;
            },
            _ => return Err(ExcelError::Unexpected(
                    format!("Expecting alphanumeric character, got {:?}", c))),
        }
    }
    let row = try!(range[rowpos..].parse());
    Ok((row, col))
}

#[cfg(test)]
mod tests {
    use super::Excel;
    #[test]
    fn it_works() {
        let mut xl = Excel::open("/home/jtuffe/download/DailyValo_FX_Rates_Credit_05 25 16.xlsm")
            .expect("cannot open excel file");
        println!("{:?}", xl.sheets);
        let data = xl.worksheet_range("Sheet1");
        println!("{:?}", data);
        assert!(data.is_ok());
    }
}
<commit_msg>use unexp! macro<commit_after>extern crate zip;
extern crate quick_xml;

mod error;

use std::path::Path;
use std::fs::File;
use std::io::BufReader;
use std::collections::HashMap;

use error::{ExcelError, ExcelResult};

use zip::read::{ZipFile, ZipArchive};
use quick_xml::{XmlReader, Event, AsStr};

macro_rules! unexp {
    ($pat: expr) => {
        {
            return Err(ExcelError::Unexpected($pat.to_string()));
        }
    };
    ($pat: expr, $($args: expr)* ) => {
        {
            return Err(ExcelError::Unexpected(format!($pat, $($args)*)));
        }
    };
}

#[derive(Debug, Clone)]
pub enum DataType {
    Int(i64),
    Float(f64),
    String(String),
    Empty,
}

pub struct Excel {
    zip: ZipArchive<File>,
    strings: Vec<String>,
    /// Map of sheet names/sheet path within zip archive
    sheets: HashMap<String, String>,
}

#[derive(Debug, Default)]
pub struct Range {
    position: (u32, u32),
    size: (usize, usize),
    inner: Vec<DataType>,
}

impl Excel {

    /// Opens a new workbook
    pub fn open<P: AsRef<Path>>(path: P) -> ExcelResult<Excel> {
        let f = try!(File::open(path));
        let zip = try!(ZipArchive::new(f));
        let mut xl = Excel { zip: zip, strings: vec![], sheets: HashMap::new() };
        try!(xl.read_shared_strings());
        try!(xl.read_sheets_names());
        Ok(xl)
    }

    /// Get all data from `Worksheet`
    pub fn worksheet_range(&mut self, name: &str) -> ExcelResult<Range> {
        let strings = &self.strings;
        let ws = match self.sheets.get(name) {
            Some(p) => try!(self.zip.by_name(p)),
            None => unexp!("Sheet '{}' does not exist", name),
        };
        Range::from_worksheet(ws, strings)
    }

    /// Loop through all archive files and opens 'xl/worksheets' files
    /// Store sheet name and path into self.sheets
    fn read_sheets_names(&mut self) -> ExcelResult<()> {
        let sheets = {
            let mut sheets = HashMap::new();
            for i in 0..self.zip.len() {
                let f = try!(self.zip.by_index(i));
                let name = f.name().to_string();
                if name.starts_with("xl/worksheets/") {
                    let xml = XmlReader::from_reader(BufReader::new(f))
                        .with_check(false)
                        .trim_text(false);
                    'xml_loop: for res_event in xml {
                        if let Ok(Event::Start(ref e)) = res_event {
                            if e.name() == b"sheetPr" {
                                for a in e.attributes() {
                                    if let Ok((b"codeName", v)) = a {
                                        sheets.insert(try!(v.as_str()).to_string(), name);
                                        break 'xml_loop;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            sheets
        };
        self.sheets = sheets;
        Ok(())
    }

    /// Read shared string list
    fn read_shared_strings(&mut self) -> ExcelResult<()> {
        let strings = {
            let f = try!(self.zip.by_name("xl/sharedStrings.xml"));
            let mut xml = XmlReader::from_reader(BufReader::new(f))
                .with_check(false)
                .trim_text(false);

            let mut strings = Vec::new();
            while let Some(res_event) = xml.next() {
                match res_event {
                    Ok(Event::Start(ref e)) if e.name() == b"t" => {
                        strings.push(try!(xml.read_text(b"t")));
                    }
                    Err(e) => return Err(ExcelError::Xml(e)),
                    _ => (),
                }
            }
            strings
        };
        self.strings = strings;
        Ok(())
    }

}

impl Range {

    /// open a xml `ZipFile` reader and read content of *sheetData* and *dimension* node
    fn from_worksheet(xml: ZipFile, strings: &[String]) -> ExcelResult<Range> {
        let mut xml = XmlReader::from_reader(BufReader::new(xml))
            .with_check(false)
            .trim_text(false);
        let mut data = Range::default();
        while let Some(res_event) = xml.next() {
            match res_event {
                Err(e) => return Err(ExcelError::Xml(e)),
                Ok(Event::Start(ref e)) => {
                    match e.name() {
                        b"dimension" => match e.attributes().filter_map(|a| a.ok())
                                .find(|&(key, _)| key == b"ref") {
                            Some((_, dim)) => {
                                let (position, size) = try!(get_dimension(try!(dim.as_str())));
                                data.position = position;
                                data.size = (size.0 as usize, size.1 as usize);
                                data.inner.reserve_exact(data.size.0 * data.size.1);
                            },
                            None => unexp!("Expecting dimension, got {:?}", e),
                        },
                        b"sheetData" => {
                            let _ = try!(data.read_sheet_data(&mut xml, strings));
                        }
                        _ => (),
                    }
                },
                _ => (),
            }
        }
        data.inner.shrink_to_fit();
        Ok(data)
    }

    /// get worksheet position (row, column)
    pub fn get_position(&self) -> (u32, u32) {
        self.position
    }

    /// get size
    pub fn get_size(&self) -> (usize, usize) {
        self.size
    }

    /// get cell value
    pub fn get_value(&self, i: usize, j: usize) -> &DataType {
        let idx = i * self.size.0 + j;
        &self.inner[idx]
    }

    /// read sheetData node
    fn read_sheet_data(&mut self, xml: &mut XmlReader<BufReader<ZipFile>>, strings: &[String])
        -> ExcelResult<()>
    {
        while let Some(res_event) = xml.next() {
            match res_event {
                Err(e) => return Err(ExcelError::Xml(e)),
                Ok(Event::Start(ref c_element)) => {
                    if c_element.name() == b"c" {
                        loop {
                            match xml.next() {
                                Some(Err(e)) => return Err(ExcelError::Xml(e)),
                                Some(Ok(Event::Start(ref e))) => {
                                    if e.name() == b"v" {
                                        let v = try!(xml.read_text(b"v"));
                                        let value = match c_element.attributes()
                                            .filter_map(|a| a.ok())
                                            .find(|&(k, _)| k == b"t") {
                                                Some((_, b"s")) => {
                                                    let idx: usize = try!(v.parse());
                                                    DataType::String(strings[idx].clone())
                                                },
                                                // TODO: check in styles to know which type is
                                                // supposed to be used
                                                _ => match v.parse() {
                                                    Ok(i) => DataType::Int(i),
                                                    Err(_) => try!(v.parse()
                                                                   .map(DataType::Float)),
                                                },
                                            };
                                        self.inner.push(value);
                                        break;
                                    } else {
                                        unexp!("not v node");
                                    }
                                },
                                Some(Ok(Event::End(ref e))) => {
                                    if e.name() == b"c" {
                                        self.inner.push(DataType::Empty);
                                        break;
                                    }
                                }
                                None => unexp!("End of xml"),
                                _ => (),
                            }
                        }
                    }
                },
                Ok(Event::End(ref e)) if e.name() == b"sheetData" => return Ok(()),
                _ => (),
            }
        }
        unexp!("Could not find </sheetData>")
    }

}

/// converts a text representation (e.g. "A6:G67") of a dimension into integers
/// - top left (row, column),
/// - size (width, height)
fn get_dimension(dimension: &str) -> ExcelResult<((u32, u32), (u32, u32))> {
    match dimension.chars().position(|c| c == ':') {
        None => {
            get_row_column(dimension).map(|position| (position, (1, 1)))
        },
        Some(p) => {
            let top_left = try!(get_row_column(&dimension[..p]));
            let bottom_right = try!(get_row_column(&dimension[p + 1..]));
            Ok((top_left, (bottom_right.0 - top_left.0 + 1, bottom_right.1 - top_left.1 + 1)))
        }
    }
}

/// converts a text range name into its position (row, column)
fn get_row_column(range: &str) -> ExcelResult<(u32, u32)> {
    let mut col = 0;
    let mut pow = 1;
    let mut rowpos = range.len();
    let mut readrow = true;
    for c in range.chars().rev() {
        match c {
            '0'...'9' => {
                if readrow {
                    rowpos -= 1;
                } else {
                    unexp!("Numeric character are only allowed at the end of the range: {}", c);
                }
            }
            c @ 'A'...'Z' => {
                readrow = false;
                col += ((c as u8 - b'A') as u32 + 1) * pow;
                pow *= 26;
            },
            c @ 'a'...'z' => {
                readrow = false;
                col += ((c as u8 - b'a') as u32 + 1) * pow;
                pow *= 26;
            },
            _ => unexp!("Expecting alphanumeric character, got {:?}", c),
        }
    }
    let row = try!(range[rowpos..].parse());
    Ok((row, col))
}

#[cfg(test)]
mod tests {
    use super::Excel;
    #[test]
    fn it_works() {
        let mut xl = Excel::open("/home/jtuffe/download/DailyValo_FX_Rates_Credit_05 25 16.xlsm")
            .expect("cannot open excel file");
        println!("{:?}", xl.sheets);
        let data = xl.worksheet_range("Sheet1");
        println!("{:?}", data);
        assert!(data.is_ok());
    }
}
<|endoftext|>


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

use sys::{Component, Disk, DiskType, NetworkData, Process, Processor};
use Pid;
use ProcessStatus;
use RefreshKind;

use std::collections::HashMap;
use std::ffi::OsStr;
use std::path::Path;

/// Contains all the methods of the `Disk` struct.
pub trait DiskExt {
    /// Returns the disk type.
    fn get_type(&self) -> DiskType;

    /// Returns the disk name.
    fn get_name(&self) -> &OsStr;

    /// Returns the file system used on this disk (so for example: `EXT4`, `NTFS`, etc...).
    fn get_file_system(&self) -> &[u8];

    /// Returns the mount point of the disk (`/` for example).
    fn get_mount_point(&self) -> &Path;

    /// Returns the total disk size, in bytes.
    fn get_total_space(&self) -> u64;

    /// Returns the available disk size, in bytes.
    fn get_available_space(&self) -> u64;

    /// Update the disk' information.
    fn update(&mut self) -> bool;
}

/// Contains all the methods of the `Process` struct.
pub trait ProcessExt {
    /// Create a new process only containing the given information.
    ///
    /// On windows, the `start_time` argument is ignored.
    fn new(pid: Pid, parent: Option<Pid>, start_time: u64) -> Self;

    /// Sends the given `signal` to the process.
    fn kill(&self, signal: ::Signal) -> bool;

    /// Returns the name of the process.
    fn name(&self) -> &str;

    /// Returns the command line.
    // ///
    // /// On Windows, this is always a one element vector.
    fn cmd(&self) -> &[String];

    /// Returns the path to the process.
    fn exe(&self) -> &Path;

    /// Returns the pid of the process.
    fn pid(&self) -> Pid;

    /// Returns the environment of the process.
    ///
    /// Always empty on Windows except for current process.
    fn environ(&self) -> &[String];

    /// Returns the current working directory.
    ///
    /// Always empty on Windows.
    fn cwd(&self) -> &Path;

    /// Returns the path of the root directory.
    ///
    /// Always empty on Windows.
    fn root(&self) -> &Path;

    /// Returns the memory usage (in kB).
    fn memory(&self) -> u64;

    /// Returns the virtual memory usage (in kB).
    fn virtual_memory(&self) -> u64;

    /// Returns the parent pid.
    fn parent(&self) -> Option<Pid>;

    /// Returns the status of the processus.
    fn status(&self) -> ProcessStatus;

    /// Returns the time of process launch (in seconds).
    fn start_time(&self) -> u64;

    /// Returns the total CPU usage.
    fn cpu_usage(&self) -> f32;
}

/// Contains all the methods of the `Processor` struct.
pub trait ProcessorExt {
    /// Returns this processor's usage.
    ///
    /// Note: You'll need to refresh it at least twice at first if you want to have a
    /// non-zero value.
    fn get_cpu_usage(&self) -> f32;

    /// Returns this processor's name.
    fn get_name(&self) -> &str;
}

/// Contains all the methods of the [`System`] type.
pub trait SystemExt: Sized {
    /// Creates a new [`System`] instance. It only contains the disks' list  and the processes list
    /// at this stage. Use the [`refresh_all`] method to update its internal information (or any of
    /// the `refresh_` method).
    ///
    /// [`refresh_all`]: #method.refresh_all
    fn new() -> Self {
        let mut s = Self::new_with_specifics(RefreshKind::new());
        s.refresh_disk_list();
        s.refresh_all();
        s
    }

    /// Creates a new [`System`] instance and refresh the data corresponding to the
    /// given [`RefreshKind`].
    ///
    /// # Example
    ///
    /// ```
    /// use sysinfo::{RefreshKind, System, SystemExt};
    ///
    /// // We want everything except disks.
    /// let mut system = System::new_with_specifics(RefreshKind::everything().without_disk_list());
    ///
    /// assert_eq!(system.get_disks().len(), 0);
    /// assert!(system.get_process_list().len() > 0);
    ///
    /// // If you want the disks list afterwards, just call the corresponding
    /// // "refresh_disk_list":
    /// system.refresh_disk_list();
    /// assert!(system.get_disks().len() > 0);
    /// ```
    fn new_with_specifics(refreshes: RefreshKind) -> Self;

    /// Refreshes according to the given [`RefreshKind`]. It calls the corresponding
    /// "refresh_" methods.
    ///
    /// # Examples
    ///
    /// ```
    /// use sysinfo::{RefreshKind, System, SystemExt};
    ///
    /// let mut s = System::new();
    ///
    /// // Let's just update network data and processes:
    /// s.refresh_specifics(RefreshKind::new().with_network().with_processes());
    /// ```
    fn refresh_specifics(&mut self, refreshes: RefreshKind) {
        if refreshes.memory() {
            self.refresh_memory();
        }
        if refreshes.cpu() {
            self.refresh_cpu();
        }
        if refreshes.temperatures() {
            self.refresh_temperatures();
        }
        if refreshes.network() {
            self.refresh_network();
        }
        if refreshes.processes() {
            self.refresh_processes();
        }
        if refreshes.disk_list() {
            self.refresh_disk_list();
        }
        if refreshes.disks() {
            self.refresh_disks();
        }
    }

    /// Refresh system information (such as memory, swap, CPU usage and components' temperature).
    ///
    /// If you want some more specific refresh, you might be interested into looking at
    /// [`refresh_memory`], [`refresh_cpu`] and [`refresh_temperatures`].
    ///
    /// [`refresh_memory`]: SystemExt::refresh_memory
    /// [`refresh_cpu`]: SystemExt::refresh_memory
    /// [`refresh_temperatures`]: SystemExt::refresh_temperatures
    fn refresh_system(&mut self) {
        self.refresh_memory();
        self.refresh_cpu();
        self.refresh_temperatures();
    }

    /// Refresh RAM and SWAP usage.
    fn refresh_memory(&mut self);

    /// Refresh CPU usage.
    fn refresh_cpu(&mut self);

    /// Refresh components' temperature.
    fn refresh_temperatures(&mut self);

    /// Get all processes and update their information.
    fn refresh_processes(&mut self);

    /// Refresh *only* the process corresponding to `pid`. Returns `false` if the process doesn't
    /// exist.
    fn refresh_process(&mut self, pid: Pid) -> bool;

    /// Refreshes the listed disks' information.
    fn refresh_disks(&mut self);

    /// The disk list will be emptied then completely recomputed.
    fn refresh_disk_list(&mut self);

    /// Refresh data network.
    fn refresh_network(&mut self);

    /// Refreshes all system, processes and disks information.
    fn refresh_all(&mut self) {
        self.refresh_system();
        self.refresh_processes();
        self.refresh_disks();
        self.refresh_network();
    }

    /// Returns the process list.
    fn get_process_list(&self) -> &HashMap<Pid, Process>;

    /// Returns the process corresponding to the given pid or `None` if no such process exists.
    fn get_process(&self, pid: Pid) -> Option<&Process>;

    /// Returns a list of process containing the given `name`.
    fn get_process_by_name(&self, name: &str) -> Vec<&Process> {
        let mut ret = vec![];
        for val in self.get_process_list().values() {
            if val.name().contains(name) {
                ret.push(val);
            }
        }
        ret
    }

    /// The first processor in the array is the "main" one (aka the addition of all the others).
    fn get_processor_list(&self) -> &[Processor];

    /// Returns total RAM size in KiB.
    fn get_total_memory(&self) -> u64;

    /// Returns free RAM size in KiB.
    fn get_free_memory(&self) -> u64;

    /// Returns used RAM size in KiB.
    fn get_used_memory(&self) -> u64;

    /// Returns SWAP size in KiB.
    fn get_total_swap(&self) -> u64;

    /// Returns free SWAP size in KiB.
    fn get_free_swap(&self) -> u64;

    /// Returns used SWAP size in KiB.
    fn get_used_swap(&self) -> u64;

    /// Returns components list.
    fn get_components_list(&self) -> &[Component];

    /// Returns disks' list.
    fn get_disks(&self) -> &[Disk];

    /// Returns network data.
    fn get_network(&self) -> &NetworkData;

    /// Returns system uptime.
    fn get_uptime(&self) -> u64;
}

/// Getting volume of incoming and outgoing data.
pub trait NetworkExt {
    /// Returns the number of incoming bytes.
    fn get_income(&self) -> u64;

    /// Returns the number of outgoing bytes.
    fn get_outcome(&self) -> u64;
}

/// Getting a component temperature information.
pub trait ComponentExt {
    /// Returns the component's temperature (in celsius degree).
    fn get_temperature(&self) -> f32;
    /// Returns the maximum temperature of this component.
    fn get_max(&self) -> f32;
    /// Returns the highest temperature before the computer halts.
    fn get_critical(&self) -> Option<f32>;
    /// Returns component's label.
    fn get_label(&self) -> &str;
}
<commit_msg>Fix doc example<commit_after>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

use sys::{Component, Disk, DiskType, NetworkData, Process, Processor};
use Pid;
use ProcessStatus;
use RefreshKind;

use std::collections::HashMap;
use std::ffi::OsStr;
use std::path::Path;

/// Contains all the methods of the `Disk` struct.
pub trait DiskExt {
    /// Returns the disk type.
    fn get_type(&self) -> DiskType;

    /// Returns the disk name.
    fn get_name(&self) -> &OsStr;

    /// Returns the file system used on this disk (so for example: `EXT4`, `NTFS`, etc...).
    fn get_file_system(&self) -> &[u8];

    /// Returns the mount point of the disk (`/` for example).
    fn get_mount_point(&self) -> &Path;

    /// Returns the total disk size, in bytes.
    fn get_total_space(&self) -> u64;

    /// Returns the available disk size, in bytes.
    fn get_available_space(&self) -> u64;

    /// Update the disk' information.
    fn update(&mut self) -> bool;
}

/// Contains all the methods of the `Process` struct.
pub trait ProcessExt {
    /// Create a new process only containing the given information.
    ///
    /// On windows, the `start_time` argument is ignored.
    fn new(pid: Pid, parent: Option<Pid>, start_time: u64) -> Self;

    /// Sends the given `signal` to the process.
    fn kill(&self, signal: ::Signal) -> bool;

    /// Returns the name of the process.
    fn name(&self) -> &str;

    /// Returns the command line.
    // ///
    // /// On Windows, this is always a one element vector.
    fn cmd(&self) -> &[String];

    /// Returns the path to the process.
    fn exe(&self) -> &Path;

    /// Returns the pid of the process.
    fn pid(&self) -> Pid;

    /// Returns the environment of the process.
    ///
    /// Always empty on Windows except for current process.
    fn environ(&self) -> &[String];

    /// Returns the current working directory.
    ///
    /// Always empty on Windows.
    fn cwd(&self) -> &Path;

    /// Returns the path of the root directory.
    ///
    /// Always empty on Windows.
    fn root(&self) -> &Path;

    /// Returns the memory usage (in kB).
    fn memory(&self) -> u64;

    /// Returns the virtual memory usage (in kB).
    fn virtual_memory(&self) -> u64;

    /// Returns the parent pid.
    fn parent(&self) -> Option<Pid>;

    /// Returns the status of the processus.
    fn status(&self) -> ProcessStatus;

    /// Returns the time of process launch (in seconds).
    fn start_time(&self) -> u64;

    /// Returns the total CPU usage.
    fn cpu_usage(&self) -> f32;
}

/// Contains all the methods of the `Processor` struct.
pub trait ProcessorExt {
    /// Returns this processor's usage.
    ///
    /// Note: You'll need to refresh it at least twice at first if you want to have a
    /// non-zero value.
    fn get_cpu_usage(&self) -> f32;

    /// Returns this processor's name.
    fn get_name(&self) -> &str;
}

/// Contains all the methods of the [`System`] type.
pub trait SystemExt: Sized {
    /// Creates a new [`System`] instance. It only contains the disks' list  and the processes list
    /// at this stage. Use the [`refresh_all`] method to update its internal information (or any of
    /// the `refresh_` method).
    ///
    /// [`refresh_all`]: #method.refresh_all
    fn new() -> Self {
        let mut s = Self::new_with_specifics(RefreshKind::new());
        s.refresh_disk_list();
        s.refresh_all();
        s
    }

    /// Creates a new [`System`] instance and refresh the data corresponding to the
    /// given [`RefreshKind`].
    ///
    /// # Example
    ///
    /// ```
    /// use sysinfo::{RefreshKind, System, SystemExt};
    ///
    /// // We want everything except disks.
    /// let mut system = System::new_with_specifics(RefreshKind::everything().without_disk_list());
    ///
    /// assert_eq!(system.get_disks().len(), 0);
    /// assert!(system.get_process_list().len() > 0);
    ///
    /// // If you want the disks list afterwards, just call the corresponding
    /// // "refresh_disk_list":
    /// system.refresh_disk_list();
    /// let disks = system.get_disks();
    /// ```
    fn new_with_specifics(refreshes: RefreshKind) -> Self;

    /// Refreshes according to the given [`RefreshKind`]. It calls the corresponding
    /// "refresh_" methods.
    ///
    /// # Examples
    ///
    /// ```
    /// use sysinfo::{RefreshKind, System, SystemExt};
    ///
    /// let mut s = System::new();
    ///
    /// // Let's just update network data and processes:
    /// s.refresh_specifics(RefreshKind::new().with_network().with_processes());
    /// ```
    fn refresh_specifics(&mut self, refreshes: RefreshKind) {
        if refreshes.memory() {
            self.refresh_memory();
        }
        if refreshes.cpu() {
            self.refresh_cpu();
        }
        if refreshes.temperatures() {
            self.refresh_temperatures();
        }
        if refreshes.network() {
            self.refresh_network();
        }
        if refreshes.processes() {
            self.refresh_processes();
        }
        if refreshes.disk_list() {
            self.refresh_disk_list();
        }
        if refreshes.disks() {
            self.refresh_disks();
        }
    }

    /// Refresh system information (such as memory, swap, CPU usage and components' temperature).
    ///
    /// If you want some more specific refresh, you might be interested into looking at
    /// [`refresh_memory`], [`refresh_cpu`] and [`refresh_temperatures`].
    ///
    /// [`refresh_memory`]: SystemExt::refresh_memory
    /// [`refresh_cpu`]: SystemExt::refresh_memory
    /// [`refresh_temperatures`]: SystemExt::refresh_temperatures
    fn refresh_system(&mut self) {
        self.refresh_memory();
        self.refresh_cpu();
        self.refresh_temperatures();
    }

    /// Refresh RAM and SWAP usage.
    fn refresh_memory(&mut self);

    /// Refresh CPU usage.
    fn refresh_cpu(&mut self);

    /// Refresh components' temperature.
    fn refresh_temperatures(&mut self);

    /// Get all processes and update their information.
    fn refresh_processes(&mut self);

    /// Refresh *only* the process corresponding to `pid`. Returns `false` if the process doesn't
    /// exist.
    fn refresh_process(&mut self, pid: Pid) -> bool;

    /// Refreshes the listed disks' information.
    fn refresh_disks(&mut self);

    /// The disk list will be emptied then completely recomputed.
    fn refresh_disk_list(&mut self);

    /// Refresh data network.
    fn refresh_network(&mut self);

    /// Refreshes all system, processes and disks information.
    fn refresh_all(&mut self) {
        self.refresh_system();
        self.refresh_processes();
        self.refresh_disks();
        self.refresh_network();
    }

    /// Returns the process list.
    fn get_process_list(&self) -> &HashMap<Pid, Process>;

    /// Returns the process corresponding to the given pid or `None` if no such process exists.
    fn get_process(&self, pid: Pid) -> Option<&Process>;

    /// Returns a list of process containing the given `name`.
    fn get_process_by_name(&self, name: &str) -> Vec<&Process> {
        let mut ret = vec![];
        for val in self.get_process_list().values() {
            if val.name().contains(name) {
                ret.push(val);
            }
        }
        ret
    }

    /// The first processor in the array is the "main" one (aka the addition of all the others).
    fn get_processor_list(&self) -> &[Processor];

    /// Returns total RAM size in KiB.
    fn get_total_memory(&self) -> u64;

    /// Returns free RAM size in KiB.
    fn get_free_memory(&self) -> u64;

    /// Returns used RAM size in KiB.
    fn get_used_memory(&self) -> u64;

    /// Returns SWAP size in KiB.
    fn get_total_swap(&self) -> u64;

    /// Returns free SWAP size in KiB.
    fn get_free_swap(&self) -> u64;

    /// Returns used SWAP size in KiB.
    fn get_used_swap(&self) -> u64;

    /// Returns components list.
    fn get_components_list(&self) -> &[Component];

    /// Returns disks' list.
    fn get_disks(&self) -> &[Disk];

    /// Returns network data.
    fn get_network(&self) -> &NetworkData;

    /// Returns system uptime.
    fn get_uptime(&self) -> u64;
}

/// Getting volume of incoming and outgoing data.
pub trait NetworkExt {
    /// Returns the number of incoming bytes.
    fn get_income(&self) -> u64;

    /// Returns the number of outgoing bytes.
    fn get_outcome(&self) -> u64;
}

/// Getting a component temperature information.
pub trait ComponentExt {
    /// Returns the component's temperature (in celsius degree).
    fn get_temperature(&self) -> f32;
    /// Returns the maximum temperature of this component.
    fn get_max(&self) -> f32;
    /// Returns the highest temperature before the computer halts.
    fn get_critical(&self) -> Option<f32>;
    /// Returns component's label.
    fn get_label(&self) -> &str;
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::path::Path;
use std::mem::size_of;
use std::mem::transmute;
use std::mem::zeroed;
use std::os::errno;
use std::os::unix::AsRawFd;
use std::num::Float;
use std::fs::File;
use std::thread::Thread;
use std::sync::mpsc::Sender;
use std::io::Read;

use geom::point::TypedPoint2D;

use libc::c_int;
use libc::c_long;
use libc::time_t;

use compositing::windowing::WindowEvent;
use compositing::windowing::MouseWindowEvent;

extern {
    // XXX: no variadic form in std libs?
    fn ioctl(fd: c_int, req: c_int, ...) -> c_int;
}

#[repr(C)]
struct linux_input_event {
    sec: time_t,
    msec: c_long,
    evt_type: u16,
    code: u16,
    value: i32,
}

#[repr(C)]
struct linux_input_absinfo {
    value: i32,
    minimum: i32,
    maximum: i32,
    fuzz: i32,
    flat: i32,
    resolution: i32,
}

const IOC_NONE: c_int = 0;
const IOC_WRITE: c_int = 1;
const IOC_READ: c_int = 2;

fn ioc(dir: c_int, ioctype: c_int, nr: c_int, size: c_int) -> c_int {
    dir << 30 | size << 16 | ioctype << 8 | nr
}

fn ev_ioc_g_abs(abs: u16) -> c_int {
    ioc(IOC_READ, 'E' as c_int, (0x40 + abs) as i32, size_of::<linux_input_absinfo>() as i32)
}

const EV_SYN: u16 = 0;
const EV_ABS: u16 = 3;

const EV_REPORT: u16 = 0;

const ABS_MT_SLOT: u16 = 0x2F;
const ABS_MT_TOUCH_MAJOR: u16 = 0x30;
const ABS_MT_TOUCH_MINOR: u16 = 0x31;
const ABS_MT_WIDTH_MAJOR: u16 = 0x32;
const ABS_MT_WIDTH_MINOR: u16 = 0x33;
const ABS_MT_ORIENTATION: u16 = 0x34;
const ABS_MT_POSITION_X: u16 = 0x35;
const ABS_MT_POSITION_Y: u16 = 0x36;
const ABS_MT_TRACKING_ID: u16 = 0x39;

struct InputSlot {
    tracking_id: i32,
    x: i32,
    y: i32,
}

fn dist(x1: i32, x2: i32, y1: i32, y2: i32) -> f32 {
    let deltaX = (x2 - x1) as f32;
    let deltaY = (y2 - y1) as f32;
    (deltaX * deltaX + deltaY * deltaY).sqrt()
}

fn read_input_device(device_path: &Path,
                     sender: &Sender<WindowEvent>) {
    let mut device = match File::open(device_path) {
        Ok(dev) => dev,
        Err(e) => {
            println!("Couldn't open device! {}", e);
            return;
        },
    };
    let fd = device.as_raw_fd();

    let mut x_info: linux_input_absinfo = unsafe { zeroed() };
    let mut y_info: linux_input_absinfo = unsafe { zeroed() };
    unsafe {
        let ret = ioctl(fd, ev_ioc_g_abs(ABS_MT_POSITION_X), &mut x_info);
        if ret < 0 {
            println!("Couldn't get ABS_MT_POSITION_X info {} {}", ret, errno());
        }
    }
    unsafe {
        let ret = ioctl(fd, ev_ioc_g_abs(ABS_MT_POSITION_Y), &mut y_info);
        if ret < 0 {
            println!("Couldn't get ABS_MT_POSITION_Y info {} {}", ret, errno());
        }
    }

    let touchWidth = x_info.maximum - x_info.minimum;
    let touchHeight = y_info.maximum - y_info.minimum;

    println!("xMin: {}, yMin: {}, touchWidth: {}, touchHeight: {}", x_info.minimum, y_info.minimum, touchWidth, touchHeight);

    // XXX: Why isn't size_of treated as constant?
    // let buf: [u8; (16 * size_of::<linux_input_event>())];
    let mut buf: [u8; (16 * 16)] = unsafe { zeroed() };
    let mut slots: [InputSlot; 10] = unsafe { zeroed() };
    for slot in slots.iter_mut() {
        slot.tracking_id = -1;
    }

    let mut last_x = 0;
    let mut last_y = 0;
    let mut first_x = 0;
    let mut first_y = 0;

    let mut last_dist: f32 = 0f32;
    let mut touch_count: i32 = 0;
    let mut current_slot: uint = 0;
    // XXX: Need to use the real dimensions of the screen
    let screen_dist = dist(0, 480, 854, 0);
    loop {
        let read = match device.read(buf.as_mut_slice()) {
            Ok(count) => {
                assert!(count % size_of::<linux_input_event>() == 0,
                        "Unexpected input device read length!");
                count
            },
            Err(e) => {
                println!("Couldn't read device! {}", e);
                return;
            }
        };

        let count = read / size_of::<linux_input_event>();
        let events: *mut linux_input_event = unsafe { transmute(buf.as_mut_ptr()) };
        let mut tracking_updated = false;
        for idx in range(0, count as int) {
            let event: &linux_input_event = unsafe { transmute(events.offset(idx)) };
            match (event.evt_type, event.code) {
                (EV_SYN, EV_REPORT) => {
                    let slotA = &slots[0];
                    if tracking_updated {
                        tracking_updated = false;
                        if slotA.tracking_id == -1 {
                            println!("Touch up");
                            let delta_x = slotA.x - first_x;
                            let delta_y = slotA.y - first_y;
                            let dist = delta_x * delta_x + delta_y * delta_y;
                            if dist < 16 {
                                let click_pt = TypedPoint2D(slotA.x as f32, slotA.y as f32);
                                println!("Dispatching click!");
                                sender.send(WindowEvent::MouseWindowEventClass(MouseWindowEvent::MouseDown(0, click_pt))).ok().unwrap();
                                sender.send(WindowEvent::MouseWindowEventClass(MouseWindowEvent::MouseUp(0, click_pt))).ok().unwrap();
                                sender.send(WindowEvent::MouseWindowEventClass(MouseWindowEvent::Click(0, click_pt))).ok().unwrap();
                            }
                        } else {
                            println!("Touch down");
                            last_x = slotA.x;
                            last_y = slotA.y;
                            first_x = slotA.x;
                            first_y = slotA.y;
                            if touch_count >= 2 {
                                let slotB = &slots[1];
                                last_dist = dist(slotA.x, slotB.x, slotA.y, slotB.y);
                            }
                        }
                    } else {
                        println!("Touch move x: {}, y: {}", slotA.x, slotA.y);
                        sender.send(WindowEvent::Scroll(TypedPoint2D((slotA.x - last_x) as f32, (slotA.y - last_y) as f32),
                                                        TypedPoint2D(slotA.x, slotA.y))).ok().unwrap();
                        last_x = slotA.x;
                        last_y = slotA.y;
                        if touch_count >= 2 {
                            let slotB = &slots[1];
                            let cur_dist = dist(slotA.x, slotB.x, slotA.y, slotB.y);
                            println!("Zooming {} {} {} {}", cur_dist, last_dist, screen_dist, ((screen_dist + (cur_dist - last_dist))/screen_dist));
                            sender.send(WindowEvent::Zoom((screen_dist + (cur_dist - last_dist))/screen_dist)).ok().unwrap();
                            last_dist = cur_dist;
                        }
                    }
                },
                (EV_SYN, _) => println!("Unknown SYN code {}", event.code),
                (EV_ABS, ABS_MT_SLOT) => {
                            if (event.value as uint) < slots.len() {
                                current_slot = event.value as uint;
                            } else {
                                println!("Invalid slot! {}", event.value);
                            }
                        },
                (EV_ABS, ABS_MT_TOUCH_MAJOR) => (),
                (EV_ABS, ABS_MT_TOUCH_MINOR) => (),
                (EV_ABS, ABS_MT_WIDTH_MAJOR) => (),
                (EV_ABS, ABS_MT_WIDTH_MINOR) => (),
                (EV_ABS, ABS_MT_ORIENTATION) => (),
                (EV_ABS, ABS_MT_POSITION_X) => {
                    slots[current_slot].x = event.value - x_info.minimum;
                },
                (EV_ABS, ABS_MT_POSITION_Y) => {
                    slots[current_slot].y = event.value - y_info.minimum;
                },
                (EV_ABS, ABS_MT_TRACKING_ID) => {
                    let current_id = slots[current_slot].tracking_id;
                    if current_id != event.value &&
                       (current_id == -1 || event.value == -1) {
                        tracking_updated = true;
                        if event.value == -1 {
                            touch_count -= 1;
                        } else {
                            touch_count += 1;
                        }
                    }
                    slots[current_slot].tracking_id = event.value;
                },
                (EV_ABS, _) => println!("Unknown ABS code {}", event.code),
                (_, _) => println!("Unknown event type {}", event.evt_type),
            }
        }
    }
}

pub fn run_input_loop(event_sender: &Sender<WindowEvent>) {
    let sender = event_sender.clone();
    Thread::spawn(move || {
        // XXX need to scan all devices and read every one.
        let touchinputdev = Path::new("/dev/input/event0");
        read_input_device(&touchinputdev, &sender);
    });
}
<commit_msg>Fix warning in gonk input code<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::path::Path;
use std::mem::size_of;
use std::mem::transmute;
use std::mem::zeroed;
use std::os::errno;
use std::os::unix::AsRawFd;
use std::num::Float;
use std::fs::File;
use std::thread;
use std::sync::mpsc::Sender;
use std::io::Read;

use geom::point::TypedPoint2D;

use libc::c_int;
use libc::c_long;
use libc::time_t;

use compositing::windowing::WindowEvent;
use compositing::windowing::MouseWindowEvent;

extern {
    // XXX: no variadic form in std libs?
    fn ioctl(fd: c_int, req: c_int, ...) -> c_int;
}

#[repr(C)]
struct linux_input_event {
    sec: time_t,
    msec: c_long,
    evt_type: u16,
    code: u16,
    value: i32,
}

#[repr(C)]
struct linux_input_absinfo {
    value: i32,
    minimum: i32,
    maximum: i32,
    fuzz: i32,
    flat: i32,
    resolution: i32,
}

const IOC_NONE: c_int = 0;
const IOC_WRITE: c_int = 1;
const IOC_READ: c_int = 2;

fn ioc(dir: c_int, ioctype: c_int, nr: c_int, size: c_int) -> c_int {
    dir << 30 | size << 16 | ioctype << 8 | nr
}

fn ev_ioc_g_abs(abs: u16) -> c_int {
    ioc(IOC_READ, 'E' as c_int, (0x40 + abs) as i32, size_of::<linux_input_absinfo>() as i32)
}

const EV_SYN: u16 = 0;
const EV_ABS: u16 = 3;

const EV_REPORT: u16 = 0;

const ABS_MT_SLOT: u16 = 0x2F;
const ABS_MT_TOUCH_MAJOR: u16 = 0x30;
const ABS_MT_TOUCH_MINOR: u16 = 0x31;
const ABS_MT_WIDTH_MAJOR: u16 = 0x32;
const ABS_MT_WIDTH_MINOR: u16 = 0x33;
const ABS_MT_ORIENTATION: u16 = 0x34;
const ABS_MT_POSITION_X: u16 = 0x35;
const ABS_MT_POSITION_Y: u16 = 0x36;
const ABS_MT_TRACKING_ID: u16 = 0x39;

struct InputSlot {
    tracking_id: i32,
    x: i32,
    y: i32,
}

fn dist(x1: i32, x2: i32, y1: i32, y2: i32) -> f32 {
    let deltaX = (x2 - x1) as f32;
    let deltaY = (y2 - y1) as f32;
    (deltaX * deltaX + deltaY * deltaY).sqrt()
}

fn read_input_device(device_path: &Path,
                     sender: &Sender<WindowEvent>) {
    let mut device = match File::open(device_path) {
        Ok(dev) => dev,
        Err(e) => {
            println!("Couldn't open device! {}", e);
            return;
        },
    };
    let fd = device.as_raw_fd();

    let mut x_info: linux_input_absinfo = unsafe { zeroed() };
    let mut y_info: linux_input_absinfo = unsafe { zeroed() };
    unsafe {
        let ret = ioctl(fd, ev_ioc_g_abs(ABS_MT_POSITION_X), &mut x_info);
        if ret < 0 {
            println!("Couldn't get ABS_MT_POSITION_X info {} {}", ret, errno());
        }
    }
    unsafe {
        let ret = ioctl(fd, ev_ioc_g_abs(ABS_MT_POSITION_Y), &mut y_info);
        if ret < 0 {
            println!("Couldn't get ABS_MT_POSITION_Y info {} {}", ret, errno());
        }
    }

    let touchWidth = x_info.maximum - x_info.minimum;
    let touchHeight = y_info.maximum - y_info.minimum;

    println!("xMin: {}, yMin: {}, touchWidth: {}, touchHeight: {}", x_info.minimum, y_info.minimum, touchWidth, touchHeight);

    // XXX: Why isn't size_of treated as constant?
    // let buf: [u8; (16 * size_of::<linux_input_event>())];
    let mut buf: [u8; (16 * 16)] = unsafe { zeroed() };
    let mut slots: [InputSlot; 10] = unsafe { zeroed() };
    for slot in slots.iter_mut() {
        slot.tracking_id = -1;
    }

    let mut last_x = 0;
    let mut last_y = 0;
    let mut first_x = 0;
    let mut first_y = 0;

    let mut last_dist: f32 = 0f32;
    let mut touch_count: i32 = 0;
    let mut current_slot: uint = 0;
    // XXX: Need to use the real dimensions of the screen
    let screen_dist = dist(0, 480, 854, 0);
    loop {
        let read = match device.read(buf.as_mut_slice()) {
            Ok(count) => {
                assert!(count % size_of::<linux_input_event>() == 0,
                        "Unexpected input device read length!");
                count
            },
            Err(e) => {
                println!("Couldn't read device! {}", e);
                return;
            }
        };

        let count = read / size_of::<linux_input_event>();
        let events: *mut linux_input_event = unsafe { transmute(buf.as_mut_ptr()) };
        let mut tracking_updated = false;
        for idx in range(0, count as int) {
            let event: &linux_input_event = unsafe { transmute(events.offset(idx)) };
            match (event.evt_type, event.code) {
                (EV_SYN, EV_REPORT) => {
                    let slotA = &slots[0];
                    if tracking_updated {
                        tracking_updated = false;
                        if slotA.tracking_id == -1 {
                            println!("Touch up");
                            let delta_x = slotA.x - first_x;
                            let delta_y = slotA.y - first_y;
                            let dist = delta_x * delta_x + delta_y * delta_y;
                            if dist < 16 {
                                let click_pt = TypedPoint2D(slotA.x as f32, slotA.y as f32);
                                println!("Dispatching click!");
                                sender.send(WindowEvent::MouseWindowEventClass(MouseWindowEvent::MouseDown(0, click_pt))).ok().unwrap();
                                sender.send(WindowEvent::MouseWindowEventClass(MouseWindowEvent::MouseUp(0, click_pt))).ok().unwrap();
                                sender.send(WindowEvent::MouseWindowEventClass(MouseWindowEvent::Click(0, click_pt))).ok().unwrap();
                            }
                        } else {
                            println!("Touch down");
                            last_x = slotA.x;
                            last_y = slotA.y;
                            first_x = slotA.x;
                            first_y = slotA.y;
                            if touch_count >= 2 {
                                let slotB = &slots[1];
                                last_dist = dist(slotA.x, slotB.x, slotA.y, slotB.y);
                            }
                        }
                    } else {
                        println!("Touch move x: {}, y: {}", slotA.x, slotA.y);
                        sender.send(WindowEvent::Scroll(TypedPoint2D((slotA.x - last_x) as f32, (slotA.y - last_y) as f32),
                                                        TypedPoint2D(slotA.x, slotA.y))).ok().unwrap();
                        last_x = slotA.x;
                        last_y = slotA.y;
                        if touch_count >= 2 {
                            let slotB = &slots[1];
                            let cur_dist = dist(slotA.x, slotB.x, slotA.y, slotB.y);
                            println!("Zooming {} {} {} {}", cur_dist, last_dist, screen_dist, ((screen_dist + (cur_dist - last_dist))/screen_dist));
                            sender.send(WindowEvent::Zoom((screen_dist + (cur_dist - last_dist))/screen_dist)).ok().unwrap();
                            last_dist = cur_dist;
                        }
                    }
                },
                (EV_SYN, _) => println!("Unknown SYN code {}", event.code),
                (EV_ABS, ABS_MT_SLOT) => {
                            if (event.value as uint) < slots.len() {
                                current_slot = event.value as uint;
                            } else {
                                println!("Invalid slot! {}", event.value);
                            }
                        },
                (EV_ABS, ABS_MT_TOUCH_MAJOR) => (),
                (EV_ABS, ABS_MT_TOUCH_MINOR) => (),
                (EV_ABS, ABS_MT_WIDTH_MAJOR) => (),
                (EV_ABS, ABS_MT_WIDTH_MINOR) => (),
                (EV_ABS, ABS_MT_ORIENTATION) => (),
                (EV_ABS, ABS_MT_POSITION_X) => {
                    slots[current_slot].x = event.value - x_info.minimum;
                },
                (EV_ABS, ABS_MT_POSITION_Y) => {
                    slots[current_slot].y = event.value - y_info.minimum;
                },
                (EV_ABS, ABS_MT_TRACKING_ID) => {
                    let current_id = slots[current_slot].tracking_id;
                    if current_id != event.value &&
                       (current_id == -1 || event.value == -1) {
                        tracking_updated = true;
                        if event.value == -1 {
                            touch_count -= 1;
                        } else {
                            touch_count += 1;
                        }
                    }
                    slots[current_slot].tracking_id = event.value;
                },
                (EV_ABS, _) => println!("Unknown ABS code {}", event.code),
                (_, _) => println!("Unknown event type {}", event.evt_type),
            }
        }
    }
}

pub fn run_input_loop(event_sender: &Sender<WindowEvent>) {
    let sender = event_sender.clone();
    thread::spawn(move || {
        // XXX need to scan all devices and read every one.
        let touchinputdev = Path::new("/dev/input/event0");
        read_input_device(&touchinputdev, &sender);
    });
}
<|endoftext|>


<commit_before>use crate::ty::context::TyCtxt;
use crate::ty::{DefId, DefIdTree};
use rustc_hir::CRATE_HIR_ID;
use smallvec::SmallVec;
use std::mem;

/// Represents a forest of `DefId`s closed under the ancestor relation. That is,
/// if a `DefId` representing a module is contained in the forest then all
/// `DefId`s defined in that module or submodules are also implicitly contained
/// in the forest.
///
/// This is used to represent a set of modules in which a type is visibly
/// uninhabited.
#[derive(Clone)]
pub struct DefIdForest {
    /// The minimal set of `DefId`s required to represent the whole set.
    /// If A and B are DefIds in the `DefIdForest`, and A is a descendant
    /// of B, then only B will be in `root_ids`.
    /// We use a `SmallVec` here because (for its use for caching inhabitedness)
    /// its rare that this will contain even two IDs.
    root_ids: SmallVec<[DefId; 1]>,
}

impl<'tcx> DefIdForest {
    /// Creates an empty forest.
    pub fn empty() -> DefIdForest {
        DefIdForest { root_ids: SmallVec::new() }
    }

    /// Creates a forest consisting of a single tree representing the entire
    /// crate.
    #[inline]
    pub fn full(tcx: TyCtxt<'tcx>) -> DefIdForest {
        let crate_id = tcx.hir().local_def_id(CRATE_HIR_ID);
        DefIdForest::from_id(crate_id.to_def_id())
    }

    /// Creates a forest containing a `DefId` and all its descendants.
    pub fn from_id(id: DefId) -> DefIdForest {
        let mut root_ids = SmallVec::new();
        root_ids.push(id);
        DefIdForest { root_ids }
    }

    /// Tests whether the forest is empty.
    pub fn is_empty(&self) -> bool {
        self.root_ids.is_empty()
    }

    /// Tests whether the forest contains a given DefId.
    pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool {
        self.root_ids.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
    }

    /// Calculate the intersection of a collection of forests.
    pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
    where
        I: IntoIterator<Item = DefIdForest>,
    {
        let mut iter = iter.into_iter();
        let mut ret = if let Some(first) = iter.next() {
            first
        } else {
            return DefIdForest::full(tcx);
        };

        let mut next_ret = SmallVec::new();
        let mut old_ret: SmallVec<[DefId; 1]> = SmallVec::new();
        for next_forest in iter {
            // No need to continue if the intersection is already empty.
            if ret.is_empty() {
                break;
            }

            for id in ret.root_ids.drain(..) {
                if next_forest.contains(tcx, id) {
                    next_ret.push(id);
                } else {
                    old_ret.push(id);
                }
            }
            ret.root_ids.extend(old_ret.drain(..));

            next_ret.extend(next_forest.root_ids.into_iter().filter(|&id| ret.contains(tcx, id)));

            mem::swap(&mut next_ret, &mut ret.root_ids);
            next_ret.drain(..);
        }
        ret
    }

    /// Calculate the union of a collection of forests.
    pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
    where
        I: IntoIterator<Item = DefIdForest>,
    {
        let mut ret = DefIdForest::empty();
        let mut next_ret = SmallVec::new();
        for next_forest in iter {
            next_ret.extend(ret.root_ids.drain(..).filter(|&id| !next_forest.contains(tcx, id)));

            for id in next_forest.root_ids {
                if !next_ret.contains(&id) {
                    next_ret.push(id);
                }
            }

            mem::swap(&mut next_ret, &mut ret.root_ids);
            next_ret.drain(..);
        }
        ret
    }
}
<commit_msg>Fix typo<commit_after>use crate::ty::context::TyCtxt;
use crate::ty::{DefId, DefIdTree};
use rustc_hir::CRATE_HIR_ID;
use smallvec::SmallVec;
use std::mem;

/// Represents a forest of `DefId`s closed under the ancestor relation. That is,
/// if a `DefId` representing a module is contained in the forest then all
/// `DefId`s defined in that module or submodules are also implicitly contained
/// in the forest.
///
/// This is used to represent a set of modules in which a type is visibly
/// uninhabited.
#[derive(Clone)]
pub struct DefIdForest {
    /// The minimal set of `DefId`s required to represent the whole set.
    /// If A and B are DefIds in the `DefIdForest`, and A is a descendant
    /// of B, then only B will be in `root_ids`.
    /// We use a `SmallVec` here because (for its use for caching inhabitedness)
    /// it's rare that this will contain even two IDs.
    root_ids: SmallVec<[DefId; 1]>,
}

impl<'tcx> DefIdForest {
    /// Creates an empty forest.
    pub fn empty() -> DefIdForest {
        DefIdForest { root_ids: SmallVec::new() }
    }

    /// Creates a forest consisting of a single tree representing the entire
    /// crate.
    #[inline]
    pub fn full(tcx: TyCtxt<'tcx>) -> DefIdForest {
        let crate_id = tcx.hir().local_def_id(CRATE_HIR_ID);
        DefIdForest::from_id(crate_id.to_def_id())
    }

    /// Creates a forest containing a `DefId` and all its descendants.
    pub fn from_id(id: DefId) -> DefIdForest {
        let mut root_ids = SmallVec::new();
        root_ids.push(id);
        DefIdForest { root_ids }
    }

    /// Tests whether the forest is empty.
    pub fn is_empty(&self) -> bool {
        self.root_ids.is_empty()
    }

    /// Tests whether the forest contains a given DefId.
    pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool {
        self.root_ids.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
    }

    /// Calculate the intersection of a collection of forests.
    pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
    where
        I: IntoIterator<Item = DefIdForest>,
    {
        let mut iter = iter.into_iter();
        let mut ret = if let Some(first) = iter.next() {
            first
        } else {
            return DefIdForest::full(tcx);
        };

        let mut next_ret = SmallVec::new();
        let mut old_ret: SmallVec<[DefId; 1]> = SmallVec::new();
        for next_forest in iter {
            // No need to continue if the intersection is already empty.
            if ret.is_empty() {
                break;
            }

            for id in ret.root_ids.drain(..) {
                if next_forest.contains(tcx, id) {
                    next_ret.push(id);
                } else {
                    old_ret.push(id);
                }
            }
            ret.root_ids.extend(old_ret.drain(..));

            next_ret.extend(next_forest.root_ids.into_iter().filter(|&id| ret.contains(tcx, id)));

            mem::swap(&mut next_ret, &mut ret.root_ids);
            next_ret.drain(..);
        }
        ret
    }

    /// Calculate the union of a collection of forests.
    pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
    where
        I: IntoIterator<Item = DefIdForest>,
    {
        let mut ret = DefIdForest::empty();
        let mut next_ret = SmallVec::new();
        for next_forest in iter {
            next_ret.extend(ret.root_ids.drain(..).filter(|&id| !next_forest.contains(tcx, id)));

            for id in next_forest.root_ids {
                if !next_ret.contains(&id) {
                    next_ret.push(id);
                }
            }

            mem::swap(&mut next_ret, &mut ret.root_ids);
            next_ret.drain(..);
        }
        ret
    }
}
<|endoftext|>


<commit_before>// xfail-test
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

struct X {
    x: ~str,
}

impl Drop for X {
    fn finalize(&self) {
        error!("value: %s", self.x);
    }
}

fn unwrap(x: X) -> ~str {
    let X { x: y } = x; //~ ERROR cannot bind by-move within struct
    y
}

fn main() {
    let x = X { x: ~"hello" };
    let y = unwrap(x);
    error!("contents: %s", y);
}
<commit_msg>Issue number on xfailed test<commit_after>// xfail-test #3024
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

struct X {
    x: ~str,
}

impl Drop for X {
    fn finalize(&self) {
        error!("value: %s", self.x);
    }
}

fn unwrap(x: X) -> ~str {
    let X { x: y } = x; //~ ERROR cannot bind by-move within struct
    y
}

fn main() {
    let x = X { x: ~"hello" };
    let y = unwrap(x);
    error!("contents: %s", y);
}
<|endoftext|>


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

//! Simple efficient composable primitives for pretty printing.
//!
//! The implementation is derived from the paper ["A New Approach to Optimal
//! Code Formatting"][pp-paper] by Phillip M. Yelland.
//!
//! [pp-paper]: https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/44667.pdf

extern crate unicode_width;

mod knot_column;
mod knot_set;
mod linear_value;
mod resolved_layout;
mod shared_string;

use std::borrow::Borrow;
use std::collections as col;
use std::fmt;
use std::rc;

use self::shared_string::SharedString;

const OVERFLOW_COST: f32 = 100.0;
const NEWLINE_COST: f32 = 1.0;

/// The primary representation of pretty-printed text. Logically, it represents
/// a set of possible permissible layouts of text.
///
/// Layouts are constructed with four different primitives:
///
/// 1. Text
///
///    A literal string which is laid out as written. Its length is obtained
/// using the    `unicode-width` package.
///
/// 2. Stack
///
///    Vertically stacks two layouts. The left margins of the two layouts will
///    be aligned.
///
/// 3. Juxtapose
///
///    Horizontally juxtapose two layouts. The left margin of the second layout
///    will be aligned with the end of the first layout's last line.
///
/// 4. Choice
///
///    Creates a choice between two or more layouts. The choice is made at
/// layout    time based on the cost of each possible layout. See the `layout`
/// method.
#[derive(Clone)]
pub struct Layout(rc::Rc<LayoutContents>);

impl Layout {
  fn with_contents(contents: LayoutContents) -> Layout {
    Layout(rc::Rc::new(contents))
  }

  fn contents(&self) -> &LayoutContents {
    &*self.0
  }

  /// Create a text layout value. This is a literal string with no layout
  /// variance.
  pub fn text(lit_text: impl Into<String>) -> Layout {
    Layout::with_contents(LayoutContents::Text(lit_text.into().into()))
  }

  fn choice_pair(first: &Layout, second: &Layout) -> Layout {
    // We should canonicalize this so that the choices are always in the same
    // order.
    Layout::with_contents(LayoutContents::Choice(first.clone(), second.clone()))
  }

  fn stack_pair(top: &Layout, bottom: &Layout) -> Layout {
    Layout::with_contents(LayoutContents::Stack(top.clone(), bottom.clone()))
  }

  /// Create a layout that is the juxtaposition of two other layouts.
  ///
  /// This lays out the latter layout immediately to the right of the last line
  /// of the left layout.
  pub fn juxtapose_pair(left: &Layout, right: &Layout) -> Layout {
    let mut builder = JuxtaposeBuilder::new(right);
    builder.juxtapose(left)
  }

  /// Creates a layout that is the lowest-cost choice of layouts provided.
  pub fn choices<S, T>(items: S) -> Layout
  where
    S: AsRef<[T]>,
    T: Borrow<Layout>,
  {
    let items = items.as_ref();
    assert!(items.len() > 0);
    let mut curr_layout = items[0].borrow().clone();
    for item in &items[1..] {
      curr_layout = Layout::choice_pair(&curr_layout, item.borrow());
    }

    curr_layout
  }

  /// Create a stack of the layouts, where each of the layouts are
  /// vertically stacked on top of each other in the order provided.
  pub fn stack<'a, S, T>(items: S) -> Layout
  where
    S: AsRef<[T]>,
    T: Borrow<Layout>,
  {
    let items = items.as_ref();
    if items.len() == 0 {
      return Layout::text("");
    }
    assert!(items.len() > 0);
    let mut curr_layout = items[0].borrow().clone();
    for item in &items[1..] {
      curr_layout = Layout::stack_pair(&curr_layout, item.borrow());
    }
    curr_layout
  }

  /// Creates a juxtoposition of layouts, with each layout immediately
  /// following the last line of the previous layout.
  pub fn juxtapose<S, T>(items: S) -> Layout
  where
    S: AsRef<[T]>,
    T: Borrow<Layout>,
  {
    let items = items.as_ref();
    assert!(items.len() > 0);
    let mut curr_layout = items[0].borrow().clone();
    for item in &items[1..] {
      curr_layout = Layout::juxtapose_pair(&curr_layout, item.borrow());
    }
    curr_layout
  }

  /// Lays out the contents of this layout for a text buffer of width margin.
  pub fn layout(&self, margin: u16) -> String {
    self.layout_with_costs(margin, OVERFLOW_COST, NEWLINE_COST)
  }

  /// Lays out the contents of this layout for a text buffer of width margin,
  /// and with newline costs and overflow costs as provided.
  ///
  /// For each character over the margin width, the overflow cost is incurred.
  /// For each newline in the result, the newline cost is incurred. The layout
  /// chosen is that with the smallest overall cost.
  pub fn layout_with_costs(
    &self,
    margin: u16,
    overflow_cost: f32,
    newline_cost: f32,
  ) -> String {
    let final_layout =
      knot_set::do_layout(self, overflow_cost, newline_cost, margin);
    return final_layout.to_text(0);
  }

  #[doc(hidden)]
  pub fn debug_num_nodes(&self) -> usize {
    let mut counter = NodeCounter::new();
    counter.visit_node(self);
    counter.get_count()
  }

  fn wrap_inner<T: Borrow<Layout>>(
    layouts: &[T],
  ) -> (Layout, Vec<(Layout, Option<Layout>)>) {
    if layouts.len() == 0 {
      (Layout::text(""), vec![])
    } else if layouts.len() == 1 {
      let singleton = layouts[0].borrow();
      (
        singleton.borrow().clone(),
        vec![(singleton.borrow().clone(), None)],
      )
    } else {
      let first = layouts[0].borrow();
      let rest = &layouts[1..];
      let (block, line_blocks) = Layout::wrap_inner(rest);

      let mut new_line_pairs: Vec<_> = line_blocks
        .into_iter()
        .map(|(l, b)| {
          (
            Layout::juxtapose(&[first.borrow(), &Layout::text(" "), &l]),
            b,
          )
        })
        .collect();
      new_line_pairs.push((first.borrow().clone(), Some(block)));

      let new_choices: Vec<_> = new_line_pairs
        .iter()
        .map(|(k, v)| match v {
          Some(b) => Layout::stack_pair(k, b),
          None => k.clone(),
        })
        .collect();

      (Layout::choices(&new_choices), new_line_pairs)
    }
  }

  pub fn wrap<S, T>(layouts: S) -> Layout
  where
    S: AsRef<[T]>,
    T: Borrow<Layout>,
  {
    let slice = layouts.as_ref();
    let (result, _) = Layout::wrap_inner(slice);
    result
  }
}

impl fmt::Debug for Layout {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    <LayoutContents as fmt::Debug>::fmt(&*self.0, f)
  }
}

#[derive(Debug)]
enum LayoutContents {
  Text(SharedString),
  Choice(Layout, Layout),
  Stack(Layout, Layout),
  Juxtapose(SharedString, Layout),
}

struct JuxtaposeBuilder {
  right: Layout,
  memo: col::BTreeMap<*const LayoutContents, Layout>,
}

impl JuxtaposeBuilder {
  fn new(right: &Layout) -> Self {
    JuxtaposeBuilder {
      right: right.clone(),
      memo: col::BTreeMap::new(),
    }
  }

  fn juxtapose(&mut self, left: &Layout) -> Layout {
    if let Some(v) = self.memo.get(&(left.contents() as *const LayoutContents))
    {
      return v.clone();
    }

    let new_layout = match left.contents() {
      LayoutContents::Text(t) => Layout::with_contents(
        LayoutContents::Juxtapose(t.clone(), self.right.clone()),
      ),
      LayoutContents::Choice(first, second) => Layout::with_contents(
        LayoutContents::Choice(self.juxtapose(first), self.juxtapose(second)),
      ),
      LayoutContents::Stack(top, bottom) => Layout::with_contents(
        LayoutContents::Stack(top.clone(), self.juxtapose(bottom)),
      ),
      LayoutContents::Juxtapose(text, jux_right) => Layout::with_contents(
        LayoutContents::Juxtapose(text.clone(), self.juxtapose(jux_right)),
      ),
    };

    self
      .memo
      .insert(left.contents() as *const LayoutContents, new_layout.clone());
    new_layout
  }
}

struct NodeCounter {
  seen: col::BTreeSet<*const LayoutContents>,
}

impl NodeCounter {
  fn new() -> Self {
    NodeCounter {
      seen: col::BTreeSet::new(),
    }
  }
  fn visit_node(&mut self, layout: &Layout) {
    if self.seen.insert(layout.contents() as *const LayoutContents) {
      use self::LayoutContents::*;
      match layout.contents() {
        Text(_) => {}
        Choice(first, second) => {
          self.visit_node(first);
          self.visit_node(second);
        }
        Stack(top, bottom) => {
          self.visit_node(top);
          self.visit_node(bottom);
        }
        Juxtapose(_left, right) => {
          self.visit_node(right);
        }
      }
    }
  }

  fn get_count(&self) -> usize {
    self.seen.len()
  }
}

#[cfg(test)]
mod test {
  use super::Layout;

  #[test]
  fn test_simple_set() {
    let foo = Layout::text("foo");
    let pair = Layout::juxtapose(&[&foo, &foo]);
    assert_eq!(pair.layout(10), "foofoo");
  }

  #[test]
  fn test_simple_stack() {
    let foo = Layout::text("foo");
    let pair = Layout::stack(&[&foo, &foo]);
    assert_eq!(pair.layout(10), "foo\nfoo");
  }

  #[test]
  fn test_simple_choice() {
    let foo = Layout::text("foo");
    let pair = Layout::choices(&[
      &Layout::juxtapose(&[&foo, &foo]),
      &Layout::stack(&[&foo, &foo]),
    ]);
    assert_eq!(pair.layout(10), "foofoo");
    assert_eq!(pair.layout(4), "foo\nfoo");
  }

  #[test]
  fn test_wrap() {
    let lorem = &"Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    Nullam suscipit dolor sed dolor facilisis ultrices ut id nisl. Nam
    malesuada malesuada dolor, eget dapibus nibh euismod at. Vestibulum
    aliquam aliquam mi at tincidunt. Sed imperdiet eget purus in egestas.
    Suspendisse id odio in augue cursus tempor. Duis imperdiet imperdiet eros
    et lobortis. Vestibulum vestibulum condimentum dui, sit amet fringilla libero
    commodo at. Sed aliquam mauris vitae egestas convallis. Integer sed est vitae
    nibh pellentesque sodales. Suspendisse sit amet dignissim arcu. Quisque hendrerit
    pellentesque egestas. Nulla at elementum est. Maecenas lectus turpis, placerat
    vitae est sit amet, mattis pharetra orci. Praesent.";
    let words: Vec<_> =
      lorem.split_whitespace().map(|k| Layout::text(k)).collect();
    let layout = Layout::wrap(words);
    println!("{}", layout.debug_num_nodes());
    assert_eq!(layout.layout(80).chars().filter(|c| c == &'\n').count(), 9);
    assert_eq!(layout.layout(100).chars().filter(|c| c == &'\n').count(), 7);
  }

  #[test]
  fn test_large_stack() {
    let foo = Layout::text("foo");
    let bar = Layout::text("bar");
    let foo_stack = Layout::stack(&[&foo, &bar]);
    let foo_jux = Layout::juxtapose(&[&foo, &bar]);
    let foo_choice = Layout::choices(&[&foo_stack, &foo_jux]);

    let choice = Layout::juxtapose(&vec![&foo_choice; 1000]);

    println!("Done creating layout.");
    println!("Num nodes: {}", choice.debug_num_nodes());

    choice.layout(500);
  }
}
<commit_msg>Revert "Remove configuration flag to make the code compatible with Rust 1.31"<commit_after>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(uniform_paths)]
//! Simple efficient composable primitives for pretty printing.
//!
//! The implementation is derived from the paper ["A New Approach to Optimal
//! Code Formatting"][pp-paper] by Phillip M. Yelland.
//!
//! [pp-paper]: https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/44667.pdf

extern crate unicode_width;

mod knot_column;
mod knot_set;
mod linear_value;
mod resolved_layout;
mod shared_string;

use std::borrow::Borrow;
use std::collections as col;
use std::fmt;
use std::rc;

use shared_string::SharedString;

const OVERFLOW_COST: f32 = 100.0;
const NEWLINE_COST: f32 = 1.0;

/// The primary representation of pretty-printed text. Logically, it represents
/// a set of possible permissible layouts of text.
///
/// Layouts are constructed with four different primitives:
///
/// 1. Text
///
///    A literal string which is laid out as written. Its length is obtained
/// using the    `unicode-width` package.
///
/// 2. Stack
///
///    Vertically stacks two layouts. The left margins of the two layouts will
/// be    aligned.
///
/// 3. Juxtapose
///
///    Horizontally juxtapose two layouts. The left margin of the second layout
///    will be aligned with the end of the first layout's last line.
///
/// 4. Choice
///
///    Creates a choice between two or more layouts. The choice is made at
/// layout    time based on the cost of each possible layout. See the `layout`
/// method.
#[derive(Clone)]
pub struct Layout(rc::Rc<LayoutContents>);

impl Layout {
  fn with_contents(contents: LayoutContents) -> Layout {
    Layout(rc::Rc::new(contents))
  }

  fn contents(&self) -> &LayoutContents {
    &*self.0
  }

  /// Create a text layout value. This is a literal string with no layout
  /// variance.
  pub fn text(lit_text: impl Into<String>) -> Layout {
    Layout::with_contents(LayoutContents::Text(lit_text.into().into()))
  }

  fn choice_pair(first: &Layout, second: &Layout) -> Layout {
    // We should canonicalize this so that the choices are always in the same
    // order.
    Layout::with_contents(LayoutContents::Choice(first.clone(), second.clone()))
  }

  fn stack_pair(top: &Layout, bottom: &Layout) -> Layout {
    Layout::with_contents(LayoutContents::Stack(top.clone(), bottom.clone()))
  }

  /// Create a layout that is the juxtaposition of two other layouts.
  ///
  /// This lays out the latter layout immediately to the right of the last line
  /// of the left layout.
  pub fn juxtapose_pair(left: &Layout, right: &Layout) -> Layout {
    let mut builder = JuxtaposeBuilder::new(right);
    builder.juxtapose(left)
  }

  /// Creates a layout that is the lowest-cost choice of layouts provided.
  pub fn choices<S, T>(items: S) -> Layout
  where
    S: AsRef<[T]>,
    T: Borrow<Layout>,
  {
    let items = items.as_ref();
    assert!(items.len() > 0);
    let mut curr_layout = items[0].borrow().clone();
    for item in &items[1..] {
      curr_layout = Layout::choice_pair(&curr_layout, item.borrow());
    }

    curr_layout
  }

  /// Create a stack of the layouts, where each of the layouts are
  /// vertically stacked on top of each other in the order provided.
  pub fn stack<'a, S, T>(items: S) -> Layout
  where
    S: AsRef<[T]>,
    T: Borrow<Layout>,
  {
    let items = items.as_ref();
    if items.len() == 0 {
      return Layout::text("");
    }
    assert!(items.len() > 0);
    let mut curr_layout = items[0].borrow().clone();
    for item in &items[1..] {
      curr_layout = Layout::stack_pair(&curr_layout, item.borrow());
    }
    curr_layout
  }

  /// Creates a juxtoposition of layouts, with each layout immediately
  /// following the last line of the previous layout.
  pub fn juxtapose<S, T>(items: S) -> Layout
  where
    S: AsRef<[T]>,
    T: Borrow<Layout>,
  {
    let items = items.as_ref();
    assert!(items.len() > 0);
    let mut curr_layout = items[0].borrow().clone();
    for item in &items[1..] {
      curr_layout = Layout::juxtapose_pair(&curr_layout, item.borrow());
    }
    curr_layout
  }

  /// Lays out the contents of this layout for a text buffer of width margin.
  pub fn layout(&self, margin: u16) -> String {
    self.layout_with_costs(margin, OVERFLOW_COST, NEWLINE_COST)
  }

  /// Lays out the contents of this layout for a text buffer of width margin,
  /// and with newline costs and overflow costs as provided.
  ///
  /// For each character over the margin width, the overflow cost is incurred.
  /// For each newline in the result, the newline cost is incurred. The layout
  /// chosen is that with the smallest overall cost.
  pub fn layout_with_costs(
    &self,
    margin: u16,
    overflow_cost: f32,
    newline_cost: f32,
  ) -> String {
    let final_layout =
      knot_set::do_layout(self, overflow_cost, newline_cost, margin);
    return final_layout.to_text(0);
  }

  #[doc(hidden)]
  pub fn debug_num_nodes(&self) -> usize {
    let mut counter = NodeCounter::new();
    counter.visit_node(self);
    counter.get_count()
  }

  fn wrap_inner<T: Borrow<Layout>>(
    layouts: &[T],
  ) -> (Layout, Vec<(Layout, Option<Layout>)>) {
    if layouts.len() == 0 {
      (Layout::text(""), vec![])
    } else if layouts.len() == 1 {
      let singleton = layouts[0].borrow();
      (
        singleton.borrow().clone(),
        vec![(singleton.borrow().clone(), None)],
      )
    } else {
      let first = layouts[0].borrow();
      let rest = &layouts[1..];
      let (block, line_blocks) = Layout::wrap_inner(rest);

      let mut new_line_pairs: Vec<_> = line_blocks
        .into_iter()
        .map(|(l, b)| {
          (
            Layout::juxtapose(&[first.borrow(), &Layout::text(" "), &l]),
            b,
          )
        })
        .collect();
      new_line_pairs.push((first.borrow().clone(), Some(block)));

      let new_choices: Vec<_> = new_line_pairs
        .iter()
        .map(|(k, v)| match v {
          Some(b) => Layout::stack_pair(k, b),
          None => k.clone(),
        })
        .collect();

      (Layout::choices(&new_choices), new_line_pairs)
    }
  }

  pub fn wrap<S, T>(layouts: S) -> Layout
  where
    S: AsRef<[T]>,
    T: Borrow<Layout>,
  {
    let slice = layouts.as_ref();
    let (result, _) = Layout::wrap_inner(slice);
    result
  }
}

impl fmt::Debug for Layout {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    <LayoutContents as fmt::Debug>::fmt(&*self.0, f)
  }
}

#[derive(Debug)]
enum LayoutContents {
  Text(SharedString),
  Choice(Layout, Layout),
  Stack(Layout, Layout),
  Juxtapose(SharedString, Layout),
}

struct JuxtaposeBuilder {
  right: Layout,
  memo: col::BTreeMap<*const LayoutContents, Layout>,
}

impl JuxtaposeBuilder {
  fn new(right: &Layout) -> Self {
    JuxtaposeBuilder {
      right: right.clone(),
      memo: col::BTreeMap::new(),
    }
  }

  fn juxtapose(&mut self, left: &Layout) -> Layout {
    if let Some(v) = self.memo.get(&(left.contents() as *const LayoutContents))
    {
      return v.clone();
    }

    let new_layout = match left.contents() {
      LayoutContents::Text(t) => Layout::with_contents(
        LayoutContents::Juxtapose(t.clone(), self.right.clone()),
      ),
      LayoutContents::Choice(first, second) => Layout::with_contents(
        LayoutContents::Choice(self.juxtapose(first), self.juxtapose(second)),
      ),
      LayoutContents::Stack(top, bottom) => Layout::with_contents(
        LayoutContents::Stack(top.clone(), self.juxtapose(bottom)),
      ),
      LayoutContents::Juxtapose(text, jux_right) => Layout::with_contents(
        LayoutContents::Juxtapose(text.clone(), self.juxtapose(jux_right)),
      ),
    };

    self
      .memo
      .insert(left.contents() as *const LayoutContents, new_layout.clone());
    new_layout
  }
}

struct NodeCounter {
  seen: col::BTreeSet<*const LayoutContents>,
}

impl NodeCounter {
  fn new() -> Self {
    NodeCounter {
      seen: col::BTreeSet::new(),
    }
  }
  fn visit_node(&mut self, layout: &Layout) {
    if self.seen.insert(layout.contents() as *const LayoutContents) {
      use LayoutContents::*;
      match layout.contents() {
        Text(_) => {}
        Choice(first, second) => {
          self.visit_node(first);
          self.visit_node(second);
        }
        Stack(top, bottom) => {
          self.visit_node(top);
          self.visit_node(bottom);
        }
        Juxtapose(_left, right) => {
          self.visit_node(right);
        }
      }
    }
  }

  fn get_count(&self) -> usize {
    self.seen.len()
  }
}

#[cfg(test)]
mod test {
  use super::Layout;

  #[test]
  fn test_simple_set() {
    let foo = Layout::text("foo");
    let pair = Layout::juxtapose(&[&foo, &foo]);
    assert_eq!(pair.layout(10), "foofoo");
  }

  #[test]
  fn test_simple_stack() {
    let foo = Layout::text("foo");
    let pair = Layout::stack(&[&foo, &foo]);
    assert_eq!(pair.layout(10), "foo\nfoo");
  }

  #[test]
  fn test_simple_choice() {
    let foo = Layout::text("foo");
    let pair = Layout::choices(&[
      &Layout::juxtapose(&[&foo, &foo]),
      &Layout::stack(&[&foo, &foo]),
    ]);
    assert_eq!(pair.layout(10), "foofoo");
    assert_eq!(pair.layout(4), "foo\nfoo");
  }

  #[test]
  fn test_wrap() {
    let lorem = &"Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    Nullam suscipit dolor sed dolor facilisis ultrices ut id nisl. Nam
    malesuada malesuada dolor, eget dapibus nibh euismod at. Vestibulum
    aliquam aliquam mi at tincidunt. Sed imperdiet eget purus in egestas.
    Suspendisse id odio in augue cursus tempor. Duis imperdiet imperdiet eros
    et lobortis. Vestibulum vestibulum condimentum dui, sit amet fringilla libero
    commodo at. Sed aliquam mauris vitae egestas convallis. Integer sed est vitae
    nibh pellentesque sodales. Suspendisse sit amet dignissim arcu. Quisque hendrerit
    pellentesque egestas. Nulla at elementum est. Maecenas lectus turpis, placerat
    vitae est sit amet, mattis pharetra orci. Praesent.";
    let words: Vec<_> =
      lorem.split_whitespace().map(|k| Layout::text(k)).collect();
    let layout = Layout::wrap(words);
    println!("{}", layout.debug_num_nodes());
    assert_eq!(layout.layout(80).chars().filter(|c| c == &'\n').count(), 9);
    assert_eq!(layout.layout(100).chars().filter(|c| c == &'\n').count(), 7);
  }

  #[test]
  fn test_large_stack() {
    let foo = Layout::text("foo");
    let bar = Layout::text("bar");
    let foo_stack = Layout::stack(&[&foo, &bar]);
    let foo_jux = Layout::juxtapose(&[&foo, &bar]);
    let foo_choice = Layout::choices(&[&foo_stack, &foo_jux]);

    let choice = Layout::juxtapose(&vec![&foo_choice; 1000]);

    println!("Done creating layout.");
    println!("Num nodes: {}", choice.debug_num_nodes());

    choice.layout(500);
  }
}
<|endoftext|>


<commit_before>/*
DIRECTED CONTEXT

In this example we will try to solve the problem:

    A farmer want to cross a river, using a boat with room for two objects.
    With him he has a wolf, a sheep, and some cabbage.
    If not watching, the wolf eats the sheep, and the sheep eats the cabbage.
    Find the a way to cross the river without the farmer loosing any object.

We have 4 objects: Wolf, sheep, cabbage and the boat.
The wolf, sheep and cabbage can be in 3 locations: Side A, boat, side B.
The boat can be in 2 locations: Side A or side B.
This becomes a N-dimensional configuration space of dimensions `[3, 3, 3, 2]`.

A directed context space models how a configuration space can change by moving
one object into another state at a time.
Each position in the space is equivalent to one move.

When we construct a directed context space with dimension `[3, 3, 3, 2]`,
we get 378 moves. These are all possible ways the objects can move ignoring
all physical rules.

There is a rule for context spaces that information that is symmetric
or invariant for one object can be removed without loosing context.
The boat in this case can always move from one side to the other,
regardless the states of other objects.

Therefore, we can reduce the space to `[3, 3, 3]`.

*/

extern crate discrete;

use discrete::*;

fn main() {
    let context: DirectedContext<Data> = Construct::new();

    let object = ["wolf", "sheep", "cabbage", "boat"];
    let side = ["side A", "boat", "side B"];
    let side_map: &[&[usize]] = &[&[0, 1, 2], &[0, 1, 2], &[0, 1, 2], &[0, 2]];
    let dim = vec![3, 3, 3, 2]; /* wolf, sheep, cabbage, boat */
    let count = context.count(&dim);
    for x in 0..count {
        let mut pos = (vec![], 0, 0);
        context.to_pos(&dim, x, &mut pos);

        println!("{:?}", pos);
        print!("the {} ", object[pos.1]);
        print!("went from {} ", side[side_map[pos.1][pos.0[pos.1]]]);
        println!("to {}", side[side_map[pos.1][pos.2]]);

        for i in 0..4 {
            let pos_state = pos.0[i];
            println!("{} is at {}", object[i], side[side_map[i][pos_state]]);
        }
    }
    println!("count {}", count);
}
<commit_msg>Simplified<commit_after>/*
DIRECTED CONTEXT

In this example we will try to solve the problem:

    A farmer want to cross a river, using a boat with room for two objects.
    With him he has a wolf, a sheep, and some cabbage.
    If not watching, the wolf eats the sheep, and the sheep eats the cabbage.
    Find an upper bound of legal moves below 200.

We have 4 objects: Wolf, sheep, cabbage and the boat.
The wolf, sheep and cabbage can be in 3 locations: Side A, boat, side B.
The boat can be in 2 locations: Side A or side B.
This becomes a N-dimensional configuration space of dimensions `[3, 3, 3, 2]`.

A directed context space models how a configuration space can change by moving
one object into another state at a time.
Each position in the space is equivalent to one move.

When we construct a directed context space with dimension `[3, 3, 3, 2]`,
we get 378 moves. These are all possible ways the objects can move ignoring
all physical rules.

There is a rule for context spaces that information that is symmetric
or invariant for one object can be removed without loosing context.
The boat in this case can always move from one side to the other,
regardless the states of other objects.
Therefore, we can reduce the space to `[3, 3, 3]`.
This leaves us with 162 moves.

A side note: The amount of memory needed to store any rules for such a puzzle
is in worst case 162 bits, because each bit can tell us whether a move is legal
or not. This is the same information we get from rules.

*/

extern crate discrete;

use discrete::*;

fn main() {
    let context: DirectedContext<Data> = Construct::new();

    let object = ["wolf", "sheep", "cabbage"];
    let side = ["side A", "boat", "side B"];
    let dim = vec![3, 3, 3]; /* wolf, sheep, cabbage, boat */
    let count = context.count(&dim);
    for x in 0..count {
        let mut pos = (vec![], 0, 0);
        context.to_pos(&dim, x, &mut pos);

        println!("{:?}", pos);
        print!("the {} ", object[pos.1]);
        print!("went from {} ", side[pos.0[pos.1]]);
        println!("to {}", side[pos.2]);

        for i in 0..3 {
            let pos_state = pos.0[i];
            println!("{} is at {}", object[i], side[pos_state]);
        }
    }
    println!("count {}", count);
}
<|endoftext|>