<commit_before>#[macro_use]
extern crate woodpecker;
use woodpecker as wp;
use wp::handlers::{rotating_file, stdout};

extern crate argparse;
use argparse::{ArgumentParser, StoreTrue, Store};

#[macro_use]
extern crate lazy_static;

extern crate libc;

extern crate mio;
use mio::{Events, Poll, Ready, PollOpt, Token};
use mio::unix::{EventedFd, UnixReady};

use std::ops::Deref;
use std::path::Path;
use std::io::{Write, Read};
use std::process;
use std::fs::File;
use std::os::unix::io::FromRawFd;

lazy_static! {
    static ref B_SUFFIX: Vec<&'static str> = vec!["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
    static ref B_SUFFIX_LOWER: Vec<String> = B_SUFFIX.iter().map(|x| x.to_lowercase()).collect();
}

#[derive(Debug)]
enum ParseError {
    Invalid,
}

fn unbytify(value: &String) -> Result<u64, ParseError> {
    let value = value.to_lowercase();
    let value = value.trim();

    // w/o any suffix
    match value.parse() {
        Ok(x) => return Ok(x),
        _ => {},
    }

    for (idx, suffix) in B_SUFFIX_LOWER.iter().enumerate().rev() {
        let sfx = &suffix[..1];
        let mut res = value.split(sfx);

        let val: f64 = match res.next() {
            Some(x) => {
                match x.parse() {
                    Ok(x) => x,
                    _ => continue,
                }
            },
            _ => continue,
        };

        match res.next() {
            Some(rest) => {
                if rest.len() > 0 && rest != "b" && rest != "ib" {
                    return Err(ParseError::Invalid);
                }
            },
            _ => {},
        };

        let val = val * 1024u64.pow(idx as u32) as f64;
        return Ok(val.round() as u64);
    }

    Err(ParseError::Invalid)
}

pub fn set_nonblock(fd: libc::c_int) -> Result<(), ()> {
    unsafe {
        let flags = libc::fcntl(fd, libc::F_GETFL);
        let res = libc::fcntl(fd, libc::F_SETFL, flags | libc::O_NONBLOCK);
        if res == -1 {
            Err(())
        } else {
            Ok(())
        }
    }
}

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

    let mut count = 10;
    let mut size = "1M".to_string();
    let mut stdout = false;
    let mut date = false;
    let mut file = String::new();

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Pipe logger");
        ap.refer(&mut stdout).add_option(&["--stdout"], StoreTrue, "Log to stdout");
        ap.refer(&mut date).add_option(&["-d", "--date"], StoreTrue, "Insert a timestamp before the log message");
        ap.refer(&mut count).add_option(&["-c", "--count"], Store, "Max number of log files");
        ap.refer(&mut size).add_option(&["-s", "--size"], Store, "Max size of a single log file");
        ap.refer(&mut file).add_argument("file", Store, "Log file name");
        ap.parse_args_or_exit();
    }

    let size: u64 = match unbytify(&size) {
        Ok(val) if val > 0 => val,
        _ => {
            writeln!(&mut std::io::stderr(), "Invalid size").unwrap();
            process::exit(2);
        }
    };

    if stdout {
        wp_register_handler!(stdout::handler());
    }

    if date {
        wp_set_formatter!(Box::new(|record| {
            format!("{} {}", record.ts_utc(), record.msg())
        }));
    } else {
        wp_set_formatter!(Box::new(|record| {
            record.msg().deref().clone()
        }));
    }

    wp_register_handler!(rotating_file::handler(Path::new(&file), count, size));

    let mut stdin = unsafe { File::from_raw_fd(libc::STDIN_FILENO) };
    set_nonblock(libc::STDIN_FILENO).unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1);
    let token = Token(0);

    poll.register(&EventedFd(&libc::STDIN_FILENO),
                  token,
                  Ready::readable() | UnixReady::hup(),
                  PollOpt::edge() | PollOpt::level()
    ).unwrap();

    let mut buffer = Vec::new();
    loop {
        poll.poll(&mut events, None).unwrap();

        for event in &events {
            if token != event.token() {
                continue;
            }

            let readiness = event.readiness();

            if readiness.is_readable() {
                let mut bit = [0; 1];
                match stdin.read_exact(&mut bit) {
                    Ok(_) => {
                        buffer.push(bit[0]);
                        if buffer.len() > 1024 || bit[0] == '\n' as u8 {
                            log!("{}", String::from_utf8_lossy(&buffer));
                            buffer.clear();
                        }
                    },
                    _ => {
                        break;
                    },
                }
                continue;
            }

            if UnixReady::from(readiness).is_hup()  {
                return;
            }
        }
    }
}
<commit_msg>rs: properly flush on termination<commit_after>#[macro_use]
extern crate woodpecker;
use woodpecker as wp;
use wp::handlers::{rotating_file, stdout};

extern crate argparse;
use argparse::{ArgumentParser, StoreTrue, Store};

#[macro_use]
extern crate lazy_static;

extern crate libc;

extern crate mio;
use mio::{Events, Poll, Ready, PollOpt, Token};
use mio::unix::{EventedFd, UnixReady};

use std::ops::Deref;
use std::path::Path;
use std::io::{Write, Read};
use std::process;
use std::fs::File;
use std::os::unix::io::FromRawFd;

lazy_static! {
    static ref B_SUFFIX: Vec<&'static str> = vec!["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
    static ref B_SUFFIX_LOWER: Vec<String> = B_SUFFIX.iter().map(|x| x.to_lowercase()).collect();
}

const BUF_SIZE: usize = 4096;
const NL: u8 = '\n' as u8;
const CR: u8 = '\r' as u8;

#[derive(Debug)]
enum ParseError {
    Invalid,
}

fn unbytify(value: &String) -> Result<u64, ParseError> {
    let value = value.to_lowercase();
    let value = value.trim();

    // w/o any suffix
    match value.parse() {
        Ok(x) => return Ok(x),
        _ => {},
    }

    for (idx, suffix) in B_SUFFIX_LOWER.iter().enumerate().rev() {
        let sfx = &suffix[..1];
        let mut res = value.split(sfx);

        let val: f64 = match res.next() {
            Some(x) => {
                match x.parse() {
                    Ok(x) => x,
                    _ => continue,
                }
            },
            _ => continue,
        };

        match res.next() {
            Some(rest) => {
                if rest.len() > 0 && rest != "b" && rest != "ib" {
                    return Err(ParseError::Invalid);
                }
            },
            _ => {},
        };

        let val = val * 1024u64.pow(idx as u32) as f64;
        return Ok(val.round() as u64);
    }

    Err(ParseError::Invalid)
}

