<commit_before>// Copyright 2015 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.

use std::collections::BTreeMap;
use std::path::{Path, PathBuf};

use syntax::ast;
use syntax::codemap;
use syntax::parse::parser;

use utils::contains_skip;

/// List all the files containing modules of a crate.
/// If a file is used twice in a crate, it appears only once.
pub fn list_files<'a>(
    krate: &'a ast::Crate,
    codemap: &codemap::CodeMap,
) -> BTreeMap<PathBuf, &'a ast::Mod> {
    let mut result = BTreeMap::new(); // Enforce file order determinism
    let root_filename: PathBuf = codemap.span_to_filename(krate.span).into();
    list_submodules(
        &krate.module,
        root_filename.parent().unwrap(),
        codemap,
        &mut result,
    );
    result.insert(root_filename, &krate.module);
    result
}

/// Recursively list all external modules included in a module.
fn list_submodules<'a>(
    module: &'a ast::Mod,
    search_dir: &Path,
    codemap: &codemap::CodeMap,
    result: &mut BTreeMap<PathBuf, &'a ast::Mod>,
) {
    debug!("list_submodules: search_dir: {:?}", search_dir);
    for item in &module.items {
        if let ast::ItemKind::Mod(ref sub_mod) = item.node {
            if !contains_skip(&item.attrs) {
                let is_internal =
                    codemap.span_to_filename(item.span) == codemap.span_to_filename(sub_mod.inner);
                let dir_path = if is_internal {
                    search_dir.join(&item.ident.to_string())
                } else {
                    let mod_path = module_file(item.ident, &item.attrs, search_dir, codemap);
                    let dir_path = mod_path.parent().unwrap().to_owned();
                    result.insert(mod_path, sub_mod);
                    dir_path
                };
                list_submodules(sub_mod, &dir_path, codemap, result);
            }
        }
    }
}

/// Find the file corresponding to an external mod
fn module_file(
    id: ast::Ident,
    attrs: &[ast::Attribute],
    dir_path: &Path,
    codemap: &codemap::CodeMap,
) -> PathBuf {
    if let Some(path) = parser::Parser::submod_path_from_attr(attrs, dir_path) {
        return path;
    }

    match parser::Parser::default_submod_path(id, dir_path, codemap).result {
        Ok(parser::ModulePathSuccess { path, .. }) => path,
        Err(_) => panic!("Couldn't find module {}", id),
    }
}
<commit_msg>Prefer unreachable! to panic!<commit_after>// Copyright 2015 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.

use std::collections::BTreeMap;
use std::path::{Path, PathBuf};

use syntax::ast;
use syntax::codemap;
use syntax::parse::parser;

use utils::contains_skip;

/// List all the files containing modules of a crate.
/// If a file is used twice in a crate, it appears only once.
pub fn list_files<'a>(
    krate: &'a ast::Crate,
    codemap: &codemap::CodeMap,
) -> BTreeMap<PathBuf, &'a ast::Mod> {
    let mut result = BTreeMap::new(); // Enforce file order determinism
    let root_filename: PathBuf = codemap.span_to_filename(krate.span).into();
    list_submodules(
        &krate.module,
        root_filename.parent().unwrap(),
        codemap,
        &mut result,
    );
    result.insert(root_filename, &krate.module);
    result
}

/// Recursively list all external modules included in a module.
fn list_submodules<'a>(
    module: &'a ast::Mod,
    search_dir: &Path,
    codemap: &codemap::CodeMap,
    result: &mut BTreeMap<PathBuf, &'a ast::Mod>,
) {
    debug!("list_submodules: search_dir: {:?}", search_dir);
    for item in &module.items {
        if let ast::ItemKind::Mod(ref sub_mod) = item.node {
            if !contains_skip(&item.attrs) {
                let is_internal =
                    codemap.span_to_filename(item.span) == codemap.span_to_filename(sub_mod.inner);
                let dir_path = if is_internal {
                    search_dir.join(&item.ident.to_string())
                } else {
                    let mod_path = module_file(item.ident, &item.attrs, search_dir, codemap);
                    let dir_path = mod_path.parent().unwrap().to_owned();
                    result.insert(mod_path, sub_mod);
                    dir_path
                };
                list_submodules(sub_mod, &dir_path, codemap, result);
            }
        }
    }
}

/// Find the file corresponding to an external mod
fn module_file(
    id: ast::Ident,
    attrs: &[ast::Attribute],
    dir_path: &Path,
    codemap: &codemap::CodeMap,
) -> PathBuf {
    if let Some(path) = parser::Parser::submod_path_from_attr(attrs, dir_path) {
        return path;
    }

    match parser::Parser::default_submod_path(id, dir_path, codemap).result {
        Ok(parser::ModulePathSuccess { path, .. }) => path,
        Err(_) => unreachable!("Couldn't find module {}", id),
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ptr;

use std::ffi::{CString,OsStr};
use std::ops::Deref;
use std::os::unix::io::{RawFd,AsRawFd};

use ::context::{Context};
use ::device::{Device};
use ::error::{Error};
use ::handle::prelude::*;

pub struct MonitorSpec<'a> {
    context: &'a Context,
    monitor: *mut ::ffi::udev_monitor
}

impl<'a> Drop for MonitorSpec<'a> {
    fn drop(&mut self) {
        unsafe {
            ::ffi::udev_monitor_unref(self.monitor);
        }
    }
}

impl<'a> MonitorSpec<'a> {
    pub fn new(context: &'a Context) -> Result<Self,Error> {
        let name = CString::new("udev").unwrap();

        let ptr = try_alloc!(unsafe {
            ::ffi::udev_monitor_new_from_netlink(context.as_ptr(), name.as_ptr())
        });

        Ok(MonitorSpec {
            context: context,
            monitor: ptr
        })
    }

    pub fn match_subsystem<T: AsRef<OsStr>>(&mut self, subsystem: T) -> Result<(),Error> {
        let subsystem = try!(::util::os_str_to_cstring(subsystem));

        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), ptr::null())
        })
    }

    pub fn match_subsystem_devtype<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, subsystem: T, devtype: U) -> Result<(),Error> {
        let subsystem = try!(::util::os_str_to_cstring(subsystem));
        let devtype = try!(::util::os_str_to_cstring(devtype));

        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), devtype.as_ptr())
        })
    }

    pub fn match_tag<T: AsRef<OsStr>>(&mut self, tag: T) -> Result<(),Error> {
        let tag = try!(::util::os_str_to_cstring(tag));

        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_add_match_tag(self.monitor, tag.as_ptr())
        })
    }

    pub fn clear_filters(&mut self) -> Result<(),Error> {
        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_remove(self.monitor)
        })
    }

    pub fn listen(self) -> Result<Monitor<'a>,Error> {
        try!(::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_enable_receiving(self.monitor)
        }));

        Ok(Monitor { spec: self })
    }
}

pub struct Monitor<'a> {
    spec: MonitorSpec<'a>
}

impl<'a> AsRawFd for Monitor<'a> {
    fn as_raw_fd(&self) -> RawFd {
        unsafe {
            ::ffi::udev_monitor_get_fd(self.spec.monitor)
        }
    }
}

impl<'a> Monitor<'a> {
    pub fn receive_event(&mut self) -> Option<MonitorEvent> {
        let device = unsafe {
            ::ffi::udev_monitor_receive_device(self.spec.monitor)
        };

        if device.is_null() {
            None
        }
        else {
            let device = ::device::new(self.spec.context, device);

            Some(MonitorEvent { device: device })
        }
    }
}

#[derive(Debug)]
pub enum EventType {
    Add,
    Change,
    Remove,
    Unknown,
}

impl Default for EventType {
    fn default() -> EventType { EventType::Unknown }
}

impl fmt::Display for EventType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(match self {
            &EventType::Add => "add",
            &EventType::Change => "change",
            &EventType::Remove => "remove",
            &EventType::Unknown => "unknown",
        })
    }
}

pub struct MonitorEvent<'a> {
    device: Device<'a>
}

impl<'a> Deref for MonitorEvent<'a> {
    type Target = Device<'a>;

    fn deref(&self) -> &Device<'a> {
        &self.device
    }
}

impl<'a> MonitorEvent<'a> {
    pub fn event_type(&self) -> EventType {
        let value = match self.device.property_value("ACTION") {
            Some(s) => s.to_str(),
            None => None
        };

        match value {
            Some("add") => EventType::Add,
            Some("change") => EventType::Change,
            Some("remove") => EventType::Remove,
            _ => EventType::Unknown
        }
    }

    pub fn sequence_number(&self) -> u64 {
        unsafe {
            ::ffi::udev_device_get_seqnum(self.device.as_ptr()) as u64
        }
    }

    pub fn device(&self) -> &Device {
        &self.device
    }
}
<commit_msg>adds derived traits for EventType enum<commit_after>use std::fmt;
use std::ptr;

use std::ffi::{CString,OsStr};
use std::ops::Deref;
use std::os::unix::io::{RawFd,AsRawFd};

use ::context::{Context};
use ::device::{Device};
use ::error::{Error};
use ::handle::prelude::*;

pub struct MonitorSpec<'a> {
    context: &'a Context,
    monitor: *mut ::ffi::udev_monitor
}

impl<'a> Drop for MonitorSpec<'a> {
    fn drop(&mut self) {
        unsafe {
            ::ffi::udev_monitor_unref(self.monitor);
        }
    }
}

impl<'a> MonitorSpec<'a> {
    pub fn new(context: &'a Context) -> Result<Self,Error> {
        let name = CString::new("udev").unwrap();

        let ptr = try_alloc!(unsafe {
            ::ffi::udev_monitor_new_from_netlink(context.as_ptr(), name.as_ptr())
        });

        Ok(MonitorSpec {
            context: context,
            monitor: ptr
        })
    }

    pub fn match_subsystem<T: AsRef<OsStr>>(&mut self, subsystem: T) -> Result<(),Error> {
        let subsystem = try!(::util::os_str_to_cstring(subsystem));

        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), ptr::null())
        })
    }

    pub fn match_subsystem_devtype<T: AsRef<OsStr>, U: AsRef<OsStr>>(&mut self, subsystem: T, devtype: U) -> Result<(),Error> {
        let subsystem = try!(::util::os_str_to_cstring(subsystem));
        let devtype = try!(::util::os_str_to_cstring(devtype));

        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem.as_ptr(), devtype.as_ptr())
        })
    }

    pub fn match_tag<T: AsRef<OsStr>>(&mut self, tag: T) -> Result<(),Error> {
        let tag = try!(::util::os_str_to_cstring(tag));

        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_add_match_tag(self.monitor, tag.as_ptr())
        })
    }

    pub fn clear_filters(&mut self) -> Result<(),Error> {
        ::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_filter_remove(self.monitor)
        })
    }

    pub fn listen(self) -> Result<Monitor<'a>,Error> {
        try!(::util::errno_to_result(unsafe {
            ::ffi::udev_monitor_enable_receiving(self.monitor)
        }));

        Ok(Monitor { spec: self })
    }
}

pub struct Monitor<'a> {
    spec: MonitorSpec<'a>
}

impl<'a> AsRawFd for Monitor<'a> {
    fn as_raw_fd(&self) -> RawFd {
        unsafe {
            ::ffi::udev_monitor_get_fd(self.spec.monitor)
        }
    }
}

impl<'a> Monitor<'a> {
    pub fn receive_event(&mut self) -> Option<MonitorEvent> {
        let device = unsafe {
            ::ffi::udev_monitor_receive_device(self.spec.monitor)
        };

        if device.is_null() {
            None
        }
        else {
            let device = ::device::new(self.spec.context, device);

            Some(MonitorEvent { device: device })
        }
    }
}

#[derive(Debug,Clone,Copy,PartialEq,Eq)]
pub enum EventType {
    Add,
    Change,
    Remove,
    Unknown,
}

impl Default for EventType {
    fn default() -> EventType { EventType::Unknown }
}

impl fmt::Display for EventType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(match self {
            &EventType::Add => "add",
            &EventType::Change => "change",
            &EventType::Remove => "remove",
            &EventType::Unknown => "unknown",
        })
    }
}

pub struct MonitorEvent<'a> {
    device: Device<'a>
}

impl<'a> Deref for MonitorEvent<'a> {
    type Target = Device<'a>;

    fn deref(&self) -> &Device<'a> {
        &self.device
    }
}

impl<'a> MonitorEvent<'a> {
    pub fn event_type(&self) -> EventType {
        let value = match self.device.property_value("ACTION") {
            Some(s) => s.to_str(),
            None => None
        };

        match value {
            Some("add") => EventType::Add,
            Some("change") => EventType::Change,
            Some("remove") => EventType::Remove,
            _ => EventType::Unknown
        }
    }

    pub fn sequence_number(&self) -> u64 {
        unsafe {
            ::ffi::udev_device_get_seqnum(self.device.as_ptr()) as u64
        }
    }

