<commit_before>extern crate mmap;
extern crate time;
extern crate timely;
extern crate getopts;

extern crate graph_map;
extern crate graph_layout;
extern crate radix_sort;

use timely::progress::timestamp::RootTimestamp;
use timely::progress::nested::Summary::Local;
use timely::dataflow::*;
use timely::dataflow::operators::*;
use timely::dataflow::channels::pact::{Pipeline, Exchange};
use timely::drain::DrainExt;

use graph_layout::layout::*;
use graph_layout::compression::*;

use graph_map::graph_map::GraphMMap;

use radix_sort::*;

fn main () {

    /*
        The plan here is to partition the rows of the matrix into #processes parts, and the columns
        into #threads parts. This could be generally #row_parts and #col_parts, but that requires
        more thinking about things.
    */

    let threads: u32 = ::std::env::args().nth(1).unwrap().parse().unwrap();
    let filename = ::std::env::args().nth(2).unwrap();
    let nodes: u32 = ::std::env::args().nth(3).unwrap().parse().unwrap();

    timely::execute_from_args(::std::env::args().skip(3), move |root| {

        let index = root.index() as u32;
        let peers = root.peers() as u32;
        let processes = (peers / threads) as u32;
        let dst_index = index % threads;

        let start = time::precise_time_s();
        let mut going = start;

        let mut counter = 0;
        let mut sorter = RadixSorter::new();
        let hilbert = Hilbert::new();
        let mut decoder = BytewiseCached::new();
        let mut compressed = vec![];

        // let nodes: u32 = 3_563_602_788 + 1;

        let local_srcs = (nodes / processes) + 1;
        let local_dsts = (nodes / threads) + 1;

        // degree is ignored at the moment.
        // mostly just a pain to put together.
        let deg = vec![1.0f32; local_srcs as usize];
        let mut src = vec![1.0f32; local_srcs as usize];
        let mut dst = vec![0.0f32; local_dsts as usize];

        let mut input = root.scoped(|builder| {

            let (input, edges) = builder.new_input::<(u32, u32)>();
            let (cycle, ranks) = builder.loop_variable::<(u32, f32)>(RootTimestamp::new(20), Local(1));

            let ranks = edges.binary_notify(&ranks,
                                Exchange::new(|x: &(u32,u32)| x.0 as u64),
                                Pipeline,   // data are partitioned as part of the broadcast step.
                                "hilbrank",
                                vec![RootTimestamp::new(0)],
                                move |input1, input2, output, notificator| {

                // receive incoming edges (should only be iter 0)
                while let Some((_index, data)) = input1.next() {
                    counter += data.len();
                    for &(src,dst) in data.iter() {
                        let shrunk = (src / processes, dst / threads);
                        sorter.push(hilbert.entangle(shrunk), &|&x| x);
                    }

                    // should be 1GB per worker
                    if counter > (1 << 27) {
                        let mut results = sorter.finish(&|&x| x);
                        let mut compressor = Compressor::with_capacity(counter);
                        for vec in results.iter_mut() {
                            for elem in vec.drain_temp() {
                                compressor.push(elem);
                            }
                        }
                        sorter.recycle(results);
                        compressed.push(compressor.done());
                        counter = 0;
                    }
                }

                if counter > 0 {
                    // round out any remaining edges
                    println!("starting a sort of {} elements", counter);
                    let mut results = sorter.finish(&|&x| x);
                    println!("sorting done! compressing");
                    let mut compressor = Compressor::with_capacity(counter);
                    for vec in results.iter_mut() {
                        for elem in vec.drain_temp() {
                            compressor.push(elem);
                        }
                    }
                    println!("compression done!");
                    compressed.push(compressor.done());
                    counter = 0;
                }

                // all inputs received for iter, commence multiplication
                while let Some((iter, _)) = notificator.next() {

                    let now = time::now();

                    if index == 0 { println!("{}:{}:{}.{} starting iteration {}", now.tm_hour, now.tm_min, now.tm_sec, now.tm_nsec, iter.inner); }

                    // if the very first iteration, prepare some stuff.
                    if iter.inner == 0 {
                        // now we would merge the compressed representations, if we want to.
                        // let's measure both doing this and not doing it. :)

                    }

                    // record some timings in order to estimate per-iteration times
                    // if iter.inner == 0  && index == 0 { println!("src: {}, dst: {}, edges: {}", src.len(), rev.len(), trn.len()); }
                    if iter.inner == 10 && index == 0 { going = time::precise_time_s(); }
                    if iter.inner == 20 && index == 0 { println!("average: {}", (time::precise_time_s() - going) / 10.0 ); }

                    // prepare src for transmitting to destinations
                    for s in 0..src.len() { src[s] = 0.15 + 0.85 * src[s] / deg[s] as f32; }
                    for d in 0..dst.len() { dst[d] = 0.0; }

                    // do the multiplication for each compressed sequence
                    for sequence in &compressed {
                        for element in sequence.decompress() {
                            let (s,d) = decoder.detangle(element);
                            dst[d as usize] += src[s as usize];
                        }
                    }

                    for s in 0..src.len() { src[s] = 0.0; }

                    // now we need to send some stuff to other threads.
                    // TODO : This could be done as blocks, as they mostly go to the same place.
                    let mut session = output.session(&iter);
                    for (index, &value) in dst.iter().enumerate() {
                        if value != 0.0 {
                            session.give((index as u32 * threads + dst_index, value));
                        }
                    }
                }

                // receive data from threads, accumulate in src
                while let Some((iter, data)) = input2.next() {
                    notificator.notify_at(&iter);
                    for &(node, rank) in data.iter() {
                        src[(node / processes) as usize] += rank;
                    }
                }
            });

            let mut aggregates = vec![0.0f32; (nodes / peers) as usize];
            // want to do aggregation so that aggregates are local to the folks who will need them.
            // that is, (node, rank) goes to some worker on machine#: name % processes
            let aggregated = ranks.unary_notify(
                Exchange::new(move |&(n,_): &(u32,f32)| (((n % processes) * threads) + ((n / processes) % threads)) as u64),
                "aggregation",
                vec![],
                move |input, output, notificator | {

                while let Some((time, data)) = input.next() {
                    notificator.notify_at(time);
                    for &(node, rank) in data.iter() {
                        aggregates[(node / peers) as usize] += rank;
                    }
                }

                while let Some((time, _)) = notificator.next() {
                    println!("notificating aggregator at {:?}", time);
                    let mut session = output.session(&time);
                    for (node, &rank) in aggregates.iter().enumerate() {
                        if rank != 0.0 {
                            session.give((node as u32 * peers, rank));
                        }
                    }
                }
            });

            // data are now aggregated, and only need to be broadcast out to the intended recipients
            // ideally, none of this actually ends up hitting the network. also, it seems like it
            // shouldn't even require looking at `node`, on account of already putting all the data
            // on the right processes. We should be able to use (index / threads) * threads, I think.
            let mut exchanged = aggregated.exchange(move |&(node, _)| ((node % processes) * threads) as u64);
            for i in 1..threads {
                exchanged = aggregated.exchange(move |&(node, _)| (((node % processes) * threads) + i) as u64)
                                      .concat(&exchanged);
            }

            exchanged.connect_loop(cycle);

            input
        });

        println!("about to open up prefix: {}", filename);

        // introduce edges into the computation;
        // allow mmaped file to drop
        {
            let graph = GraphMMap::new(&filename);
            for node in 0..graph.nodes() {
                if node as u32 % peers == index {
                    for dst in graph.edges(node) {
                        input.send((node as u32, *dst as u32));
                    }
                }
            }
        }
        input.close();
        while root.step() { }

        if index == 0 { println!("elapsed: {}", time::precise_time_s() - start); }
    });

}
<commit_msg>diagnostics<commit_after>extern crate mmap;
extern crate time;
extern crate timely;
extern crate getopts;

extern crate graph_map;
extern crate graph_layout;
extern crate radix_sort;

use timely::progress::timestamp::RootTimestamp;
use timely::progress::nested::Summary::Local;
use timely::dataflow::*;
use timely::dataflow::operators::*;
use timely::dataflow::channels::pact::{Pipeline, Exchange};
use timely::drain::DrainExt;

use graph_layout::layout::*;
use graph_layout::compression::*;

use graph_map::graph_map::GraphMMap;

use radix_sort::*;