pub fn set_nonblock(fd: libc::c_int) -> Result<(), ()> {
    unsafe {
        let flags = libc::fcntl(fd, libc::F_GETFL);
        let res = libc::fcntl(fd, libc::F_SETFL, flags | libc::O_NONBLOCK);
        if res == -1 {
            Err(())
        } else {
            Ok(())
        }
    }
}

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

    let mut count = 10;
    let mut size = "1M".to_string();
    let mut stdout = false;
    let mut date = false;
    let mut file = String::new();

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Pipe logger");
        ap.refer(&mut stdout).add_option(&["--stdout"], StoreTrue, "Log to stdout");
        ap.refer(&mut date).add_option(&["-d", "--date"], StoreTrue, "Insert a timestamp before the log message");
        ap.refer(&mut count).add_option(&["-c", "--count"], Store, "Max number of log files");
        ap.refer(&mut size).add_option(&["-s", "--size"], Store, "Max size of a single log file");
        ap.refer(&mut file).add_argument("file", Store, "Log file name");
        ap.parse_args_or_exit();
    }

    let size: u64 = match unbytify(&size) {
        Ok(val) if val > 0 => val,
        _ => {
            writeln!(&mut std::io::stderr(), "Invalid size").unwrap();
            process::exit(2);
        }
    };

    if stdout {
        wp_register_handler!(stdout::handler());
    }

    if date {
        wp_set_formatter!(Box::new(|record| {
            format!("{} {}", record.ts_utc(), record.msg())
        }));
    } else {
        wp_set_formatter!(Box::new(|record| {
            record.msg().deref().clone()
        }));
    }

    wp_register_handler!(rotating_file::handler(Path::new(&file), count, size));

    let mut stdin = unsafe { File::from_raw_fd(libc::STDIN_FILENO) };
    set_nonblock(libc::STDIN_FILENO).unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1);
    let token = Token(0);

    poll.register(&EventedFd(&libc::STDIN_FILENO),
                  token,
                  Ready::readable() | UnixReady::hup(),
                  PollOpt::edge() | PollOpt::level()
    ).unwrap();

    let mut buffer = Vec::new();
    loop {
        poll.poll(&mut events, None).unwrap();

        for event in &events {
            if token != event.token() {
                continue;
            }

            let readiness = event.readiness();

            if readiness.is_readable() {
                let mut chunk = [0; 1];
                match stdin.read_exact(&mut chunk) {
                    Ok(_) => {
                        let ch = chunk[0];
                        if ch == CR {
                            continue;
                        }
                        buffer.push(ch);
                        if ch == NL || buffer.len() == BUF_SIZE {
                            log!("{}", String::from_utf8_lossy(&buffer));
                            buffer.clear();
                        }
                    },
                    _ => {
                        break;
                    },
                }
                continue;
            }

            if UnixReady::from(readiness).is_hup()  {
                if buffer.len() > 0 {
                    log!("{}", String::from_utf8_lossy(&buffer));
                }
                return;
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate rudit;
extern crate termion;

use std::io::{Write, stdout};
use termion::raw::IntoRawMode;
use termion::event::Key;
use termion::input::TermRead;
use termion::cursor::Goto;
use rudit::gapbuffer::GapBuffer;

fn main() {
    let mut buffer = GapBuffer::new(30);
    let mut stdout = stdout().into_raw_mode().unwrap();
    let mut index = 0;
    let mut cx: u16 = 3;
    let mut cy: u16 = 1;
    // buffer.insert(0, 'a');
    // buffer.insert(1, 'b');
    // buffer.insert(2, '\n');
    // buffer.insert(3, 'c');
    // index = 3;
    // cy = 2;
    write!(stdout,
           "{}{}",
           termion::clear::All,
           termion::cursor::Goto(cx, cy))
            .unwrap();
    stdout.flush().unwrap();
    'main: loop {

        write!(stdout, "{}", termion::clear::CurrentLine).unwrap();

        draw_lines(&mut stdout, &buffer.buffer);
        draw_cursor(&mut stdout, cx, cy);

        stdout.flush().unwrap();

        for c in std::io::stdin().keys() {
            match c.unwrap() {
                Key::Char('\n') => {
                    buffer.insert(index, '\n');
                    cx = 3;
                    cy += 1;
                    index += 1;
                }
                Key::Char(c) => {
                    buffer.insert(index, c);
                    index += 1;
                    cx += 1;
                }
                Key::Up => {
                    let mut new_line_pos = index;
                    let mut count_previous_line = 0;
                    for i in (0..index).rev() {
                        new_line_pos -= 1;
                        if i == 0 || buffer.buffer[i] == '\n' {
                            break;
                        }
                    }
                    if new_line_pos == 0 {
                        count_previous_line = 1;
                    }
                    for i in (0..new_line_pos).rev() {
                        count_previous_line += 1;
                        if i == 0 || buffer.buffer[i] == '\n' {
                            count_previous_line += 1;
                            break;
                        }
                    }
                    index = (cy as usize) - 1 +
                            std::cmp::min((cx as usize) - 3, count_previous_line - 1);
                    index -= 1;
                    cy -= 1;
                }
                Key::Left => {
                    if cx > 3 {
                        cx -= 1;
                        index -= 1;
                    }
                }
                Key::Right => {
                    if buffer.buffer[index] != '\0' ||
                       buffer.buffer[buffer.buffer.len() - index + buffer.gap_start - 1] != '\0' {
                        cx += 1;
                        index += 1;
                    }
                }
                Key::Esc => break,
                _ => (),
            }
            continue 'main;
        }
        write!(stdout, "{}", termion::clear::All).unwrap();
        stdout.flush().unwrap();
        break;
    }
}

fn draw_lines(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, buffer: &Vec<char>) {
    let s: String = buffer.iter().collect();
    for (index, i) in s.split('\n').enumerate() {
        write!(stdout,
               "{}{}{}{}",
               Goto(0, (index + 1) as u16),
               index + 1,
               Goto(3, (index + 1) as u16),
               i)
                .unwrap();
    }
}

fn draw_cursor(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, cx: u16, cy: u16) {
    write!(stdout, "{}", termion::cursor::Goto(cx, cy)).unwrap();
}
<commit_msg>cursor doing the right thing<commit_after>extern crate rudit;
extern crate termion;

use std::io::{Write, stdout};
use termion::raw::IntoRawMode;
use termion::event::Key;
use termion::input::TermRead;
use termion::cursor::Goto;
use rudit::gapbuffer::GapBuffer;

fn main() {
    let mut buffer = GapBuffer::new(30);
    let mut stdout = stdout().into_raw_mode().unwrap();
    let mut index = 0;
    let mut cx: u16 = 3;
    let mut cy: u16 = 1;
    // buffer.insert(0, 'a');
    // buffer.insert(1, 'b');
    // buffer.insert(2, '\n');
    // buffer.insert(3, 'c');
    // index = 3;
    // cy = 2;
    write!(stdout,
           "{}{}",
           termion::clear::All,
           termion::cursor::Goto(cx, cy))
            .unwrap();
    stdout.flush().unwrap();
    'main: loop {

        write!(stdout, "{}", termion::clear::CurrentLine).unwrap();

        draw_lines(&mut stdout, &buffer.buffer);
        draw_cursor(&mut stdout, cx, cy);

        stdout.flush().unwrap();

        for c in std::io::stdin().keys() {
            match c.unwrap() {
                Key::Char('\n') => {
                    buffer.insert(index, '\n');
                    cx = 3;
                    cy += 1;
                    index += 1;
                }
                Key::Char(c) => {
                    buffer.insert(index, c);
                    index += 1;
                    cx += 1;
                }
                Key::Up => {
                    let mut new_line_pos = index;
                    let mut count_previous_line = 0;
                    for i in (0..index).rev() {
                        new_line_pos -= 1;
                        if i == 0 || buffer.buffer[i] == '\n' {
                            break;
                        }
                    }
                    if new_line_pos == 0 {
                        count_previous_line = 1;
                    }
                    for i in (0..new_line_pos).rev() {
                        count_previous_line += 1;
                        if i == 0 || buffer.buffer[i] == '\n' {
                            count_previous_line += 1;
                            break;
                        }
                    }
                    index = (cy as usize) - 1 +
                            std::cmp::min((cx as usize) - 3, count_previous_line - 1);
                    index -= 1;
                    if cx - 3 > count_previous_line as u16 {
                        cx -= count_previous_line as u16 + 3;

                    }
                    cy -= 1;
                }
                Key::Left => {
                    if cx > 3 {
                        cx -= 1;
                        index -= 1;
                    }
                }
                Key::Right => {
                    if buffer.buffer[index] != '\0' ||
                       buffer.buffer[buffer.buffer.len() - index + buffer.gap_start - 1] != '\0' {
                        cx += 1;
                        index += 1;
                    }
                }
                Key::Esc => break,
                _ => (),
            }
            continue 'main;
        }
        write!(stdout, "{}", termion::clear::All).unwrap();
        stdout.flush().unwrap();
        break;
    }
}

fn draw_lines(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, buffer: &Vec<char>) {
    let s: String = buffer.iter().collect();
    for (index, i) in s.split('\n').enumerate() {
        write!(stdout,
               "{}{}{}{}",
               Goto(0, (index + 1) as u16),
               index + 1,
               Goto(3, (index + 1) as u16),
               i)
                .unwrap();
    }
}

fn draw_cursor(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, cx: u16, cy: u16) {
    write!(stdout, "{}", termion::cursor::Goto(cx, cy)).unwrap();
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use log::{
    debug,
    LevelFilter
};
use structopt::StructOpt;

mod command;
mod util;
mod template;
mod version;
mod vut;

use vut::BumpVersion;

#[derive(StructOpt, Debug)]
#[structopt(name = "Vut", version = env!("CARGO_PKG_VERSION"), author = env!("CARGO_PKG_AUTHORS"))]
struct Opt {
    #[structopt(short = "v", parse(from_occurrences), help = "Verbosity")]
    verbosity: u8,
    #[structopt(subcommand)]
    command: Command,
}

#[derive(StructOpt, Debug)]
enum Command {
    #[structopt(name = "init", help = "Initialize version file")]
    Init {
        #[structopt(name = "version", help = "Specify initial version")]
        version: Option<String>,
    },

    #[structopt(name = "get", help = "Get version info")]
    Get {
        #[structopt(name = "format", help = "Specify output format")]
        format: String,
    },

    #[structopt(name = "set", help = "Set version info")]
    Set {
        #[structopt(name = "version", help = "Specify version to set")]
        version: String,
    },

    #[structopt(name = "bump", help = "Bump version")]
    Bump {
        #[structopt(help = "Specify step")]
        bump_version: BumpVersion,
    },

    #[structopt(name = "generate", help = "Generate templates")]
    Generate,
}

fn main() {
    let opt = Opt::from_args();

    // Vary the output based on how many times the user used the "verbose" flag
    // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
    let log_level = match opt.verbosity {
        0 => LevelFilter::Off,
        1 => LevelFilter::Error,
        2 => LevelFilter::Warn,
        3 => LevelFilter::Info,
        4 => LevelFilter::Debug,
        5 | _ => LevelFilter::Trace,
    };

    // Initialize logging
    initialize_logging(log_level);

    debug!("Debug logging enabled.");

    let cmd_result = match opt.command {
        Command::Bump { bump_version } => command::bump(bump_version),
        Command::Generate => command::generate(),
        Command::Get { format } => command::get(&format),
        Command::Init { version } => command::init(version.as_ref().map(|v| v.as_str())),
        Command::Set { version } => command::set(&version),
    };

    match cmd_result {
        Ok(_) => { },
        Err(err) => {
            // Print error description to stderr
            eprintln!("{}", err.description);

            // Return the exit code that corresponds to the error kind
            std::process::exit(err.kind.exit_code());
        },
    };
}

fn initialize_logging(our_level_filter: LevelFilter) {
    use chrono::Utc;

    fern::Dispatch::new()
        .level(our_level_filter)
        .chain(std::io::stderr())
        .format(|out, message, record| {
            out.finish(format_args!(
                "{} | {} | {} | {}",
                Utc::now().format("%Y-%m-%d %H:%M:%S%.3f"),
                record.target(),
                record.level(),
                message
            ))
        })
        .apply()
        .unwrap();
}
<commit_msg>fix: CLI usage info<commit_after>#![allow(dead_code)]

use log::{
    debug,
    LevelFilter
};
use structopt::StructOpt;

mod command;
mod util;
mod template;
mod version;
mod vut;

use vut::BumpVersion;

#[derive(StructOpt, Debug)]
#[structopt(name = "Vut", version = env!("CARGO_PKG_VERSION"), author = env!("CARGO_PKG_AUTHORS"))]
struct Opt {
    #[structopt(short = "v", parse(from_occurrences), help = "Verbosity")]
    verbosity: u8,
    #[structopt(subcommand)]
    command: Command,
}

#[derive(StructOpt, Debug)]
enum Command {
    #[structopt(name = "init", about = "Initialize version file")]
    Init {
        #[structopt(name = "version", about = "Specify initial version")]
        version: Option<String>,
    },

    #[structopt(name = "get", help = "Get version")]
    Get {
        #[structopt(name = "format", about = "Specify output format")]
        format: String,
    },

    #[structopt(name = "set", help = "Set version")]
    Set {
        #[structopt(name = "version", about = "Specify version to set")]
        version: String,
    },

    #[structopt(name = "bump", about = "Bump version")]
    Bump {
        #[structopt(help = "Version to bump (major|minor|prerelease|build)")]
        bump_version: BumpVersion,
    },

    #[structopt(name = "generate", alias = "gen", about = "Generate template output")]
    Generate,
}

fn main() {
    let opt = Opt::from_args();

    // Vary the output based on how many times the user used the "verbose" flag
    // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
    let log_level = match opt.verbosity {
        0 => LevelFilter::Off,
        1 => LevelFilter::Error,
        2 => LevelFilter::Warn,
        3 => LevelFilter::Info,
        4 => LevelFilter::Debug,
        5 | _ => LevelFilter::Trace,
    };

    // Initialize logging
    initialize_logging(log_level);

    debug!("Debug logging enabled.");

    let cmd_result = match opt.command {
        Command::Bump { bump_version } => command::bump(bump_version),
        Command::Generate => command::generate(),
        Command::Get { format } => command::get(&format),
        Command::Init { version } => command::init(version.as_ref().map(|v| v.as_str())),
        Command::Set { version } => command::set(&version),
    };

    match cmd_result {
        Ok(_) => { },
        Err(err) => {
            // Print error description to stderr
            eprintln!("{}", err.description);

            // Return the exit code that corresponds to the error kind
            std::process::exit(err.kind.exit_code());
        },
    };
}

fn initialize_logging(our_level_filter: LevelFilter) {
    use chrono::Utc;

    fern::Dispatch::new()
        .level(our_level_filter)
        .chain(std::io::stderr())
        .format(|out, message, record| {
            out.finish(format_args!(
                "{} | {} | {} | {}",
                Utc::now().format("%Y-%m-%d %H:%M:%S%.3f"),
                record.target(),
                record.level(),
                message
            ))
        })
        .apply()
        .unwrap();
}
<|endoftext|>


<commit_before>#[macro_use] extern crate log;

use std::num::{Int, FromPrimitive};
use std::os;
use std::io::File;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::iter::range_step;

struct EDS {
    needle: Vec<char>,
    haystack: Vec<char>,
    indexed_haystack: HashMap<char, Vec<usize>>,
    first_poses: Vec<usize>,
    first_poses_idx: usize,
    second_poses: Vec<usize>,
    second_poses_idx: usize,
}

impl Iterator for EDS {
    type Item = (usize, i64);

    fn next(&mut self) -> Option<(usize, i64)> {
        let len_first_poses = self.first_poses.len();
        let len_second_poses = self.second_poses.len();
        let len_needle = self.needle.len();
        let len_haystack = self.haystack.len();
        let mut have_done_one_loop = false;

        loop {
            // Starts off at 0/0, and we don't want to increment it the first time
            if ! (self.first_poses_idx == 0 && self.second_poses_idx == 0 && !have_done_one_loop) {
                if self.second_poses_idx == len_second_poses {
                    self.second_poses_idx = 0;
                    self.first_poses_idx += 1;
                } else{
                    self.second_poses_idx += 1;
                }
            }
            have_done_one_loop = true;

            let first_pos = self.first_poses[self.first_poses_idx];
            let second_pos = self.second_poses[self.second_poses_idx];
            debug!("first_pos {} second_pos {}", first_pos, second_pos);

            let step: i64 = (second_pos as i64) - (first_pos as i64);
            if step == 1 {
                continue;
            }
            let positions: Vec<i64> = std::iter::count(first_pos as i64, step as i64).take(len_needle).collect();
            //let positions: Vec<i64> = range_step(first_pos as i64, step*len_needle, step).collect();
            debug!("Start {} step {}", first_pos, step);
            if positions.iter().any(|&x| { x<0 }) {
                // TODO there's probably a better maths way to do this
                continue;
            }
            let positions: Vec<usize> = positions.iter().map(|&x| { FromPrimitive::from_i64(x).unwrap() }).collect();
            debug!("positions {:?}", positions);
            if positions.len() == 0 {
                // WTF
                continue;
            }

            if positions[positions.len()-1] > len_haystack - 1 {
                debug!("Past end");
                break;
            }
            if positions.iter().map(|&c| { &self.haystack[c] }).zip(self.needle.iter()).all(|(&a, &b)| { a == b }) {
                //println!("Found starting at {} with step of {}", first_pos, step);
                return Some((first_pos, step));
            }
        }
        None
    }
}

fn index_chars(input: &Vec<char>) -> HashMap<char, Vec<usize>> {
    let mut indexed_haystack = HashMap::new();
    for (idx, &c) in input.iter().enumerate() {
        match indexed_haystack.entry(c) {
            Vacant(entry) => { entry.insert(vec![idx]); },
            Occupied(mut entry) => { (*entry.get_mut()).push(idx); }
        }
    }

    indexed_haystack
}

impl EDS {
    fn new(needle: Vec<char>, haystack: Vec<char>) -> Option<EDS> {
        let indexed_haystack = index_chars(&haystack);

        let first_poses;
        match indexed_haystack.get(&needle[0]) {
            None => { return None ; }
            Some(ref entries) => {
                first_poses = (**entries).clone();
            }
        }

        let second_poses;
        match indexed_haystack.get(&needle[1]) {
            None => { return None ; }
            Some(ref entries) => {
                second_poses = (**entries).clone();
            }
        }

        let result = EDS {
            needle: needle, haystack: haystack,
            indexed_haystack: indexed_haystack,
            first_poses: first_poses, second_poses: second_poses,
            first_poses_idx: 0, second_poses_idx: 0,
        };

        Some(result)
    }

}

fn only_alphanumeric(input: Vec<char>) -> Vec<char> {
    input.iter().filter(|&c| { c.is_alphabetic() }).map(|&c| { c.to_lowercase() }).collect()
}

//fn only_constants(input: Vec<char>) -> Vec<char> {
    //input.filter(|&c| { c.is_alphabetic() && ! ( c }).collect()
//}

fn main() {
    let file_to_search = &os::args()[1];
    println!("Reading in {}", file_to_search);
    let haystack: Vec<char> = File::open(&Path::new(file_to_search)).read_to_string().unwrap().chars().filter(|&x| { x.is_alphabetic() }).map(|x| { x.to_lowercase() }).collect();

    let needle = (&os::args()[2]).to_string();
    println!("Looking for {}", needle);
    let needle: Vec<char> = needle.chars().collect();

    let eds_searcher: EDS;
    match EDS::new(needle, haystack) {
        None => {
            println!("Cannot look for this string");
        }
        Some(ref mut eds_searcher) => {
            for (start, step) in *eds_searcher {
                println!("Found starting at {} with step of {}", start, step);
            }
        }
    }

}
<commit_msg>fixes<commit_after>#[macro_use] extern crate log;

use std::num::{Int, FromPrimitive};
use std::os;
use std::io::File;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::iter::range_step;

struct EDS {
    needle: Vec<char>,
    haystack: Vec<char>,
    indexed_haystack: HashMap<char, Vec<usize>>,
    first_poses: Vec<usize>,
    first_poses_idx: usize,
    second_poses: Vec<usize>,
    second_poses_idx: usize,
}

impl Iterator for EDS {
    type Item = (usize, i64);

    fn next(&mut self) -> Option<(usize, i64)> {
        debug!("Start of next call");
        let len_first_poses = self.first_poses.len();
        let len_second_poses = self.second_poses.len();

        if self.first_poses_idx == len_first_poses {
            debug!("Reached end, finishing");
            // reached the end
            return None;
        }

        let len_needle = self.needle.len();
        let len_haystack = self.haystack.len();
        let mut have_done_one_loop = false;
        let first_run = (self.first_poses_idx == 0 && self.second_poses_idx == 0);

        loop {
            debug!("Start of loop");
            // Starts off at 0/0, and we don't want to increment it the first time
            if ! (self.first_poses_idx == 0 && self.second_poses_idx == 0 && !have_done_one_loop) {
                debug!("Incrementing counters");
                if self.second_poses_idx == len_second_poses - 1 {
                    self.second_poses_idx = 0;
                    self.first_poses_idx += 1;
                } else{
                    self.second_poses_idx += 1;
                }
            }
            have_done_one_loop = true;
            if self.first_poses_idx == len_first_poses {
                debug!("Reached end, finishing");
                // reached the end
                return None;
            }

            debug!("first_poses_idx {} second_poses_idx {}", self.first_poses_idx, self.second_poses_idx);
            let first_pos = self.first_poses[self.first_poses_idx];
            let second_pos = self.second_poses[self.second_poses_idx];
            debug!("first_pos {} second_pos {}", first_pos, second_pos);

            let step: i64 = (second_pos as i64) - (first_pos as i64);
            if step == 1 {
                continue;
            }
            let positions: Vec<i64> = std::iter::count(first_pos as i64, step as i64).take(len_needle).collect();
            //let positions: Vec<i64> = range_step(first_pos as i64, step*len_needle, step).collect();
            debug!("Start {} step {}", first_pos, step);
            if positions.iter().any(|&x| { x<0 }) {
                // TODO there's probably a better maths way to do this
                continue;
            }
            let positions: Vec<usize> = positions.iter().map(|&x| { FromPrimitive::from_i64(x).unwrap() }).collect();
            debug!("positions {:?}", positions);
            if positions.len() == 0 {
                // WTF
                continue;
            }

            if positions[positions.len()-1] > len_haystack - 1 {
                debug!("Past end");
                continue;
            }
            if positions.iter().map(|&c| { &self.haystack[c] }).zip(self.needle.iter()).all(|(&a, &b)| { a == b }) {
                //println!("Found starting at {} with step of {}", first_pos, step);
                return Some((first_pos, step));
            }
        }
        None
    }
}

fn index_chars(input: &Vec<char>) -> HashMap<char, Vec<usize>> {
    let mut indexed_haystack = HashMap::new();
    for (idx, &c) in input.iter().enumerate() {
        match indexed_haystack.entry(c) {
            Vacant(entry) => { entry.insert(vec![idx]); },
            Occupied(mut entry) => { (*entry.get_mut()).push(idx); }
        }
    }

    indexed_haystack
}

impl EDS {
    fn new(needle: Vec<char>, haystack: Vec<char>) -> Option<EDS> {
        let indexed_haystack = index_chars(&haystack);

        let first_poses;
        match indexed_haystack.get(&needle[0]) {
            None => { return None ; }
            Some(ref entries) => {
                first_poses = (**entries).clone();
            }
        }

        let second_poses;
        match indexed_haystack.get(&needle[1]) {
            None => { return None ; }
            Some(ref entries) => {
                second_poses = (**entries).clone();
            }
        }

        let result = EDS {
            needle: needle, haystack: haystack,
            indexed_haystack: indexed_haystack,
            first_poses: first_poses, second_poses: second_poses,
            first_poses_idx: 0, second_poses_idx: 0,
        };

        Some(result)
    }

}

fn only_alphanumeric(input: String) -> Vec<char> {
    input.chars().filter(|c| { c.is_alphabetic() }).map(|c| { c.to_lowercase() }).collect()
}

//fn only_constants(input: Vec<char>) -> Vec<char> {
    //input.filter(|&c| { c.is_alphabetic() && ! ( c }).collect()
//}

fn main() {
    let file_to_search = &os::args()[1];
    println!("Reading in {}", file_to_search);
    let haystack: Vec<char> = only_alphanumeric(File::open(&Path::new(file_to_search)).read_to_string().unwrap());

    let needle = (&os::args()[2]).to_string();
    println!("Looking for {}", needle);
    let needle = only_alphanumeric(needle);

    let eds_searcher: EDS;
    match EDS::new(needle, haystack) {
        None => {
            println!("Cannot look for this string");
        }
        Some(ref mut eds_searcher) => {
            for (start, step) in *eds_searcher {
                println!("Found starting at {} with step of {}", start, step);
            }
        }
    }

}
<|endoftext|>


<commit_before>extern crate cline;
extern crate termios;

use std::io;
use std::io::prelude::*;
use std::os::unix::io::RawFd;
use termios::*;

fn main() {
    let mut termios = Termios::from_fd(0).unwrap();
    let term_orig = termios;
    let mut cli = cline::Cli::new();
    let mut buf:Vec<u8> = Vec::new();

    cli.register(vec!["show", "stuff"], | _ | { println!("wooo haaa") });
    cli.register(vec!["show", "other"], | _ | { println!("wooo haaa") });
    cli.register(vec!["foo", "bar"], | _ | { println!("wooo haaa") });
    cli.register(vec!["exit"], | _ | {
        tcsetattr(0, termios::TCSANOW, &term_orig);
        std::process::exit(0);
    });

    //termios.c_lflag = ECHONL;
    termios.c_lflag &= !(ICANON | IEXTEN | ISIG | ECHO);
    tcsetattr(0, TCSANOW, &termios);
    tcflush(0, TCIOFLUSH);

    println!("-----> {:?}", term_orig);
    print!(">> ");
    io::stdout().flush();
    for byte in io::stdin().bytes() {
        let b = byte.unwrap();
        let mut command:String = String::new();
        if let Ok(string) = String::from_utf8(buf.clone()) {
            command = string;
        }

        match b {
            3 => break,
            9 => {
                //Tab
                let mut outbuf:String = String::new();
                let res = cli.complete(&command);

                for suggestion in res.iter() {
                    outbuf.push_str(suggestion);
                    outbuf.push_str("  ");
                }

                //TODO: meh...
                match command.chars().last() {
                    Some(' ') => {
                        if res.len() == 1 {
                            buf.extend(res[0].bytes());
                            command.push_str(res[0]);
                        }
                    }
                    _ => {
                        if res.len() > 1 {
                        } else if res.len() == 1 {
                        } else {
                            //nothing found
                        }
                    }
                }

                println!("\n{}", outbuf);
                print!(">> {}", command);
                io::stdout().flush();
            }
            10 => {
                //CRLF
                println!("\nexecute for: '{}'", command);
                cli.exec(&command);
                command.clear();
                buf.clear();
                print!(">> ");
                io::stdout().flush();
            }
            0x7f => {
                //backspace
                print!("{} {}", 0x08 as char, 0x08 as char);
                io::stdout().flush();
                buf.pop();
            }
            _ => {
                buf.push(b);
                print!("{}", b as char);
                io::stdout().flush();
            }
        }
    }

    tcsetattr(0, termios::TCSANOW, &term_orig);
}
<commit_msg>implement termios based client - completion only suggests and arrow keys (history) is not implemented yet<commit_after>extern crate cline;
extern crate termios;

use std::io;
use std::io::prelude::*;
use std::os::unix::io::RawFd;
use cline::Cli;
use termios::*;

#[derive(Debug)]
enum Direction {
    Up,
    Down,
    Left,
    Right
}

#[derive(Debug)]
enum Key {
    Char(char),
    Symbol(char),
    Digit(u8),
    Arrow(Direction),
    Whitespace,
    Backspace,
    Del,
    Tab,
    Newline,
    Etx
}

fn read_key<T: Read>(bytes: &mut std::io::Bytes<T>) -> Option<Key> {
    match bytes.next() {
        Some(Ok(0x1B)) => { //Esc
            match bytes.next() {
                Some(Ok(0x5b)) => { // [
                    match bytes.next() {
                        Some(Ok(0x41)) => { // A
                            Some(Key::Arrow(Direction::Up))
                        },
                        Some(Ok(0x42)) => { // B
                            Some(Key::Arrow(Direction::Down))
                        },
                        Some(Ok(0x43)) => { // C
                            Some(Key::Arrow(Direction::Right))
                        },
                        Some(Ok(0x44)) => { // D
                            Some(Key::Arrow(Direction::Left))
                        },
                        c @ _ => {
                            println!("{} {} {}", 0x1B, 0x5b, c.unwrap().unwrap());
                            None
                        }
                    }
                },
                c @ _ => {
                    println!("{} {}", 0x1B, c.unwrap().unwrap());
                    None
                }
            }
        },
        Some(Ok(c)) if c >= 0x30 && c <= 0x39 => {
            Some(Key::Digit(c - 0x30))
        },
        Some(Ok(c)) if (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A) => {
            Some(Key::Char(c as char))
        },
        Some(Ok(0x20)) => {
            Some(Key::Whitespace)
        },
        Some(Ok(0x7f)) => {
            Some(Key::Del)
        },
        Some(Ok(0x09)) => {
            Some(Key::Tab)
        },
        Some(Ok(0x08)) => {
            Some(Key::Backspace)
        },
        Some(Ok(0xA)) => {
            Some(Key::Newline)
        },
        Some(Ok(0x3)) => {
            Some(Key::Etx)
        },
        Some(Ok(c)) => {
            println!("{:?}", c);
            Some(Key::Symbol(c as char))
        },
        _ => {
            None
        }
    }
}

fn run(cli: &mut Cli) {
    let mut termios = Termios::from_fd(0).unwrap();
    let term_orig = termios;
    let mut input_iter = io::stdin().bytes();
    let mut command = String::new();

    termios.c_lflag &= !(ICANON | IEXTEN | ISIG | ECHO);
    tcsetattr(0, TCSANOW, &termios);
    tcflush(0, TCIOFLUSH);

    print!(">> ");
    io::stdout().flush();

    loop {
        match(read_key(&mut input_iter)) {
            Some(key) => {
                match key {
                    Key::Char(c) => {
                        command.push(c);
                        print!("{}", c);
                        io::stdout().flush();
                    },
                    Key::Whitespace => {
                        command.push(' ');
                        print!(" ");
                        io::stdout().flush();
                    }
                    Key::Del | Key::Backspace => {
                        command.pop();
                        print!("{} {}", 0x08 as char, 0x08 as char);
                        io::stdout().flush();
                    },
                    Key::Tab => {
                        let suggestions = cli.complete(&command);
                        print!("{}", '\n');
                        for cmd in suggestions.iter() {
                            print!("{} ", cmd);
                        }
                        print!("\n>> {}", command);
                        io::stdout().flush();
                    },
                    Key::Newline => {
                        println!("");
                        cli.exec(&command);
                        command.clear();
                        print!(">> ");
                        io::stdout().flush();
                    },
                    Key::Etx => { //Ctrl + C
                        println!("");
                        break;
                    }
                    x @ _ => {
                        println!("unhandled: {:?}", x);
                    }
                }
            },
            None => {
                break;
            }
        }
    }
    tcsetattr(0, termios::TCSANOW, &term_orig);
}

fn main() {
    let mut cli = Cli::new();

    cli.register(vec!["foo", "bar"], | _ | { println!("running foo bar") });
    cli.register(vec!["foo", "baz"], | _ | { println!("running foo baz") });

    run(&mut cli);
}
<|endoftext|>


<commit_before>extern crate rudit;
extern crate termion;

use std::io::{Write, stdout};
use termion::raw::IntoRawMode;
use termion::event::Key;
use termion::input::TermRead;
use termion::cursor::Goto;
use rudit::gapbuffer::GapBuffer;
use termion::cursor::DetectCursorPos;

fn main() {
    let mut buffer = GapBuffer::new(30);
    let mut stdout = stdout().into_raw_mode().unwrap();
    let mut index = 0;
    let mut line_num = 1;
    let mut cx: u16 = 3;
    let mut cy: u16 = 1;
    write!(stdout,
           "{}{}",
           termion::clear::All,
           termion::cursor::Goto(cx, cy))
        .unwrap();
    stdout.flush().unwrap();
    'main: loop {
        write!(stdout, "{}", termion::clear::All).unwrap();

        draw_lines(&mut stdout, &buffer.buffer);
        draw_info(&mut stdout, index, line_num, cx, cy);
        draw_cursor(&mut stdout, cx, cy);
        stdout.flush().unwrap();

        for c in std::io::stdin().keys() {
            match c.unwrap() {
                Key::Char('\n') => {
                    buffer.insert(index, '\n');
                    cx = 3;
                    cy += 1;
                    index += 1;
                    line_num += 1;
                }
                Key::Char(c) => {
                    buffer.insert(index, c);
                    index += 1;
                    cx += 1;
                }
                Key::Up => {
                    if cy > 1 {
                        cy -= 1;
                    }
                }
                Key::Down => {
                    if cy < line_num as u16 {
                        cy += 1;
                    }
                }
                Key::Left => {
                    if cx > 3 {
                        cx -= 1;
                        index -= 1;
                    }
                }
                Key::Right => {
                    if buffer.buffer[index] != '\0' ||
                       buffer.buffer[buffer.buffer.len() - index + buffer.gap_start - 1] != '\0' {
                        cx += 1;
                        index += 1;
                    }
                }
                Key::Esc => break,
                _ => (),
            }
            continue 'main;
        }
        write!(stdout, "{}", termion::clear::All).unwrap();
        stdout.flush().unwrap();
        break;
    }
}
fn draw_info(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>,
             index: usize,
             line_num: usize,
             cx: u16,
             cy: u16) {
    write!(stdout,
           "{} index {} line_num {} cx {} cy {}",
           termion::cursor::Goto(0, termion::terminal_size().unwrap().1),
           index,
           line_num,
           cx - 2,
           cy)
        .unwrap();
}
fn draw_lines(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, buffer: &Vec<char>) {
    let s: String = buffer.iter().collect();
    for (index, i) in s.split('\n').enumerate() {
        write!(stdout,
               "{}{}{}{}",
               Goto(0, (index + 1) as u16),
               index + 1,
               Goto(3, (index + 1) as u16),
               i)
            .unwrap();
    }
}

fn draw_cursor(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, cx: u16, cy: u16) {
    write!(stdout, "{}", termion::cursor::Goto(cx, cy)).unwrap();
}
<commit_msg>namespace rewriting<commit_after>extern crate rudit;
extern crate termion;

use std::io::{Write, stdout, Stdout};

use termion::raw::IntoRawMode;
use termion::event::Key;
use termion::input::TermRead;
use termion::cursor::Goto;
use termion::raw::RawTerminal;
use rudit::gapbuffer::GapBuffer;

fn main() {
    let mut buffer = GapBuffer::new(30);
    let mut stdout = stdout().into_raw_mode().unwrap();
    let mut index = 0;
    let mut line_num = 1;
    let mut cx: u16 = 3;
    let mut cy: u16 = 1;
    write!(stdout,
           "{}{}",
           termion::clear::All,
           termion::cursor::Goto(cx, cy))
        .unwrap();
    stdout.flush().unwrap();
    'main: loop {
        write!(stdout, "{}", termion::clear::All).unwrap();

        draw_lines(&mut stdout, &buffer.buffer);
        draw_info(&mut stdout, index, line_num, cx, cy);
        draw_cursor(&mut stdout, cx, cy);
        stdout.flush().unwrap();

        for c in std::io::stdin().keys() {
            match c.unwrap() {
                Key::Char('\n') => {
                    buffer.insert(index, '\n');
                    cx = 3;
                    cy += 1;
                    index += 1;
                    line_num += 1;
                }
                Key::Char(c) => {
                    buffer.insert(index, c);
                    index += 1;
                    cx += 1;
                }
                Key::Up => {
                    if cy > 1 {
                        cy -= 1;
                    }
                }
                Key::Down => {
                    if cy < line_num as u16 {
                        cy += 1;
                    }
                }
                Key::Left => {
                    if cx > 3 {
                        cx -= 1;
                        index -= 1;
                    }
                }
                Key::Right => {
                    if buffer.buffer[index] != '\0' ||
                       buffer.buffer[buffer.buffer.len() - index + buffer.gap_start - 1] != '\0' {
                        cx += 1;
                        index += 1;
                    }
                }
                Key::Esc => break,
                _ => (),
            }
            continue 'main;
        }
        write!(stdout, "{}", termion::clear::All).unwrap();
        stdout.flush().unwrap();
        break;
    }
}
fn draw_info(stdout: &mut RawTerminal<Stdout>, index: usize, line_num: usize, cx: u16, cy: u16) {
    write!(stdout,
           "{} index {} line_num {} cx {} cy {}",
           termion::cursor::Goto(0, termion::terminal_size().unwrap().1),
           index,
           line_num,
           cx - 2,
           cy)
        .unwrap();
}
fn draw_lines(stdout: &mut RawTerminal<Stdout>, buffer: &Vec<char>) {
    let s: String = buffer.iter().collect();
    for (index, i) in s.split('\n').enumerate() {
        write!(stdout,
               "{}{}{}{}",
               Goto(0, (index + 1) as u16),
               index + 1,
               Goto(3, (index + 1) as u16),
               i)
            .unwrap();
    }
}