    pub fn device(&self) -> &Device {
        &self.device
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate adapton_lab;

use std::rc::Rc;
use std::io::BufReader;
use std::io::BufWriter;
use std::io::Write;
use std::io::BufRead;
use std::fs::File;
use std::collections::HashMap;

use adapton_lab::labviz::{Div,WriteHTML};

// Temp: Make this better at some point?
type Graph = HashMap<Rc<String>, Vec<Rc<String>>>;
type NodeSet = HashMap<Rc<String>,()>;
type NodeCount = HashMap<Rc<String>,usize>;

#[derive(Debug)]
struct Options {
    tooltips: bool,
    tooltips_visited: bool,
}

impl Options {
    fn new() -> Self {
        Options {
            tooltips:true,
            tooltips_visited:false,
        }
    }
}

struct St {
    nodes: NodeSet,
    leaves:NodeSet,
    roots: NodeSet,
    graph: Graph,
    edges: Vec<(Rc<String>, Rc<String>)>,
    rev_graph:Graph,
}

impl St {
    fn new() -> Self {
        St {
            nodes: HashMap::new(),
            leaves:HashMap::new(),
            roots: HashMap::new(),
            graph: HashMap::new(),
            edges: Vec::new(),
            rev_graph:HashMap::new()
        }
    }
    fn process_nodes(self:&mut Self) {
        self.leaves=HashMap::new();
        self.roots=HashMap::new();
        for (node,_) in self.nodes.iter() {
            match self.graph.get(node) {
                None => { self.leaves.insert(node.clone(),()); },
                Some(_out) => {}
            };
            match self.rev_graph.get(node) {
                None => { self.roots.insert(node.clone(),()); },
                Some(_out) => {}
            };
        }
    }
    fn add_edge(self:&mut Self, src:Rc<String>, tgt:Rc<String>) {
        self.nodes.insert(src.clone(), ());
        self.nodes.insert(tgt.clone(), ());
        let edge = if false {
            //(Rc::new(v[0].to_string()), Rc::new(v[1].to_string()))
            (src, tgt)
        } else {
            //(Rc::new(v[1].to_string()), Rc::new(v[0].to_string()))
            (tgt, src)
        };
        self.edges.push(edge.clone());

        let inserted : bool = match self.graph.get_mut(&edge.0) {
            None => { false }
            Some(out) => {
                out.push(edge.1.clone());
                true
            },
        };
        if !inserted {
            self.graph.insert(edge.0.clone(), vec![ edge.1.clone() ]);
        };

        let inserted : bool = match self.rev_graph.get_mut(&edge.1) {
            None => { false }
            Some(out) => {
                out.push(edge.0.clone());
                true
            },
        };
        if !inserted {
            self.rev_graph.insert(edge.1, vec![ edge.0 ]);
        };
    }
}

fn main() {
    let mut options = Options::new();
    let args = clap::App::new("dep-viz")
        .version("0.1")
        .author("Matthew Hammer <matthew.hammer@colorado.edu>")
        .about("Consumes Rustc dependency information; Produces visualizations as HTML via a depth-first traversal.")
        .args_from_usage("\
                --no-tips            'smaller HTML files: do not show tips for nodes on hover'
                --tips-visited       'even larger HTML files: show tips even for visited nodes'
            -i, --infile=[infile]    'name for input file'
            -o, --outfile=[outfile]  'name for output file'")
    .get_matches();
    let infile_name = args.value_of("infile").unwrap_or("dep_graph.txt");
    let outfile_name = args.value_of("outfile").unwrap_or("dep_graph.html");

    options.tooltips = !(args.is_present("no-tips"));
    options.tooltips_visited = args.is_present("tips-visited");

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

    println!("Reading input file: {}", infile_name);
    let f = File::open(infile_name).unwrap();
    let file = BufReader::new(&f);
    let mut st = St::new();
    for (_num, line) in file.lines().enumerate() {
        let line = line.unwrap();
        let v: Vec<&str> = line.split(" -> ").map(|s|s.trim()).collect();
        assert_eq!(v.len(), 2);
        st.add_edge(Rc::new(v[0].to_string()),
                    Rc::new(v[1].to_string()));
    }
    println!("...Read input file: {}", infile_name);
    st.process_nodes();
    println!("  Found {} edges", st.edges.len());
    println!("  Found {} nodes", st.nodes.len());
    println!("    Found {} root nodes", st.roots.len());
    println!("    Found {} leaf nodes", st.leaves.len());

    println!("\nPerforming DFS on graph...");
    let mut stack = vec![];
    for (node,_) in st.roots.iter() {
        stack.push(node.clone());
        //break;
    }

    let (div, visited) = dfs(&options, &st.graph, stack);
    println!("...Performed DFS on graph.");
    println!("  Visited {} nodes, {:.1}% of total", visited.len(),
             100f32 * (visited.len() as f32) / (st.nodes.len() as f32));

    println!("\nFinding unvisited graph nodes...");
    let mut unvisited : NodeSet = HashMap::new();
    for (node, _) in st.nodes.iter() {
        if visited.get(node) == None {
            unvisited.insert(node.clone(), ());
            //println!("unvisited: {}", node);
        }
    }
    assert_eq!(visited.len() + unvisited.len(),
               st.nodes.len());
    //println!("...Found graph nodes.");
    println!("...Found {} unvisited graph nodes, {:.1}% of total.",
             unvisited.len(),
             100f32 * (unvisited.len() as f32) / (st.nodes.len() as f32));

    println!("Writing HTML output: {}", outfile_name);
    let outfile = File::create(outfile_name).unwrap();
    let mut buf_writer = BufWriter::new(outfile);
    let _ = buf_writer.write_all(style_string().as_bytes());
    div.write_html(&mut buf_writer);
    let _ = buf_writer.flush();
    println!("..Wrote HTML output: {}", outfile_name);
}

fn dfs (options:&Options, graph: &Graph, stack:Vec<Rc<String>>) -> (Div, NodeCount) {
    let mut visited:NodeCount = HashMap::new();
    let mut divs:Vec<Div> = Vec::new();
    for n in stack.iter() {
        divs.push(dfs_rec(options, graph, &mut visited, 0, n));
        //if visited.len() > 10000 { break } else { continue }
    }
    (Div{tag:"dfs".to_string(),
         classes:vec![],
         extent:Box::new(divs),
         text: None}, visited)
}

fn cons_of_node_name(node:&Rc<String>) -> String {
    let cons : Vec<&str> = node.trim().split("(").collect();
    assert!(cons.len() > 0 && cons[0] != "");
    cons[0].to_string()
}

fn append_classes_of_node(node:&Rc<String>, mut classes:Vec<String>) -> Vec<String> {
    classes.push(cons_of_node_name(node));
    classes
}

fn append_tooltip(options:&Options, node:&Rc<String>, mut extent:Vec<Div>, visited:bool, depth: usize) -> Vec<Div> {
    if options.tooltips && (!visited || options.tooltips_visited) {
        let show_full_details_depth = 2;
        extent.insert(0, Div{tag:"tooltip".to_string(),
                             classes:vec![],
                             extent:Box::new(vec![]),
                             text: Some(
                                 format!("{}: {}", depth,
                                         if !visited && depth < show_full_details_depth
                                         { (**node).clone() }
                                         else
                                         { cons_of_node_name(node) }))
        });
        extent
    }
    else {
        extent
    }
}

fn dfs_rec (options:&Options, graph: &Graph, visited: &mut NodeCount, depth:usize, node:&Rc<String>) -> Div {
    if visited.get(node) == None {
        visited.insert(node.clone(),1);
        match graph.get(node) {
            None => {
                /* Has no children */
                Div{tag:if false {(**node).clone()} else { "".to_string() },
                    classes:append_classes_of_node(node, vec![
                        "node".to_string(),
                        "no-extent".to_string()
                    ]),
                    extent:Box::new(append_tooltip(options, node, vec![], false, depth)),
                    text:None}
            }
            Some(out) => {
                /* Has children */
                let mut divs = vec![];
                for n in out {
                    divs.push(dfs_rec(options, graph, visited, depth+1, n))
                }
                Div{tag:if false {(**node).clone()} else { "".to_string() },
                    classes:append_classes_of_node(node, vec![
                        "node".to_string()
                    ]),
                    extent:Box::new(append_tooltip(options, node, divs, false, depth)),
                    text:None}
            }
        }
    }
    else {
        // increment counter
        let node_count = visited.get(node).unwrap() + 1;
        visited.insert(node.clone(), node_count);
        // Already visited
        Div{tag:if false {(**node).clone()} else { "".to_string() },
            classes:append_classes_of_node(node, vec![
                "node".to_string(),
                "visited".to_string()
            ]),
            extent:Box::new(append_tooltip(options, node, vec![], true, depth)),
            //extent:Box::new(vec![]),
            text:None}
    }
}

pub fn style_string() -> &'static str {
"
<html>
<head>
<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>

<style>
div {
  display: inline
}
body {
  display: inline;
  color: #aa88cc;
  background: #313;
  font-family: sans-serif;
  text-decoration: none;
  padding: 0px;
  margin: 0px;
}
body:visited {
  color: #aa88cc;
}
a {
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}
hr {
  display: block;
  float: left;
  clear: both;
  width: 0px;
  border: none;
}

.node {
  color: black;
  display: inline-block;
  border-style: solid;
  border-color: #221133;
  border-width: 1px;
  background: #ffccff;
  font-size: 0px;
  padding: 0px;
  margin: 1px;
  border-radius: 5px;
}

.visited {
  border-width: 2px;
}

.no-extent {
  padding: 3px;
}
.tooltip {
  visibility: hidden;
  background-color: #324;
  border-style: solid;
  border-color: #eeeeee;
  border-width: 1px;
  color: #eae;
  text-align: left;
  padding: 5px 0;
  border-radius: 2px;
  font-size: 12px;
  position: absolute;
  z-index: 1;
}
.node:hover {
  border-color: green;
}
.node:hover > .tooltip {
  visibility: visible;
}

.WorkProduct {
  border-width: 2px;
  border-color: blue;
  background: #999;
}

.MetaData {
  border-color: #000055;
  background: #0000ff;
}

.Hir {
  border-color: #005555;
  background: #00aaff;
}

</style>
</head>
<body>
"
}
<commit_msg>minor code cleanup<commit_after>extern crate clap;
extern crate adapton_lab;

use std::rc::Rc;
use std::io::BufReader;
use std::io::BufWriter;
use std::io::Write;
use std::io::BufRead;
use std::fs::File;
use std::collections::HashMap;

use adapton_lab::labviz::{Div,WriteHTML};

// Temp: Make this better at some point?
type Graph = HashMap<Rc<String>, Vec<Rc<String>>>;
type NodeSet = HashMap<Rc<String>,()>;
type NodeCount = HashMap<Rc<String>,usize>;

#[derive(Debug)]
struct Options {
    tips: bool,
    tips_visited: bool,
}

impl Options {
    fn new() -> Self {
        Options {
            tips:true,
            tips_visited:false,
        }
    }
}

struct St {
    nodes: NodeSet,
    leaves:NodeSet,
    roots: NodeSet,
    graph: Graph,
    edges: Vec<(Rc<String>, Rc<String>)>,
    rev_graph:Graph,
}

impl St {
    fn new() -> Self {
        St {
            nodes: HashMap::new(),
            leaves:HashMap::new(),
            roots: HashMap::new(),
            graph: HashMap::new(),
            edges: Vec::new(),
            rev_graph:HashMap::new()
        }
    }
    fn process_nodes(self:&mut Self) {
        self.leaves=HashMap::new();
        self.roots=HashMap::new();
        for (node,_) in self.nodes.iter() {
            match self.graph.get(node) {
                None => { self.leaves.insert(node.clone(),()); },
                Some(_out) => {}
            };
            match self.rev_graph.get(node) {
                None => { self.roots.insert(node.clone(),()); },
                Some(_out) => {}
            };
        }
    }
    fn add_edge(self:&mut Self, src:Rc<String>, tgt:Rc<String>) {
        self.nodes.insert(src.clone(), ());
        self.nodes.insert(tgt.clone(), ());
        let edge = if false {
            //(Rc::new(v[0].to_string()), Rc::new(v[1].to_string()))
            (src, tgt)
        } else {
            //(Rc::new(v[1].to_string()), Rc::new(v[0].to_string()))
            (tgt, src)
        };
        self.edges.push(edge.clone());

        let inserted : bool = match self.graph.get_mut(&edge.0) {
            None => { false }
            Some(out) => {
                out.push(edge.1.clone());
                true
            },
        };
        if !inserted {
            self.graph.insert(edge.0.clone(), vec![ edge.1.clone() ]);
        };

        let inserted : bool = match self.rev_graph.get_mut(&edge.1) {
            None => { false }
            Some(out) => {
                out.push(edge.0.clone());
                true
            },
        };
        if !inserted {
            self.rev_graph.insert(edge.1, vec![ edge.0 ]);
        };
    }
}

fn main() {
    let mut options = Options::new();
    let args = clap::App::new("dep-viz")
        .version("0.1")
        .author("Matthew Hammer <matthew.hammer@colorado.edu>")
        .about("Consumes Rustc dependency information; Produces visualizations as HTML via a depth-first traversal.")
        .args_from_usage("\
                --no-tips            'smaller HTML files: do not show tips for nodes on hover'
                --tips-visited       'even larger HTML files: show tips even for visited nodes'
            -i, --infile=[infile]    'name for input file'
            -o, --outfile=[outfile]  'name for output file'")
    .get_matches();
    let infile_name = args.value_of("infile").unwrap_or("dep_graph.txt");
    let outfile_name = args.value_of("outfile").unwrap_or("dep_graph.html");

    options.tips = !(args.is_present("no-tips"));
    options.tips_visited = args.is_present("tips-visited");

    println!("{:?}\n", options);

    println!("Reading input file: {}", infile_name);
    let f = File::open(infile_name).unwrap();
    let file = BufReader::new(&f);
    let mut st = St::new();
    for (_num, line) in file.lines().enumerate() {
        let line = line.unwrap();
        let v: Vec<&str> = line.split(" -> ").map(|s|s.trim()).collect();
        assert_eq!(v.len(), 2);
        st.add_edge(Rc::new(v[0].to_string()),
                    Rc::new(v[1].to_string()));
    }
    println!("...Read input file: {}", infile_name);
    st.process_nodes();
    println!("  Found {} edges", st.edges.len());
    println!("  Found {} nodes", st.nodes.len());
    println!("    Found {} root nodes", st.roots.len());
    println!("    Found {} leaf nodes", st.leaves.len());

    println!("\nPerforming DFS on graph...");
    let mut stack = vec![];
    for (node,_) in st.roots.iter() {
        stack.push(node.clone());
        //break;
    }

    let (div, visited) = dfs(&options, &st.graph, stack);
    println!("...Performed DFS on graph.");
    println!("  Visited {} nodes, {:.1}% of total", visited.len(),
             100f32 * (visited.len() as f32) / (st.nodes.len() as f32));

    if false {
        println!("\nFinding unvisited graph nodes...");
        let mut unvisited : NodeSet = HashMap::new();
        for (node, _) in st.nodes.iter() {
            if visited.get(node) == None {
                unvisited.insert(node.clone(), ());
                //println!("unvisited: {}", node);
            }
        }
        assert_eq!(visited.len() + unvisited.len(),
                   st.nodes.len());
        //println!("...Found graph nodes.");
        println!("...Found {} unvisited graph nodes, {:.1}% of total.",
                 unvisited.len(),
                 100f32 * (unvisited.len() as f32) / (st.nodes.len() as f32));
    }

    println!("\nWriting HTML output: {}", outfile_name);
    let outfile = File::create(outfile_name).unwrap();
    let mut buf_writer = BufWriter::new(outfile);
    let _ = buf_writer.write_all(style_string().as_bytes());
    div.write_html(&mut buf_writer);
    let _ = buf_writer.flush();
    println!("..Wrote HTML output: {}", outfile_name);
}

fn dfs (options:&Options, graph: &Graph, stack:Vec<Rc<String>>) -> (Div, NodeCount) {
    let mut visited:NodeCount = HashMap::new();
    let mut divs:Vec<Div> = Vec::new();
    for n in stack.iter() {
        divs.push(dfs_rec(options, graph, &mut visited, 0, n));
        //if visited.len() > 10000 { break } else { continue }
    }
    (Div{tag:"dfs".to_string(),
         classes:vec![],
         extent:Box::new(divs),
         text: None}, visited)
}

fn cons_of_node_name(node:&Rc<String>) -> String {
    let cons : Vec<&str> = node.trim().split("(").collect();
    assert!(cons.len() > 0 && cons[0] != "");
    cons[0].to_string()
}

fn append_classes_of_node(node:&Rc<String>, mut classes:Vec<String>) -> Vec<String> {
    classes.push(cons_of_node_name(node));
    classes
}

fn append_tooltip(options:&Options, node:&Rc<String>, mut extent:Vec<Div>, visited:bool, depth: usize) -> Vec<Div> {
    if options.tips && (!visited || options.tips_visited) {
        let show_full_details_depth = 2;
        extent.insert(0, Div{tag:"tooltip".to_string(),
                             classes:vec![],
                             extent:Box::new(vec![]),
                             text: Some(
                                 format!("{}: {}", depth,
                                         if !visited && depth < show_full_details_depth
                                         { (**node).clone() }
                                         else
                                         { cons_of_node_name(node) }))
        });
        extent
    }
    else {
        extent
    }
}

fn dfs_rec (options:&Options, graph: &Graph, visited: &mut NodeCount, depth:usize, node:&Rc<String>) -> Div {
    if visited.get(node) == None {
        visited.insert(node.clone(),1);
        match graph.get(node) {
            None => {
                /* Has no children */
                Div{tag:if false {(**node).clone()} else { "".to_string() },
                    classes:append_classes_of_node(node, vec![
                        "node".to_string(),
                        "no-extent".to_string()
                    ]),
                    extent:Box::new(append_tooltip(options, node, vec![], false, depth)),
                    text:None}
            }
            Some(out) => {
                /* Has children */
                let mut divs = vec![];
                for n in out {
                    divs.push(dfs_rec(options, graph, visited, depth+1, n))
                }
                Div{tag:if false {(**node).clone()} else { "".to_string() },
                    classes:append_classes_of_node(node, vec![
                        "node".to_string()
                    ]),
                    extent:Box::new(append_tooltip(options, node, divs, false, depth)),
                    text:None}
            }
        }
    }
    else {
        // increment counter
        let node_count = visited.get(node).unwrap() + 1;
        visited.insert(node.clone(), node_count);
        // Already visited
        Div{tag:if false {(**node).clone()} else { "".to_string() },
            classes:append_classes_of_node(node, vec![
                "node".to_string(),
                "visited".to_string()
            ]),
            extent:Box::new(append_tooltip(options, node, vec![], true, depth)),
            //extent:Box::new(vec![]),
            text:None}
    }
}

pub fn style_string() -> &'static str {
"
<html>
<head>
<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>

<style>
div {
  display: inline
}
body {
  display: inline;
  color: #aa88cc;
  background: #313;
  font-family: sans-serif;
  text-decoration: none;
  padding: 0px;
  margin: 0px;
}
body:visited {
  color: #aa88cc;
}
a {
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}
hr {
  display: block;
  float: left;
  clear: both;
  width: 0px;
  border: none;
}

.node {
  color: black;
  display: inline-block;
  border-style: solid;
  border-color: #221133;
  border-width: 1px;
  background: #ffccff;
  font-size: 0px;
  padding: 0px;
  margin: 1px;
  border-radius: 5px;
}

.visited {
  border-width: 2px;
}

.no-extent {
  padding: 3px;
}
.tooltip {
  visibility: hidden;
  background-color: #324;
  border-style: solid;
  border-color: #eeeeee;
  border-width: 1px;
  color: #eae;
  text-align: left;
  padding: 5px 0;
  border-radius: 2px;
  font-size: 12px;
  position: absolute;
  z-index: 1;
}
.node:hover {
  border-color: green;
}
.node:hover > .tooltip {
  visibility: visible;
}

.WorkProduct {
  border-width: 2px;
  border-color: blue;
  background: #999;
}

.MetaData {
  border-color: #000055;
  background: #0000ff;
}

.Hir {
  border-color: #005555;
  background: #00aaff;
}

</style>
</head>
<body>
"
}
<|endoftext|>


<commit_before>use super::*;
use ethereum_types::H256;

macro_rules! impl_encodable_for_uint {
    ($type: ident, $bit_size: expr) => {
        impl Encodable for $type {
            fn is_ssz_fixed_len() -> bool {
                true
            }

            fn ssz_fixed_len() -> usize {
                $bit_size / 8
            }

            fn as_ssz_bytes(&self) -> Vec<u8> {
                self.to_le_bytes().to_vec()
            }
        }
    };
}

impl_encodable_for_uint!(u8, 8);
impl_encodable_for_uint!(u16, 16);
impl_encodable_for_uint!(u32, 32);
impl_encodable_for_uint!(u64, 64);
impl_encodable_for_uint!(usize, 64);

impl<T: Encodable> Encodable for Vec<T> {
    fn is_ssz_fixed_len() -> bool {
        false
    }

    fn as_ssz_bytes(&self) -> Vec<u8> {
        if T::is_ssz_fixed_len() {
            let mut bytes = Vec::with_capacity(T::ssz_fixed_len() * self.len());

            for item in self {
                bytes.append(&mut item.as_ssz_bytes());
            }

            bytes
        } else {
            let mut offset = self.len() * BYTES_PER_LENGTH_OFFSET;
            let mut fixed = Vec::with_capacity(offset);
            let mut variable = vec![];

            for item in self {
                fixed.append(&mut encode_length(offset));
                let mut bytes = item.as_ssz_bytes();
                offset += bytes.len();
                variable.append(&mut bytes);
            }

            fixed.append(&mut variable);

            fixed
        }
    }
}

/*
impl Encodable for bool {
    fn ssz_fixed_len() -> Option<usize> {
        Some(8)
    }

    fn as_ssz_bytes(&self) -> Vec<u8> {
        (*self as u8).to_le_bytes().to_vec()
    }
}

impl Encodable for H256 {
    fn ssz_fixed_len() -> Option<usize> {
        Some(32)
    }

    fn as_ssz_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_vec()
    }
}

macro_rules! impl_encodable_for_u8_array {
    ($len: expr) => {
        impl Encodable for [u8; $len] {
            fn ssz_fixed_len() -> Option<usize> {
                Some($len)
            }

            fn as_ssz_bytes(&self) -> Vec<u8> {
                self.to_vec()
            }
        }
    };
}

impl_encodable_for_u8_array!(4);

macro_rules! impl_encodable_for_u8_array {
    ($len: expr) => {
        impl Encodable for [u8; $len] {

            fn ssz_append(&self, s: &mut SszStream) {
                let bytes: Vec<u8> = self.iter().cloned().collect();
                s.append_encoded_raw(&bytes);
            }
        }
    };
}

impl_encodable_for_u8_array!(4);

impl Encodable for bool {
    fn ssz_append(&self, s: &mut SszStream) {
        let byte = if *self { 0b0000_0001 } else { 0b0000_0000 };
        s.append_encoded_raw(&[byte]);
    }
}

impl Encodable for H256 {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_encoded_raw(self.as_bytes());
    }
}

impl Encodable for Address {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_encoded_raw(self.as_bytes());
    }
}

impl<T> Encodable for Vec<T>
where
    T: Encodable,
{
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_vec(&self);
    }
}
*/

#[cfg(test)]
mod tests {
    use super::*;
    use crate::ssz_encode;

    #[test]
    fn vec_of_u8() {
        let vec: Vec<u8> = vec![];
        assert_eq!(vec.as_ssz_bytes(), vec![]);

        let vec: Vec<u8> = vec![1];
        assert_eq!(vec.as_ssz_bytes(), vec![1]);

        let vec: Vec<u8> = vec![0, 1, 2, 3];
        assert_eq!(vec.as_ssz_bytes(), vec![0, 1, 2, 3]);
    }

    #[test]
    fn vec_of_vec_of_u8() {
        let vec: Vec<Vec<u8>> = vec![];
        assert_eq!(vec.as_ssz_bytes(), vec![]);

        let vec: Vec<Vec<u8>> = vec![vec![]];
        assert_eq!(vec.as_ssz_bytes(), vec![4, 0, 0, 0]);

        let vec: Vec<Vec<u8>> = vec![vec![], vec![]];
        assert_eq!(vec.as_ssz_bytes(), vec![8, 0, 0, 0, 8, 0, 0, 0]);

        let vec: Vec<Vec<u8>> = vec![vec![0, 1, 2], vec![11, 22, 33]];
        assert_eq!(
            vec.as_ssz_bytes(),
            vec![8, 0, 0, 0, 11, 0, 0, 0, 0, 1, 2, 11, 22, 33]
        );
    }

    #[test]
    fn ssz_encode_u8() {
        let x: u8 = 0;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0]);

        let x: u8 = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![1]);