fn main () {

    /*
        The plan here is to partition the rows of the matrix into #processes parts, and the columns
        into #threads parts. This could be generally #row_parts and #col_parts, but that requires
        more thinking about things.
    */

    let threads: u32 = ::std::env::args().nth(1).unwrap().parse().unwrap();
    println!("threads: {}", threads);
    let filename = ::std::env::args().nth(2).unwrap();
    println!("filename: {}", filename);
    let nodes: u32 = ::std::env::args().nth(3).unwrap().parse().unwrap();
    println!("nodes: {}", nodes);

    timely::execute_from_args(::std::env::args().skip(4), move |root| {

        let index = root.index() as u32;
        let peers = root.peers() as u32;
        let processes = (peers / threads) as u32;
        let dst_index = index % threads;

        let start = time::precise_time_s();
        let mut going = start;

        let mut counter = 0;
        let mut sorter = RadixSorter::new();
        let hilbert = Hilbert::new();
        let mut decoder = BytewiseCached::new();
        let mut compressed = vec![];

        // let nodes: u32 = 3_563_602_788 + 1;

        let local_srcs = (nodes / processes) + 1;
        let local_dsts = (nodes / threads) + 1;

        // degree is ignored at the moment.
        // mostly just a pain to put together.
        let deg = vec![1.0f32; local_srcs as usize];
        let mut src = vec![1.0f32; local_srcs as usize];
        let mut dst = vec![0.0f32; local_dsts as usize];

        let mut input = root.scoped(|builder| {

            let (input, edges) = builder.new_input::<(u32, u32)>();
            let (cycle, ranks) = builder.loop_variable::<(u32, f32)>(RootTimestamp::new(20), Local(1));

            let ranks = edges.binary_notify(&ranks,
                                Exchange::new(|x: &(u32,u32)| x.0 as u64),
                                Pipeline,   // data are partitioned as part of the broadcast step.
                                "hilbrank",
                                vec![RootTimestamp::new(0)],
                                move |input1, input2, output, notificator| {

                // receive incoming edges (should only be iter 0)
                while let Some((_index, data)) = input1.next() {
                    counter += data.len();
                    for &(src,dst) in data.iter() {
                        let shrunk = (src / processes, dst / threads);
                        sorter.push(hilbert.entangle(shrunk), &|&x| x);
                    }

                    // should be 1GB per worker
                    if counter > (1 << 27) {
                        let mut results = sorter.finish(&|&x| x);
                        let mut compressor = Compressor::with_capacity(counter);
                        for vec in results.iter_mut() {
                            for elem in vec.drain_temp() {
                                compressor.push(elem);
                            }
                        }
                        sorter.recycle(results);
                        compressed.push(compressor.done());
                        counter = 0;
                    }
                }

                if counter > 0 {
                    // round out any remaining edges
                    println!("starting a sort of {} elements", counter);
                    let mut results = sorter.finish(&|&x| x);
                    println!("sorting done! compressing");
                    let mut compressor = Compressor::with_capacity(counter);
                    for vec in results.iter_mut() {
                        for elem in vec.drain_temp() {
                            compressor.push(elem);
                        }
                    }
                    println!("compression done!");
                    compressed.push(compressor.done());
                    counter = 0;
                }

                // all inputs received for iter, commence multiplication
                while let Some((iter, _)) = notificator.next() {

                    let now = time::now();

                    if index == 0 { println!("{}:{}:{}.{} starting iteration {}", now.tm_hour, now.tm_min, now.tm_sec, now.tm_nsec, iter.inner); }

                    // if the very first iteration, prepare some stuff.
                    if iter.inner == 0 {
                        // now we would merge the compressed representations, if we want to.
                        // let's measure both doing this and not doing it. :)

                    }

                    // record some timings in order to estimate per-iteration times
                    // if iter.inner == 0  && index == 0 { println!("src: {}, dst: {}, edges: {}", src.len(), rev.len(), trn.len()); }
                    if iter.inner == 10 && index == 0 { going = time::precise_time_s(); }
                    if iter.inner == 20 && index == 0 { println!("average: {}", (time::precise_time_s() - going) / 10.0 ); }

                    // prepare src for transmitting to destinations
                    for s in 0..src.len() { src[s] = 0.15 + 0.85 * src[s] / deg[s] as f32; }
                    for d in 0..dst.len() { dst[d] = 0.0; }

                    // do the multiplication for each compressed sequence
                    for sequence in &compressed {
                        for element in sequence.decompress() {
                            let (s,d) = decoder.detangle(element);
                            dst[d as usize] += src[s as usize];
                        }
                    }

                    for s in 0..src.len() { src[s] = 0.0; }

                    // now we need to send some stuff to other threads.
                    // TODO : This could be done as blocks, as they mostly go to the same place.
                    let mut session = output.session(&iter);
                    for (index, &value) in dst.iter().enumerate() {
                        if value != 0.0 {
                            session.give((index as u32 * threads + dst_index, value));
                        }
                    }
                }

                // receive data from threads, accumulate in src
                while let Some((iter, data)) = input2.next() {
                    notificator.notify_at(&iter);
                    for &(node, rank) in data.iter() {
                        src[(node / processes) as usize] += rank;
                    }
                }
            });

            let mut aggregates = vec![0.0f32; (nodes / peers) as usize];
            // want to do aggregation so that aggregates are local to the folks who will need them.
            // that is, (node, rank) goes to some worker on machine#: name % processes
            let aggregated = ranks.unary_notify(
                Exchange::new(move |&(n,_): &(u32,f32)| (((n % processes) * threads) + ((n / processes) % threads)) as u64),
                "aggregation",
                vec![],
                move |input, output, notificator | {

                while let Some((time, data)) = input.next() {
                    notificator.notify_at(time);
                    for &(node, rank) in data.iter() {
                        aggregates[(node / peers) as usize] += rank;
                    }
                }

                while let Some((time, _)) = notificator.next() {
                    println!("notificating aggregator at {:?}", time);
                    let mut session = output.session(&time);
                    for (node, &rank) in aggregates.iter().enumerate() {
                        if rank != 0.0 {
                            session.give((node as u32 * peers, rank));
                        }
                    }
                }
            });

            // data are now aggregated, and only need to be broadcast out to the intended recipients
            // ideally, none of this actually ends up hitting the network. also, it seems like it
            // shouldn't even require looking at `node`, on account of already putting all the data
            // on the right processes. We should be able to use (index / threads) * threads, I think.
            let mut exchanged = aggregated.exchange(move |&(node, _)| ((node % processes) * threads) as u64);
            for i in 1..threads {
                exchanged = aggregated.exchange(move |&(node, _)| (((node % processes) * threads) + i) as u64)
                                      .concat(&exchanged);
            }

            exchanged.connect_loop(cycle);

            input
        });

        println!("about to open up prefix: {}", filename);

        // introduce edges into the computation;
        // allow mmaped file to drop
        {
            let graph = GraphMMap::new(&filename);
            for node in 0..graph.nodes() {
                if node as u32 % peers == index {
                    for dst in graph.edges(node) {
                        input.send((node as u32, *dst as u32));
                    }
                }
            }
        }
        input.close();
        while root.step() { }

        if index == 0 { println!("elapsed: {}", time::precise_time_s() - start); }
    });

}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]
// #![deny(clippy_pedantic)]
extern crate termion;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate log4rs;

mod core;

use termion::{clear, cursor};
use termion::raw::IntoRawMode;
use termion::input::TermRead;
use std::io::{stdout, Write, stdin};
use std::sync::mpsc;
use std::{thread, time};
use core::Core;

struct Screen {
    stdout: termion::raw::RawTerminal<std::io::Stdout>,
    size: (u16, u16),
}

impl Screen {

    fn new() -> Screen {
        let mut stdout = stdout().into_raw_mode().unwrap();
        write!(stdout, "{}", clear::All).unwrap();
        stdout.flush().unwrap();
        Screen {
            size: termion::terminal_size().unwrap(),
            stdout: stdout,
        }
    }

    fn redraw(&mut self, mut update: &Update) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        for (_, line) in update.lines.iter().enumerate() {
            write!(self.stdout, "{}", cursor::Left(self.size.0)).unwrap();
            self.stdout.write_all(line.text.as_bytes()).unwrap();
        }
        // this is pretty weird
        write!(self.stdout, "{}", cursor::Goto(update.scroll_to.1 as u16 + 1, update.scroll_to.0 as u16 + 1)).unwrap();
        self.stdout.flush().unwrap();
    }

    fn init(&mut self) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        self.stdout.flush().unwrap();
    }

}

struct Update {
    lines: Vec<Line>,
    height: u64,
    scroll_to: (u64, u64),
    first_line: u64
}

impl Update {
    fn from_value(value: &serde_json::Value) -> Update {
        let object = value.as_object().unwrap();
        let scroll_to = object.get("scrollto").unwrap().as_array().unwrap();
        let mut lines: Vec<Line> = vec![];
        for line in object.get("lines").unwrap().as_array().unwrap().iter() {
            lines.push(Line::from_value(line));
        }
        info!("{:?}", object);
        Update {
            height: object.get("height").unwrap().as_u64().unwrap(),
            first_line: object.get("first_line").unwrap().as_u64().unwrap(),
            lines: lines,
            scroll_to: (scroll_to[0].as_u64().unwrap(), scroll_to[1].as_u64().unwrap()),
        }
    }
}

struct Line {
    text: String,
    selection: Option<(u64, u64)>,
    cursor: Option<u64>,
}

impl Line {
    fn from_value(value: &serde_json::Value) -> Line {
        let line_arr = value.as_array().unwrap();
        let mut line = Line {
            text: line_arr[0].as_str().unwrap().to_string(),
            cursor: None,
            selection: None,
        };
        for annotation in line_arr.iter().skip(1).map(|a| a.as_array().unwrap()) {
            match annotation[0].as_str().unwrap() {
                "cursor" => {
                    line.cursor = Some(annotation[1].as_u64().unwrap());
                },
                "sel" => {
                    line.selection = Some((annotation[1].as_u64().unwrap(), annotation[2].as_u64().unwrap()));
                },
                _ => {
                    error!("unknown annotation");
                }
            }
        }
        line
    }
}

fn update_screen(core: &mut Core, screen: &mut Screen) {
    if let Ok(msg) = core.update_rx.try_recv() {
        let update = Update::from_value(msg.as_object().unwrap().get("update").unwrap());
        screen.redraw(&update);
    } else {
        thread::sleep_ms(10);
    }
}

pub struct Input {
    tx: mpsc::Sender<termion::event::Event>,
    rx: mpsc::Receiver<termion::event::Event>,
}

impl Input {
    pub fn new() -> Input {
        let (tx, rx) = mpsc::channel();
        Input {
            tx: tx,
            rx: rx,
        }
    }

    pub fn run(&mut self) {
        let tx = self.tx.clone();
        thread::spawn(move || {
            for event_res in stdin().events() {
                match event_res {
                    Ok(event) => {
                        info!("event: {:?}", event);
                        tx.send(event).unwrap();
                    },
                    Err(err) => {
                        error!("{:?}", err);
                    }
                }
            }
        });
    }
}

impl Default for Input {
	fn default() -> Self {
		Self::new()
	}
}

fn main() {
    log4rs::init_file("log_config.yaml", Default::default()).unwrap();
    let mut core = Core::new("../xi-editor/rust/target/debug/xi-core");
    let mut screen = Screen::new();
    let mut input = Input::new();
    input.run();
    screen.init();
    loop {
        if let Ok(event) = input.rx.try_recv() {
            match event {
                termion::event::Event::Key(key) => {
                    match key {
                        termion::event::Key::Char(c) => {
                            core.char(c);
                        },
                        termion::event::Key::Ctrl(c) => {
                            if c == 'c' {
                                info!("received ^C: exiting");
                                return;
                            }
                        },
                        _ => {
                            error!("unsupported key event");
                        }
                    }
                },
                termion::event::Event::Mouse(_) => {
                    error!("mouse events are not supported yet");
                }
                _ => {
                    error!("unsupported event");
                }
            }
        } else {
            update_screen(&mut core, &mut screen);
        }
    }
}
<commit_msg>fix un-necessary mutable borrow<commit_after>#![feature(plugin)]
#![plugin(clippy)]
// #![deny(clippy_pedantic)]
extern crate termion;
extern crate serde_json;
#[macro_use]
extern crate log;
extern crate log4rs;

mod core;

use termion::{clear, cursor};
use termion::raw::IntoRawMode;
use termion::input::TermRead;
use std::io::{stdout, Write, stdin};
use std::sync::mpsc;
use std::{thread, time};
use core::Core;

struct Screen {
    stdout: termion::raw::RawTerminal<std::io::Stdout>,
    size: (u16, u16),
}

impl Screen {

    fn new() -> Screen {
        let mut stdout = stdout().into_raw_mode().unwrap();
        write!(stdout, "{}", clear::All).unwrap();
        stdout.flush().unwrap();
        Screen {
            size: termion::terminal_size().unwrap(),
            stdout: stdout,
        }
    }

    fn redraw(&mut self, update: &Update) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        for (_, line) in update.lines.iter().enumerate() {
            write!(self.stdout, "{}", cursor::Left(self.size.0)).unwrap();
            self.stdout.write_all(line.text.as_bytes()).unwrap();
        }
        // this is pretty weird
        write!(self.stdout, "{}", cursor::Goto(update.scroll_to.1 as u16 + 1, update.scroll_to.0 as u16 + 1)).unwrap();
        self.stdout.flush().unwrap();
    }

    fn init(&mut self) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        self.stdout.flush().unwrap();
    }

}

struct Update {
    lines: Vec<Line>,
    height: u64,
    scroll_to: (u64, u64),
    first_line: u64
}

impl Update {
    fn from_value(value: &serde_json::Value) -> Update {
        let object = value.as_object().unwrap();
        let scroll_to = object.get("scrollto").unwrap().as_array().unwrap();
        let mut lines: Vec<Line> = vec![];
        for line in object.get("lines").unwrap().as_array().unwrap().iter() {
            lines.push(Line::from_value(line));
        }
        info!("{:?}", object);
        Update {
            height: object.get("height").unwrap().as_u64().unwrap(),
            first_line: object.get("first_line").unwrap().as_u64().unwrap(),
            lines: lines,
            scroll_to: (scroll_to[0].as_u64().unwrap(), scroll_to[1].as_u64().unwrap()),
        }
    }
}

struct Line {
    text: String,
    selection: Option<(u64, u64)>,
    cursor: Option<u64>,
}