fn draw_cursor(stdout: &mut RawTerminal<Stdout>, cx: u16, cy: u16) {
    write!(stdout, "{}", termion::cursor::Goto(cx, cy)).unwrap();
}
<|endoftext|>


<commit_before>extern crate multirust;

fn main() {
    println!("Hello, world!");
}
<commit_msg>Get multirust::Cfg set up<commit_after>#[macro_use(shared_ntfy)]
extern crate rust_install;

extern crate multirust;

use multirust::{Cfg, Result, Notification};

// Copied from multirust-rs.
fn set_globals() -> Result<Cfg> {
    // Base config
    let verbose = false;
    Cfg::from_env(shared_ntfy!(move |n: Notification| {
        use multirust::notify::NotificationLevel::*;
        match n.level() {
            Verbose => {
                if verbose {
                    println!("{}", n);
                }
            }
            _ => {
                println!("{}", n);
            }
        }
    }))
}

fn main() {
    let cfg = set_globals().expect("set_globals");
    println!("{:?}", cfg.multirust_dir);
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate futures;
extern crate tokio_core;
extern crate tokio_tls;
extern crate native_tls;
extern crate clap;
extern crate tls_api_openssl;
extern crate tls_api;

use std::thread::sleep;
use std::time::Duration;
use std::process::{Child, Command, Stdio};
use futures::{Stream, Future};
use hyper::server::Http;

use tokio_core::reactor::Core;
use tokio_core::net::TcpListener;
use tokio_tls::TlsAcceptorExt;
use native_tls::{Pkcs12, TlsAcceptor};
use tls_api_openssl::TlsAcceptorBuilder;
use tls_api::TlsAcceptorBuilder as tls_api_TlsAcceptorBuilder;

use clap::{App, Arg};

mod proxy;
mod http2;

const BASE_PORT: i32 = 60000;
const APP_NAME: &'static str = "kamasu";
const VERSION: &'static str = "0.2.0";

struct PHPSpawnOption {
    host: String,
    docroot: String,
    phpini: String,
}

fn spawn_php_server_process(opts: &PHPSpawnOption, n: usize, procs: &mut Vec<(Child, String)>) {
    for port_offset in 0..n {
        let port = BASE_PORT + port_offset as i32;
        let backend_addr = format!("{}:{}", opts.host, port);
        let ret = Command::new("php")
            .arg("-S").arg(backend_addr.clone())
            .arg("-t").arg(opts.docroot.as_str())
            .arg("-c").arg(opts.phpini.as_str())
            .stdout(Stdio::null())
            .spawn()
            .expect("php command not execution");
        procs.push((ret, backend_addr));
    }
}

fn spawn_proxy(routes: Vec<String>, addr_str: String, https_acceptor: Option<TlsAcceptor>) -> std::thread::JoinHandle<()> {
    std::thread::spawn(move || {
        let mut core = Core::new().unwrap();
        let handle = core.handle();
        let http = Http::new();
        let backend_client = hyper::Client::new(&handle);

        let addr = addr_str.as_str().parse().unwrap();
        let sock = TcpListener::bind(&addr, &handle)
            .expect(format!("bind error. addr={}", addr).as_str());
        let host = format!("{}", sock.local_addr().unwrap().ip());
        let port = sock.local_addr().unwrap().port();

        if let Some(https_acceptor) = https_acceptor {
            println!("Listening on {}:{} with https", host, port);
            let server = sock.incoming().for_each(|(client, client_addr)| {
                let service = proxy::Proxy {
                    routes: routes.clone(),
                    client: backend_client.clone(),
                };
                https_acceptor.accept_async(client).join(Ok(client_addr)).and_then(|(stream, client_addr)| {
                    http.bind_connection(&handle, stream, client_addr, service);
                    Ok(())
                }).or_else(|e| { println!("error accepting TLS connection: {}", e); Ok(()) })
            });
            core.run(server).unwrap();
        } else {
            println!("Listening on {}:{}", host, port);
            let server = sock.incoming().for_each(|(client, client_addr)| {
                let service = proxy::Proxy {
                    routes: routes.clone(),
                    client: backend_client.clone(),
                };
                futures::future::ok(client_addr).and_then(|client_addr| {
                    http.bind_connection(&handle, client, client_addr, service);
                    Ok(())
                })
            });
            core.run(server).unwrap();
        };
    })
}

fn main() {
    let app = App::new(APP_NAME)
        .version(VERSION)
        .about("Reverse Proxy for PHP built-in Server")
        .arg(Arg::with_name("server")
             .short("S")
             .takes_value(true)
             .value_name("ADDR")
             .help("Run with HTTP Web Server"))
        .arg(Arg::with_name("https")
             .short("s")
             .long("https")
             .takes_value(true)
             .value_name("ADDR")
             .help("Run with HTTPS Web Server"))
        .arg(Arg::with_name("http2")
             .short("h2")
             .long("http2")
             .takes_value(true)
             .value_name("ADDR")
             .help("Run with HTTP2 Web Server"))
        .arg(Arg::with_name("procs")
             .short("n")
             .takes_value(true)
             .value_name("PROCS")
             .help("Spawn N php procs"))
        .arg(Arg::with_name("phpini")
             .short("c")
             .takes_value(true)
             .value_name("FILE_OR_DIR")
             .help("Specify php.ini file or in this directory"))
        .arg(Arg::with_name("docroot")
             .short("t")
             .takes_value(true)
             .value_name("DIR")
             .help("Specify document root <docroot>"));

    let matches = app.get_matches();

    // bind address
    let addr_str = match matches.value_of("server") {
        Some(v) => v.to_string(),
        None => "127.0.0.1:8000".to_string(),
    };

    // PHP docroot
    let docroot = match matches.value_of("docroot") {
        Some(v) => v,
        None => "./",
    };

    // php.ini path or directory
    let phpini = match matches.value_of("phpini") {
        Some(v) => v,
        None => "./",
    };

    // N procs
    let proc_num: usize = match matches.value_of("procs") {
        Some(v) => {
            match v.parse::<usize>() {
                Ok(i) => i,
                Err(_) => 1,
            }
        },
        None => 10,
    };

    // spawn php server processes
    let mut procs = vec![];
    let phpopts = PHPSpawnOption {
        host: "127.0.0.1".to_string(),
        phpini: phpini.to_string(),
        docroot: docroot.to_string(),
    };
    spawn_php_server_process(&phpopts, proc_num, &mut procs);

    let routes: Vec<String> = procs.iter().map(|p| p.1.clone()).collect();

    let mut proxy_procs = vec![];
    proxy_procs.push(spawn_proxy(routes.clone(), addr_str, None));

    // use HTTPS
    match matches.value_of("https") {
        Some(addr) => {
            let der = include_bytes!("kamasu.p12");
            let cert = Pkcs12::from_der(der, APP_NAME).unwrap();
            proxy_procs.push(
                spawn_proxy(routes.clone(), addr.to_string(),
                Some(TlsAcceptor::builder(cert).unwrap().build().unwrap())));
        },
        None => {},
    };

    // use HTTP2
    match matches.value_of("http2") {
        Some(addr) => {
            let der = include_bytes!("kamasu.p12");
            let mut tls_acceptor = TlsAcceptorBuilder::from_pkcs12(der, APP_NAME).expect("acceptor build error");
            tls_acceptor.set_alpn_protocols(&[b"h2"]).expect("set_alpn_protocols error");

            proxy_procs.push(http2::spawn_proxy(
                    routes, addr.to_string(),
                    tls_acceptor.build().expect("tls acceptor build error")));
        },
        None => {},
    };

    loop {
        for p in procs.iter_mut() {
            match p.0.try_wait() {
                Ok(Some(status)) => {
                    println!("pid={}, exited with: {}", p.0.id(), status);
                },
                Ok(None) => {},
                Err(e) => println!("error occured: {}", e),
            }
        }
        sleep(Duration::from_millis(1_000));
    }
}
<commit_msg>app name and version string get from CARGO_PKG_XX<commit_after>extern crate hyper;
extern crate futures;
extern crate tokio_core;
extern crate tokio_tls;
extern crate native_tls;
extern crate clap;
extern crate tls_api_openssl;
extern crate tls_api;

use std::thread::sleep;
use std::time::Duration;
use std::process::{Child, Command, Stdio};
use futures::{Stream, Future};
use hyper::server::Http;

use tokio_core::reactor::Core;
use tokio_core::net::TcpListener;
use tokio_tls::TlsAcceptorExt;
use native_tls::{Pkcs12, TlsAcceptor};
use tls_api_openssl::TlsAcceptorBuilder;
use tls_api::TlsAcceptorBuilder as tls_api_TlsAcceptorBuilder;

use clap::{App, Arg};

mod proxy;
mod http2;

const APP_NAME: &'static str = env!("CARGO_PKG_NAME");
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const BASE_PORT: i32 = 60000;

struct PHPSpawnOption {
    host: String,
    docroot: String,
    phpini: String,
}

fn spawn_php_server_process(opts: &PHPSpawnOption, n: usize, procs: &mut Vec<(Child, String)>) {
    for port_offset in 0..n {
        let port = BASE_PORT + port_offset as i32;
        let backend_addr = format!("{}:{}", opts.host, port);
        let ret = Command::new("php")
            .arg("-S").arg(backend_addr.clone())
            .arg("-t").arg(opts.docroot.as_str())
            .arg("-c").arg(opts.phpini.as_str())
            .stdout(Stdio::null())
            .spawn()
            .expect("php command not execution");
        procs.push((ret, backend_addr));
    }
}

fn spawn_proxy(routes: Vec<String>, addr_str: String, https_acceptor: Option<TlsAcceptor>) -> std::thread::JoinHandle<()> {
    std::thread::spawn(move || {
        let mut core = Core::new().unwrap();
        let handle = core.handle();
        let http = Http::new();
        let backend_client = hyper::Client::new(&handle);

        let addr = addr_str.as_str().parse().unwrap();
        let sock = TcpListener::bind(&addr, &handle)
            .expect(format!("bind error. addr={}", addr).as_str());
        let host = format!("{}", sock.local_addr().unwrap().ip());
        let port = sock.local_addr().unwrap().port();

        if let Some(https_acceptor) = https_acceptor {
            println!("Listening on {}:{} with https", host, port);
            let server = sock.incoming().for_each(|(client, client_addr)| {
                let service = proxy::Proxy {
                    routes: routes.clone(),
                    client: backend_client.clone(),
                };
                https_acceptor.accept_async(client).join(Ok(client_addr)).and_then(|(stream, client_addr)| {
                    http.bind_connection(&handle, stream, client_addr, service);
                    Ok(())
                }).or_else(|e| { println!("error accepting TLS connection: {}", e); Ok(()) })
            });
            core.run(server).unwrap();
        } else {
            println!("Listening on {}:{}", host, port);
            let server = sock.incoming().for_each(|(client, client_addr)| {
                let service = proxy::Proxy {
                    routes: routes.clone(),
                    client: backend_client.clone(),
                };
                futures::future::ok(client_addr).and_then(|client_addr| {
                    http.bind_connection(&handle, client, client_addr, service);
                    Ok(())
                })
            });
            core.run(server).unwrap();
        };
    })
}

fn main() {
    let app = App::new(APP_NAME)
        .version(VERSION)
        .about("Reverse Proxy for PHP built-in Server")
        .arg(Arg::with_name("server")
             .short("S")
             .takes_value(true)
             .value_name("ADDR")
             .help("Run with HTTP Web Server"))
        .arg(Arg::with_name("https")
             .short("s")
             .long("https")
             .takes_value(true)
             .value_name("ADDR")
             .help("Run with HTTPS Web Server"))
        .arg(Arg::with_name("http2")
             .short("h2")
             .long("http2")
             .takes_value(true)
             .value_name("ADDR")
             .help("Run with HTTP2 Web Server"))
        .arg(Arg::with_name("procs")
             .short("n")
             .takes_value(true)
             .value_name("PROCS")
             .help("Spawn N php procs"))
        .arg(Arg::with_name("phpini")
             .short("c")
             .takes_value(true)
             .value_name("FILE_OR_DIR")
             .help("Specify php.ini file or in this directory"))
        .arg(Arg::with_name("docroot")
             .short("t")
             .takes_value(true)
             .value_name("DIR")
             .help("Specify document root <docroot>"));

    let matches = app.get_matches();

    // bind address
    let addr_str = match matches.value_of("server") {
        Some(v) => v.to_string(),
        None => "127.0.0.1:8000".to_string(),
    };

    // PHP docroot
    let docroot = match matches.value_of("docroot") {
        Some(v) => v,
        None => "./",
    };

    // php.ini path or directory
    let phpini = match matches.value_of("phpini") {
        Some(v) => v,
        None => "./",
    };

    // N procs
    let proc_num: usize = match matches.value_of("procs") {
        Some(v) => {
            match v.parse::<usize>() {
                Ok(i) => i,
                Err(_) => 1,
            }
        },
        None => 10,
    };

    // spawn php server processes
    let mut procs = vec![];
    let phpopts = PHPSpawnOption {
        host: "127.0.0.1".to_string(),
        phpini: phpini.to_string(),
        docroot: docroot.to_string(),
    };
    spawn_php_server_process(&phpopts, proc_num, &mut procs);

    let routes: Vec<String> = procs.iter().map(|p| p.1.clone()).collect();

    let mut proxy_procs = vec![];
    proxy_procs.push(spawn_proxy(routes.clone(), addr_str, None));

    // use HTTPS
    match matches.value_of("https") {
        Some(addr) => {
            let der = include_bytes!("kamasu.p12");
            let cert = Pkcs12::from_der(der, APP_NAME).unwrap();
            proxy_procs.push(
                spawn_proxy(routes.clone(), addr.to_string(),
                Some(TlsAcceptor::builder(cert).unwrap().build().unwrap())));
        },
        None => {},
    };

    // use HTTP2
    match matches.value_of("http2") {
        Some(addr) => {
            let der = include_bytes!("kamasu.p12");
            let mut tls_acceptor = TlsAcceptorBuilder::from_pkcs12(der, APP_NAME).expect("acceptor build error");
            tls_acceptor.set_alpn_protocols(&[b"h2"]).expect("set_alpn_protocols error");

            proxy_procs.push(http2::spawn_proxy(
                    routes, addr.to_string(),
                    tls_acceptor.build().expect("tls acceptor build error")));
        },
        None => {},
    };

    loop {
        for p in procs.iter_mut() {
            match p.0.try_wait() {
                Ok(Some(status)) => {
                    println!("pid={}, exited with: {}", p.0.id(), status);
                },
                Ok(None) => {},
                Err(e) => println!("error occured: {}", e),
            }
        }
        sleep(Duration::from_millis(1_000));
    }
}
<|endoftext|>


<commit_before>
extern crate clap;

use std::collections::HashMap;
use std::io::{Read, BufReader, BufRead};
use clap::{App, Arg};
use std::fs::File;

fn main() {

    let matches = App::new("scotext")
        .version("0.1.0")
        .about("Scores input based on english language character frequency")
        .author("Gavyn Riebau")
        .arg(Arg::with_name("verbose")
             .help("Increases the verbosity of output")
             .long("verbose")
             .short("v")
             .takes_value(false))
        .arg(Arg::with_name("dictionary")
             .help("Path to a dictionary file with english language words. If one of the words in the dictionary is found in the input, the text score will be increased.")
             .long("dictionary")
             .short("w")
             .value_name("dictionary"))
        .get_matches();

    let character_scores = get_char_score_map();
    let mut score = 0.0;
    let mut stdin = std::io::stdin();
    let mut buffer = String::new();

    let _ = stdin.read_to_string(&mut buffer);
    let input = buffer.to_lowercase();

    if matches.is_present("verbose") {
        println!("Read input: {}", input);
    }

    // Iterate each character and increment "score" by the frequency score for that character.
    for c in input.chars() {
        if character_scores.contains_key(&c) {
            let char_score = character_scores.get(&c).unwrap();
            if matches.is_present("verbose") {
                println!("Char: {} - {}", c, char_score);
            }
            score = score + char_score;
        }
    }

    // Check if each word in the provided dictionary is present.
    if matches.is_present("dictionary") {
        let path = matches.value_of("dictionary").unwrap();
        match File::open(path) {
            Ok(file) => {
                // Will hold all the words in the dictionary file.
                let mut dictionary_lines : Vec<String> = Vec::new();

                // Read all the words and push them to the dictionary vector.
                let reader = BufReader::new(file);
                for line in reader.lines() {
                    let word = line.unwrap().to_lowercase();
                    dictionary_lines.push(word);
                }

                // Sort the dictionary in order of word length, largest words to smallest words.
                dictionary_lines.sort_by(|a, b| {
                    let x = a.len();
                    let y = b.len();

                    y.cmp(&x)
                });

                // Check if the input contains a word from the dictionary.
                // Each time a word is matched it's removed from the input so there isn't double
                // counting of words.
                //
                // For each word the score is increased by 3 * e ^ word_length.
                // In this way large words contribute exponentially more to the overall score.
                let mut cloned_input = input.clone();
                for word in dictionary_lines {
                    if cloned_input.contains(word.as_str()) {
                        if matches.is_present("verbose") {
                            println!("Matched word: {}", word);
                        }
                        let adjustment = 3.0 * (word.len() as f32).exp();
                        score = score + adjustment;

                        cloned_input = cloned_input.replacen(word.as_str(), "", 1);
                    }
                }
            },
            Err(err) => {
                println!("Failed to open dictionary file '{}' because: {:?}", path, err);
            }
        }
    }

    if matches.is_present("verbose") {
        println!("Character score was: {}", score);
    } else {
        println!("{}", score);
    }
}

// Creates a dictionary where:
// key      - character
// value    - frequency score
fn get_char_score_map() -> HashMap<char, f32> {
    let mut character_scores = HashMap::new();

    character_scores.insert('e', 12.702);
    character_scores.insert('t', 9.056);
    character_scores.insert('a', 8.167);
    character_scores.insert('o', 7.507);
    character_scores.insert('i', 6.966);
    character_scores.insert('n', 6.749);
    character_scores.insert('s', 6.327);
    character_scores.insert('h', 6.094);
    character_scores.insert('r', 5.987);
    character_scores.insert('d', 4.253);
    character_scores.insert('l', 4.025);
    character_scores.insert('c', 2.782);
    character_scores.insert('u', 2.758);
    character_scores.insert('m', 2.406);
    character_scores.insert('w', 2.360);
    character_scores.insert('f', 2.228);
    character_scores.insert('g', 2.015);
    character_scores.insert('y', 1.974);
    character_scores.insert('p', 1.929);
    character_scores.insert('b', 1.492);
    character_scores.insert('v', 0.978);
    character_scores.insert('k', 0.772);
    character_scores.insert('j', 0.153);
    character_scores.insert('x', 0.150);
    character_scores.insert('q', 0.095);
    character_scores.insert('z', 0.074);

    character_scores
}

<commit_msg>Read all dictionary file data at once to attempt to increase performance<commit_after>
extern crate clap;

use std::collections::HashMap;
use std::io::{Read, BufReader};
use clap::{App, Arg};
use std::fs::File;

fn main() {

    let matches = App::new("scotext")
        .version("0.1.0")
        .about("Scores input based on english language character frequency")
        .author("Gavyn Riebau")
        .arg(Arg::with_name("verbose")
             .help("Increases the verbosity of output")
             .long("verbose")
             .short("v")
             .takes_value(false))
        .arg(Arg::with_name("dictionary")
             .help("Path to a dictionary file with english language words. If one of the words in the dictionary is found in the input, the text score will be increased.")
             .long("dictionary")
             .short("w")
             .value_name("dictionary"))
        .get_matches();

    let character_scores = get_char_score_map();
    let mut score = 0.0;
    let mut stdin = std::io::stdin();
    let mut buffer = String::new();

    let _ = stdin.read_to_string(&mut buffer);
    let input = buffer.to_lowercase();

    if matches.is_present("verbose") {
        println!("Read input: {}", input);
    }

    // Iterate each character and increment "score" by the frequency score for that character.
    for c in input.chars() {
        if character_scores.contains_key(&c) {
            let char_score = character_scores.get(&c).unwrap();
            if matches.is_present("verbose") {
                println!("Char: {} - {}", c, char_score);
            }
            score = score + char_score;
        }
    }

    // Check if each word in the provided dictionary is present.
    if matches.is_present("dictionary") {
        let path = matches.value_of("dictionary").unwrap();
        match File::open(path) {
            Ok(file) => {
                // Will hold all the words in the dictionary file.
                let mut dictionary_lines : Vec<String> = Vec::new();

                // Read all the words and push them to the dictionary vector.
                let mut reader = BufReader::new(file);
                let mut dictionary_data = String::new();
                let _ = reader.read_to_string(&mut dictionary_data);

                for line in dictionary_data.lines() {
                    let word = line.to_lowercase();
                    dictionary_lines.push(word);
                }

                // Sort the dictionary in order of word length, largest words to smallest words.
                dictionary_lines.sort_by(|a, b| {
                    let x = a.len();
                    let y = b.len();

                    y.cmp(&x)
                });

                // Check if the input contains a word from the dictionary.
                // Each time a word is matched it's removed from the input so there isn't double
                // counting of words.
                //
                // For each word the score is increased by 3 * e ^ word_length.
                // In this way large words contribute exponentially more to the overall score.
                let mut cloned_input = input.clone();
                for word in dictionary_lines {
                    if cloned_input.contains(word.as_str()) {
                        if matches.is_present("verbose") {
                            println!("Matched word: {}", word);
                        }
                        let adjustment = 3.0 * (word.len() as f32).exp();
                        score = score + adjustment;

                        cloned_input = cloned_input.replacen(word.as_str(), "", 1);
                    }
                }
            },
            Err(err) => {
                println!("Failed to open dictionary file '{}' because: {:?}", path, err);
            }
        }
    }

    if matches.is_present("verbose") {
        println!("Character score was: {}", score);
    } else {
        println!("{:>8.2}", score);
    }
}

// Creates a dictionary where:
// key      - character
// value    - frequency score
fn get_char_score_map() -> HashMap<char, f32> {
    let mut character_scores = HashMap::new();

    character_scores.insert('e', 12.702);
    character_scores.insert('t', 9.056);
    character_scores.insert('a', 8.167);
    character_scores.insert('o', 7.507);
    character_scores.insert('i', 6.966);
    character_scores.insert('n', 6.749);
    character_scores.insert('s', 6.327);
    character_scores.insert('h', 6.094);
    character_scores.insert('r', 5.987);
    character_scores.insert('d', 4.253);
    character_scores.insert('l', 4.025);
    character_scores.insert('c', 2.782);
    character_scores.insert('u', 2.758);
    character_scores.insert('m', 2.406);
    character_scores.insert('w', 2.360);
    character_scores.insert('f', 2.228);
    character_scores.insert('g', 2.015);
    character_scores.insert('y', 1.974);
    character_scores.insert('p', 1.929);
    character_scores.insert('b', 1.492);
    character_scores.insert('v', 0.978);
    character_scores.insert('k', 0.772);
    character_scores.insert('j', 0.153);
    character_scores.insert('x', 0.150);
    character_scores.insert('q', 0.095);
    character_scores.insert('z', 0.074);

    character_scores
}

<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::iter::repeat;
use std::str::FromStr;

enum Hamming { Encode, Decode, EncodeBinary, DecodeBinary }

fn main() {
    let title = "RUSTYHAM: A HAMMING CODE GENERATOR IN RUST";
    let border: String = repeat('=').take(title.len()).collect::<>();
    println!("{}", border);
    println!("{}", title);
    println!("{}", border);

    loop {
        let mut linebuf = String::new();
        println!("(1) Encode ASCII");
        println!("(2) Encode binary");
        println!("(3) Decode to ASCII");
        println!("(4) Decode to binary");
        print!("Enter your choice: ");
        io::stdout().flush().unwrap();
        io::stdin().read_line(&mut linebuf).unwrap();

        let num = i32::from_str(linebuf.trim());
        match num.ok() {
            Some(n) => {
                let mut good = true;
                println!("{}", match n {
                    1 => hamming(Hamming::Encode, prompt("Enter string to encode: ")),
                    2 => hamming(Hamming::EncodeBinary, prompt("Enter binary string to encode: ")),
                    3 => hamming(Hamming::Decode, prompt("Enter Hamming code to decode: ")),
                    4 => hamming(Hamming::DecodeBinary, prompt("Enter Hamming code to decode to binary: ")),
                    _ => { good = false; "Invalid input.".to_string() }
                });
                if good { break; }
            }
            None => {
                println!("Invalid input.");
            }
        };
    }
}

fn hamming(action: Hamming, s: String) -> String {
    match action {
        Hamming::Encode | Hamming::EncodeBinary => {
            // get an iterator over the individual bits
            let mut bytes;
            let bytes_str = match action {
                Hamming::EncodeBinary => s,
                _ => {
                    // convert ASCII string to binary
                    bytes = s.into_bytes();  // takes ownership of s
                    bytes.iter().map(|&c| format!("{:0>1$b}", c, 7))
                        .collect::<Vec<String>>().concat()
                }
            };
            let mut bytes_iter = bytes_str.chars();
            // we should assume that ownership of s has already been
            // transferred away by this point

            // compute block and message length
            let mlen = bytes_str.len() as u32;
            let lenpow = (2..).find(|&r| 2u32.pow(r) - r - 1 >= mlen).unwrap();
            let len = 2us.pow(lenpow) - 1;

            // the thing we're storing the hamming code in
            let mut code: Vec<bool> = repeat(false).take(len).collect();

            // set data bits
            for i in 1..len {
                if (i & (i - 1)) != 0 {  // if i is not a power of 2
                    code[i-1] = bytes_iter.next().unwrap_or('0') == '1';
                }
            }

            // set parity bits
            for i in 0..lenpow {
                code[2us.pow(i) - 1] = calc_parity(&code, i);
            }

            code.into_iter().map(|x| if x {"1"} else {"0"})
                .collect::<Vec<_>>().concat()
        },
        Hamming::Decode | Hamming::DecodeBinary => {
            // verify parity bits, fix 1-bit-flipped errors if any
            let len = s.len();
            let lenpow = ((len + 1) as f32).sqrt().round() as u32;
            let mut chars = s.chars().map(|x| x == '1').collect::<Vec<bool>>();
            let mut flipped_bit = -1i32;
            while (0..lenpow).any(|i| calc_parity(&chars, i)) {
                if flipped_bit != -1 {
                    chars[flipped_bit as usize] = !chars[flipped_bit as usize];
                }
                flipped_bit += 1;
                chars[flipped_bit as usize] = !chars[flipped_bit as usize];
            }

            // collect all bits at non-powers-of-2
            let data = chars.iter().enumerate()
                .filter(|x| ((x.0 + 1) & x.0) != 0)
                .map(|x| if *x.1 {'1'} else {'0'});

            // return
            match action {
                Hamming::DecodeBinary => {
                    data.collect::<String>()
                },
                _ => {
                    let chars = (&data.collect::<Vec<char>>()[..]).chunks(7)
                        .map(|x| {
                            let ss = &x.iter().cloned().collect::<String>()[..];
                            u8::from_str_radix(ss, 2).unwrap()
                        })
                        .collect::<Vec<u8>>();
                    String::from_utf8(chars).unwrap()
                }
            }
        }
    }
}

fn calc_parity(code: &Vec<bool>, i: u32) -> bool {
    let bi = 2us.pow(i) - 1;
    let (mut parity, mut ignore, mut counter) = (false, false, 0);
    for j in bi..code.len() {
        if !ignore && code[j] { parity = !parity }
        counter += 1;
        if counter >= 2u32.pow(i) {
            ignore = !ignore;
            counter = 0;
        }
    }
    parity
}

fn prompt(s: &str) -> String {
    let mut input = String::new();
    print!("{}", s);
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut input).unwrap();
    input.trim().to_string()
}
<commit_msg>trim when decoding to ASCII<commit_after>use std::io;
use std::io::prelude::*;
use std::iter::repeat;
use std::str::FromStr;