        let x: u8 = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![100]);

        let x: u8 = 255;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![255]);
    }

    #[test]
    fn ssz_encode_u16() {
        let x: u16 = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![1, 0]);

        let x: u16 = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![100, 0]);

        let x: u16 = 1 << 8;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 1]);

        let x: u16 = 65535;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![255, 255]);
    }

    #[test]
    fn ssz_encode_u32() {
        let x: u32 = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![1, 0, 0, 0]);

        let x: u32 = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![100, 0, 0, 0]);

        let x: u32 = 1 << 16;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 0]);

        let x: u32 = 1 << 24;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 0, 1]);

        let x: u32 = !0;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![255, 255, 255, 255]);
    }

    #[test]
    fn ssz_encode_u64() {
        let x: u64 = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![1, 0, 0, 0, 0, 0, 0, 0]);

        let x: u64 = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![100, 0, 0, 0, 0, 0, 0, 0]);

        let x: u64 = 1 << 32;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 1, 0, 0, 0]);

        let x: u64 = !0;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![255, 255, 255, 255, 255, 255, 255, 255]);
    }

    #[test]
    fn ssz_encode_usize() {
        let x: usize = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![1, 0, 0, 0, 0, 0, 0, 0]);

        let x: usize = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![100, 0, 0, 0, 0, 0, 0, 0]);

        let x: usize = 1 << 32;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 1, 0, 0, 0]);

        let x: usize = !0;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![255, 255, 255, 255, 255, 255, 255, 255]);
    }

    /*
    #[test]
    fn ssz_encode_h256() {
        let h = H256::zero();
        let mut ssz = SszStream::new();
        ssz.append(&h);
        assert_eq!(ssz.drain(), vec![0; 32]);
    }

    #[test]
    fn ssz_mixed() {
        let mut stream = SszStream::new();

        let h = H256::zero();
        let a: u8 = 100;
        let b: u16 = 65535;
        let c: u32 = 1 << 24;

        stream.append(&h);
        stream.append(&a);
        stream.append(&b);
        stream.append(&c);

        let ssz = stream.drain();
        assert_eq!(ssz[0..32], *vec![0; 32]);
        assert_eq!(ssz[32], 100);
        assert_eq!(ssz[33..55], *vec![255, 255]);
        assert_eq!(ssz[55..59], *vec![0, 0, 0, 1]);
    }

    #[test]
    fn ssz_encode_bool() {
        let x: bool = false;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0b0000_0000]);

        let x: bool = true;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0b0000_0001]);
    }

    #[test]
    fn ssz_encode_u8_array() {
        let x: [u8; 4] = [0, 1, 7, 8];
        let ssz = ssz_encode(&x);
        assert_eq!(ssz, vec![0, 1, 7, 8]);

        let x: [u8; 4] = [255, 255, 255, 255];
        let ssz = ssz_encode(&x);
        assert_eq!(ssz, vec![255, 255, 255, 255]);
    }
    */
}
<commit_msg>Tidy encode impl tests<commit_after>use super::*;
use ethereum_types::H256;