impl Line {
    fn from_value(value: &serde_json::Value) -> Line {
        let line_arr = value.as_array().unwrap();
        let mut line = Line {
            text: line_arr[0].as_str().unwrap().to_string(),
            cursor: None,
            selection: None,
        };
        for annotation in line_arr.iter().skip(1).map(|a| a.as_array().unwrap()) {
            match annotation[0].as_str().unwrap() {
                "cursor" => {
                    line.cursor = Some(annotation[1].as_u64().unwrap());
                },
                "sel" => {
                    line.selection = Some((annotation[1].as_u64().unwrap(), annotation[2].as_u64().unwrap()));
                },
                _ => {
                    error!("unknown annotation");
                }
            }
        }
        line
    }
}

fn update_screen(core: &mut Core, screen: &mut Screen) {
    if let Ok(msg) = core.update_rx.try_recv() {
        let update = Update::from_value(msg.as_object().unwrap().get("update").unwrap());
        screen.redraw(&update);
    } else {
        thread::sleep_ms(10);
    }
}

pub struct Input {
    tx: mpsc::Sender<termion::event::Event>,
    rx: mpsc::Receiver<termion::event::Event>,
}

impl Input {
    pub fn new() -> Input {
        let (tx, rx) = mpsc::channel();
        Input {
            tx: tx,
            rx: rx,
        }
    }

    pub fn run(&mut self) {
        let tx = self.tx.clone();
        thread::spawn(move || {
            for event_res in stdin().events() {
                match event_res {
                    Ok(event) => {
                        info!("event: {:?}", event);
                        tx.send(event).unwrap();
                    },
                    Err(err) => {
                        error!("{:?}", err);
                    }
                }
            }
        });
    }
}

impl Default for Input {
	fn default() -> Self {
		Self::new()
	}
}

fn main() {
    log4rs::init_file("log_config.yaml", Default::default()).unwrap();
    let mut core = Core::new("../xi-editor/rust/target/debug/xi-core");
    let mut screen = Screen::new();
    let mut input = Input::new();
    input.run();
    screen.init();
    loop {
        if let Ok(event) = input.rx.try_recv() {
            match event {
                termion::event::Event::Key(key) => {
                    match key {
                        termion::event::Key::Char(c) => {
                            core.char(c);
                        },
                        termion::event::Key::Ctrl(c) => {
                            if c == 'c' {
                                info!("received ^C: exiting");
                                return;
                            }
                        },
                        _ => {
                            error!("unsupported key event");
                        }
                    }
                },
                termion::event::Event::Mouse(_) => {
                    error!("mouse events are not supported yet");
                }
                _ => {
                    error!("unsupported event");
                }
            }
        } else {
            update_screen(&mut core, &mut screen);
        }
    }
}
<|endoftext|>


<commit_before>//#![deny(warnings)]

extern crate git2;
extern crate docopt;
extern crate rustc_serialize;

use std::str;
use docopt::Docopt;
use git2::{Repository, Error, StatusOptions, ErrorCode, SubmoduleIgnore};

#[derive(RustcDecodable)]
struct Args {
    arg_spec: Vec<String>,
    flag_git_dir: Option<String>,
}

fn run(args: &Args) -> Result<(), Error> {
    let path = args.flag_git_dir.clone().unwrap_or(".".to_string());
    let repo = try!(Repository::open(&path));

    if repo.is_bare() {
        return Err(Error::from_str("Bare repositories are not allowed"))
    }

    let mut opts = StatusOptions::new();

    for spec in args.arg_spec.iter() {
        opts.pathspec(spec);
    }

    loop {
        let statuses = try!(repo.statuses(Some(&mut opts)));
        let current_branch = try!(branch(&repo));

        println!("Current branch {:?}", current_branch);

        print_short(&repo, statuses);

        return Ok(())
    }
}

fn branch<'a>(repo: &'a Repository) -> Result<String, Error> {
    let head = match repo.head() {
        Ok(head) => Some(head),
            Err(ref e) if e.code() == ErrorCode::UnbornBranch ||
                          e.code() == ErrorCode::NotFound
                       => None,
            Err(e) => return Err(e),
    };
    let branchref = head.as_ref().and_then(|h| h.shorthand());
    let branchname = branchref.unwrap_or("HEAD (no branch)").to_string();

    Ok(branchname)
}

// This version of the output prefixes each path with two status columns and
// shows submodule status information.
fn print_short(repo: &Repository, statuses: git2::Statuses) {
    for entry in statuses.iter().filter(|e| e.status() != git2::STATUS_CURRENT) {
        let mut istatus = match entry.status() {
            s if s.contains(git2::STATUS_INDEX_NEW) => 'A',
            s if s.contains(git2::STATUS_INDEX_MODIFIED) => 'M',
            s if s.contains(git2::STATUS_INDEX_DELETED) => 'D',
            s if s.contains(git2::STATUS_INDEX_RENAMED) => 'R',
            s if s.contains(git2::STATUS_INDEX_TYPECHANGE) => 'T',
            _ => ' ',
        };
        let mut wstatus = match entry.status() {
            s if s.contains(git2::STATUS_WT_NEW) => {
                if istatus == ' ' { istatus = '?'; } '?'
            }
            s if s.contains(git2::STATUS_WT_MODIFIED) => 'M',
            s if s.contains(git2::STATUS_WT_DELETED) => 'D',
            s if s.contains(git2::STATUS_WT_RENAMED) => 'R',
            s if s.contains(git2::STATUS_WT_TYPECHANGE) => 'T',
            _ => ' ',
        };

        if entry.status().contains(git2::STATUS_IGNORED) {
            istatus = '!';
            wstatus = '!';
        }
        if istatus == '?' && wstatus == '?' { continue }
        let mut extra = "";

        // TODO: check for GIT_FILEMODE_COMMIT
        let status = entry.index_to_workdir().and_then(|diff| {
            let ignore = SubmoduleIgnore::Unspecified;
            diff.new_file().path_bytes()
                .and_then(|s| str::from_utf8(s).ok())
                .and_then(|name| repo.submodule_status(name, ignore).ok())
        });
        if let Some(status) = status {
            if status.contains(git2::SUBMODULE_STATUS_WD_MODIFIED) {
                extra = " (new commits)";
            } else if status.contains(git2::SUBMODULE_STATUS_WD_INDEX_MODIFIED) {
                extra = " (modified content)";
            } else if status.contains(git2::SUBMODULE_STATUS_WD_WD_MODIFIED) {
                extra = " (modified content)";
            } else if status.contains(git2::SUBMODULE_STATUS_WD_UNTRACKED) {
                extra = " (untracked content)";
            }
        }

        let (mut a, mut b, mut c) = (None, None, None);
        if let Some(diff) = entry.head_to_index() {
            a = diff.old_file().path();
            b = diff.new_file().path();
        }
        if let Some(diff) = entry.index_to_workdir() {
            a = a.or(diff.old_file().path());
            b = b.or(diff.old_file().path());
            c = diff.new_file().path();
        }

        match (istatus, wstatus) {
            ('R', 'R') => println!("RR {} {} {}{}", a.unwrap().display(),
                                   b.unwrap().display(), c.unwrap().display(),
                                   extra),
            ('R', w) => println!("R{} {} {}{}", w, a.unwrap().display(),
                                 b.unwrap().display(), extra),
            (i, 'R') => println!("{}R {} {}{}", i, a.unwrap().display(),
                                 c.unwrap().display(), extra),
            (i, w) => println!("{}{} {}{}", i, w, a.unwrap().display(), extra),
        }
    }

    for entry in statuses.iter().filter(|e| e.status() == git2::STATUS_WT_NEW) {
        println!("?? {}", entry.index_to_workdir().unwrap().old_file()
                               .path().unwrap().display());
    }
}

// impl Args {
// }

fn main() {
    const USAGE: &'static str = "
usage: absorb [options] [--] [<branchname>]

Options:
    -h, --help                  show this message
";

    let args = Docopt::new(USAGE).and_then(|d| d.decode())
                                 .unwrap_or_else(|e| e.exit());
    match run(&args) {
        Ok(()) => {}
        Err(e) => println!("error: {}", e),
    }
}
<commit_msg>Add checkout() and pull()<commit_after>//#![deny(warnings)]

extern crate git2;
extern crate docopt;
extern crate rustc_serialize;

use std::process::{Command, exit};

use docopt::Docopt;
use git2::{Repository, Error, StatusOptions, ErrorCode};

#[derive(RustcDecodable)]
struct Args {
    arg_spec: Vec<String>,
    flag_git_dir: Option<String>,
}

/// Gets the current branch.
///
/// # Examples
///
/// ```
/// let repo = try!(Repository::open("."));
/// let branchname = try!(branch(&repo));
/// ```
fn branch<'a>(repo: &'a Repository) -> Result<String, Error> {
    let head = match repo.head() {
        Ok(head) => Some(head),
            Err(ref e) if e.code() == ErrorCode::UnbornBranch ||
                          e.code() == ErrorCode::NotFound
                       => None,
            Err(e) => return Err(e),
    };
    let branchref = head.as_ref().and_then(|h| h.shorthand());
    let branchname = branchref.unwrap_or("HEAD (no branch)").to_string();

    Ok(branchname)
}

fn run(args: &Args) -> Result<(), Error> {
    let path = args.flag_git_dir.clone().unwrap_or(".".to_string());
    let repo = try!(Repository::open(&path));

    if repo.is_bare() {
        return Err(Error::from_str("Bare repositories are not allowed"))
    }

    let mut opts = StatusOptions::new();

    for spec in args.arg_spec.iter() {
        opts.pathspec(spec);
    }

    let current_branch = try!(branch(&repo));

    println!("Current branch {:?}", current_branch);

    checkout("master");
    pull("origin", "master");
    checkout(current_branch);
    // rebase("master");

    return Ok(())
}