enum Hamming { Encode, Decode, EncodeBinary, DecodeBinary }

fn main() {
    let title = "RUSTYHAM: A HAMMING CODE GENERATOR IN RUST";
    let border: String = repeat('=').take(title.len()).collect::<>();
    println!("{}", border);
    println!("{}", title);
    println!("{}", border);

    loop {
        let mut linebuf = String::new();
        println!("(1) Encode ASCII");
        println!("(2) Encode binary");
        println!("(3) Decode to ASCII");
        println!("(4) Decode to binary");
        print!("Enter your choice: ");
        io::stdout().flush().unwrap();
        io::stdin().read_line(&mut linebuf).unwrap();

        let num = i32::from_str(linebuf.trim());
        match num.ok() {
            Some(n) => {
                let mut good = true;
                println!("{}", match n {
                    1 => hamming(Hamming::Encode, prompt("Enter string to encode: ")),
                    2 => hamming(Hamming::EncodeBinary, prompt("Enter binary string to encode: ")),
                    3 => hamming(Hamming::Decode, prompt("Enter Hamming code to decode: ")),
                    4 => hamming(Hamming::DecodeBinary, prompt("Enter Hamming code to decode to binary: ")),
                    _ => { good = false; "Invalid input.".to_string() }
                });
                if good { break; }
            }
            None => {
                println!("Invalid input.");
            }
        };
    }
}