macro_rules! impl_encodable_for_uint {
    ($type: ident, $bit_size: expr) => {
        impl Encodable for $type {
            fn is_ssz_fixed_len() -> bool {
                true
            }

            fn ssz_fixed_len() -> usize {
                $bit_size / 8
            }

            fn as_ssz_bytes(&self) -> Vec<u8> {
                self.to_le_bytes().to_vec()
            }
        }
    };
}

impl_encodable_for_uint!(u8, 8);
impl_encodable_for_uint!(u16, 16);
impl_encodable_for_uint!(u32, 32);
impl_encodable_for_uint!(u64, 64);
impl_encodable_for_uint!(usize, 64);

impl<T: Encodable> Encodable for Vec<T> {
    fn is_ssz_fixed_len() -> bool {
        false
    }

    fn as_ssz_bytes(&self) -> Vec<u8> {
        if T::is_ssz_fixed_len() {
            let mut bytes = Vec::with_capacity(T::ssz_fixed_len() * self.len());

            for item in self {
                bytes.append(&mut item.as_ssz_bytes());
            }

            bytes
        } else {
            let mut offset = self.len() * BYTES_PER_LENGTH_OFFSET;
            let mut fixed = Vec::with_capacity(offset);
            let mut variable = vec![];

            for item in self {
                fixed.append(&mut encode_length(offset));
                let mut bytes = item.as_ssz_bytes();
                offset += bytes.len();
                variable.append(&mut bytes);
            }

            fixed.append(&mut variable);

            fixed
        }
    }
}

/*
impl Encodable for bool {
    fn ssz_fixed_len() -> Option<usize> {
        Some(8)
    }

    fn as_ssz_bytes(&self) -> Vec<u8> {
        (*self as u8).to_le_bytes().to_vec()
    }
}

impl Encodable for H256 {
    fn ssz_fixed_len() -> Option<usize> {
        Some(32)
    }

    fn as_ssz_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_vec()
    }
}

macro_rules! impl_encodable_for_u8_array {
    ($len: expr) => {
        impl Encodable for [u8; $len] {
            fn ssz_fixed_len() -> Option<usize> {
                Some($len)
            }

            fn as_ssz_bytes(&self) -> Vec<u8> {
                self.to_vec()
            }
        }
    };
}

impl_encodable_for_u8_array!(4);

macro_rules! impl_encodable_for_u8_array {
    ($len: expr) => {
        impl Encodable for [u8; $len] {

            fn ssz_append(&self, s: &mut SszStream) {
                let bytes: Vec<u8> = self.iter().cloned().collect();
                s.append_encoded_raw(&bytes);
            }
        }
    };
}

impl_encodable_for_u8_array!(4);

impl Encodable for bool {
    fn ssz_append(&self, s: &mut SszStream) {
        let byte = if *self { 0b0000_0001 } else { 0b0000_0000 };
        s.append_encoded_raw(&[byte]);
    }
}

impl Encodable for H256 {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_encoded_raw(self.as_bytes());
    }
}

impl Encodable for Address {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_encoded_raw(self.as_bytes());
    }
}

impl<T> Encodable for Vec<T>
where
    T: Encodable,
{
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_vec(&self);
    }
}
*/

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

    #[test]
    fn vec_of_u8() {
        let vec: Vec<u8> = vec![];
        assert_eq!(vec.as_ssz_bytes(), vec![]);

        let vec: Vec<u8> = vec![1];
        assert_eq!(vec.as_ssz_bytes(), vec![1]);

        let vec: Vec<u8> = vec![0, 1, 2, 3];
        assert_eq!(vec.as_ssz_bytes(), vec![0, 1, 2, 3]);
    }

    #[test]
    fn vec_of_vec_of_u8() {
        let vec: Vec<Vec<u8>> = vec![];
        assert_eq!(vec.as_ssz_bytes(), vec![]);

        let vec: Vec<Vec<u8>> = vec![vec![]];
        assert_eq!(vec.as_ssz_bytes(), vec![4, 0, 0, 0]);

        let vec: Vec<Vec<u8>> = vec![vec![], vec![]];
        assert_eq!(vec.as_ssz_bytes(), vec![8, 0, 0, 0, 8, 0, 0, 0]);

        let vec: Vec<Vec<u8>> = vec![vec![0, 1, 2], vec![11, 22, 33]];
        assert_eq!(
            vec.as_ssz_bytes(),
            vec![8, 0, 0, 0, 11, 0, 0, 0, 0, 1, 2, 11, 22, 33]
        );
    }

    #[test]
    fn ssz_encode_u8() {
        assert_eq!(0_u8.as_ssz_bytes(), vec![0]);
        assert_eq!(1_u8.as_ssz_bytes(), vec![1]);
        assert_eq!(100_u8.as_ssz_bytes(), vec![100]);
        assert_eq!(255_u8.as_ssz_bytes(), vec![255]);
    }

    #[test]
    fn ssz_encode_u16() {
        assert_eq!(1_u16.as_ssz_bytes(), vec![1, 0]);
        assert_eq!(100_u16.as_ssz_bytes(), vec![100, 0]);
        assert_eq!((1_u16 << 8).as_ssz_bytes(), vec![0, 1]);
        assert_eq!(65535_u16.as_ssz_bytes(), vec![255, 255]);
    }

    #[test]
    fn ssz_encode_u32() {
        assert_eq!(1_u32.as_ssz_bytes(), vec![1, 0, 0, 0]);
        assert_eq!(100_u32.as_ssz_bytes(), vec![100, 0, 0, 0]);
        assert_eq!((1_u32 << 16).as_ssz_bytes(), vec![0, 0, 1, 0]);
        assert_eq!((1_u32 << 24).as_ssz_bytes(), vec![0, 0, 0, 1]);
        assert_eq!((!0_u32).as_ssz_bytes(), vec![255, 255, 255, 255]);
    }

    #[test]
    fn ssz_encode_u64() {
        assert_eq!(1_u64.as_ssz_bytes(), vec![1, 0, 0, 0, 0, 0, 0, 0]);
        assert_eq!(
            (!0_u64).as_ssz_bytes(),
            vec![255, 255, 255, 255, 255, 255, 255, 255]
        );
    }

    #[test]
    fn ssz_encode_usize() {
        assert_eq!(1_usize.as_ssz_bytes(), vec![1, 0, 0, 0, 0, 0, 0, 0]);
        assert_eq!(
            (!0_usize).as_ssz_bytes(),
            vec![255, 255, 255, 255, 255, 255, 255, 255]
        );
    }

    /*
    #[test]
    fn ssz_encode_h256() {
        let h = H256::zero();
        let mut ssz = SszStream::new();
        ssz.append(&h);
        assert_eq!(ssz.drain(), vec![0; 32]);
    }

    #[test]
    fn ssz_mixed() {
        let mut stream = SszStream::new();

        let h = H256::zero();
        let a: u8 = 100;
        let b: u16 = 65535;
        let c: u32 = 1 << 24;

        stream.append(&h);
        stream.append(&a);
        stream.append(&b);
        stream.append(&c);

        let ssz = stream.drain();
        assert_eq!(ssz[0..32], *vec![0; 32]);
        assert_eq!(ssz[32], 100);
        assert_eq!(ssz[33..55], *vec![255, 255]);
        assert_eq!(ssz[55..59], *vec![0, 0, 0, 1]);
    }

    #[test]
    fn ssz_encode_bool() {
        let x: bool = false;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0b0000_0000]);

        let x: bool = true;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0b0000_0001]);
    }

    #[test]
    fn ssz_encode_u8_array() {
        let x: [u8; 4] = [0, 1, 7, 8];
        let ssz = ssz_encode(&x);
        assert_eq!(ssz, vec![0, 1, 7, 8]);

        let x: [u8; 4] = [255, 255, 255, 255];
        let ssz = ssz_encode(&x);
        assert_eq!(ssz, vec![255, 255, 255, 255]);
    }
    */
}
<|endoftext|>


<commit_before>use curve25519_dalek::constants::ED25519_BASEPOINT;
use curve25519_dalek::scalar::Scalar;
use sha256::sha256_compress;
use std::fmt;
use util::bs58_encode_check;

const PAYMENT_ADDRESS_PREFIX_LENGTH: usize = 2;
const SPENDING_KEY_PREFIX_LENGTH: usize = 2;
const INVIEWING_KEY_PREFIX_LENGTH: usize = 3;
pub const PAYMENT_ADDRESS_PREFIX: [u8; PAYMENT_ADDRESS_PREFIX_LENGTH] = [0x16, 0x9a];
pub const SPENDING_KEY_PREFIX: [u8; SPENDING_KEY_PREFIX_LENGTH] = [0xab, 0x36];
pub const INVIEWING_KEY_PREFIX: [u8; INVIEWING_KEY_PREFIX_LENGTH] = [0xa8, 0xab, 0xd3];

/// A Zcash spending key.
pub struct SpendingKey {
    a_sk: [u8; 32], // 252 bits; first 4 bits are always 0
}

/// A Zcash incoming viewing key.
pub struct ViewingKey {
    pub a_pk: [u8; 32],
    pub sk_enc: [u8; 32],
}

/// A Zcash payment address.
pub struct PaymentAddress {
    pub a_pk: [u8; 32],
    pub pk_enc: [u8; 32],
}

impl fmt::Display for SpendingKey {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut data = [0u8; SPENDING_KEY_PREFIX_LENGTH + 32];
        {
            let (prefix, rest) = data.split_at_mut(SPENDING_KEY_PREFIX_LENGTH);
            prefix.copy_from_slice(&SPENDING_KEY_PREFIX);
            rest.copy_from_slice(&self.a_sk);
        }

        f.write_str(bs58_encode_check(&data).as_str())
    }
}

impl fmt::Display for ViewingKey {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut data = [0u8; INVIEWING_KEY_PREFIX_LENGTH + 32 * 2];
        {
            let (prefix, rest) = data.split_at_mut(INVIEWING_KEY_PREFIX_LENGTH);
            prefix.copy_from_slice(&INVIEWING_KEY_PREFIX);
            rest[..32].copy_from_slice(&self.a_pk);
            rest[32..].copy_from_slice(&self.sk_enc);
        }

        f.write_str(bs58_encode_check(&data).as_str())
    }
}

impl fmt::Display for PaymentAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut data = [0u8; PAYMENT_ADDRESS_PREFIX_LENGTH + 32 * 2];
        {
            let (prefix, rest) = data.split_at_mut(PAYMENT_ADDRESS_PREFIX_LENGTH);
            prefix.copy_from_slice(&PAYMENT_ADDRESS_PREFIX);
            rest[..32].copy_from_slice(&self.a_pk);
            rest[32..].copy_from_slice(&self.pk_enc);
        }

        f.write_str(bs58_encode_check(&data).as_str())
    }
}