fn checkout(target_branch: &str) {
    let output = Command::new("git")
                         .arg("checkout")
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Checking out {} ...", target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}

fn pull(target_remote: &str, target_branch: &str) {
    let output = Command::new("git")
                         .arg("pull")
                         .arg("--quiet")
                         .arg("--rebase=preserve")
                         .arg(target_remote)
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Pulling {} {} ...", target_remote, target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}

fn main() {
    const USAGE: &'static str = "
usage: absorb [options] [--] [<branchname>]

Options:
    -h, --help                  show this message
";

    let args = Docopt::new(USAGE).and_then(|d| d.decode())
                                 .unwrap_or_else(|e| e.exit());
    match run(&args) {
        Ok(()) => {}
        Err(e) => println!("error: {}", e),
    }
}
<|endoftext|>


<commit_before>extern crate num;
extern crate portaudio;
extern crate rtlsdr;
extern crate dft;
extern crate gnuplot;

use portaudio as pa;
use rtlsdr::{RTLSDRDevice, RTLSDRError};
use num::{Num, Zero};
use num::complex::Complex;
use std::env;
use std::f32::consts::PI;
use std::error::Error;
use pa::error::Error as PAError;
use std::thread;
use std::sync::mpsc::channel;

use gnuplot::*;
use dft::{Operation, Plan};

// Make sure that the buffer size is radix-2, otherwise the read_sync function
// will fail with an error code of -8.
const SDR_BUF_SIZE: usize = 524288;

// Separating out the buffer sizes seems to help some.
const BUF_SIZE: usize = 262144;

// Most other sample rates fail, but this one works for my particular device.
// I will investigate exactly what's happening here and generate a list of
// possible sample rates (if there are others besides this one).
const SAMPLE_RATE: u32 = 2400000;

// Here is the sample rate of the output waveform we'll try to use.
const SAMPLE_RATE_AUDIO: f32 = 48000.0;

// The number of channels being used for audio.
const CHANNELS: i32 = 2;

fn main() {
    match run() {
        Ok(()) => (),
        Err(e) => println!("ERROR: {}", e),
    }
}

struct RTLSDR {
    rtlsdr: RTLSDRDevice,
}

unsafe impl Send for RTLSDR {}

fn run() -> Result<(), Box<Error>> {
    let sdr_index: i32 = env::args()
        .nth(1)
        .expect("Please specify the SDR index.")
        .parse::<i32>()?;
    let fm_freq_mhz: f32 = env::args()
        .nth(2)
        .expect("Please specify a center frequency in MHz.")
        .parse::<f32>()?;
    let bandwidth: u32 = env::args()
        .nth(3)
        .expect("Please specify the bandwidth.")
        .parse::<u32>()?;

    // Initialize the SDR based on the user's input parameters.
    let fm_freq: u32 = (fm_freq_mhz * 1e6) as u32;
    let mut sdr =
        RTLSDR { rtlsdr: init_sdr(sdr_index, fm_freq, bandwidth).unwrap() };

    // Set up the threading channels for communication between our two threads.
    let (dongle_tx, dongle_rx) = channel();
    let (demod_tx, demod_rx) = channel();

    // This thread only collects data off of the SDR as quickly as possible and
    // sends it out.
    thread::spawn(move || loop {
        let bytes = sdr.rtlsdr.read_sync(SDR_BUF_SIZE).unwrap();
        let iq_vec = read_samples(bytes).unwrap();
        dongle_tx.send(iq_vec).unwrap();
    });

    // This thread does all of the signal processing required to demodulate
    // the signal and get it to a nice audio stream.
    thread::spawn(move || {
        // Decimating down to 100k samples seems to work the best. I don't
        // really quite get why that is, so I'll need to do more research.
        let dec_rate_filt = 12;
        let dec_rate_audio = 2;

        // TODO: the number of taps here really affects the speed of the audio.
        // Is the filter decimating or am I just doing the filter wrong?
        let taps_filt = windowed_sinc(bandwidth as f32, SAMPLE_RATE as f32, 64);
        let taps_audio = windowed_sinc(
            bandwidth as f32 / dec_rate_filt as f32,
            SAMPLE_RATE as f32 / dec_rate_filt as f32,
            64,
        );

        let mut prev = Complex::zero();
        loop {
            // First, low_pass and decimate the raw IQ signal.
            let mut iq_vec = dongle_rx.recv().unwrap();
            iq_vec = filter(&iq_vec, &taps_filt);
            iq_vec = decimate(iq_vec.as_slice(), dec_rate_filt);

            // Next, demodulate the signal and filter the signal again. The
            // second filter seems to help with the noise after demodulation.
            let res = demod_fm(iq_vec, prev);
            let mut demod_iq = filter_real(&res.0, &taps_audio);
            demod_iq = decimate(demod_iq.as_slice(), dec_rate_audio);
            prev = res.1;
            demod_tx.send(demod_iq).unwrap();
        }
    });

    // Initialize the PortAudio class. We use a blocking stream since we're
    // doing processing on the signal and can't keep up with non-blocking
    // timing requirements.
    let audio = try!(pa::PortAudio::new());
    let settings = try!(audio.default_output_stream_settings(
        CHANNELS,
        SAMPLE_RATE_AUDIO as f64,
        BUF_SIZE as u32,
    ));
    let mut stream = try!(audio.open_blocking_stream(settings));
    try!(stream.start());

    loop {
        let demod_iq = demod_rx.recv().unwrap();

        let out_frames = match stream.write_available() {
            Ok(available) => {
                match available {
                    pa::StreamAvailable::Frames(frames) => frames as u32,
                    pa::StreamAvailable::OutputUnderflowed => {
                        return Err(Box::new(PAError::OutputUnderflowed))
                    }
                    _ => return Err(Box::new(PAError::NullCallback)),
                }
            }
            Err(e) => return Err(Box::new(e)),
        };

        let buffer_frames = (demod_iq.len() / CHANNELS as usize) as u32;
        let write_frames = std::cmp::min(buffer_frames, out_frames);
        let n_write_samples = write_frames as usize * CHANNELS as usize;

        stream.write(
            write_frames,
            |output| for ix in 0..n_write_samples {
                output[ix] = demod_iq[ix];
            },
        )?;
    }
}

fn plot_spectrum<'a>(
    signal: &Vec<Complex<f32>>,
    figure: &'a mut Figure,
) -> &'a mut Figure {
    let mut sig = signal.clone();
    let radix_2: u32 = (sig.len() as f32).log2().ceil() as u32;
    let new_len = 2u32.pow(radix_2) as usize;
    sig.resize(new_len, Complex::zero());
    let plan = Plan::new(Operation::Forward, new_len);
    dft::transform(&mut sig, &plan);

    // Now generate a plot.
    figure.clear_axes();
    figure.axes2d().lines(
        0..new_len,
        sig.iter().map(|x| x.norm()),
        &[],
    );
    figure.show();
    figure
}

fn init_sdr(
    sdr_index: i32,
    fm_freq: u32,
    bandwidth: u32,
) -> Result<RTLSDRDevice, RTLSDRError> {
    let mut sdr = try!(rtlsdr::open(sdr_index));
    try!(sdr.set_center_freq(fm_freq));
    try!(sdr.set_sample_rate(SAMPLE_RATE));
    try!(sdr.set_tuner_bandwidth(bandwidth));
    try!(sdr.set_agc_mode(true));
    try!(sdr.reset_buffer());
    Ok(sdr)
}

fn decimate<T: Copy>(signal: &[T], dec_rate: usize) -> Vec<T> {
    let mut ix = 0;
    let new_size = (signal.len() / dec_rate + 1) as usize;
    let mut signal_dec = Vec::<T>::with_capacity(new_size);
    while ix < signal.len() {
        signal_dec.push(signal[ix]);
        ix += dec_rate;
    }
    signal_dec
}

fn read_samples(bytes: Vec<u8>) -> Option<Vec<Complex<f32>>> {
    // First, check that we've been given an even number of bytes. Not sure
    // what to do if we don't get I and Q.
    let bytes_len = bytes.len();
    if bytes_len % 2 != 0 {
        println!("Received an odd number of samples.");
        return None;

    }
    let mut iq_vec: Vec<Complex<f32>> = Vec::with_capacity(bytes_len / 2);

    // Write the values to the complex value and normalize from [0, 255] to
    // [-127, 128].
    for iq in bytes.chunks(2) {
        let iq_cmplx = Complex::new(
            (iq[0] as f32 - 127.0) / 127.0,
            (iq[1] as f32 - 127.0) / 127.0,
        );
        iq_vec.push(iq_cmplx);
    }
    Some(iq_vec)
}

fn demod_fm(
    iq: Vec<Complex<f32>>,
    prev: Complex<f32>,
) -> (Vec<f32>, Complex<f32>) {

    let mut p = prev.clone();
    let mut demod_queue: Vec<f32> = Vec::with_capacity(iq.len());

    let gain = SAMPLE_RATE as f32 / (2.0 * PI * 75e3);

    for samp in iq.iter() {
        let conj = p.conj() * samp;
        demod_queue.push(conj.arg() * gain);
        p = *samp;
    }
    (demod_queue, p)
}

///
/// Filters a Complex vector.
///
fn filter<T: Copy + Num + Zero>(
    samples: &Vec<Complex<T>>,
    taps: &Vec<T>,
) -> Vec<Complex<T>> {
    // We'll lose taps.len() - 1 samples from the filtering.
    let mut filt_samps: Vec<Complex<T>> =
        Vec::with_capacity(samples.len() - taps.len() + 1);

    for window in samples.windows(taps.len()) {
        let iter = window.iter().zip(taps.iter());
        let filt_samp = iter.fold(Complex::zero(), |acc, (x, y)| acc + *x * *y);
        filt_samps.push(filt_samp);
    }
    filt_samps
}

///
/// Filter a real vector.
///
fn filter_real<T: Copy + Num + Zero>(
    samples: &Vec<T>,
    taps: &Vec<T>,
) -> Vec<T> {
    // We'll lose taps.len() - 1 samples from the filtering.
    let mut filt_samps: Vec<T> =
        Vec::with_capacity(samples.len() - taps.len() + 1);
    for window in samples.windows(taps.len()) {
        let iter = window.iter().zip(taps.iter());
        let filt_samp = iter.fold(T::zero(), |acc, (x, y)| acc + *x * *y);
        filt_samps.push(filt_samp);
    }
    filt_samps
}

///
/// Generates taps for a Hamming window.
///
fn hamming(ntaps: usize) -> Vec<f32> {
    let m: f32 = ntaps as f32 - 1.0;
    let mut taps: Vec<f32> = Vec::with_capacity(ntaps);
    for ix in 0..ntaps {
        taps.push(0.54 - 0.46 * (2.0 * PI * ix as f32 / m).cos());
    }
    taps
}

///
/// Generates filter taps for a sinc filter with a Hamming window.
///
fn windowed_sinc(cutoff_freq: f32, sample_rate: f32, ntaps: usize) -> Vec<f32> {
    let wc: f32 = 2.0 * PI * cutoff_freq / sample_rate;
    let mut taps: Vec<f32> = Vec::with_capacity(ntaps);
    let win_taps: Vec<f32> = hamming(ntaps);
    let ntaps_i: i32 = ntaps as i32;
    let m: i32 = (ntaps_i - 1) / 2;

    for ix in -m..m + 1 {
        let ix_f: f32 = ix as f32;
        if ix == 0 {
            let hi = wc / PI * win_taps[(ix + m) as usize];
            taps.push(hi);
        } else {
            let hi = (ix_f * wc).sin() / (ix_f * PI) *
                win_taps[(ix + m) as usize];
            taps.push(hi);
        }
    }
    taps
}
<commit_msg>Moving the SDR initialization to the appropriate thread<commit_after>extern crate num;
extern crate portaudio;
extern crate rtlsdr;
extern crate dft;
extern crate gnuplot;

use portaudio as pa;
use rtlsdr::{RTLSDRDevice, RTLSDRError};
use num::{Num, Zero};
use num::complex::Complex;
use std::env;
use std::f32::consts::PI;
use std::error::Error;
use pa::error::Error as PAError;
use std::thread;
use std::sync::mpsc::channel;

use gnuplot::*;
use dft::{Operation, Plan};

// Make sure that the buffer size is radix-2, otherwise the read_sync function
// will fail with an error code of -8.
const SDR_BUF_SIZE: usize = 524288;

// Separating out the buffer sizes seems to help some.
const BUF_SIZE: usize = 262144;

// Most other sample rates fail, but this one works for my particular device.
// I will investigate exactly what's happening here and generate a list of
// possible sample rates (if there are others besides this one).
const SAMPLE_RATE: u32 = 2400000;

// Here is the sample rate of the output waveform we'll try to use.
const SAMPLE_RATE_AUDIO: f32 = 48000.0;

// The number of channels being used for audio.
const CHANNELS: i32 = 2;

fn main() {
    match run() {
        Ok(()) => (),
        Err(e) => println!("ERROR: {}", e),
    }
}

struct RTLSDR {
    rtlsdr: RTLSDRDevice,
}

unsafe impl Send for RTLSDR {}