fn hamming(action: Hamming, s: String) -> String {
    match action {
        Hamming::Encode | Hamming::EncodeBinary => {
            // get an iterator over the individual bits
            let mut bytes;
            let bytes_str = match action {
                Hamming::EncodeBinary => s,
                _ => {
                    // convert ASCII string to binary
                    bytes = s.into_bytes();  // takes ownership of s
                    bytes.iter().map(|&c| format!("{:0>1$b}", c, 7))
                        .collect::<Vec<String>>().concat()
                }
            };
            let mut bytes_iter = bytes_str.chars();
            // we should assume that ownership of s has already been
            // transferred away by this point

            // compute block and message length
            let mlen = bytes_str.len() as u32;
            let lenpow = (2..).find(|&r| 2u32.pow(r) - r - 1 >= mlen).unwrap();
            let len = 2us.pow(lenpow) - 1;

            // the thing we're storing the hamming code in
            let mut code: Vec<bool> = repeat(false).take(len).collect();

            // set data bits
            for i in 1..len {
                if (i & (i - 1)) != 0 {  // if i is not a power of 2
                    code[i-1] = bytes_iter.next().unwrap_or('0') == '1';
                }
            }

            // set parity bits
            for i in 0..lenpow {
                code[2us.pow(i) - 1] = calc_parity(&code, i);
            }

            code.into_iter().map(|x| if x {"1"} else {"0"})
                .collect::<Vec<_>>().concat()
        },
        Hamming::Decode | Hamming::DecodeBinary => {
            // verify parity bits, fix 1-bit-flipped errors if any
            let len = s.len();
            let lenpow = ((len + 1) as f32).sqrt().round() as u32;
            let mut chars = s.chars().map(|x| x == '1').collect::<Vec<bool>>();
            let mut flipped_bit = -1i32;
            while (0..lenpow).any(|i| calc_parity(&chars, i)) {
                if flipped_bit != -1 {
                    chars[flipped_bit as usize] = !chars[flipped_bit as usize];
                }
                flipped_bit += 1;
                chars[flipped_bit as usize] = !chars[flipped_bit as usize];
            }

            // collect all bits at non-powers-of-2
            let data = chars.iter().enumerate()
                .filter(|x| ((x.0 + 1) & x.0) != 0)
                .map(|x| if *x.1 {'1'} else {'0'});

            // return
            match action {
                Hamming::DecodeBinary => { data.collect::<String>() },
                _ => {
                    // we have to chop off the 0 padding if it exists
                    let cslice = &data.collect::<Vec<char>>()[..];
                    let mut chunks = cslice.chunks(7).map(|x| {
                        x.iter().cloned().collect::<String>()
                    }).collect::<Vec<String>>();
                    if chunks[chunks.len()-1].len() < 7 { chunks.pop(); }
                    else if chunks[chunks.len()-1] == "0000000" { chunks.pop(); }

                    let chars = chunks.iter()
                        .map(|x| u8::from_str_radix(&x[..], 2).unwrap())
                        .collect::<Vec<u8>>();
                    String::from_utf8(chars).unwrap()
                }
            }
        }
    }
}

fn calc_parity(code: &Vec<bool>, i: u32) -> bool {
    let bi = 2us.pow(i) - 1;
    let (mut parity, mut ignore, mut counter) = (false, false, 0);
    for j in bi..code.len() {
        if !ignore && code[j] { parity = !parity }
        counter += 1;
        if counter >= 2u32.pow(i) {
            ignore = !ignore;
            counter = 0;
        }
    }
    parity
}

fn prompt(s: &str) -> String {
    let mut input = String::new();
    print!("{}", s);
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut input).unwrap();
    input.trim().to_string()
}
<|endoftext|>