impl SpendingKey {
    /// Creates a new spending key instance for a given 252-bit *a_sk*.
    /// *a_sk* is represented by 32 bytes; the first four bits of the first byte are zeroed.
    pub fn new(a_sk_u256: [u8; 32]) -> SpendingKey {
        let mut a_sk_u252 = [0u8; 32];
        a_sk_u252.copy_from_slice(&a_sk_u256);
        a_sk_u252[0] &= 0x0f;

        SpendingKey { a_sk: a_sk_u252 }
    }

    /// Calculates the payment address for this spending key
    pub fn address(&self) -> PaymentAddress {
        let viewing_key = self.viewing_key();
        let pk = &Scalar(viewing_key.sk_enc) * &ED25519_BASEPOINT;
        let pk_enc = pk.compress_montgomery().unwrap().to_bytes();

        PaymentAddress {
            a_pk: viewing_key.a_pk,
            pk_enc: pk_enc,
        }
    }

    /// Computes a viewing key for this spending key.
    pub fn viewing_key(&self) -> ViewingKey {
        let mut a_pk = [0u8; 32];
        let mut sk_enc = [0u8; 32];

        pseudorandom_function_a_pk(&mut a_pk, &self.a_sk);
        pseudorandom_function_sk_enc(&mut sk_enc, &self.a_sk);
        clamp_curve25519(&mut sk_enc);

        ViewingKey {
            a_pk: a_pk,
            sk_enc: sk_enc,
        }
    }
}

pub fn pseudorandom_function_a_pk(a_pk: &mut [u8; 32], a_sk: &[u8; 32]) {
    pseudorandom_function(a_pk, a_sk, 0)
}

pub fn pseudorandom_function_sk_enc(sk_enc: &mut [u8; 32], a_sk: &[u8; 32]) {
    pseudorandom_function(sk_enc, a_sk, 1)
}

fn pseudorandom_function(dst: &mut [u8; 32], input: &[u8; 32], t: u8) {
    let mut data = [0u8; 64];
    data[..32].copy_from_slice(input);
    data[0] = 0xc0 | (data[0] & 0x0f);
    data[32] = t;
    sha256_compress(dst, &data);
}

fn clamp_curve25519(key: &mut [u8; 32]) {
    key[0] &= 248;
    key[31] &= 127;
    key[31] |= 64;
}

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

    static ENCODED: [(&str, &str, &str); 10] = [
	(
		"SKxt8pwrQipUL5KgZUcBAqyLj9R1YwMuRRR3ijGMCwCCqchmi8ut",
		"zcJLC7a3aRJohMNCVjSZQ8jFuofhAHJNAY4aX5soDkYfgNejzKnEZbucJmVibLWCwK8dyyfDhNhf3foXDDTouweC382LcX5",
		"ZiVKYQyUcyAJLKwcosSeDxkGRhygFdAPWsr3m8UgjC5X85yqNyLTtJJJYNH83Wf2AQKU6TZsd65MXBZLFj6eSCAFcnCFuVCFS",
	),
	(
		"SKxoo5QkFQgTbdc6EWRKyHPMdmtNDJhqudrAVhen9b4kjCwN6CeV",
		"zcRYvLiURno1LhXq95e8avXFcH2fKKToSFfhqaVKTy8mGH7i6SJbfuWcm4h9rEA6DvswrbxDhFGDQgpdDYV8zwUoHvwNvFX",
		"ZiVKfdhhmQ1fpXaxyW5zRXw4Dhg9cbKRgK7mNFoBLiKjiBZiHJYJTpV2gNMDMPY9sRC96vnKZcnTMSi65SKPyL4WNQNm9PT5H",
	),
	(
		"SKxsVGKsCESoVb3Gfm762psjRtGHmjmv7HVjHckud5MnESfktUuG",
		"zcWGguu2UPfNhh1ygWW9Joo3osvncsuehtz5ewvXd78vFDdnDCRNG6QeKSZpwZmYmkfEutPVf8HzCfBytqXWsEcF2iBAM1e",
		"ZiVKkMUGwx4GgtwxTedRHYewVVskWicz8APQgdcYmvUsiLYgSh3cLAa8TwiR3shyNngGbLiUbYMkZ8F1giXmmcED98rDMwNSG",
	),
	(
		"SKxp72QGQ2qtovHSoVnPp8jRFQpHBhG1xF8s27iRFjPXXkYMQUA6",
		"zcWZomPYMEjJ49S4UHcvTnhjYqogfdYJuEDMURDpbkrz94bkzdTdJEZKWkkpQ8nK62eyLkZCvLZDFtLC2Cq5BmEK3WCKGMN",
		"ZiVKkeb8STw7kpJQsjRCQKovQBciPcfjkpajuuS25DTXSQSVasnq4BkyaMLBBxAkZ8fv6f18woWgaA8W7kGvYp1C1ESaWGjwV",
	),
	(
		"SKxpmLdykLu3xxSXtw1EA7iLJnXu8hFh8hhmW1B2J2194ijh5CR4",
		"zcgjj3fJF59QGBufopx3F51jCjUpXbgEzec7YQT6jRt4Ebu5EV3AW4jHPN6ZdXhmygBvQDRJrXoZLa3Lkh5GqnsFUzt7Qok",
		"ZiVKvpWQiDpxAvWTMLkjjSbCiBGc4kXhtkgAJfW1JVbCTUY4YaAVvVZzCz6wspG9qttciRFLEXm3HLQAmssFbUp9uPEkP3uu5"),
	(
		"SKxny894fJe2rmZjeuoE6GVfNkWoXfPp8337VrLLNWG56FfQtuS1",
		"zcbxovDeXGJJikZH5wQkcQvYx1gzsRt9mR5UnQir6NY8hhPHdgK7z7dE1vfa55Bq3JHJu7isfuWQGYrvMbLnud74z2vS4tS",
		"ZiVKr3bHGa79Kpy1zx2rC9xYd11tGvsY6fSvn2k1aEx97Z19WcMMW7KeSgE6VhJrAZ4RE6AmDU3oKqoXQiZfuHqzEBhW9o5UT",
	),
	(
		"SKxoo5QkFQgTbdc6EWRKyHPMdmtNDJhqudrAVhen9b4kjCwN6CeV",
		"zcRYvLiURno1LhXq95e8avXFcH2fKKToSFfhqaVKTy8mGH7i6SJbfuWcm4h9rEA6DvswrbxDhFGDQgpdDYV8zwUoHvwNvFX",
		"ZiVKfdhhmQ1fpXaxyW5zRXw4Dhg9cbKRgK7mNFoBLiKjiBZiHJYJTpV2gNMDMPY9sRC96vnKZcnTMSi65SKPyL4WNQNm9PT5H",
	),
	(
		"SKxsVGKsCESoVb3Gfm762psjRtGHmjmv7HVjHckud5MnESfktUuG",
		"zcWGguu2UPfNhh1ygWW9Joo3osvncsuehtz5ewvXd78vFDdnDCRNG6QeKSZpwZmYmkfEutPVf8HzCfBytqXWsEcF2iBAM1e",
		"ZiVKkMUGwx4GgtwxTedRHYewVVskWicz8APQgdcYmvUsiLYgSh3cLAa8TwiR3shyNngGbLiUbYMkZ8F1giXmmcED98rDMwNSG",
	),
	(
		"SKxp72QGQ2qtovHSoVnPp8jRFQpHBhG1xF8s27iRFjPXXkYMQUA6",
		"zcWZomPYMEjJ49S4UHcvTnhjYqogfdYJuEDMURDpbkrz94bkzdTdJEZKWkkpQ8nK62eyLkZCvLZDFtLC2Cq5BmEK3WCKGMN",
		"ZiVKkeb8STw7kpJQsjRCQKovQBciPcfjkpajuuS25DTXSQSVasnq4BkyaMLBBxAkZ8fv6f18woWgaA8W7kGvYp1C1ESaWGjwV",
	),
	(
		"SKxpmLdykLu3xxSXtw1EA7iLJnXu8hFh8hhmW1B2J2194ijh5CR4",
		"zcgjj3fJF59QGBufopx3F51jCjUpXbgEzec7YQT6jRt4Ebu5EV3AW4jHPN6ZdXhmygBvQDRJrXoZLa3Lkh5GqnsFUzt7Qok",
		"ZiVKvpWQiDpxAvWTMLkjjSbCiBGc4kXhtkgAJfW1JVbCTUY4YaAVvVZzCz6wspG9qttciRFLEXm3HLQAmssFbUp9uPEkP3uu5",
	),
    ];

    #[test]
    fn spending_keys_to_payment_addresses() {
        for &(spending_key_encoded, payment_address_encoded, _) in ENCODED.iter() {
            let mut a_sk = [0u8; 32];
            a_sk.copy_from_slice(
                &bs58::decode(spending_key_encoded).into_vec().unwrap()[2..34],
            );
            let spending_key = SpendingKey::new(a_sk);
            assert_eq!(spending_key_encoded, spending_key.to_string());
            let payment_address = spending_key.address();
            assert_eq!(payment_address_encoded, payment_address.to_string());
        }
    }

    #[test]
    fn spending_keys_to_viewing_keys() {
        for &(spending_key_encoded, _,viewing_key_encoded) in ENCODED.iter() {
            let mut a_sk = [0u8; 32];
            a_sk.copy_from_slice(
                &bs58::decode(spending_key_encoded).into_vec().unwrap()[2..34],
            );
            let spending_key = SpendingKey::new(a_sk);
            assert_eq!(spending_key_encoded, spending_key.to_string());
            let viewing_key = spending_key.viewing_key();
            assert_eq!(viewing_key_encoded, viewing_key.to_string());
        }
    }
}
<commit_msg>Tweak comment.<commit_after>use curve25519_dalek::constants::ED25519_BASEPOINT;
use curve25519_dalek::scalar::Scalar;
use sha256::sha256_compress;
use std::fmt;
use util::bs58_encode_check;

const PAYMENT_ADDRESS_PREFIX_LENGTH: usize = 2;
const SPENDING_KEY_PREFIX_LENGTH: usize = 2;
const INVIEWING_KEY_PREFIX_LENGTH: usize = 3;
pub const PAYMENT_ADDRESS_PREFIX: [u8; PAYMENT_ADDRESS_PREFIX_LENGTH] = [0x16, 0x9a];
pub const SPENDING_KEY_PREFIX: [u8; SPENDING_KEY_PREFIX_LENGTH] = [0xab, 0x36];
pub const INVIEWING_KEY_PREFIX: [u8; INVIEWING_KEY_PREFIX_LENGTH] = [0xa8, 0xab, 0xd3];

/// A Zcash spending key.
pub struct SpendingKey {
    a_sk: [u8; 32], // 252 bits; first 4 bits are always 0
}

/// A Zcash incoming viewing key.
pub struct ViewingKey {
    pub a_pk: [u8; 32],
    pub sk_enc: [u8; 32],
}

/// A Zcash payment address.
pub struct PaymentAddress {
    pub a_pk: [u8; 32],
    pub pk_enc: [u8; 32],
}

impl fmt::Display for SpendingKey {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut data = [0u8; SPENDING_KEY_PREFIX_LENGTH + 32];
        {
            let (prefix, rest) = data.split_at_mut(SPENDING_KEY_PREFIX_LENGTH);
            prefix.copy_from_slice(&SPENDING_KEY_PREFIX);
            rest.copy_from_slice(&self.a_sk);
        }

        f.write_str(bs58_encode_check(&data).as_str())
    }
}

impl fmt::Display for ViewingKey {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut data = [0u8; INVIEWING_KEY_PREFIX_LENGTH + 32 * 2];
        {
            let (prefix, rest) = data.split_at_mut(INVIEWING_KEY_PREFIX_LENGTH);
            prefix.copy_from_slice(&INVIEWING_KEY_PREFIX);
            rest[..32].copy_from_slice(&self.a_pk);
            rest[32..].copy_from_slice(&self.sk_enc);
        }

        f.write_str(bs58_encode_check(&data).as_str())
    }
}

impl fmt::Display for PaymentAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut data = [0u8; PAYMENT_ADDRESS_PREFIX_LENGTH + 32 * 2];
        {
            let (prefix, rest) = data.split_at_mut(PAYMENT_ADDRESS_PREFIX_LENGTH);
            prefix.copy_from_slice(&PAYMENT_ADDRESS_PREFIX);
            rest[..32].copy_from_slice(&self.a_pk);
            rest[32..].copy_from_slice(&self.pk_enc);
        }

        f.write_str(bs58_encode_check(&data).as_str())
    }
}