fn run() -> Result<(), Box<Error>> {
    let sdr_index: i32 = env::args()
        .nth(1)
        .expect("Please specify the SDR index.")
        .parse::<i32>()?;
    let fm_freq_mhz: f32 = env::args()
        .nth(2)
        .expect("Please specify a center frequency in MHz.")
        .parse::<f32>()?;
    let bandwidth: u32 = env::args()
        .nth(3)
        .expect("Please specify the bandwidth.")
        .parse::<u32>()?;

    // Set up the threading channels for communication between our two threads.
    let (dongle_tx, dongle_rx) = channel();
    let (demod_tx, demod_rx) = channel();

    // This thread only collects data off of the SDR as quickly as possible and
    // sends it out.
    thread::spawn(move || {
        // Initialize the SDR based on the user's input parameters.
        let fm_freq: u32 = (fm_freq_mhz * 1e6) as u32;
        let mut sdr =
            RTLSDR { rtlsdr: init_sdr(sdr_index, fm_freq, bandwidth).unwrap() };

        loop {
            let bytes = sdr.rtlsdr.read_sync(SDR_BUF_SIZE).unwrap();
            let iq_vec = read_samples(bytes).unwrap();
            dongle_tx.send(iq_vec).unwrap();
        }
    });

    // This thread does all of the signal processing required to demodulate
    // the signal and get it to a nice audio stream.
    thread::spawn(move || {
        // Decimating down to 100k samples seems to work the best. I don't
        // really quite get why that is, so I'll need to do more research.
        let dec_rate_filt = 6;
        let dec_rate_audio = 4;

        // TODO: the number of taps here really affects the speed of the audio.
        // Is the filter decimating or am I just doing the filter wrong?
        let taps_filt =
            windowed_sinc(bandwidth as f32, SAMPLE_RATE as f32, 128);
        let taps_audio = windowed_sinc(
            bandwidth as f32 / dec_rate_filt as f32,
            SAMPLE_RATE as f32 / dec_rate_filt as f32,
            128,
        );

        let mut prev = Complex::zero();
        loop {
            // First, low_pass and decimate the raw IQ signal.
            let mut iq_vec = dongle_rx.recv().unwrap();
            iq_vec = filter(&iq_vec, &taps_filt);
            iq_vec = decimate(iq_vec.as_slice(), dec_rate_filt);

            // Next, demodulate the signal and filter the signal again. The
            // second filter seems to help with the noise after demodulation.
            let res = demod_fm(iq_vec, prev);
            let mut demod_iq = filter_real(&res.0, &taps_audio);
            demod_iq = decimate(demod_iq.as_slice(), dec_rate_audio);
            prev = res.1;
            demod_tx.send(demod_iq).unwrap();
        }
    });

    // Initialize the PortAudio class. We use a blocking stream since we're
    // doing processing on the signal and can't keep up with non-blocking
    // timing requirements.
    let audio = try!(pa::PortAudio::new());
    let settings = try!(audio.default_output_stream_settings(
        CHANNELS,
        SAMPLE_RATE_AUDIO as f64,
        BUF_SIZE as u32,
    ));
    let mut stream = try!(audio.open_blocking_stream(settings));
    try!(stream.start());

    loop {
        let demod_iq = demod_rx.recv().unwrap();

        let out_frames = match stream.write_available() {
            Ok(available) => {
                match available {
                    pa::StreamAvailable::Frames(frames) => frames as u32,
                    pa::StreamAvailable::OutputUnderflowed => {
                        return Err(Box::new(PAError::OutputUnderflowed))
                    }
                    _ => return Err(Box::new(PAError::NullCallback)),
                }
            }
            Err(e) => return Err(Box::new(e)),
        };

        let buffer_frames = (demod_iq.len() / CHANNELS as usize) as u32;
        let write_frames = std::cmp::min(buffer_frames, out_frames);
        let n_write_samples = write_frames as usize * CHANNELS as usize;

        stream.write(
            write_frames,
            |output| for ix in 0..n_write_samples {
                output[ix] = demod_iq[ix];
            },
        )?;
    }
}

fn plot_spectrum<'a>(
    signal: &Vec<Complex<f32>>,
    figure: &'a mut Figure,
) -> &'a mut Figure {
    let mut sig = signal.clone();
    let radix_2: u32 = (sig.len() as f32).log2().ceil() as u32;
    let new_len = 2u32.pow(radix_2) as usize;
    sig.resize(new_len, Complex::zero());
    let plan = Plan::new(Operation::Forward, new_len);
    dft::transform(&mut sig, &plan);

    // Now generate a plot.
    figure.clear_axes();
    figure.axes2d().lines(
        0..new_len,
        sig.iter().map(|x| x.norm()),
        &[],
    );
    figure.show();
    figure
}

fn init_sdr(
    sdr_index: i32,
    fm_freq: u32,
    bandwidth: u32,
) -> Result<RTLSDRDevice, RTLSDRError> {
    let mut sdr = try!(rtlsdr::open(sdr_index));
    try!(sdr.set_center_freq(fm_freq));
    try!(sdr.set_sample_rate(SAMPLE_RATE));
    try!(sdr.set_tuner_bandwidth(bandwidth));
    try!(sdr.set_agc_mode(true));
    try!(sdr.reset_buffer());
    Ok(sdr)
}

fn decimate<T: Copy>(signal: &[T], dec_rate: usize) -> Vec<T> {
    let mut ix = 0;
    let new_size = (signal.len() / dec_rate + 1) as usize;
    let mut signal_dec = Vec::<T>::with_capacity(new_size);
    while ix < signal.len() {
        signal_dec.push(signal[ix]);
        ix += dec_rate;
    }
    signal_dec
}

fn read_samples(bytes: Vec<u8>) -> Option<Vec<Complex<f32>>> {
    // First, check that we've been given an even number of bytes. Not sure
    // what to do if we don't get I and Q.
    let bytes_len = bytes.len();
    if bytes_len % 2 != 0 {
        println!("Received an odd number of samples.");
        return None;

    }
    let mut iq_vec: Vec<Complex<f32>> = Vec::with_capacity(bytes_len / 2);

    // Write the values to the complex value and normalize from [0, 255] to
    // [-127, 128].
    for iq in bytes.chunks(2) {
        let iq_cmplx = Complex::new(
            (iq[0] as f32 - 127.0) / 127.0,
            (iq[1] as f32 - 127.0) / 127.0,
        );
        iq_vec.push(iq_cmplx);
    }
    Some(iq_vec)
}

fn demod_fm(
    iq: Vec<Complex<f32>>,
    prev: Complex<f32>,
) -> (Vec<f32>, Complex<f32>) {

    let mut p = prev.clone();
    let mut demod_queue: Vec<f32> = Vec::with_capacity(iq.len());

    let gain = SAMPLE_RATE as f32 / (2.0 * PI * 75e3);

    for samp in iq.iter() {
        let conj = p.conj() * samp;
        demod_queue.push(conj.arg() * gain);
        p = *samp;
    }
    (demod_queue, p)
}

///
/// Filters a Complex vector.
///
fn filter<T: Copy + Num + Zero>(
    samples: &Vec<Complex<T>>,
    taps: &Vec<T>,
) -> Vec<Complex<T>> {
    // We'll lose taps.len() - 1 samples from the filtering.
    let mut filt_samps: Vec<Complex<T>> =
        Vec::with_capacity(samples.len() - taps.len() + 1);

    for window in samples.windows(taps.len()) {
        let iter = window.iter().zip(taps.iter());
        let filt_samp = iter.fold(Complex::zero(), |acc, (x, y)| acc + *x * *y);
        filt_samps.push(filt_samp);
    }
    filt_samps
}

///
/// Filter a real vector.
///
fn filter_real<T: Copy + Num + Zero>(
    samples: &Vec<T>,
    taps: &Vec<T>,
) -> Vec<T> {
    // We'll lose taps.len() - 1 samples from the filtering.
    let mut filt_samps: Vec<T> =
        Vec::with_capacity(samples.len() - taps.len() + 1);
    for window in samples.windows(taps.len()) {
        let iter = window.iter().zip(taps.iter());
        let filt_samp = iter.fold(T::zero(), |acc, (x, y)| acc + *x * *y);
        filt_samps.push(filt_samp);
    }
    filt_samps
}

///
/// Generates taps for a Hamming window.
///
fn hamming(ntaps: usize) -> Vec<f32> {
    let m: f32 = ntaps as f32 - 1.0;
    let mut taps: Vec<f32> = Vec::with_capacity(ntaps);
    for ix in 0..ntaps {
        taps.push(0.54 - 0.46 * (2.0 * PI * ix as f32 / m).cos());
    }
    taps
}

///
/// Generates filter taps for a sinc filter with a Hamming window.
///
fn windowed_sinc(cutoff_freq: f32, sample_rate: f32, ntaps: usize) -> Vec<f32> {
    let wc: f32 = 2.0 * PI * cutoff_freq / sample_rate;
    let mut taps: Vec<f32> = Vec::with_capacity(ntaps);
    let win_taps: Vec<f32> = hamming(ntaps);
    let ntaps_i: i32 = ntaps as i32;
    let m: i32 = (ntaps_i - 1) / 2;

    for ix in -m..m + 1 {
        let ix_f: f32 = ix as f32;
        if ix == 0 {
            let hi = wc / PI * win_taps[(ix + m) as usize];
            taps.push(hi);
        } else {
            let hi = (ix_f * wc).sin() / (ix_f * PI) *
                win_taps[(ix + m) as usize];
            taps.push(hi);
        }
    }
    taps
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate regex;

use std::env;
use std::io::{self, Read};
use getopts::Options;
use regex::Regex;
use cache::{AccessType, Cache};

mod cache;

const C1_DEFAULT: u64    = 12;
const B1_DEFAULT: u64    = 5;
const S1_DEFAULT: u64    = 3;
const V_DEFAULT:  u64    = 3;
const C2_DEFAULT: u64   = 15;
const B2_DEFAULT: u64   = 5;
const S2_DEFAULT: u64   = 4;

fn print_usage() {
    println!("cachesim [OPTIONS] < traces/file.trace");
    println!("L1 Parameters:");
    println!("  -c C1\t\tThe total size of the L1 cache is 2^C1 bytes");
    println!("  -b B1\t\tThe size of a block in the L1 cache is 2^B1 bytes");
    println!("  -s S1\t\tThe number of blocks per set in L1 is 2^S1");
    println!("Victim cache parameters:");
    println!("  -v V\t\tThe number of blocks in the Victim Cache");
    println!("L2 Parameters:");
    println!("  -C C2\t\tThe total size of the L2 cache is 2^C2 bytes");
    println!("  -B B2\t\tThe size of a block in the L2 cache is 2^B2 bytes");
    println!("  -S S2\t\tThe number of blocks per set in L2 is 2^S2");
}

fn main() {
    // 1.) Begin by handling parameters
    let args : Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflag("h", "help", "Print the help menu");

    opts.optopt("c", "", "C parameter for L1 cache", "C1");
    opts.optopt("b", "", "B parameter for L1 cache", "B1");
    opts.optopt("s", "", "S parameter for L1 cache", "S1");
    opts.optopt("v", "", "v parameter for Victim cache", "V");
    opts.optopt("C", "", "C parameter for L2 cache", "C2");
    opts.optopt("B", "", "B parameter for L2 cache", "B2");
    opts.optopt("S", "", "S parameter for L2 cache", "S2");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) },
    };

    if matches.opt_present("h") {
        print_usage();
        return;
    }

    let c1 = match matches.opt_str("c") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => C1_DEFAULT,
    };
    let b1 = match matches.opt_str("b") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => B1_DEFAULT,
    };
    let s1 = match matches.opt_str("s") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => S1_DEFAULT,
    };
    let v = match matches.opt_str("v") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => V_DEFAULT,
    };
    let c2 = match matches.opt_str("C") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => C2_DEFAULT,
    };
    let b2 = match matches.opt_str("B") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => B2_DEFAULT,
    };
    let s2 = match matches.opt_str("S") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => S2_DEFAULT,
    };

    println!("Cache Settings");
    println!("c: {}", c1);
    println!("b: {}", b1);
    println!("s: {}", s1);
    println!("v: {}", v);
    println!("C: {}", c2);
    println!("B: {}", b2);
    println!("S: {}", s2);

    // 2.) Read the trace file
    // The contents of the trace file should be in trace_buffer
    // if the file was piped in through stdin

    let mut trace_buffer = String::new();
    if let Err(e) = io::stdin().read_to_string(&mut trace_buffer) {
        panic!(e.to_string());
    }

    // 3.) Create cache system and begin processing
    let mut cache_system = Cache::setup_cache(c1, b1, s1, v, c2, b2, s2);

    let access_list = trace_buffer.split('\n');

    let re = Regex::new(r"(r|w)(\s+)(0x[:xdigit:]+)").unwrap();
    for access in access_list {
        if let Some(cap) = re.captures(access) {
            let mode: AccessType = match cap.at(1).unwrap() {
                "r" => AccessType::Read,
                "w" => AccessType::Write,
                _ => { panic!("Malformed trace file!") },
            };

            let address = match u64::from_str_radix(&cap.at(3).unwrap()[2..], 16) {
                Ok(v) => { v },
                Err(f) => { panic!(f.to_string()) },
            };

            //TODO: Replace 0u64 with properly converted address
            cache_system.cache_access(mode, address);
        }
    }

    cache_system.complete_cache();

    cache_system.print_statistics();
}
<commit_msg>Updating main.rs. Should be equivalent to starter code<commit_after>extern crate getopts;
extern crate regex;

use std::env;
use std::io::{self, Read};
use getopts::Options;
use regex::Regex;
use cache::{AccessType, Cache};

mod cache;

const C1_DEFAULT: u64    = 12;
const B1_DEFAULT: u64    = 5;
const S1_DEFAULT: u64    = 3;
const V_DEFAULT:  u64    = 3;
const C2_DEFAULT: u64   = 15;
const B2_DEFAULT: u64   = 5;
const S2_DEFAULT: u64   = 4;

fn print_usage() {
    println!("cachesim [OPTIONS] < traces/file.trace");
    println!("L1 Parameters:");
    println!("  -c C1\t\tThe total size of the L1 cache is 2^C1 bytes");
    println!("  -b B1\t\tThe size of a block in the L1 cache is 2^B1 bytes");
    println!("  -s S1\t\tThe number of blocks per set in L1 is 2^S1");
    println!("Victim cache parameters:");
    println!("  -v V\t\tThe number of blocks in the Victim Cache");
    println!("L2 Parameters:");
    println!("  -C C2\t\tThe total size of the L2 cache is 2^C2 bytes");
    println!("  -B B2\t\tThe size of a block in the L2 cache is 2^B2 bytes");
    println!("  -S S2\t\tThe number of blocks per set in L2 is 2^S2");
}

fn main() {
    // 1.) Begin by handling parameters
    let args : Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflag("h", "help", "Print the help menu");

    opts.optopt("c", "", "C parameter for L1 cache", "C1");
    opts.optopt("b", "", "B parameter for L1 cache", "B1");
    opts.optopt("s", "", "S parameter for L1 cache", "S1");
    opts.optopt("v", "", "v parameter for Victim cache", "V");
    opts.optopt("C", "", "C parameter for L2 cache", "C2");
    opts.optopt("B", "", "B parameter for L2 cache", "B2");
    opts.optopt("S", "", "S parameter for L2 cache", "S2");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) },
    };

    if matches.opt_present("h") {
        print_usage();
        return;
    }

    let c1 = match matches.opt_str("c") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => C1_DEFAULT,
    };
    let b1 = match matches.opt_str("b") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => B1_DEFAULT,
    };
    let s1 = match matches.opt_str("s") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => S1_DEFAULT,
    };
    let v = match matches.opt_str("v") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => V_DEFAULT,
    };
    let c2 = match matches.opt_str("C") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => C2_DEFAULT,
    };
    let b2 = match matches.opt_str("B") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => B2_DEFAULT,
    };
    let s2 = match matches.opt_str("S") {
        Some(s) => s.parse::<u64>().unwrap(),
        None => S2_DEFAULT,
    };

    println!("Cache Settings");
    println!("c: {}", c1);
    println!("b: {}", b1);
    println!("s: {}", s1);
    println!("v: {}", v);
    println!("C: {}", c2);
    println!("B: {}", b2);
    println!("S: {}", s2);

    // 2.) Read the trace file
    // The contents of the trace file should be in trace_buffer
    // if the file was piped in through stdin

    let mut trace_buffer = String::new();
    if let Err(e) = io::stdin().read_to_string(&mut trace_buffer) {
        panic!(e.to_string());
    }

    // 3.) Create cache system and begin processing
    let mut cache_system = Cache::setup_cache(c1, b1, s1, v, c2, b2, s2);

    let access_list = trace_buffer.split('\n');

    let re = Regex::new(r"(r|w)(\s+)(0x[:xdigit:]+)").unwrap();
    for access in access_list {
        if let Some(cap) = re.captures(access) {
            let mode: AccessType = match cap.at(1).unwrap() {
                "r" => AccessType::Read,
                "w" => AccessType::Write,
                _ => { panic!("Malformed trace file!") },
            };

            let address = match u64::from_str_radix(&cap.at(3).unwrap()[2..], 16) {
                Ok(v) => { v },
                Err(f) => { panic!(f.to_string()) },
            };

            cache_system.cache_access(mode, address);
        }
    }

    // 4.) Finish processing, and print out statistics
    cache_system.complete_cache();

    cache_system.print_statistics();
}
<|endoftext|>


<commit_before>mod snes_apu;

use std::iter;
use std::env;
use std::io::{Result, Error, ErrorKind, Write, stdout, stdin};
use std::thread;
use std::sync::{Arc, Mutex};

use snes_apu::spc::{Spc, Emulator};

fn main() {
    if let Err(e) = play_spc_files() {
        println!("ERROR: {}", e);
        std::process::exit(1);
    }
}

fn play_spc_files() -> Result<()> {
    for file_name in try!(get_file_names()) {
        try!(play_spc_file(&file_name));
    }
    Ok(())
}

fn get_file_names() -> Result<iter::Skip<env::Args>> {
    let args = env::args();
    match args.len() {
        1 => Err(Error::new(ErrorKind::Other, "No file(s) specified")),
        _ => Ok(args.skip(1))
    }
}

fn play_spc_file(file_name: &String) -> Result<()> {
    let spc = try!(Spc::load(file_name));

    println!("SPC: {}", file_name);
    println!(" Version Minor: {}", spc.version_minor);
    println!(" PC: {}", spc.pc);
    println!(" A: {}", spc.a);
    println!(" X: {}", spc.x);
    println!(" Y: {}", spc.y);
    println!(" PSW: {}", spc.psw);
    println!(" SP: {}", spc.sp);

    if let Some(id666_tag) = spc.id666_tag {
        println!(" ID666 tag present:");
        println!("  Song title: {}", id666_tag.song_title);
        println!("  Game title: {}", id666_tag.game_title);
        println!("  Dumper name: {}", id666_tag.dumper_name);
        println!("  Comments: {}", id666_tag.comments);
        println!("  Date dumped (MM/DD/YYYY): {}", id666_tag.date_dumped);
        println!("  Seconds to play before fading out: {}", id666_tag.seconds_to_play_before_fading_out);
        println!("  Fade out length: {}ms", id666_tag.fade_out_length);
        println!("  Artist name: {}", id666_tag.artist_name);
        println!("  Default channel disables: {}", id666_tag.default_channel_disables);
        println!("  Dumping emulator: {}", match id666_tag.dumping_emulator {
            Emulator::Unknown => "Unknown",
            Emulator::ZSnes => "ZSnes",
            Emulator::Snes9x => "Snes9x"
        });
    } else {
        println!(" No ID666 tag present.");
    }

    println!("Return quits.");
    try!(wait_for_key_press_with_busy_icon());

    Ok(())
}

// TODO: This function is super thread-safe but can panic XD
fn wait_for_key_press_with_busy_icon() -> Result<()> {
    let is_done = Arc::new(Mutex::new(false));

    let thread_is_done = is_done.clone();
    let handle = thread::spawn(move || {
        let chars = ['-', '/', '|', '\\'];
        let mut char_index = 0;
        loop {
            if *(thread_is_done.lock().unwrap()) {
                break;
            }

            print!("\r[{}]", chars[char_index]);
            stdout().flush().unwrap();
            char_index = (char_index + 1) % chars.len();

            thread::sleep_ms(5);
        }
        print!("\r   \r");
    });

    let mut s = String::new();
    try!(stdin().read_line(&mut s));
    *is_done.lock().unwrap() = true;
    handle.join().unwrap();

    Ok(())
}
<commit_msg>tiny cleanup<commit_after>mod snes_apu;

use std::iter;
use std::env;
use std::io::{Result, Error, ErrorKind, Write, stdout, stdin};
use std::thread;
use std::sync::{Arc, Mutex};
use snes_apu::spc::{Spc, Emulator};

fn main() {
    if let Err(e) = play_spc_files() {
        println!("ERROR: {}", e);
        std::process::exit(1);
    }
}

fn play_spc_files() -> Result<()> {
    for file_name in try!(get_file_names()) {
        try!(play_spc_file(&file_name));
    }
    Ok(())
}

fn get_file_names() -> Result<iter::Skip<env::Args>> {
    let args = env::args();
    match args.len() {
        1 => Err(Error::new(ErrorKind::Other, "No file(s) specified")),
        _ => Ok(args.skip(1))
    }
}

fn play_spc_file(file_name: &String) -> Result<()> {
    let spc = try!(Spc::load(file_name));

    println!("SPC: {}", file_name);
    println!(" Version Minor: {}", spc.version_minor);
    println!(" PC: {}", spc.pc);
    println!(" A: {}", spc.a);
    println!(" X: {}", spc.x);
    println!(" Y: {}", spc.y);
    println!(" PSW: {}", spc.psw);
    println!(" SP: {}", spc.sp);

    if let Some(id666_tag) = spc.id666_tag {
        println!(" ID666 tag present:");
        println!("  Song title: {}", id666_tag.song_title);
        println!("  Game title: {}", id666_tag.game_title);
        println!("  Dumper name: {}", id666_tag.dumper_name);
        println!("  Comments: {}", id666_tag.comments);
        println!("  Date dumped (MM/DD/YYYY): {}", id666_tag.date_dumped);
        println!("  Seconds to play before fading out: {}", id666_tag.seconds_to_play_before_fading_out);
        println!("  Fade out length: {}ms", id666_tag.fade_out_length);
        println!("  Artist name: {}", id666_tag.artist_name);
        println!("  Default channel disables: {}", id666_tag.default_channel_disables);
        println!("  Dumping emulator: {}", match id666_tag.dumping_emulator {
            Emulator::Unknown => "Unknown",
            Emulator::ZSnes => "ZSnes",
            Emulator::Snes9x => "Snes9x"
        });
    } else {
        println!(" No ID666 tag present.");
    }

    println!("Return quits.");
    try!(wait_for_key_press_with_busy_icon());

    Ok(())
}