impl SpendingKey {
    /// Creates a new spending key instance for a given 252-bit *a_sk*.
    /// *a_sk* is represented by 32 bytes; the first four bits of the first byte are zeroed.
    pub fn new(a_sk_u256: [u8; 32]) -> SpendingKey {
        let mut a_sk_u252 = [0u8; 32];
        a_sk_u252.copy_from_slice(&a_sk_u256);
        a_sk_u252[0] &= 0x0f;

        SpendingKey { a_sk: a_sk_u252 }
    }

    /// Calculates the payment address for this spending key
    pub fn address(&self) -> PaymentAddress {
        let viewing_key = self.viewing_key();
        let pk = &Scalar(viewing_key.sk_enc) * &ED25519_BASEPOINT;
        let pk_enc = pk.compress_montgomery().unwrap().to_bytes();

        PaymentAddress {
            a_pk: viewing_key.a_pk,
            pk_enc: pk_enc,
        }
    }

    /// Computes an incoming viewing key for this spending key.
    pub fn viewing_key(&self) -> ViewingKey {
        let mut a_pk = [0u8; 32];
        let mut sk_enc = [0u8; 32];

        pseudorandom_function_a_pk(&mut a_pk, &self.a_sk);
        pseudorandom_function_sk_enc(&mut sk_enc, &self.a_sk);
        clamp_curve25519(&mut sk_enc);

        ViewingKey {
            a_pk: a_pk,
            sk_enc: sk_enc,
        }
    }
}

pub fn pseudorandom_function_a_pk(a_pk: &mut [u8; 32], a_sk: &[u8; 32]) {
    pseudorandom_function(a_pk, a_sk, 0)
}

pub fn pseudorandom_function_sk_enc(sk_enc: &mut [u8; 32], a_sk: &[u8; 32]) {
    pseudorandom_function(sk_enc, a_sk, 1)
}

fn pseudorandom_function(dst: &mut [u8; 32], input: &[u8; 32], t: u8) {
    let mut data = [0u8; 64];
    data[..32].copy_from_slice(input);
    data[0] = 0xc0 | (data[0] & 0x0f);
    data[32] = t;
    sha256_compress(dst, &data);
}

fn clamp_curve25519(key: &mut [u8; 32]) {
    key[0] &= 248;
    key[31] &= 127;
    key[31] |= 64;
}

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

    static ENCODED: [(&str, &str, &str); 10] = [
	(
		"SKxt8pwrQipUL5KgZUcBAqyLj9R1YwMuRRR3ijGMCwCCqchmi8ut",
		"zcJLC7a3aRJohMNCVjSZQ8jFuofhAHJNAY4aX5soDkYfgNejzKnEZbucJmVibLWCwK8dyyfDhNhf3foXDDTouweC382LcX5",
		"ZiVKYQyUcyAJLKwcosSeDxkGRhygFdAPWsr3m8UgjC5X85yqNyLTtJJJYNH83Wf2AQKU6TZsd65MXBZLFj6eSCAFcnCFuVCFS",
	),
	(
		"SKxoo5QkFQgTbdc6EWRKyHPMdmtNDJhqudrAVhen9b4kjCwN6CeV",
		"zcRYvLiURno1LhXq95e8avXFcH2fKKToSFfhqaVKTy8mGH7i6SJbfuWcm4h9rEA6DvswrbxDhFGDQgpdDYV8zwUoHvwNvFX",
		"ZiVKfdhhmQ1fpXaxyW5zRXw4Dhg9cbKRgK7mNFoBLiKjiBZiHJYJTpV2gNMDMPY9sRC96vnKZcnTMSi65SKPyL4WNQNm9PT5H",
	),
	(
		"SKxsVGKsCESoVb3Gfm762psjRtGHmjmv7HVjHckud5MnESfktUuG",
		"zcWGguu2UPfNhh1ygWW9Joo3osvncsuehtz5ewvXd78vFDdnDCRNG6QeKSZpwZmYmkfEutPVf8HzCfBytqXWsEcF2iBAM1e",
		"ZiVKkMUGwx4GgtwxTedRHYewVVskWicz8APQgdcYmvUsiLYgSh3cLAa8TwiR3shyNngGbLiUbYMkZ8F1giXmmcED98rDMwNSG",
	),
	(
		"SKxp72QGQ2qtovHSoVnPp8jRFQpHBhG1xF8s27iRFjPXXkYMQUA6",
		"zcWZomPYMEjJ49S4UHcvTnhjYqogfdYJuEDMURDpbkrz94bkzdTdJEZKWkkpQ8nK62eyLkZCvLZDFtLC2Cq5BmEK3WCKGMN",
		"ZiVKkeb8STw7kpJQsjRCQKovQBciPcfjkpajuuS25DTXSQSVasnq4BkyaMLBBxAkZ8fv6f18woWgaA8W7kGvYp1C1ESaWGjwV",
	),
	(
		"SKxpmLdykLu3xxSXtw1EA7iLJnXu8hFh8hhmW1B2J2194ijh5CR4",
		"zcgjj3fJF59QGBufopx3F51jCjUpXbgEzec7YQT6jRt4Ebu5EV3AW4jHPN6ZdXhmygBvQDRJrXoZLa3Lkh5GqnsFUzt7Qok",
		"ZiVKvpWQiDpxAvWTMLkjjSbCiBGc4kXhtkgAJfW1JVbCTUY4YaAVvVZzCz6wspG9qttciRFLEXm3HLQAmssFbUp9uPEkP3uu5"),
	(
		"SKxny894fJe2rmZjeuoE6GVfNkWoXfPp8337VrLLNWG56FfQtuS1",
		"zcbxovDeXGJJikZH5wQkcQvYx1gzsRt9mR5UnQir6NY8hhPHdgK7z7dE1vfa55Bq3JHJu7isfuWQGYrvMbLnud74z2vS4tS",
		"ZiVKr3bHGa79Kpy1zx2rC9xYd11tGvsY6fSvn2k1aEx97Z19WcMMW7KeSgE6VhJrAZ4RE6AmDU3oKqoXQiZfuHqzEBhW9o5UT",
	),
	(
		"SKxoo5QkFQgTbdc6EWRKyHPMdmtNDJhqudrAVhen9b4kjCwN6CeV",
		"zcRYvLiURno1LhXq95e8avXFcH2fKKToSFfhqaVKTy8mGH7i6SJbfuWcm4h9rEA6DvswrbxDhFGDQgpdDYV8zwUoHvwNvFX",
		"ZiVKfdhhmQ1fpXaxyW5zRXw4Dhg9cbKRgK7mNFoBLiKjiBZiHJYJTpV2gNMDMPY9sRC96vnKZcnTMSi65SKPyL4WNQNm9PT5H",
	),
	(
		"SKxsVGKsCESoVb3Gfm762psjRtGHmjmv7HVjHckud5MnESfktUuG",
		"zcWGguu2UPfNhh1ygWW9Joo3osvncsuehtz5ewvXd78vFDdnDCRNG6QeKSZpwZmYmkfEutPVf8HzCfBytqXWsEcF2iBAM1e",
		"ZiVKkMUGwx4GgtwxTedRHYewVVskWicz8APQgdcYmvUsiLYgSh3cLAa8TwiR3shyNngGbLiUbYMkZ8F1giXmmcED98rDMwNSG",
	),
	(
		"SKxp72QGQ2qtovHSoVnPp8jRFQpHBhG1xF8s27iRFjPXXkYMQUA6",
		"zcWZomPYMEjJ49S4UHcvTnhjYqogfdYJuEDMURDpbkrz94bkzdTdJEZKWkkpQ8nK62eyLkZCvLZDFtLC2Cq5BmEK3WCKGMN",
		"ZiVKkeb8STw7kpJQsjRCQKovQBciPcfjkpajuuS25DTXSQSVasnq4BkyaMLBBxAkZ8fv6f18woWgaA8W7kGvYp1C1ESaWGjwV",
	),
	(
		"SKxpmLdykLu3xxSXtw1EA7iLJnXu8hFh8hhmW1B2J2194ijh5CR4",
		"zcgjj3fJF59QGBufopx3F51jCjUpXbgEzec7YQT6jRt4Ebu5EV3AW4jHPN6ZdXhmygBvQDRJrXoZLa3Lkh5GqnsFUzt7Qok",
		"ZiVKvpWQiDpxAvWTMLkjjSbCiBGc4kXhtkgAJfW1JVbCTUY4YaAVvVZzCz6wspG9qttciRFLEXm3HLQAmssFbUp9uPEkP3uu5",
	),
    ];

    #[test]
    fn spending_keys_to_payment_addresses() {
        for &(spending_key_encoded, payment_address_encoded, _) in ENCODED.iter() {
            let mut a_sk = [0u8; 32];
            a_sk.copy_from_slice(
                &bs58::decode(spending_key_encoded).into_vec().unwrap()[2..34],
            );
            let spending_key = SpendingKey::new(a_sk);
            assert_eq!(spending_key_encoded, spending_key.to_string());
            let payment_address = spending_key.address();
            assert_eq!(payment_address_encoded, payment_address.to_string());
        }
    }

    #[test]
    fn spending_keys_to_viewing_keys() {
        for &(spending_key_encoded, _,viewing_key_encoded) in ENCODED.iter() {
            let mut a_sk = [0u8; 32];
            a_sk.copy_from_slice(
                &bs58::decode(spending_key_encoded).into_vec().unwrap()[2..34],
            );
            let spending_key = SpendingKey::new(a_sk);
            assert_eq!(spending_key_encoded, spending_key.to_string());
            let viewing_key = spending_key.viewing_key();
            assert_eq!(viewing_key_encoded, viewing_key.to_string());
        }
    }
}
<|endoftext|>


<commit_before>//! A TCP socket implementation of Hamelin.
#![feature(env, io)]
extern crate hamelin;
extern crate mio;

use std::collections::HashMap;
use std::env::args;
use std::old_io::IoErrorKind::TimedOut;
use hamelin::{BufferedAsyncStream, Hamelin, HamelinGuard};
use mio::{EventLoop, Handler, IoAcceptor, NonBlock, Token};
use mio::event::{Interest, PollOpt, ReadHint};
use mio::net::{SockAddr};
use mio::net::tcp::{TcpSocket, TcpAcceptor};

const SERVER: Token = Token(0);

struct Client {
    stream: BufferedAsyncStream<TcpSocket>,
    guard: HamelinGuard,
}

impl Client {
    fn new(sock: TcpSocket, guard: HamelinGuard) -> Client {
        Client {
            stream: BufferedAsyncStream::new(sock),
            guard: guard
        }
    }

    fn wait(&mut self) -> Result<(), ()> {
        self.guard.wait().map_err(|_| ())
    }

    fn read(&mut self) -> Result<(), ()> {
        match self.stream.read_line() {
            Ok(line) => match self.guard.write_line(&line) {
                Ok(_) => Ok(()),
                Err(ref e) if e.kind == TimedOut => Ok(()),
                Err(_) => Err(()),
            },
            Err(ref e) if e.kind == TimedOut => Ok(()),
            Err(_) => Err(()),
        }
    }

    fn write(&mut self) -> Result<(), ()> {
        match self.guard.read_line() {
            Ok(line) => match self.stream.write_line(&line) {
                Ok(_) => {
                    Ok(())
                },
                Err(ref e) if e.kind == TimedOut => Ok(()),
                Err(_) => Err(()),
            },
            Err(ref e) if e.kind == TimedOut => Ok(()),
            Err(_) => Err(()),
        }
    }
}

struct HamelinHandler {
    server: TcpAcceptor,
    hamelin: Hamelin,
    token_index: usize,
    clients: HashMap<usize, Client>,
}

impl HamelinHandler {
    fn new(server: TcpAcceptor, hamelin: Hamelin) -> HamelinHandler {
        HamelinHandler {
            server: server,
            hamelin: hamelin,
            token_index: 1,
            clients: HashMap::new(),
        }
    }

    fn accept(&mut self, eloop: &mut EventLoop<(), ()>) {
        if let NonBlock::Ready(client) = self.server.accept().unwrap() {
            let token = mio::Token(self.token_index);
            self.token_index += 1;
            eloop.register_opt(&client, token, Interest::all(), PollOpt::level())
                 .ok().expect("Failed to accept new client.");
            self.clients.insert(
                token.as_usize(), Client::new(client, self.hamelin.spawn().unwrap())
            );
            println!("Client connected.");
        }
    }

    fn read(&mut self, token: usize) -> Result<(), ()> {
        let client = &mut self.clients[token];
        let res = client.read();
        res
    }

    fn write(&mut self, token: usize) -> Result<(), ()> {
        if let Some(ref mut client) = self.clients.get_mut(&token) {
            let res = client.write();
            res
        } else {
            Err(())
        }
    }
}