// TODO: This function is super thread-safe but can panic XD
fn wait_for_key_press_with_busy_icon() -> Result<()> {
    let is_done = Arc::new(Mutex::new(false));

    let thread_is_done = is_done.clone();
    let handle = thread::spawn(move || {
        let chars = ['-', '/', '|', '\\'];
        let mut char_index = 0;
        while !*(thread_is_done.lock().unwrap()) {
            print!("\r[{}]", chars[char_index]);
            stdout().flush().unwrap();
            char_index = (char_index + 1) % chars.len();

            thread::sleep_ms(5);
        }
        print!("\r   \r");
    });

    let mut s = String::new();
    try!(stdin().read_line(&mut s));
    *is_done.lock().unwrap() = true;
    handle.join().unwrap();

    Ok(())
}
<|endoftext|>


<commit_before>extern crate argparse;
extern crate glob;
extern crate regex;

use argparse::{ArgumentParser, StoreTrue, Store, StoreOption, Print};
use std::io::BufRead;
use glob::glob;
use regex::Regex;

fn identity<T>(x: T) -> T {x}

struct Options {
    debug: bool,
    path: String,
    file: Option<String>
}

fn get_possible_files_from_glob() -> Result<Vec<std::path::PathBuf>, glob::PatternError> {
    // Dir.glob("**/*").reject { |p| File.directory?(p) }.map { |p| Path.new(p) }
    glob("**/*").map(|paths| paths.flat_map(identity).filter(|path| path.is_file()).collect())
}

fn get_filename_minus_extension(path_str: &String) -> String {
    std::path::Path::new(path_str).file_stem().unwrap().to_str().unwrap().to_string()
}

fn is_test_file(path: &String) -> bool {
    let re = Regex::new(r"^(features/|test/|spec/|tests/)").unwrap();
    re.is_match(path.as_str())
}

fn strip_test_words(filename: &String) -> String {
    let re = Regex::new(r"(test_)?(?P<p>\w+?)(_rake_spec|_spec|_test|_steps)?(\.rb|\.exs|\.ex|\.js|\.py)?$").unwrap();
    re.replace_all(filename.as_str(), "$p")
}

fn cleanse_path(path: &String) -> String {
    let re = Regex::new(r"^(\./|\r|\n| )").unwrap();
    re.replace_all(path.as_str(), "")
}

fn find_longest_common_substring(s1: &String, s2: &String) -> String {
    // Currently this is implemented using a dynamic programming solution similar
    // to http://www.geeksforgeeks.org/longest-common-substring/. This is O(N*M)
    // where N is the length of one string and M is the length of the other
    // string.
    //
    // Another option would of course be to explore using something like a
    // suffix tree to solve this problem, something like, the following.
    // http://www.geeksforgeeks.org/suffix-tree-application-5-longest-common-substring-2/
    // This is O(M+N) to build a Generalized Suffix Tree and O(M+N) to find the
    // the longest common substring via depth first search.
    //
    // Beyond that we would have to explore not caring about longest substring
    // and moving to a similarity ranking algorithm that maybe cares about
    // subsequences rather that substrings, etc.
    if s1.is_empty() || s2.is_empty() {
        return "".to_string()
    }

    let mut m: Vec<Vec<i32>> = Vec::new();
    for x in 0..s1.len() {
        let mut v: Vec<i32> = Vec::new();
        for y in 0..s2.len() {
            v.push(0);
        }
        m.push(v);
    }

    let mut longest_length = 0;
    let mut longest_end_pos = 0;

    for i in 0..s1.len() {
        for j in 0..s2.len() {
            if s1.as_bytes()[i] == s2.as_bytes()[j] {
                m[i][j] = 1;
                if i > 0 && j > 0 {
                    m[i][j] += m[i-1][j-1];
                }
                if m[i][j] > longest_length {
                    longest_length = m[i][j];
                    longest_end_pos = i;
                }
            }
        }
    }

    let start: usize = longest_end_pos as usize - longest_length as usize + 1;
    let end: usize = longest_end_pos as usize;
    s1[start..end].to_string()
}

fn score(s1: &String, s2: &String) -> f32 {
    // TODO: Improve performance. At the moment the find_longest_common_substring
    // method is the most costly operation in this app. This leaves us with a few
    // levers to move in terms of improving performance. Specifically, we could
    // find a more performant algorithm, or find a way to reduce the number of
    // times it has to be called, or use threading to do a scatter and gather
    // approach.
    let longest_match = find_longest_common_substring(s1, s2);
    (longest_match.len() as f32/s2.len() as f32) * (longest_match.len() as f32/s1.len() as f32)
}

fn main() {
    let mut options = Options {
        debug: false,
        path: "".to_string(),
        file: None
    };

    let mut highest_score: f32 = 0.0;
    let mut best_match: String = "".to_string();

    { // block limits of borrows by refer() method calls
        let mut ap = ArgumentParser::new();
        ap.add_option(&["-v", "--version"], Print(env!("CARGO_PKG_VERSION").to_string()), "show version");
        ap.refer(&mut options.debug).add_option(&["-d", "--debug"], StoreTrue, "enable debug output");
        ap.refer(&mut options.file).add_option(&["-f", "--file"], StoreOption, "possible alternates file, - for stdin");
        ap.refer(&mut options.path).add_argument("PATH", Store, "path to find alternate for").required();
        ap.parse_args_or_exit();
    }

    //println!("debug: {}", options.debug);
    //println!("required path: {}", options.path);
    let cleansed_path = cleanse_path(&options.path);

    if let Some(unwrapped_file) = options.file {
        println!("file: {}", unwrapped_file);
        if unwrapped_file == "-" {
            let stdin = std::io::stdin();
            for line in stdin.lock().lines() {
              println!("{}", line.unwrap());
            }
        } else {
            // figure out how to open specified file and read in as content
        }
    } else {
        match get_possible_files_from_glob() {
            Ok(paths) => {
                // - get collection of possible alternate file paths
                // - cleanse possible paths (stripping prefixed ./ and postfixed \r,\n,sp)
                // - if path is test file
                //      - reduce set to paths that match filename stripped of test words and extensions
                //      - reduce set to non-test files
                //   else
                //      - reduce set to paths that match filename stripped of test words and extensions
                //      - reduce set to test files
                // - score the reduced set of possible paths, tracking the highest score
                // - return the path with the highest score

                let filename = get_filename_minus_extension(&options.path);
                if is_test_file(&cleansed_path) {
                    let filename = strip_test_words(&filename);
                    let reduced_paths = paths.iter()
                        .map(|path| cleanse_path(&path.to_str().unwrap().to_string()))
                        .filter(|path| path.contains(filename.as_str()))  // filter to paths that contain the filename
                        .filter(|path| !is_test_file(&path)); // filter to paths that aren't test files
                    for path in reduced_paths {
                        let s = score(&path, &cleansed_path);
                        if s > highest_score {
                            highest_score = s;
                            best_match = path;
                        }
                    }
                } else {
                    let reduced_paths = paths.iter()
                        .map(|path| cleanse_path(&path.to_str().unwrap().to_string()))
                        .filter(|path| path.contains(filename.as_str())) // filter to paths that contain the filename
                        .filter(|path| is_test_file(&path)); // filter to paths that ARE test files
                    for path in reduced_paths {
                        let s = score(&path, &cleansed_path);
                        if s > highest_score {
                            highest_score = s;
                            best_match = path;
                        }
                    }
                }
            },
            Err(e) => println!("{:?}", e)
        }
        println!("{}", best_match);
    }

}
<commit_msg>Fix alternate output to match current style<commit_after>extern crate argparse;
extern crate glob;
extern crate regex;

use argparse::{ArgumentParser, StoreTrue, Store, StoreOption, Print};
use std::io::BufRead;
use glob::glob;
use regex::Regex;

fn identity<T>(x: T) -> T {x}

struct Options {
    debug: bool,
    path: String,
    file: Option<String>
}

fn get_possible_files_from_glob() -> Result<Vec<std::path::PathBuf>, glob::PatternError> {
    // Dir.glob("**/*").reject { |p| File.directory?(p) }.map { |p| Path.new(p) }
    glob("**/*").map(|paths| paths.flat_map(identity).filter(|path| path.is_file()).collect())
}

fn get_filename_minus_extension(path_str: &String) -> String {
    std::path::Path::new(path_str).file_stem().unwrap().to_str().unwrap().to_string()
}

fn is_test_file(path: &String) -> bool {
    let re = Regex::new(r"^(features/|test/|spec/|tests/)").unwrap();
    re.is_match(path.as_str())
}

fn strip_test_words(filename: &String) -> String {
    let re = Regex::new(r"(test_)?(?P<p>\w+?)(_rake_spec|_spec|_test|_steps)?(\.rb|\.exs|\.ex|\.js|\.py)?$").unwrap();
    re.replace_all(filename.as_str(), "$p")
}

fn cleanse_path(path: &String) -> String {
    let re = Regex::new(r"^(\./|\r|\n| )").unwrap();
    re.replace_all(path.as_str(), "")
}

fn find_longest_common_substring(s1: &String, s2: &String) -> String {
    // Currently this is implemented using a dynamic programming solution similar
    // to http://www.geeksforgeeks.org/longest-common-substring/. This is O(N*M)
    // where N is the length of one string and M is the length of the other
    // string.
    //
    // Another option would of course be to explore using something like a
    // suffix tree to solve this problem, something like, the following.
    // http://www.geeksforgeeks.org/suffix-tree-application-5-longest-common-substring-2/
    // This is O(M+N) to build a Generalized Suffix Tree and O(M+N) to find the
    // the longest common substring via depth first search.
    //
    // Beyond that we would have to explore not caring about longest substring
    // and moving to a similarity ranking algorithm that maybe cares about
    // subsequences rather that substrings, etc.
    if s1.is_empty() || s2.is_empty() {
        return "".to_string()
    }

    let mut m: Vec<Vec<i32>> = Vec::new();
    for x in 0..s1.len() {
        let mut v: Vec<i32> = Vec::new();
        for y in 0..s2.len() {
            v.push(0);
        }
        m.push(v);
    }

    let mut longest_length = 0;
    let mut longest_end_pos = 0;

    for i in 0..s1.len() {
        for j in 0..s2.len() {
            if s1.as_bytes()[i] == s2.as_bytes()[j] {
                m[i][j] = 1;
                if i > 0 && j > 0 {
                    m[i][j] += m[i-1][j-1];
                }
                if m[i][j] > longest_length {
                    longest_length = m[i][j];
                    longest_end_pos = i;
                }
            }
        }
    }

    let start: usize = longest_end_pos as usize - longest_length as usize + 1;
    let end: usize = longest_end_pos as usize;
    s1[start..end].to_string()
}

fn score(s1: &String, s2: &String) -> f32 {
    // TODO: Improve performance. At the moment the find_longest_common_substring
    // method is the most costly operation in this app. This leaves us with a few
    // levers to move in terms of improving performance. Specifically, we could
    // find a more performant algorithm, or find a way to reduce the number of
    // times it has to be called, or use threading to do a scatter and gather
    // approach.
    let longest_match = find_longest_common_substring(s1, s2);
    (longest_match.len() as f32/s2.len() as f32) * (longest_match.len() as f32/s1.len() as f32)
}