impl Handler<(), ()> for HamelinHandler {
    fn readable(&mut self, eloop: &mut EventLoop<(), ()>, token: Token, _: ReadHint) {
        match token {
            SERVER => self.accept(eloop),
            Token(x) => {
                if let Err(_) = self.read(x) {
                    eloop.deregister(&self.clients[x].stream.stream).unwrap();
                    let _ = self.clients[x].wait();
                    self.clients.remove(&x);
                }
            },
        }
    }

    fn writable(&mut self, _: &mut EventLoop<(), ()>, token: Token) {
        match token {
            SERVER => (),
            Token(x) => {
                let _ = self.write(x);
            }
        }
    }
}

fn main() {
    let args: Vec<_> = args().skip(1).collect();
    if args.len() < 3 {
        println!("Usage: hamelin host port command [args]");
        return;
    }
    let hamelin = Hamelin::new(&args[2], if args.len() > 3 {
        Some(&args[3..])
    } else {
        None
    });
    let addr = SockAddr::parse(&format!("{}:{}", if args[0] == "localhost" { "127.0.0.1" } else
                                        { &args[0][] }, args[1])).unwrap();
    let server = TcpSocket::v4().unwrap()
                    .bind(&addr).unwrap()
                    .listen(256).unwrap();
    println!("Server bound on {:?}.", addr);
    let mut eloop = EventLoop::<(), ()>::new().unwrap();
    eloop.register(&server, SERVER).unwrap();
    eloop.run(HamelinHandler::new(server, hamelin)).ok().expect("Failed to execute event loop.");
}
<commit_msg>Fixed compilation on last mio version.<commit_after>//! A TCP socket implementation of Hamelin.
#![feature(env, io)]
extern crate hamelin;
extern crate mio;

use std::collections::HashMap;
use std::env::args;
use std::old_io::IoErrorKind::TimedOut;
use hamelin::{BufferedAsyncStream, Hamelin, HamelinGuard};
use mio::{EventLoop, Handler, Interest, IoAcceptor, NonBlock, PollOpt, ReadHint, Token};
use mio::net::SockAddr;
use mio::net::tcp::{TcpSocket, TcpAcceptor};

const SERVER: Token = Token(0);

struct Client {
    stream: BufferedAsyncStream<TcpSocket>,
    guard: HamelinGuard,
}

impl Client {
    fn new(sock: TcpSocket, guard: HamelinGuard) -> Client {
        Client {
            stream: BufferedAsyncStream::new(sock),
            guard: guard
        }
    }

    fn wait(&mut self) -> Result<(), ()> {
        self.guard.wait().map_err(|_| ())
    }

    fn read(&mut self) -> Result<(), ()> {
        match self.stream.read_line() {
            Ok(line) => match self.guard.write_line(&line) {
                Ok(_) => Ok(()),
                Err(ref e) if e.kind == TimedOut => Ok(()),
                Err(_) => Err(()),
            },
            Err(ref e) if e.kind == TimedOut => Ok(()),
            Err(_) => Err(()),
        }
    }

    fn write(&mut self) -> Result<(), ()> {
        match self.guard.read_line() {
            Ok(line) => match self.stream.write_line(&line) {
                Ok(_) => {
                    Ok(())
                },
                Err(ref e) if e.kind == TimedOut => Ok(()),
                Err(_) => Err(()),
            },
            Err(ref e) if e.kind == TimedOut => Ok(()),
            Err(_) => Err(()),
        }
    }
}

struct HamelinHandler {
    server: TcpAcceptor,
    hamelin: Hamelin,
    token_index: usize,
    clients: HashMap<usize, Client>,
}

impl HamelinHandler {
    fn new(server: TcpAcceptor, hamelin: Hamelin) -> HamelinHandler {
        HamelinHandler {
            server: server,
            hamelin: hamelin,
            token_index: 1,
            clients: HashMap::new(),
        }
    }

    fn accept(&mut self, eloop: &mut EventLoop<(), ()>) {
        if let NonBlock::Ready(client) = self.server.accept().unwrap() {
            let token = mio::Token(self.token_index);
            self.token_index += 1;
            eloop.register_opt(&client, token, Interest::all(), PollOpt::level())
                 .ok().expect("Failed to accept new client.");
            self.clients.insert(
                token.as_usize(), Client::new(client, self.hamelin.spawn().unwrap())
            );
            println!("Client connected.");
        }
    }

    fn read(&mut self, token: usize) -> Result<(), ()> {
        let client = &mut self.clients[token];
        let res = client.read();
        res
    }

    fn write(&mut self, token: usize) -> Result<(), ()> {
        if let Some(ref mut client) = self.clients.get_mut(&token) {
            let res = client.write();
            res
        } else {
            Err(())
        }
    }
}

impl Handler<(), ()> for HamelinHandler {
    fn readable(&mut self, eloop: &mut EventLoop<(), ()>, token: Token, _: ReadHint) {
        match token {
            SERVER => self.accept(eloop),
            Token(x) => {
                if let Err(_) = self.read(x) {
                    eloop.deregister(&self.clients[x].stream.stream).unwrap();
                    let _ = self.clients[x].wait();
                    self.clients.remove(&x);
                }
            },
        }
    }

    fn writable(&mut self, _: &mut EventLoop<(), ()>, token: Token) {
        match token {
            SERVER => (),
            Token(x) => {
                let _ = self.write(x);
            }
        }
    }
}

fn main() {
    let args: Vec<_> = args().skip(1).collect();
    if args.len() < 3 {
        println!("Usage: hamelin host port command [args]");
        return;
    }
    let hamelin = Hamelin::new(&args[2], if args.len() > 3 {
        Some(&args[3..])
    } else {
        None
    });
    let addr = SockAddr::parse(&format!("{}:{}", if args[0] == "localhost" { "127.0.0.1" } else
                                        { &args[0][] }, args[1])).unwrap();
    let server = TcpSocket::v4().unwrap()
                    .bind(&addr).unwrap()
                    .listen(256).unwrap();
    println!("Server bound on {:?}.", addr);
    let mut eloop = EventLoop::<(), ()>::new().unwrap();
    eloop.register(&server, SERVER).unwrap();
    eloop.run(HamelinHandler::new(server, hamelin)).ok().expect("Failed to execute event loop.");
}
<|endoftext|>


<commit_before>use std::io::process::{Command, ProcessOutput, ProcessExit, Process};
use std::io::process::StdioContainer::*;
use std::io::{IoError, IoErrorKind, IoResult};
use std::collections::VecMap;

use controls::*;
use constants::*;
use termios::*;

pub struct TermState {
    pub controls: Controls,
    tios: Termios,
    old_tios: Termios,
    jobs: VecMap<(String, Process)>
}

impl TermState {
    pub fn new() -> TermState {
        let mut controls = Controls::new();
        let mut tios = match Termios::get() {
            Some(t) => t,
            None => {
                controls.err("Warning: Could not get terminal mode\n");
                Termios::new()
            }
        };
        let old_tios = tios.clone();
        tios.fdisable(0, 0, ICANON|ECHO, 0);

        return TermState {
            controls: controls,
            tios: tios,
            old_tios: old_tios,
            jobs: VecMap::new()
        };
    }

    pub fn update_terminal(&mut self) {
        if !Termios::set(&self.tios) {
            self.controls.err("Warning: Could not set terminal mode\n");
        }
    }

    pub fn restore_terminal(&mut self) {
        if !Termios::set(&self.old_tios) {
            self.controls.err("Warning: Could not set terminal mode\n");
        }
    }

    fn find_jobs_hole(&self) -> usize {
        // find a hole in the job map
        if self.jobs.len() < 20 {
            // with less than twenty jobs just be lazy
            return self.jobs.len() + 1;
        }
        let mut last = 0;
        for key in self.jobs.keys() {
            if key - last != 1 {
                // we've found a hole
                return key - 1;
            } else {
                last = key;
            }
        }
        // job list is full
        return last + 1;
    }

    pub fn run_job(&mut self, name:&String, args:&Vec<String>) -> Result<(usize, String), String> {
        let mut process = Command::new(name);
        process.args(args.as_slice());
        // running as job means no stdin handle
        process.stdin(Ignored);
        // all others are redirected
        let mut child = match process.spawn() {
            Err(e) => {
                return Err(format!("Couldn't spawn {}: {}", name, e));
            },
            Ok(v) => v
        };
        // set wait timeout to zero so we can check for process exit quickly
        child.set_timeout(Some(0));
        let id = self.find_jobs_hole();
        // panic if we've overwritten a job
        match self.jobs.insert(id.clone(), (name.clone(), child)) {
            Some(_) => panic!("Overwrote job"),
            _ => {/* nothing */}
        }
        return Ok((id, name.clone()));
    }

    pub fn clean_jobs(&mut self) -> Vec<(usize, String, IoResult<ProcessExit>)> {
        let mut out = vec![];
        let mut remove = vec![];
        for (id, &mut (ref mut name, ref mut child)) in self.jobs.iter_mut() {
             match child.wait() {
                 Err(IoError{kind: IoErrorKind::TimedOut, desc: _, detail: _}) => {
                     // this is expected, do nothing
                 },
                 v => {
                     // all other outputs mean the job is done
                     // if it isn't it'll be cleaned up in drop
                     child.set_timeout(None);
                     remove.push(id);
                     out.push((id, name.clone(), v));
                 }
             }
        }
        for id in remove.iter() {
            self.jobs.remove(id);
        }
        return out;
    }

    pub fn run_command(&mut self, name:&String, args:&Vec<String>) -> Result<ProcessExit, String> {
        let mut process = Command::new(name);
        process.args(args.as_slice());
        process.stdout(InheritFd(STDOUT));
        process.stdin(InheritFd(STDIN));
        process.stderr(InheritFd(STDERR));
        // set terminal settings for process
        self.restore_terminal();
        let mut child = match process.spawn() {
            Err(e) => {
                self.update_terminal();
                return Err(format!("Couldn't spawn {}: {}", name, e));
            },
            Ok(v) => v
        };
        let out = match child.wait() {
            Err(e) => {
                self.update_terminal();
                return Err(format!("Couldn't wait for child to exit: {}", e));
            },
            Ok(v) => v
        };
        // restore settings for Wash
        self.update_terminal();
        return Ok(out);
    }

    pub fn run_command_directed(&mut self, name:&String,
                                args:&Vec<String>) -> Result<ProcessOutput, String> {
        let mut process = Command::new(name);
        process.args(args.as_slice());
        match process.output() {
            Err(e) => {
                return Err(format!("Couldn't spawn {}: {}", name, e));
            },
            Ok(v) => Ok(v)
        }
    }
}

<commit_msg>Push all running jobs onto job list<commit_after>use std::io::process::{Command, ProcessOutput, ProcessExit, Process};
use std::io::process::StdioContainer::*;
use std::io::{IoError, IoErrorKind, IoResult};
use std::collections::VecMap;

use controls::*;
use constants::*;
use termios::*;

pub struct TermState {
    pub controls: Controls,
    tios: Termios,
    old_tios: Termios,
    jobs: VecMap<(String, Process)>
}

impl TermState {
    pub fn new() -> TermState {
        let mut controls = Controls::new();
        let mut tios = match Termios::get() {
            Some(t) => t,
            None => {
                controls.err("Warning: Could not get terminal mode\n");
                Termios::new()
            }
        };
        let old_tios = tios.clone();
        tios.fdisable(0, 0, ICANON|ECHO, 0);

        return TermState {
            controls: controls,
            tios: tios,
            old_tios: old_tios,
            jobs: VecMap::new()
        };
    }

    pub fn update_terminal(&mut self) {
        if !Termios::set(&self.tios) {
            self.controls.err("Warning: Could not set terminal mode\n");
        }
    }

    pub fn restore_terminal(&mut self) {
        if !Termios::set(&self.old_tios) {
            self.controls.err("Warning: Could not set terminal mode\n");
        }
    }

    fn find_jobs_hole(&self) -> usize {
        // find a hole in the job map
        if self.jobs.len() < 20 {
            // with less than twenty jobs just be lazy
            return self.jobs.len() + 1;
        }
        let mut last = 0;
        for key in self.jobs.keys() {
            if key - last != 1 {
                // we've found a hole
                return key - 1;
            } else {
                last = key;
            }
        }
        // job list is full
        return last + 1;
    }

    pub fn run_job(&mut self, name:&String, args:&Vec<String>) -> Result<(usize, String), String> {
        let mut process = Command::new(name);
        process.args(args.as_slice());
        // running as job means no stdin handle
        process.stdin(Ignored);
        // all others are redirected
        let mut child = match process.spawn() {
            Err(e) => {
                return Err(format!("Couldn't spawn {}: {}", name, e));
            },
            Ok(v) => v
        };
        // set wait timeout to zero so we can check for process exit quickly
        child.set_timeout(Some(0));
        let id = self.find_jobs_hole();
        // panic if we've overwritten a job
        match self.jobs.insert(id.clone(), (name.clone(), child)) {
            Some(_) => panic!("Overwrote job"),
            _ => {/* nothing */}
        }
        return Ok((id, name.clone()));
    }

    pub fn clean_jobs(&mut self) -> Vec<(usize, String, IoResult<ProcessExit>)> {
        let mut out = vec![];
        let mut remove = vec![];
        for (id, &mut (ref mut name, ref mut child)) in self.jobs.iter_mut() {
             match child.wait() {
                 Err(IoError{kind: IoErrorKind::TimedOut, desc: _, detail: _}) => {
                     // this is expected, do nothing
                 },
                 v => {
                     // all other outputs mean the job is done
                     // if it isn't it'll be cleaned up in drop
                     child.set_timeout(None);
                     remove.push(id);
                     out.push((id, name.clone(), v));
                 }
             }
        }
        for id in remove.iter() {
            self.jobs.remove(id);
        }
        return out;
    }

    pub fn run_command(&mut self, name:&String, args:&Vec<String>) -> Result<ProcessExit, String> {
        let mut process = Command::new(name);
        process.args(args.as_slice());
        process.stdout(InheritFd(STDOUT));
        process.stdin(InheritFd(STDIN));
        process.stderr(InheritFd(STDERR));
        // set terminal settings for process
        self.restore_terminal();
        // push job into jobs
        let id = self.find_jobs_hole();
        let val = (name.clone(), match process.spawn() {
            Err(e) => {
                self.update_terminal();
                return Err(format!("Couldn't spawn {}: {}", name, e));
            },
            Ok(v) => v
        });
        self.jobs.insert(id, val);
        let out = match self.jobs.get_mut(&id).unwrap().1.wait() {
            Err(e) => {
                self.update_terminal();
                return Err(format!("Couldn't wait for child to exit: {}", e));
            },
            Ok(v) => v
        };
        // remove job
        self.jobs.remove(&id);
        // restore settings for Wash
        self.update_terminal();
        return Ok(out);
    }

    pub fn run_command_directed(&mut self, name:&String,
                                args:&Vec<String>) -> Result<ProcessOutput, String> {
        let mut process = Command::new(name);
        process.args(args.as_slice());
        let id = self.find_jobs_hole();
        let val = (name.clone(), match process.spawn() {
            Err(e) => {
                self.update_terminal();
                return Err(format!("Couldn't spawn {}: {}", name, e));
            },
            Ok(v) => v
        });
        // put job in jobs list
        self.jobs.insert(id, val);
        let out = match self.jobs.get_mut(&id).unwrap().1.stdout.as_mut().unwrap().read_to_end() {
            Ok(v) => v,
            Err(e) => {
                // remove job
                self.jobs.remove(&id);
                return Err(format!("Couldn't get stdout: {}", e));
            }
        };
        let err = match self.jobs.get_mut(&id).unwrap().1.stderr.as_mut().unwrap().read_to_end() {
            Ok(v) => v,
            Err(e) => {
                // remove job
                self.jobs.remove(&id);
                return Err(format!("Couldn't get stderr: {}", e));
            }
        };
        let output = match self.jobs.get_mut(&id).unwrap().1.wait() {
            Err(e) => {
                self.update_terminal();
                return Err(format!("Couldn't wait for child to exit: {}", e));
            },
            Ok(v) => ProcessOutput {
                status: v,
                output: out,
                error: err
            }
        };
        // remove job
        self.jobs.remove(&id);
        return Ok(output);
    }
}

<|endoftext|>


<commit_before>extern crate toml;

use constants::*;
use self::toml::Table;
use std::collections::BTreeSet;
use std::ffi::OsString;
use std::fs;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};

pub fn initialize() {
    println!("Initialize ...");

    let dir_name    = WORKING_DIR_NAME;
    let path_to_dir = Path::new(dir_name);
    if path_to_dir.exists() && path_to_dir.is_dir() {
        println!("  OK: \"{}\" directory has already exist.", dir_name);
    } else {
        match fs::create_dir(path_to_dir) {
            Ok(_)    => println!("  OK: Created \"{}\" directory.", dir_name),
            Err(why) => panic!("{:?}", why),
        }
    }

    let path_to_config = path_to_dir.clone().join(CONFIG_FILE_NAME);
    create_setting_file(path_to_config, DEFAULT_CONFIG);

    let path_to_ignore = path_to_dir.clone().join(IGNORE_FILE_NAME);
    let ignore_contents = walk_dir(".").iter()
        .fold(String::new(), |c, f| c + &f + "\n");
    create_setting_file(path_to_ignore, ignore_contents);
}

fn create_setting_file<S: AsRef<str>>(path_to_file: PathBuf, contents: S) {
    let file_name = path_to_file.file_name().and_then(|f| f.to_str()).unwrap();
    if path_to_file.exists() && path_to_file.is_file() {
        println!("  OK: \"{}\" file has already exist.", file_name);
    } else {
        match File::create(&path_to_file) {
            Ok(mut fp) => {
                println!("  OK: Created \"{}\" file.", file_name);
                match fp.write(contents.as_ref().as_bytes()) {
                    Ok(_)    => {},
                    Err(why) => panic!("{:?}", why),
                }
            },
            Err(why) => panic!("{:?}", why),
        }
    }
}

fn walk_dir<P: AsRef<Path>>(path: P) -> BTreeSet<String> {
    fn walk_dir(path: PathBuf) -> Vec<OsString> {
        let paths = match fs::read_dir(path) {
            Ok(rd)   => rd,
            Err(why) => panic!("{:?}", why),
        };
        paths
            .filter(|de| de.is_ok())
            .flat_map(|de| {
                let path = de.unwrap().path();
                if is_hidden(&path) {
                    Vec::new()
                } else if path.is_file() {
                    vec![path.into_os_string()]
                } else {
                    walk_dir(path)
                }
            })
            .collect::<Vec<OsString>>()
    }

    walk_dir(path.as_ref().to_path_buf()).iter()
        .map(|f| f.clone().into_string())
        .filter(|f| f.is_ok())
        .map(|f| f.unwrap())
        .collect::<BTreeSet<String>>()
}

fn is_hidden(path: &PathBuf) -> bool {
    let file_name = path.file_name().and_then(|f| f.to_str());
    file_name.map_or(false, |f| f.starts_with("."))
}

pub fn set_params() {
    println!("set parameters");
}

pub fn sweep() {
    println!("Sweep ...");

    let config = read_config_file();
    let ignore = read_ignore_file();

    let target_files = walk_dir(".")
        .difference(&ignore)
        .cloned()
        .collect::<Vec<String>>();

    println!("{:?}", config);
    println!("{:?}", target_files);
}

fn read_config_file() -> Table {
    let config_file = Path::new(WORKING_DIR_NAME).join(CONFIG_FILE_NAME);
    let mut fp      = match File::open(config_file) {
        Ok(fp)   => fp,
        Err(why) => panic!("{:?}", why),
    };
    let mut config = String::new();
    match fp.read_to_string(&mut config) {
        Ok(_)    => {},
        Err(why) => panic!("{:?}", why),
    };

    match toml::Parser::new(&config).parse() {
        Some(toml) => toml,
        None       => panic!("Error occurs on parsing \"{}\".", CONFIG_FILE_NAME),
    }
}

fn read_ignore_file() -> BTreeSet<String> {
    let ignore_file = Path::new(WORKING_DIR_NAME).join(IGNORE_FILE_NAME);
    let mut fp      = match File::open(ignore_file) {
        Ok(fp)   => fp,
        Err(why) => panic!("{:?}", why),
    };
    let mut contents = String::new();
    match fp.read_to_string(&mut contents) {
        Ok(_)    => {},
        Err(why) => panic!("{:?}", why),
    }
    contents
        .lines()
        .map(|l| l.trim().to_string())
        .collect::<BTreeSet<String>>()
}

pub fn burn() {
    println!("burn");
}

pub fn register_with_cron() {
    println!("register");
}

pub fn unregister_cron() {
    println!("unregister");
}

pub fn destroy() {
    println!("Destroy ...");

    match fs::remove_dir_all(WORKING_DIR_NAME) {
        Ok(_)    => println!("  OK: Removed \"{}\" directory.", WORKING_DIR_NAME),
        Err(why) => panic!("{:?}", why),
    }
}
<commit_msg>Rename the variable "fp" => "f"<commit_after>extern crate toml;

use constants::*;
use self::toml::Table;
use std::collections::BTreeSet;
use std::ffi::OsString;
use std::fs;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};

pub fn initialize() {
    println!("Initialize ...");

    let dir_name    = WORKING_DIR_NAME;
    let path_to_dir = Path::new(dir_name);
    if path_to_dir.exists() && path_to_dir.is_dir() {
        println!("  OK: \"{}\" directory has already exist.", dir_name);
    } else {
        match fs::create_dir(path_to_dir) {
            Ok(_)    => println!("  OK: Created \"{}\" directory.", dir_name),
            Err(why) => panic!("{:?}", why),
        }
    }

    let path_to_config = path_to_dir.clone().join(CONFIG_FILE_NAME);
    create_setting_file(path_to_config, DEFAULT_CONFIG);

    let path_to_ignore = path_to_dir.clone().join(IGNORE_FILE_NAME);
    let ignore_contents = walk_dir(".").iter()
        .fold(String::new(), |c, f| c + &f + "\n");
    create_setting_file(path_to_ignore, ignore_contents);
}

fn create_setting_file<S: AsRef<str>>(path_to_file: PathBuf, contents: S) {
    let file_name = path_to_file.file_name().and_then(|f| f.to_str()).unwrap();
    if path_to_file.exists() && path_to_file.is_file() {
        println!("  OK: \"{}\" file has already exist.", file_name);
    } else {
        match File::create(&path_to_file) {
            Ok(mut f) => {
                println!("  OK: Created \"{}\" file.", file_name);
                match f.write(contents.as_ref().as_bytes()) {
                    Ok(_)    => {},
                    Err(why) => panic!("{:?}", why),
                }
            },
            Err(why) => panic!("{:?}", why),
        }
    }
}

fn walk_dir<P: AsRef<Path>>(path: P) -> BTreeSet<String> {
    fn walk_dir(path: PathBuf) -> Vec<OsString> {
        let paths = match fs::read_dir(path) {
            Ok(rd)   => rd,
            Err(why) => panic!("{:?}", why),
        };
        paths
            .filter(|de| de.is_ok())
            .flat_map(|de| {
                let path = de.unwrap().path();
                if is_hidden(&path) {
                    Vec::new()
                } else if path.is_file() {
                    vec![path.into_os_string()]
                } else {
                    walk_dir(path)
                }
            })
            .collect::<Vec<OsString>>()
    }

    walk_dir(path.as_ref().to_path_buf()).iter()
        .map(|f| f.clone().into_string())
        .filter(|f| f.is_ok())
        .map(|f| f.unwrap())
        .collect::<BTreeSet<String>>()
}

fn is_hidden(path: &PathBuf) -> bool {
    let file_name = path.file_name().and_then(|f| f.to_str());
    file_name.map_or(false, |f| f.starts_with("."))
}

pub fn set_params() {
    println!("set parameters");
}

pub fn sweep() {
    println!("Sweep ...");

    let config = read_config_file();
    let ignore = read_ignore_file();

    let target_files = walk_dir(".")
        .difference(&ignore)
        .cloned()
        .collect::<Vec<String>>();

    println!("{:?}", config);
    println!("{:?}", target_files);
}

fn read_config_file() -> Table {
    let config_file = Path::new(WORKING_DIR_NAME).join(CONFIG_FILE_NAME);
    let mut f       = match File::open(config_file) {
        Ok(f)    => f,
        Err(why) => panic!("{:?}", why),
    };
    let mut config = String::new();
    match f.read_to_string(&mut config) {
        Ok(_)    => {},
        Err(why) => panic!("{:?}", why),
    };

    match toml::Parser::new(&config).parse() {
        Some(toml) => toml,
        None       => panic!("Error occurs on parsing \"{}\".", CONFIG_FILE_NAME),
    }
}

fn read_ignore_file() -> BTreeSet<String> {
    let ignore_file = Path::new(WORKING_DIR_NAME).join(IGNORE_FILE_NAME);
    let mut f       = match File::open(ignore_file) {
        Ok(f)    => f,
        Err(why) => panic!("{:?}", why),
    };
    let mut contents = String::new();
    match f.read_to_string(&mut contents) {
        Ok(_)    => {},
        Err(why) => panic!("{:?}", why),
    }
    contents
        .lines()
        .map(|l| l.trim().to_string())
        .collect::<BTreeSet<String>>()
}

pub fn burn() {
    println!("burn");
}

pub fn register_with_cron() {
    println!("register");
}

pub fn unregister_cron() {
    println!("unregister");
}

pub fn destroy() {
    println!("Destroy ...");

    match fs::remove_dir_all(WORKING_DIR_NAME) {
        Ok(_)    => println!("  OK: Removed \"{}\" directory.", WORKING_DIR_NAME),
        Err(why) => panic!("{:?}", why),
    }
}
<|endoftext|>