fn main() {
    let mut options = Options {
        debug: false,
        path: "".to_string(),
        file: None
    };

    let mut highest_score: f32 = 0.0;
    let mut best_match: String = "".to_string();

    { // block limits of borrows by refer() method calls
        let mut ap = ArgumentParser::new();
        ap.add_option(&["-v", "--version"], Print(env!("CARGO_PKG_VERSION").to_string()), "show version");
        ap.refer(&mut options.debug).add_option(&["-d", "--debug"], StoreTrue, "enable debug output");
        ap.refer(&mut options.file).add_option(&["-f", "--file"], StoreOption, "possible alternates file, - for stdin");
        ap.refer(&mut options.path).add_argument("PATH", Store, "path to find alternate for").required();
        ap.parse_args_or_exit();
    }

    //println!("debug: {}", options.debug);
    //println!("required path: {}", options.path);
    let cleansed_path = cleanse_path(&options.path);

    if let Some(unwrapped_file) = options.file {
        println!("file: {}", unwrapped_file);
        if unwrapped_file == "-" {
            let stdin = std::io::stdin();
            for line in stdin.lock().lines() {
              println!("{}", line.unwrap());
            }
        } else {
            // figure out how to open specified file and read in as content
        }
    } else {
        match get_possible_files_from_glob() {
            Ok(paths) => {
                // - get collection of possible alternate file paths
                // - cleanse possible paths (stripping prefixed ./ and postfixed \r,\n,sp)
                // - if path is test file
                //      - reduce set to paths that match filename stripped of test words and extensions
                //      - reduce set to non-test files
                //   else
                //      - reduce set to paths that match filename stripped of test words and extensions
                //      - reduce set to test files
                // - score the reduced set of possible paths, tracking the highest score
                // - return the path with the highest score

                let filename = get_filename_minus_extension(&options.path);
                if is_test_file(&cleansed_path) {
                    let filename = strip_test_words(&filename);
                    let reduced_paths = paths.iter()
                        .map(|path| cleanse_path(&path.to_str().unwrap().to_string()))
                        .filter(|path| path.contains(filename.as_str()))  // filter to paths that contain the filename
                        .filter(|path| !is_test_file(&path)); // filter to paths that aren't test files
                    for path in reduced_paths {
                        let s = score(&path, &cleansed_path);
                        if s > highest_score {
                            highest_score = s;
                            best_match = path;
                        }
                    }
                } else {
                    let reduced_paths = paths.iter()
                        .map(|path| cleanse_path(&path.to_str().unwrap().to_string()))
                        .filter(|path| path.contains(filename.as_str())) // filter to paths that contain the filename
                        .filter(|path| is_test_file(&path)); // filter to paths that ARE test files
                    for path in reduced_paths {
                        let s = score(&path, &cleansed_path);
                        if s > highest_score {
                            highest_score = s;
                            best_match = path;
                        }
                    }
                }
            },
            Err(e) => println!("{:?}", e)
        }
        print!("{}", best_match);
    }

}
<|endoftext|>


<commit_before>use std::ops::{Add, Mul, Sub};

type Float = f32;

struct Time(Float);

#[derive(Debug)]
struct Vector((Float, Float));

impl Mul for Vector {
  type Output = Float;
  fn mul(self, rhs: Vector) -> Float {
    let Vector(v1) = self;
    let Vector(v2) = rhs;
    v1.0 * v2.0 + v1.1 * v2.1
  }
}

impl Add for Vector {
  type Output = Vector;
  fn add(self, rhs: Vector) -> Vector {
    let Vector(v1) = self;
    let Vector(v2) = rhs;
    Vector((v1.0 + v2.0, v1.1 + v2.1))
  }
}

impl Sub for Vector {
  type Output = Vector;
  fn sub(self, rhs: Vector) -> Vector {
    let Vector(v1) = self;
    let Vector(v2) = rhs;
    Vector((v1.0 - v2.0, v1.1 - v2.1))
  }
}

#[derive(Debug)]
struct Particle {
  x: Vector,
  v: Vector,
  r: Float,
  m: Float,
}

impl Particle {
  fn tt_impact(&self, other: &Particle) -> Time {
    Time(0.0)
  }

  fn bounce(&self, other: &Particle) -> (Particle, Particle) {
    let v1 = Particle {
      x: Vector((1., 1.)),
      v: Vector((1., 1.)),
      r: 1.,
      m: 1.
    };
    let v2 = Particle {
      x: Vector((1., 1.)),
      v: Vector((1., 1.)),
      r: 1.,
      m: 1.
    };
    (v1, v2)
  }
}

trait Box<P> {
  fn create(initial: Vec<P>) -> Self;
  fn next_collision(&self) -> (&P, &P);
  fn update<'l>(&'l mut self, &p1: Particle, &p2: Particle) -> &'l mut Self;
}

fn main() {
  let v1 = Particle {
    x: Vector((1., 1.)),
    v: Vector((1., 1.)),
    r: 1.,
    m: 1.
  };

  let v2 = Particle {
    x: Vector((1., 1.)),
    v: Vector((1., 1.)),
    r: 1.,
    m: 1.
  };
  println!("v1: {:?}", v1);
  println!("delta: {:?}", v1.x - v2.x);
}
<commit_msg>[r] create vector with traits; particle; box trait<commit_after>use std::ops::{Add, Mul, Sub};

type Float = f32;

struct Time(Float);

#[derive(Debug)]
struct Vector((Float, Float));

impl<'l> Mul for &'l Vector {
  type Output = Float;
  fn mul(self, rhs: &Vector) -> Float {
    let &Vector(v1) = self;
    let &Vector(v2) = rhs;
    v1.0 * v2.0 + v1.1 * v2.1
  }
}

impl<'l> Add for &'l Vector {
  type Output = Vector;
  fn add(self, rhs: &Vector) -> Vector {
    let &Vector(v1) = self;
    let &Vector(v2) = rhs;
    Vector((v1.0 + v2.0, v1.1 + v2.1))
  }
}

impl<'l> Sub for &'l Vector {
  type Output = Vector;
  fn sub(self, rhs: &Vector) -> Vector {
    let &Vector(v1) = self;
    let &Vector(v2) = rhs;
    Vector((v1.0 - v2.0, v1.1 - v2.1))
  }
}

#[derive(Debug)]
struct Particle {
  x: Vector,
  v: Vector,
  r: Float,
  m: Float,
}

impl Particle {
  fn tt_impact(&self, other: &Particle) -> Time {
    Time(0.0)
  }

  fn bounce(&self, other: &Particle) -> (Particle, Particle) {
    let v1 = Particle {
      x: Vector((1., 1.)),
      v: Vector((1., 1.)),
      r: 1.,
      m: 1.
    };
    let v2 = Particle {
      x: Vector((1., 1.)),
      v: Vector((1., 1.)),
      r: 1.,
      m: 1.
    };
    (v1, v2)
  }
}

trait Box<P> {
  fn create(initial: Vec<P>) -> Self;
  fn next_collision(&self) -> (&P, &P);
  fn update<'l>(&'l mut self, &p1: Particle, &p2: Particle) -> &'l mut Self;
}

fn main() {
  let v1 = Particle {
    x: Vector((1., 1.)),
    v: Vector((1., 1.)),
    r: 1.,
    m: 1.
  };

  let v2 = Particle {
    x: Vector((1., 1.)),
    v: Vector((1., 1.)),
    r: 1.,
    m: 1.
  };
  println!("v1: {:?}", v1);
  println!("delta: {:?}", &v1.x - &v2.x);
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2015 Rodolphe Breard
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//

extern crate libreauth;

use libreauth::oath::TOTPBuilder;
use std::io;

fn get_secret_key() -> String {
    let mut key = String::new();
    io::stdin().read_line(&mut key)
        .ok()
        .expect("Failed to read the secret key.");
    key.trim().to_string()
}

fn main() {
    let key = get_secret_key();
    let code = TOTPBuilder::new()
        .base32_key(&key)
        .finalize()
        .unwrap()
        .generate();
    println!("{}", code);
}
<commit_msg>Read several lines<commit_after>//
// Copyright (c) 2015 Rodolphe Breard
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//

extern crate libreauth;

use libreauth::oath::TOTPBuilder;
use std::io;

fn get_secret_key() -> Option<String> {
    let mut key = String::new();
    let read_len = match io::stdin().read_line(&mut key) {
        Ok(l) => l,
        Err(_) => { return None; },
    };
    if read_len != 0 {
        Some(key.trim().to_string())
    } else {
        None
    }
}

fn main() {
    loop {
        let key = match get_secret_key() {
            Some(k) => k,
            None => { return ; },
        };
        let code = TOTPBuilder::new()
            .base32_key(&key)
            .finalize()
            .unwrap()
            .generate();
        println!("{}", code);
    }
}
<|endoftext|>


<commit_before>mod connection;
mod commands;
mod parser;
extern crate rusqlite;

use std::env;
use std::io::{self, Write};
use std::net::TcpListener;
use std::thread;
use std::sync::{Arc, Mutex};
use self::rusqlite::Connection;

fn main() {
    let args: Vec<String> = env::args().collect();

    if args.len() != 3 {
        writeln!(io::stderr(), "usage: blueis host:port database.sqlite3").unwrap();
        std::process::exit(1);
    }

    let listener = TcpListener::bind(args[1].clone()).unwrap();

    let connection = Connection::open(args[2].clone()).unwrap();

    connection.execute("CREATE TABLE list_items (id integer primary key autoincrement, key string, value blob, position integer)", &[]).ok();
    connection.execute("CREATE INDEX list_items_key ON list_items(key, position)", &[]).ok();

    let connection_mutex = Arc::new(Mutex::new(connection));

    for stream in listener.incoming() {
        match stream {
            Err(_) => {}
            Ok(stream) => {
                let connection_mutex = connection_mutex.clone();
                thread::spawn(move || connection::handle_connection(stream, connection_mutex));
            }
        }
    }
}
<commit_msg>store a database version for compatibility testing<commit_after>mod connection;
mod commands;
mod parser;
extern crate rusqlite;

use std::env;
use std::io::{self, Write};
use std::net::TcpListener;
use std::thread;
use std::sync::{Arc, Mutex};
use self::rusqlite::Connection;

const DATABASE_VERSION: &'static str = "1";

fn main() {
    let args: Vec<String> = env::args().collect();

    if args.len() != 3 {
        writeln!(io::stderr(), "usage: blueis host:port database.sqlite3").unwrap();
        std::process::exit(1);
    }

    let listener = TcpListener::bind(args[1].clone()).unwrap();

    let connection = Connection::open(args[2].clone()).unwrap();

    set_up_tables(&connection);

    let connection_mutex = Arc::new(Mutex::new(connection));

    for stream in listener.incoming() {
        match stream {
            Err(_) => {}
            Ok(stream) => {
                let connection_mutex = connection_mutex.clone();
                thread::spawn(move || connection::handle_connection(stream, connection_mutex));
            }
        }
    }
}

fn set_up_tables(connection: &Connection) {
    connection.execute("CREATE TABLE blueis (id integer primary key autoincrement, key string, value blob)", &[]).ok();
    connection.execute("CREATE UNIQUE INDEX blueis_key_index ON blueis(key)", &[]).ok();

    match connection.prepare("SELECT value FROM blueis WHERE key = 'version'").unwrap().query_row(&[], |row| row.get(0)) as Result<String, _> {
        Ok(value) => {
            if value.as_str() != DATABASE_VERSION {
                panic!("the database supplied has been used on a later version of blueis, and therefore is incompatible with this version");
            }
        }

        Err(rusqlite::Error::QueryReturnedNoRows) => {
            connection.execute("INSERT INTO blueis (key, value) VALUES ('version', '1')", &[]).unwrap();
        }

        Err(e) => panic!(e)
    }

    connection.execute("CREATE TABLE list_items (id integer primary key autoincrement, key string, value blob, position integer)", &[]).ok();
    connection.execute("CREATE INDEX list_items_key ON list_items(key, position)", &[]).ok();
}
<|endoftext|>