<commit_before>#[macro_use]
extern crate clap;
extern crate kbdi;

use kbdi::*;

fn main() {
    let matches = clap_app!(kbdi =>
        (@setting SubcommandRequiredElseHelp)
        (version: crate_version!())
        (author: "Brendan Molloy <brendan@bbqsrc.net>")
        (about: "Configure Windows registry values for keyboards")
        (@subcommand install =>
            (about: "Installs a keyboard layout to the registry")
            (@arg GUID: -g --guid +takes_value +required "Product code GUID for linking to MSI (eg: {42c3de12-28...})")
            (@arg LANG: -l --language +takes_value +required "Language name in specified language (eg: Norsk)")
            (@arg DLL: -d --dll +takes_value +required "Name of keyboard DLL (eg: kbdfoo01.dll)")
            (@arg LAYOUT: -n --layout_name +takes_value "Layout name, defaults to LANG (eg: US Extended)")
            (@arg CODE: -i --language_code +takes_value +required "Language code as supported by Windows (eg: sma-Latn-NO)")
        )
        (@subcommand enabled_languages =>
            (about: "Lists all languages enabled for the current user from the registry")
        )
        (@subcommand list_locales =>
            (about: "Lists all supported locales of the operating system")
        )
    ).get_matches();

    match matches.subcommand_name() {
        Some("install") => {
            let lang_name = matches.value_of("LANG").unwrap();
            let layout_dll = matches.value_of("DLL").unwrap();
            let layout_name = matches.value_of("LAYOUT").unwrap_or(&lang_name);
            let lang_code = matches.value_of("CODE").unwrap();
            let guid = matches.value_of("GUID").unwrap();

            install_keyboard(lang_name, guid, layout_dll, layout_name, lang_code);
        },
        Some("enabled_languages") => {
            let languages = enabled_languages();
            let a: Vec<&str> = languages.split("\n").collect();
            let out: String = a.join(" ");

            println!("{}", &out);
        }
        Some("list_locales") => {
            let mut locales = system_locales();

            locales.sort();
            for locale in locales {
                println!("{}", locale);
            }
        },
        _ => {}
    }
}<commit_msg>Update binary flags<commit_after>#[macro_use]
extern crate clap;
extern crate kbdi;

use kbdi::*;

fn main() {
    let matches = clap_app!(kbdi =>
        (@setting SubcommandRequiredElseHelp)
        (version: crate_version!())
        (author: "Brendan Molloy <brendan@bbqsrc.net>")
        (about: "Configure Windows registry values for keyboards")
        (@subcommand install =>
            (about: "Installs a keyboard layout to the registry")
            (@arg GUID: -g --guid +takes_value +required "Product code GUID for linking to MSI (eg: {42c3de12-28...})")
            (@arg LANG: -l --language +takes_value +required "Native language name (eg: Norsk)")
            (@arg DLL: -d --dll +takes_value +required "Name of keyboard DLL (eg: kbdfoo01.dll)")
            (@arg LAYOUT: -n --("layout-name") +takes_value "Layout name, defaults to LANG (eg: Skolt Sami (Norway))")
            (@arg CODE: -i --("language-code") +takes_value +required "Language code in BCP 47 style (eg: sma-Latn-NO)")
        )
        (@subcommand enable_language =>
            (about: "Enable a language with provided native name and code")
            (@arg LANG: -l --language +takes_value +required "Native language name (eg: Norsk)")
            (@arg CODE: -i --("language-code") +takes_value +required "Language code in BCP 47 style (eg: sma-Latn-NO)")
        )
        (@subcommand list_languages =>
            (about: "Lists all languages enabled for the current user")
        )
        (@subcommand list_locales =>
            (about: "Lists all supported locales of the operating system")
        )
    ).get_matches();

    match matches.subcommand() {
        ("install", Some(matches)) => {
            let lang_name = matches.value_of("LANG").unwrap();
            let layout_dll = matches.value_of("DLL").unwrap();
            let layout_name = matches.value_of("LAYOUT").unwrap_or(&lang_name);
            let lang_code = matches.value_of("CODE").unwrap();
            let guid = matches.value_of("GUID").unwrap();

            install_keyboard(lang_name, guid, layout_dll, layout_name, lang_code);
            println!("Rebooting is required to complete installation.");
        },
        ("enable_language", Some(matches)) => {
            let lang_name = matches.value_of("LANG").unwrap();
            let lang_code = matches.value_of("CODE").unwrap();

            LanguageRegKey::create(lang_code, lang_name);
            enable_language(lang_code);
        },
        ("list_languages", _) => {
            let languages = enabled_languages();
            let a: Vec<&str> = languages.split("\n").collect();
            let out: String = a.join(" ");

            println!("{}", &out);
        },
        ("list_locales", _) => {
            let mut locales = system_locales();

            locales.sort();
            for locale in locales {
                println!("{}", locale);
            }
        },
        _ => {}
    }
}<|endoftext|>


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

use std::collections::{HashMap, HashSet};
use std::env;
use std::io::{Write, Read};
use std::process::{Command, Stdio};

use tiny_http::{Header, Response};

extern crate crates_index;
extern crate tiny_http;

static INDEX_LOCAL_PATH: &'static str = "crates.io-index";

fn build_dot(crate_name: &str, dep_map: &HashMap<String, Vec<String>>) -> Vec<u8> {
    let mut crate_names = vec![crate_name];

    let mut dot = String::new();
    dot.push_str("digraph graphname {");

    // Which dependencies we've already seen
    let mut seen_set = HashSet::new();

    while let Some(crate_name) = crate_names.pop() {
        if seen_set.contains(crate_name as &str) {
            continue;
        }
        seen_set.insert(crate_name);
        for crate_dep in dep_map.get(crate_name).unwrap() {
            dot.push_str(&format!("{} -> {};", crate_name.replace("-", "_"), crate_dep.replace("-", "_")));
            if !seen_set.contains(crate_dep as &str) {
                crate_names.push(crate_dep);
            }
        }
    }
    dot.push_str("}");

    let child = Command::new("dot").arg("-Tpng").stdin(Stdio::piped()).stdout(Stdio::piped()).spawn().unwrap();
    {
        child.stdin.unwrap().write_all(dot.as_bytes()).unwrap();
    }

    let mut ret = vec![];
    child.stdout.unwrap().read_to_end(&mut ret).unwrap();
    ret
}

fn main() {
    let index = crates_index::CratesIndex::new(INDEX_LOCAL_PATH.into());
    if !index.exists() {
        println!("Cloning crates.io-index");
        index.clone_index();
    }

    let dep_map = index.dependency_map();

    let port = match env::var("PORT") {
        Ok(p) => p.parse::<u16>().unwrap(),
        Err(..) => 8000,
    };

    let server = tiny_http::ServerBuilder::new().with_port(port).build().unwrap();

    println!("Server listening on port {}", port);
    for req in server.incoming_requests() {
        let response = {
            let crate_name = req.get_url().trim_left_matches("/");
            if dep_map.get(crate_name).is_some() {
                let data = build_dot(crate_name, &dep_map);
                let content_type_header = "Content-Type: image/png".parse::<Header>().unwrap();
                Response::from_data(data).with_header(content_type_header)
            } else {
                Response::from_string("could not find crate").with_status_code(400)
            }
        };
        req.respond(response);
    }
}
<commit_msg>Remove unnecessary block<commit_after>// Copyright 2015 Corey Farwell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::{HashMap, HashSet};
use std::env;
use std::io::{Write, Read};
use std::process::{Command, Stdio};

use tiny_http::{Header, Response};

extern crate crates_index;
extern crate tiny_http;

static INDEX_LOCAL_PATH: &'static str = "crates.io-index";

fn build_dot(crate_name: &str, dep_map: &HashMap<String, Vec<String>>) -> Vec<u8> {
    let mut crate_names = vec![crate_name];

    let mut dot = String::new();
    dot.push_str("digraph graphname {");

    // Which dependencies we've already seen
    let mut seen_set = HashSet::new();

    while let Some(crate_name) = crate_names.pop() {
        if seen_set.contains(crate_name as &str) {
            continue;
        }
        seen_set.insert(crate_name);
        for crate_dep in dep_map.get(crate_name).unwrap() {
            dot.push_str(&format!("{} -> {};", crate_name.replace("-", "_"), crate_dep.replace("-", "_")));
            if !seen_set.contains(crate_dep as &str) {
                crate_names.push(crate_dep);
            }
        }
    }
    dot.push_str("}");

    let child = Command::new("dot").arg("-Tpng").stdin(Stdio::piped()).stdout(Stdio::piped()).spawn().unwrap();
    child.stdin.unwrap().write_all(dot.as_bytes()).unwrap();

    let mut ret = vec![];
    child.stdout.unwrap().read_to_end(&mut ret).unwrap();
    ret
}

fn main() {
    let index = crates_index::CratesIndex::new(INDEX_LOCAL_PATH.into());
    if !index.exists() {
        println!("Cloning crates.io-index");
        index.clone_index();
    }

    let dep_map = index.dependency_map();

    let port = match env::var("PORT") {
        Ok(p) => p.parse::<u16>().unwrap(),
        Err(..) => 8000,
    };

    let server = tiny_http::ServerBuilder::new().with_port(port).build().unwrap();

    println!("Server listening on port {}", port);
    for req in server.incoming_requests() {
        let response = {
            let crate_name = req.get_url().trim_left_matches("/");
            if dep_map.get(crate_name).is_some() {
                let data = build_dot(crate_name, &dep_map);
                let content_type_header = "Content-Type: image/png".parse::<Header>().unwrap();
                Response::from_data(data).with_header(content_type_header)
            } else {
                Response::from_string("could not find crate").with_status_code(400)
            }
        };
        req.respond(response);
    }
}
<|endoftext|>


<commit_before>//! Client for tldr-pages writting in Rust

#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_import_braces, unused_qualifications)]

extern crate hyper;
extern crate clap;
#[macro_use] extern crate quick_error;

use std::io::{stderr, Read, Write};
use clap::{Arg, App};
use hyper::client::response::Response as HttpResponse;

#[cfg(target_os = "macos")]
const PLATFORM: &'static str = "osx";
#[cfg(not(target_os = "macos"))]
const PLATFORM: &'static str = "linux";

fn fetch_tldr(command: &str, platform: &str) -> Result<HttpResponse, Error> {
    let client = hyper::Client::new();
    let url = format!(
        "http://raw.github.com/rprieto/tldr/master/pages/{platform}/{page}.md",
        platform = platform,
        page = command
    );

    let res = try!(client.get(&url)
        .header(hyper::header::Connection::close())
        .header(hyper::header::ContentType::plaintext())
        .send()
        .map_err(|err| Error::HttpRequest(command.to_owned(), err)));

    if res.status.is_success() {
        Ok(res)
    } else {
        Err(Error::HttpReponse(command.to_owned(), res.status))
    }
}

fn render_tldr<R: Read>(text: &mut R) -> Result<(), Error> {
    let mut buf = String::with_capacity(1024);
    try!(text.read_to_string(&mut buf));

    println!("{}", buf);
    Ok(())
}

quick_error! {
    #[derive(Debug)]
    enum Error {
        HttpRequest(command: String, err: hyper::Error) {
            from(err)
            cause(err)
            description("Error fetching page")
            display("Error fetching description for `{}`: {}", command, err)
        }
        HttpReponse(command: String, status: hyper::status::StatusCode) {
            description("Could not fetch description for command")
            display("Could not fetch description for command `{}`: {}", command, status)
        }
        Io(err: std::io::Error) {
            from()
            cause(err)
            description(err.description())
            display("Couldn't read stream")
        }
    }
}

fn main() {
    let matches = App::new("tldr")
            .version(env!("CARGO_PKG_VERSION"))
            .author("Pascal Hertleif <killercup@gmail.com>")
            .about("Simplified and community-driven man pages")
            .arg(Arg::with_name("command")
                        .help("Fetch the docs for command and render them to the terminal.")
                        .required(true)
                        .index(1))
            .get_matches();

    let command = matches.value_of("command").unwrap();

    fetch_tldr(command, "common")
    .or_else(|_| fetch_tldr(command, PLATFORM))
    .and_then(|mut res| render_tldr(&mut res))
    .unwrap_or_else(|err| {
        writeln!(stderr(), "{}", err).unwrap();
        std::process::exit(1);
    });
}
<commit_msg>chore(tools): Rustfmt<commit_after>//! Client for tldr-pages writting in Rust

#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_import_braces, unused_qualifications)]

extern crate hyper;
extern crate clap;
#[macro_use]
extern crate quick_error;

use std::io::{stderr, Read, Write};
use clap::{Arg, App};
use hyper::client::response::Response as HttpResponse;

#[cfg(target_os = "macos")]
const PLATFORM: &'static str = "osx";
#[cfg(not(target_os = "macos"))]
const PLATFORM: &'static str = "linux";

fn fetch_tldr(command: &str, platform: &str) -> Result<HttpResponse, Error> {
    let client = hyper::Client::new();
    let url = format!("http://raw.github.com/rprieto/tldr/master/pages/{platform}/{page}.md",
                      platform = platform,
                      page = command);

    let res = try!(client.get(&url)
                         .header(hyper::header::Connection::close())
                         .header(hyper::header::ContentType::plaintext())
                         .send()
                         .map_err(|err| Error::HttpRequest(command.to_owned(), err)));

    if res.status.is_success() {
        Ok(res)
    } else {
        Err(Error::HttpReponse(command.to_owned(), res.status))
    }
}

fn render_tldr<R: Read>(text: &mut R) -> Result<(), Error> {
    let mut buf = String::with_capacity(1024);
    try!(text.read_to_string(&mut buf));

    println!("{}", buf);
    Ok(())
}

quick_error! {
    #[derive(Debug)]
    enum Error {
        HttpRequest(command: String, err: hyper::Error) {
            from(err)
            cause(err)
            description("Error fetching page")
            display("Error fetching description for `{}`: {}", command, err)
        }
        HttpReponse(command: String, status: hyper::status::StatusCode) {
            description("Could not fetch description for command")
            display("Could not fetch description for command `{}`: {}", command, status)
        }
        Io(err: std::io::Error) {
            from()
            cause(err)
            description(err.description())
            display("Couldn't read stream")
        }
    }
}

fn main() {
    let matches = App::new("tldr")
                      .version(env!("CARGO_PKG_VERSION"))
                      .author("Pascal Hertleif <killercup@gmail.com>")
                      .about("Simplified and community-driven man pages")
                      .arg(Arg::with_name("command")
                               .help("Fetch the docs for command and render them to the \
                                      terminal.")
                               .required(true)
                               .index(1))
                      .get_matches();

    let command = matches.value_of("command").unwrap();

    fetch_tldr(command, "common")
        .or_else(|_| fetch_tldr(command, PLATFORM))
        .and_then(|mut res| render_tldr(&mut res))
        .unwrap_or_else(|err| {
            writeln!(stderr(), "{}", err).unwrap();
            std::process::exit(1);
        });
}
<|endoftext|>


<commit_before>extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;

use std::io::File;
use std::os;
use git2::Repository;
use rustc_serialize::json;
use rustc_serialize::hex::ToHex;

#[derive(RustcDecodable, RustcEncodable)]
struct Commit {
    hash: String,
    author: String,
    date: i64,
    message: String
}

fn main() {
    let mut output = File::create(&os::getcwd().unwrap().join("log.json")).unwrap();

    let repo_path = os::getcwd().unwrap().join("rust");
    let repo = match Repository::open(&repo_path) {
        Ok(repo) => repo,
        Err(e) => panic!("failed to init `{}`: {}", repo_path.display(), e),
    };
    let mut revs = match repo.revwalk() {
        Ok(revs) => revs,
        Err(e) => panic!("failed to revwalk: {}", e),
    };

    revs.push_head().unwrap();

    let commits = revs
    .filter_map(|commit_id| { repo.find_commit(commit_id).ok() })
    .filter_map(|commit| {
        match commit.message().and_then(|msg| { Some(msg.contains("[breaking-change]")) }) {
            Some(true) => Some(commit),
            _ => None
        }
    })
    .map(|commit| {
        Commit {
            hash: commit.id().as_bytes().to_hex().to_string(),
            author: commit.author().name()
                .or(commit.author().email())
                .or(Some("Some dude"))
                .unwrap().trim().to_string(),
            date: commit.time().seconds(),
            message: commit.message()
                .or(Some(""))
                .unwrap().trim().to_string()
        }
    })
    .take(100)
    .collect::<Vec<Commit>>();

    match write!(&mut output, "{}", json::as_pretty_json(&commits)) {
        Ok(_) => println!("wrote commits to `log.json`."),
        Err(e) => panic!("failed to write commits to file: {}", e),
    };
}
<commit_msg>Move Commit Query Stuff into Function<commit_after>extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;

use std::io::File;
use std::os;
use git2::{Repository, Error};
use rustc_serialize::json;
use rustc_serialize::hex::ToHex;

#[derive(RustcDecodable, RustcEncodable)]
struct Commit {
    hash: String,
    author: String,
    date: i64,
    message: String
}

fn fetch_commits(repo: &Repository, query: &str, amount: uint) -> Result<Vec<Commit>, Error> {
    let mut revs = try!(repo.revwalk());
    try!(revs.push_head());

    let commits = revs
    .filter_map(|commit_id| { repo.find_commit(commit_id).ok() })
    .filter_map(|commit| {
        match commit.message().and_then(|msg| { Some(msg.contains(query)) }) {
            Some(true) => Some(commit),
            _ => None
        }
    })
    .map(|commit| {
        Commit {
            hash: commit.id().as_bytes().to_hex().to_string(),
            author: commit.author().name()
                .or(commit.author().email())
                .or(Some("Some dude"))
                .unwrap().trim().to_string(),
            date: commit.time().seconds(),
            message: commit.message()
                .or(Some(""))
                .unwrap().trim().to_string()
        }
    })
    .take(amount)
    .collect();

    Result::Ok(commits)
}

fn main() {
    let cwd = os::getcwd().unwrap();
    let repo = Repository::open(&cwd.join("rust")).unwrap();

    let mut output = File::create(&cwd.join("log.json")).unwrap();

    let commits = fetch_commits(&repo, "[breaking-change]", 100).unwrap();

    match write!(&mut output, "{}", json::as_pretty_json(&commits)) {
        Ok(_) => println!("wrote commits to `log.json`."),
        Err(e) => panic!("failed to write commits to file: {}", e),
    };
}
<|endoftext|>


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

#![feature(collections)]
#![feature(core)]
#![feature(env)]
#![feature(io)]
#![feature(os)]
#![feature(path)]

extern crate getopts;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied,Vacant};
use std::env;
use std::old_io::{BufferedReader, File};
use std::rt::heap;

use getopts::Options;

type Hash = u64;
type Count = u32;
type Words = HashMap<Hash, Count>;
type Clusters = HashMap<String, Count>;

fn main() {
    let mut opts = Options::new();
    opts.optopt("c", "cluster-threshold", "cluster appearance threshold for diplay", "CLUSTERTHRESHOLD");
    opts.optflag("m", "mem-stats", "print memory allocator statistics at the end");
    opts.optflag("r", "rare", "display only clusters below CLUSTERTHRESHOLD");
    opts.optopt("w", "word-threshold", "minimum frequency of a word to be considered for a cluster", "WORDTHRESHOLD");
    opts.optopt("", "max-line-length", "discard lines longer than this many characters", "MAX_LINE_LENGTH");

    let args: Vec<String> = env::args().map(|s| s.into_string().unwrap()).collect();
    let matches = opts.parse(args.tail()).unwrap_or_else(|f| panic!(f.to_string()));

    let cluster_threshold: Count = match matches.opt_str("c") {
        Some(ct) => { ct.parse().unwrap() }
        None => { 1000 }
    };

    let word_threshold: Count = match matches.opt_str("w") {
        Some(wt) => { wt.parse().unwrap() }
        None => { 1000 }
    };

    let max_line_length: usize = match matches.opt_str("max-line-length") {
        Some(len) => len.parse().unwrap(),
        None => 1000,
    };

    let show_rare = matches.opt_present("r");
    let print_mem_stats = matches.opt_present("m");

    let inputs: Vec<Path> = matches.free.iter().map(|f| Path::new(f)).collect();

    let word_freq = calc_word_freq(&inputs, max_line_length);
    println!("found {} unique words", word_freq.len());

    let clusters = calc_clusters(&inputs, &word_freq, word_threshold, max_line_length);
    println!("found {} clusters", clusters.len());

    if print_mem_stats {
        heap::stats_print();
    }

    for (k,v) in clusters.iter() {
        if show_rare == (*v < cluster_threshold) {
            println!("{}\t{}", v, k);
        }
    }
}

fn calc_word_freq(paths: &Vec<Path>, max_line_length: usize) -> Words {
    let mut word_freq: HashMap<Hash, Count> = HashMap::new();

    for path in paths.iter() {
        let file = File::open(path);
        let mut reader = BufferedReader::new(file);

        let mut i = 0;
        for l in reader.lines() {
            let line = l.ok().unwrap();
            if max_line_length > 0 && line.len() > max_line_length {
                continue;
            }

            for w in line.words() {
                let hash = fnv1a(w);
                match word_freq.entry(hash) {
                    Vacant(wf) => { wf.insert(1); },
                    Occupied(mut wf) => { *wf.get_mut() += 1; },
                };
            }
        }
    }

    word_freq
}

fn calc_clusters(paths: &Vec<Path>, word_freq: &Words, word_threshold: Count, max_line_length: usize) -> Clusters {
    let mut clusters: HashMap<String, Count> = HashMap::new();

    for path in paths.iter() {
        let mut file = BufferedReader::new(File::open(path));
        for l in file.lines() {
            let line = l.ok().unwrap();
            if max_line_length > 0 && line.len() > max_line_length {
                continue;
            }

            let cluster = clusterify(line, word_freq, word_threshold);
            if !cluster.is_empty() {
                match clusters.entry(cluster) {
                    Vacant(c) => { c.insert(1); },
                    Occupied(mut c) => { *c.get_mut() += 1; },
                };
            }
        }
    }

    clusters
}

fn clusterify(line: String, word_freq: &Words, word_threshold: Count) -> String {
    let words: Vec<&str> = line.words().map({ |w|
        if word_freq[fnv1a(w)] < word_threshold {
            "*"
        } else {
            w
        }
    }).collect();

    words.connect(" ")
}

static FNV_PRIME_64: Hash = 1099511628211;
static FNV1_OFFSET_BASIS_64: Hash = 14695981039346656037;

fn fnv1a(s: &str) -> Hash {
    let mut hash = FNV1_OFFSET_BASIS_64;
    for b in s.as_bytes().iter() {
        hash = (hash ^ *b as Hash) * FNV_PRIME_64;
    }
    hash
}
<commit_msg>Remove unused variable<commit_after>#![crate_type = "bin"]

#![feature(collections)]
#![feature(core)]
#![feature(env)]
#![feature(io)]
#![feature(os)]
#![feature(path)]

extern crate getopts;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied,Vacant};
use std::env;
use std::old_io::{BufferedReader, File};
use std::rt::heap;

use getopts::Options;

type Hash = u64;
type Count = u32;
type Words = HashMap<Hash, Count>;
type Clusters = HashMap<String, Count>;

fn main() {
    let mut opts = Options::new();
    opts.optopt("c", "cluster-threshold", "cluster appearance threshold for diplay", "CLUSTERTHRESHOLD");
    opts.optflag("m", "mem-stats", "print memory allocator statistics at the end");
    opts.optflag("r", "rare", "display only clusters below CLUSTERTHRESHOLD");
    opts.optopt("w", "word-threshold", "minimum frequency of a word to be considered for a cluster", "WORDTHRESHOLD");
    opts.optopt("", "max-line-length", "discard lines longer than this many characters", "MAX_LINE_LENGTH");

    let args: Vec<String> = env::args().map(|s| s.into_string().unwrap()).collect();
    let matches = opts.parse(args.tail()).unwrap_or_else(|f| panic!(f.to_string()));

    let cluster_threshold: Count = match matches.opt_str("c") {
        Some(ct) => { ct.parse().unwrap() }
        None => { 1000 }
    };

    let word_threshold: Count = match matches.opt_str("w") {
        Some(wt) => { wt.parse().unwrap() }
        None => { 1000 }
    };

    let max_line_length: usize = match matches.opt_str("max-line-length") {
        Some(len) => len.parse().unwrap(),
        None => 1000,
    };

    let show_rare = matches.opt_present("r");
    let print_mem_stats = matches.opt_present("m");

    let inputs: Vec<Path> = matches.free.iter().map(|f| Path::new(f)).collect();

    let word_freq = calc_word_freq(&inputs, max_line_length);
    println!("found {} unique words", word_freq.len());

    let clusters = calc_clusters(&inputs, &word_freq, word_threshold, max_line_length);
    println!("found {} clusters", clusters.len());

    if print_mem_stats {
        heap::stats_print();
    }

    for (k,v) in clusters.iter() {
        if show_rare == (*v < cluster_threshold) {
            println!("{}\t{}", v, k);
        }
    }
}

fn calc_word_freq(paths: &Vec<Path>, max_line_length: usize) -> Words {
    let mut word_freq: HashMap<Hash, Count> = HashMap::new();

    for path in paths.iter() {
        let file = File::open(path);
        let mut reader = BufferedReader::new(file);

        for l in reader.lines() {
            let line = l.ok().unwrap();
            if max_line_length > 0 && line.len() > max_line_length {
                continue;
            }

            for w in line.words() {
                let hash = fnv1a(w);
                match word_freq.entry(hash) {
                    Vacant(wf) => { wf.insert(1); },
                    Occupied(mut wf) => { *wf.get_mut() += 1; },
                };
            }
        }
    }

    word_freq
}

fn calc_clusters(paths: &Vec<Path>, word_freq: &Words, word_threshold: Count, max_line_length: usize) -> Clusters {
    let mut clusters: HashMap<String, Count> = HashMap::new();

    for path in paths.iter() {
        let mut file = BufferedReader::new(File::open(path));
        for l in file.lines() {
            let line = l.ok().unwrap();
            if max_line_length > 0 && line.len() > max_line_length {
                continue;
            }

            let cluster = clusterify(line, word_freq, word_threshold);
            if !cluster.is_empty() {
                match clusters.entry(cluster) {
                    Vacant(c) => { c.insert(1); },
                    Occupied(mut c) => { *c.get_mut() += 1; },
                };
            }
        }
    }

    clusters
}

fn clusterify(line: String, word_freq: &Words, word_threshold: Count) -> String {
    let words: Vec<&str> = line.words().map({ |w|
        if word_freq[fnv1a(w)] < word_threshold {
            "*"
        } else {
            w
        }
    }).collect();

    words.connect(" ")
}

static FNV_PRIME_64: Hash = 1099511628211;
static FNV1_OFFSET_BASIS_64: Hash = 14695981039346656037;

fn fnv1a(s: &str) -> Hash {
    let mut hash = FNV1_OFFSET_BASIS_64;
    for b in s.as_bytes().iter() {
        hash = (hash ^ *b as Hash) * FNV_PRIME_64;
    }
    hash
}
<|endoftext|>


<commit_before>#![feature(collections)]

extern crate byteorder;
extern crate crc;
extern crate unix_socket;
extern crate nix;

use std::path;
use std::io::Result;
use std::io::Error;
use std::io::ErrorKind::Other;
use std::collections::btree_map::BTreeMap;

mod lexer;
mod lvmetad;
mod pvlabel;

use lexer::{Entry, LvmTextMap, MapFromMeta};

#[derive(Debug, PartialEq, Clone)]
struct VG {
    name: String,
    id: String,
    seqno: u64,
    format: String,
    status: Vec<String>,
    flags: Vec<String>,
    extent_size: u64,
    max_lv: u64,
    max_pv: u64,
    metadata_copies: u64,
    pvs: Vec<PV>,
    lvs: Vec<LV>,
}

#[derive(Debug, PartialEq, Clone)]
struct PV {
    name: String,
    id: String,
    status: Vec<String>,
    //flags
    dev_size: u64,
    pe_start: u64,
    pe_count: u64,
}

#[derive(Debug, PartialEq, Clone)]
struct LV {
    name: String,
    id: String,
    status: Vec<String>,
    //flags
    creation_host: String,
    creation_time: u64,
    segment_count: u64,
    //segments
}

fn get_first_vg_meta() -> Result<(String, LvmTextMap)> {
    let dirs = vec![path::Path::new("/dev")];

    for pv in try!(pvlabel::scan_for_pvs(&dirs)) {
        let map = try!(pvlabel::metadata_from_dev(pv.as_path()));

        for (key, value) in map {
            match value {
                lexer::Entry::Dict(x) => return Ok((key, *x)),
                _ => {}
            }
        }

    }

    Err(Error::new(Other, "dude"))
}

fn pvs_from_meta(map: LvmTextMap) -> Result<Vec<PV>> {
    let err = || Error::new(Other, "dude");

    let mut ret_vec = Vec::new();

    for (key, value) in map {
        let mut pv_dict = match value {
            Entry::Dict(x) => *x,
            _ => return Err(Error::new(Other, "dude")),
        };

        let id = try!(pv_dict.string_from_meta("id").ok_or(err()));
        let dev_size = try!(pv_dict.u64_from_meta("dev_size").ok_or(err()));
        let pe_start = try!(pv_dict.u64_from_meta("pe_start").ok_or(err()));
        let pe_count = try!(pv_dict.u64_from_meta("pe_count").ok_or(err()));

        let status_list = try!(pv_dict.list_from_meta("status").ok_or(err()));
        let status: Vec<_> = status_list.into_iter()
            .filter_map(|item| match item { Entry::String(x) => Some(x), _ => {None}})
            .collect();

        ret_vec.push(PV {
            name: key,
            id: id,
            status: status,
            dev_size: dev_size,
            pe_start: pe_start,
            pe_count: pe_count,
            });
    }

    Ok(ret_vec)
}

fn lvs_from_meta(map: LvmTextMap) -> Result<Vec<LV>> {
    let err = || Error::new(Other, "dude");

    let mut ret_vec = Vec::new();

    for (key, value) in map {
        let mut lv_dict = match value {
            Entry::Dict(x) => *x,
            _ => return Err(Error::new(Other, "dude")),
        };

        let id = try!(lv_dict.string_from_meta("id").ok_or(err()));
        let creation_host = try!(lv_dict.string_from_meta("creation_host").ok_or(err()));
        let creation_time = try!(lv_dict.u64_from_meta("creation_time").ok_or(err()));
        let segment_count = try!(lv_dict.u64_from_meta("segment_count").ok_or(err()));

        let status_list = try!(lv_dict.list_from_meta("status").ok_or(err()));
        let status: Vec<_> = status_list.into_iter()
            .filter_map(|item| match item { Entry::String(x) => Some(x), _ => {None}})
            .collect();

        ret_vec.push(LV {
            name: key,
            id: id,
            status: status,
            creation_host: creation_host,
            creation_time: creation_time,
            segment_count: segment_count,
            });
    }

    Ok(ret_vec)
}

fn vg_from_meta(name: &str, map: &mut LvmTextMap) -> Result<VG> {

    let err = || Error::new(Other, "dude");

    println!("D");

    let id = try!(map.string_from_meta("id").ok_or(err()));
    let seqno = try!(map.u64_from_meta("seqno").ok_or(err()));
    let format = try!(map.string_from_meta("format").ok_or(err()));
    let extent_size = try!(map.u64_from_meta("extent_size").ok_or(err()));
    let max_lv = try!(map.u64_from_meta("max_lv").ok_or(err()));
    let max_pv = try!(map.u64_from_meta("max_pv").ok_or(err()));
    let metadata_copies = try!(map.u64_from_meta("metadata_copies").ok_or(err()));

    let raw_status = try!(map.list_from_meta("status").ok_or(err()));
    let flags = try!(map.list_from_meta("flags").ok_or(err()));

    println!("E");
    let mut pv_meta = try!(map.dict_from_meta("physical_volumes").ok_or(err()));
    println!("E1");
    let pvs = try!(pvs_from_meta(pv_meta));
    println!("F");

    let mut lv_meta = try!(map.dict_from_meta("logical_volumes").ok_or(err()));
    let lvs = try!(lvs_from_meta(lv_meta));

    println!("G");

    let vg = VG {
        name: name.to_string(),
        id: id,
        seqno: seqno,
        format: format,
        status: Vec::new(),
        flags: Vec::new(),
        extent_size: extent_size,
        max_lv: max_lv,
        max_pv: max_pv,
        metadata_copies: metadata_copies,
        pvs: pvs,
        lvs: lvs,
    };

    println!("VG is {:?}", vg);

    Ok(vg)
}

fn main() {
    println!("A");
    let (name, mut map) = get_first_vg_meta().unwrap();
    println!("B");
    let vg = vg_from_meta(&name, &mut map);
    println!("C");
}
<commit_msg>vg status and flags<commit_after>#![feature(collections)]

extern crate byteorder;
extern crate crc;
extern crate unix_socket;
extern crate nix;

use std::path;
use std::io::Result;
use std::io::Error;
use std::io::ErrorKind::Other;
use std::collections::btree_map::BTreeMap;

mod lexer;
mod lvmetad;
mod pvlabel;

use lexer::{Entry, LvmTextMap, MapFromMeta};

#[derive(Debug, PartialEq, Clone)]
struct VG {
    name: String,
    id: String,
    seqno: u64,
    format: String,
    status: Vec<String>,
    flags: Vec<String>,
    extent_size: u64,
    max_lv: u64,
    max_pv: u64,
    metadata_copies: u64,
    pvs: Vec<PV>,
    lvs: Vec<LV>,
}

#[derive(Debug, PartialEq, Clone)]
struct PV {
    name: String,
    id: String,
    status: Vec<String>,
    //flags
    dev_size: u64,
    pe_start: u64,
    pe_count: u64,
}

#[derive(Debug, PartialEq, Clone)]
struct LV {
    name: String,
    id: String,
    status: Vec<String>,
    //flags
    creation_host: String,
    creation_time: u64,
    segment_count: u64,
    //segments
}

fn get_first_vg_meta() -> Result<(String, LvmTextMap)> {
    let dirs = vec![path::Path::new("/dev")];

    for pv in try!(pvlabel::scan_for_pvs(&dirs)) {
        let map = try!(pvlabel::metadata_from_dev(pv.as_path()));

        for (key, value) in map {
            match value {
                lexer::Entry::Dict(x) => return Ok((key, *x)),
                _ => {}
            }
        }

    }

    Err(Error::new(Other, "dude"))
}

fn pvs_from_meta(map: LvmTextMap) -> Result<Vec<PV>> {
    let err = || Error::new(Other, "dude");

    let mut ret_vec = Vec::new();

    for (key, value) in map {
        let mut pv_dict = match value {
            Entry::Dict(x) => *x,
            _ => return Err(Error::new(Other, "dude")),
        };

        let id = try!(pv_dict.string_from_meta("id").ok_or(err()));
        let dev_size = try!(pv_dict.u64_from_meta("dev_size").ok_or(err()));
        let pe_start = try!(pv_dict.u64_from_meta("pe_start").ok_or(err()));
        let pe_count = try!(pv_dict.u64_from_meta("pe_count").ok_or(err()));

        let status_list = try!(pv_dict.list_from_meta("status").ok_or(err()));
        let status: Vec<_> = status_list.into_iter()
            .filter_map(|item| match item { Entry::String(x) => Some(x), _ => {None}})
            .collect();

        ret_vec.push(PV {
            name: key,
            id: id,
            status: status,
            dev_size: dev_size,
            pe_start: pe_start,
            pe_count: pe_count,
            });
    }

    Ok(ret_vec)
}

fn lvs_from_meta(map: LvmTextMap) -> Result<Vec<LV>> {
    let err = || Error::new(Other, "dude");

    let mut ret_vec = Vec::new();

    for (key, value) in map {
        let mut lv_dict = match value {
            Entry::Dict(x) => *x,
            _ => return Err(Error::new(Other, "dude")),
        };

        let id = try!(lv_dict.string_from_meta("id").ok_or(err()));
        let creation_host = try!(lv_dict.string_from_meta("creation_host").ok_or(err()));
        let creation_time = try!(lv_dict.u64_from_meta("creation_time").ok_or(err()));
        let segment_count = try!(lv_dict.u64_from_meta("segment_count").ok_or(err()));

        let status_list = try!(lv_dict.list_from_meta("status").ok_or(err()));
        let status: Vec<_> = status_list.into_iter()
            .filter_map(|item| match item { Entry::String(x) => Some(x), _ => {None}})
            .collect();

        ret_vec.push(LV {
            name: key,
            id: id,
            status: status,
            creation_host: creation_host,
            creation_time: creation_time,
            segment_count: segment_count,
            });
    }

    Ok(ret_vec)
}

fn vg_from_meta(name: &str, map: &mut LvmTextMap) -> Result<VG> {

    let err = || Error::new(Other, "dude");

    let id = try!(map.string_from_meta("id").ok_or(err()));
    let seqno = try!(map.u64_from_meta("seqno").ok_or(err()));
    let format = try!(map.string_from_meta("format").ok_or(err()));
    let extent_size = try!(map.u64_from_meta("extent_size").ok_or(err()));
    let max_lv = try!(map.u64_from_meta("max_lv").ok_or(err()));
    let max_pv = try!(map.u64_from_meta("max_pv").ok_or(err()));
    let metadata_copies = try!(map.u64_from_meta("metadata_copies").ok_or(err()));

    let status_list = try!(map.list_from_meta("status").ok_or(err()));
    let status: Vec<_> = status_list.into_iter()
        .filter_map(|item| match item { Entry::String(x) => Some(x), _ => {None}})
        .collect();

    let flags_list = try!(map.list_from_meta("flags").ok_or(err()));
    let flags: Vec<_> = flags_list.into_iter()
        .filter_map(|item| match item { Entry::String(x) => Some(x), _ => {None}})
        .collect();

    let mut pv_meta = try!(map.dict_from_meta("physical_volumes").ok_or(err()));
    let pvs = try!(pvs_from_meta(pv_meta));

    let mut lv_meta = try!(map.dict_from_meta("logical_volumes").ok_or(err()));
    let lvs = try!(lvs_from_meta(lv_meta));

    let vg = VG {
        name: name.to_string(),
        id: id,
        seqno: seqno,
        format: format,
        status: status,
        flags: flags,
        extent_size: extent_size,
        max_lv: max_lv,
        max_pv: max_pv,
        metadata_copies: metadata_copies,
        pvs: pvs,
        lvs: lvs,
    };

    println!("VG is {:?}", vg);

    Ok(vg)
}

fn main() {
    println!("A");
    let (name, mut map) = get_first_vg_meta().unwrap();
    println!("B");
    let vg = vg_from_meta(&name, &mut map);
    println!("C");
}
<|endoftext|>


<commit_before>extern crate ncurses;
extern crate regex;

mod utils;
mod prompt;
mod pager;
mod curses_pager;
mod greps;

use prompt::*;
use curses_pager::*;
use pager::*;
use greps::*;

fn main() {
    let buffer = utils::test_buffer_from_file();

    let mut pager = CursesPager::new();
    pager.initialize();
    let mut greps = Greps::new(utils::Text::from(&buffer).lines);
    greps.decorations.insert(String::from("errors"),
                             utils::DecorationPattern::from_single_attr(utils::Attribute::Red,
                                                                        "ERR|error"));
    greps.decorations.insert(String::from("informations"),
                             utils::DecorationPattern::from_single_attr(utils::Attribute::Blue,
                                                                        "INF|INFO|inf|info"));
    loop {
        let index = greps.current_grep().line_index;
        let printed_lines = pager.print_logs(&greps.current_grep().lines[index..],
                                             greps.decorations());

        pager.status(&greps);
        match prompt(&mut pager, PromptMode::Visual) {
            Prompt::Exit => break,
            Prompt::SearchPattern(pat) => {
                greps.apply_search_patern(&pat);
            }
            Prompt::GrepPattern(pat) => {
                greps.new_grep(&pat);
                pager.clear();
            }
            Prompt::GrepLeft => greps.select_one_to_left(),
            Prompt::GrepRight => greps.select_one_to_right(),
            Prompt::CloseGrep => greps.close_grep(),
            Prompt::SingleLineDown => {
                let last_index = greps.current_grep().lines.len() - 1;
                if index < last_index - printed_lines + 2 {
                    greps.change_current_line_index(index + 1)
                }
            }
            Prompt::SingleLineUp => {
                if index > 0 {
                    greps.change_current_line_index(index - 1);
                }
            }
            Prompt::ScrollTop => greps.change_current_line_index(0),
            Prompt::NextPage => greps.change_current_line_index(index + printed_lines),
            Prompt::ScrollBottom => {
                let last_index = greps.current_grep().lines.len() - printed_lines + 1;
                greps.change_current_line_index(last_index);
            }
            Prompt::NextSearch => greps.next_search(),
            Prompt::PrevSearch => greps.prev_search(),
            //_ => {}
        }
        pager.mv_cursor((0, 0));
    }
}<commit_msg>Fixed glitches caused by ncurses optimalization<commit_after>extern crate ncurses;
extern crate regex;

mod utils;
mod prompt;
mod pager;
mod curses_pager;
mod greps;

use prompt::*;
use curses_pager::*;
use pager::*;
use greps::*;

fn main() {
    let buffer = utils::test_buffer_from_file();

    let mut pager = CursesPager::new();
    pager.initialize();
    let mut greps = Greps::new(utils::Text::from(&buffer).lines);
    greps.decorations.insert(String::from("errors"),
                             utils::DecorationPattern::from_single_attr(utils::Attribute::Red,
                                                                        "ERR|error"));
    greps.decorations.insert(String::from("informations"),
                             utils::DecorationPattern::from_single_attr(utils::Attribute::Blue,
                                                                        "INF|INFO|inf|info"));
    loop {
        let index = greps.current_grep().line_index;
        let printed_lines = pager.print_logs(&greps.current_grep().lines[index..],
                                             greps.decorations());

        pager.status(&greps);
        match prompt(&mut pager, PromptMode::Visual) {
            Prompt::Exit => break,
            Prompt::SearchPattern(pat) => {
                greps.apply_search_patern(&pat);
            }
            Prompt::GrepPattern(pat) => {
                greps.new_grep(&pat);
                pager.clear();
            }
            Prompt::GrepLeft => greps.select_one_to_left(),
            Prompt::GrepRight => greps.select_one_to_right(),
            Prompt::CloseGrep => greps.close_grep(),
            Prompt::SingleLineDown => {
                let last_index = greps.current_grep().lines.len() - 1;
                if index < last_index - printed_lines + 2 {
                    greps.change_current_line_index(index + 1)
                }
            }
            Prompt::SingleLineUp => {
                if index > 0 {
                    pager.clear();
                    greps.change_current_line_index(index - 1);
                }
            }
            Prompt::ScrollTop => greps.change_current_line_index(0),
            Prompt::NextPage => greps.change_current_line_index(index + printed_lines),
            Prompt::ScrollBottom => {
                let last_index = greps.current_grep().lines.len() - printed_lines + 1;
                greps.change_current_line_index(last_index);
            }
            Prompt::NextSearch => greps.next_search(),
            Prompt::PrevSearch => greps.prev_search(),
            //_ => {}
        }
        pager.mv_cursor((0, 0));
    }
}<|endoftext|>


<commit_before>extern crate ordered_float;
extern crate thrift;
extern crate try_from;

mod kv_server;
use std::collections::HashMap;
use std::convert::{From, Into};
use std::default::Default;

use thrift::server::TServer;
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::RwLock;
use std::result::Result;
use std::ops::{DerefMut, Deref};
use thrift::protocol::{TInputProtocolFactory, TOutputProtocolFactory};
use thrift::protocol::{TCompactInputProtocolFactory, TCompactOutputProtocolFactory};
use thrift::transport::{TFramedReadTransportFactory, TFramedWriteTransportFactory};
use kv_server::{KeyNotFound, ServiceException};
use kv_server::{KVObject};
use kv_server::{KVServerSyncHandler, KVServerSyncProcessor};

fn main() {
    match run() {
        Ok(()) => println!("tutorial server ran successfully"),
        Err(e) => {
            println!("tutorial server failed with error {:?}", e);
            std::process::exit(1);
        }
    }
}

fn run() -> thrift::Result<()> {

    let listen_address = format!("127.0.0.1:6677");

    println!("binding to {}", listen_address);

    let i_tran_fact: Box<TFramedReadTransportFactory> = Box::new(TFramedReadTransportFactory::new());
    let i_prot_fact: Box<TInputProtocolFactory> = Box::new(TCompactInputProtocolFactory::new());

    let o_tran_fact: Box<TFramedWriteTransportFactory> = Box::new(TFramedWriteTransportFactory::new());
    let o_prot_fact: Box<TOutputProtocolFactory> = Box::new(TCompactOutputProtocolFactory::new());

    // demux incoming messages
    let processor = KVServerSyncProcessor::new(KVServer { ..Default::default() });

    // create the server and start listening
    let mut server = TServer::new(i_tran_fact,
                                        i_prot_fact,
                                        o_tran_fact,
                                        o_prot_fact,
                                        processor,
                                        10);

    server.listen(&listen_address)
}

struct KVStore {
    store: HashMap<String, String>,
}

impl KVStore{
    fn new() -> KVStore {
        KVStore{store: HashMap::new()}
    }
}

struct KVServer {
    store: RwLock<KVStore>
}

impl Default for KVServer {
    fn default() -> KVServer {
        KVServer { store: RwLock::new(KVStore::new()) }
    }
}

impl KVServerSyncHandler for KVServer {
    fn handle_set_key(&self, kv: kv_server::KVObject) -> Result<bool, thrift::Error> {
        let key = kv.key.unwrap();
        let value = kv.value.unwrap();
        println!("Storing value: {}  into key: {}", value, key);
        let mut store = self.store.write().unwrap();
        {
            let w_store = store.deref_mut();
            w_store.store.insert(key, value);
        }
        Ok(true)
    }

    fn handle_get_val(&self, key: String)  -> Result<std::string::String, thrift::Error>{
         let store = self.store.read().unwrap();
         let r_store = store.deref();
         if r_store.store.contains_key(&key) {
             let val = r_store.store.get(&key).unwrap().clone();
             Ok(val)
         } else {
             Err(thrift::Error::from(KeyNotFound{ key: Some(key) }))
         }
    }

    fn handle_get_obj(&self, key: String)  -> Result<kv_server::KVObject, thrift::Error> {
        let store = self.store.read().unwrap();
        let r_store = store.deref();
        if r_store.store.contains_key(&key) {
            let val = r_store.store.get(&key).unwrap().clone();
            let obj = kv_server::KVObject{key: Some(key), value: Some(val)};
            Ok(obj)
        } else {
            Err(thrift::Error::from(KeyNotFound{ key: Some(key) }))
        }
    }

    fn handle_del_key(&self, key: String) -> Result<(), thrift::Error> {
         unimplemented!();
    }
}
<commit_msg>Add del_key logic<commit_after>extern crate ordered_float;
extern crate thrift;
extern crate try_from;

mod kv_server;
use std::collections::HashMap;
use std::convert::{From};
use std::default::Default;

use thrift::server::TServer;
use std::sync::RwLock;
use std::result::Result;
use std::ops::{DerefMut, Deref};
use thrift::protocol::{TInputProtocolFactory, TOutputProtocolFactory};
use thrift::protocol::{TCompactInputProtocolFactory, TCompactOutputProtocolFactory};
use thrift::transport::{TFramedReadTransportFactory, TFramedWriteTransportFactory};
use kv_server::{KeyNotFound, ServiceException};
use kv_server::{KVObject};
use kv_server::{KVServerSyncHandler, KVServerSyncProcessor};

fn main() {
    match run() {
        Ok(()) => println!("tutorial server ran successfully"),
        Err(e) => {
            println!("tutorial server failed with error {:?}", e);
            std::process::exit(1);
        }
    }
}

fn run() -> thrift::Result<()> {

    let listen_address = format!("127.0.0.1:6677");

    println!("binding to {}", listen_address);

    let i_tran_fact: Box<TFramedReadTransportFactory> = Box::new(TFramedReadTransportFactory::new());
    let i_prot_fact: Box<TInputProtocolFactory> = Box::new(TCompactInputProtocolFactory::new());

    let o_tran_fact: Box<TFramedWriteTransportFactory> = Box::new(TFramedWriteTransportFactory::new());
    let o_prot_fact: Box<TOutputProtocolFactory> = Box::new(TCompactOutputProtocolFactory::new());

    // demux incoming messages
    let processor = KVServerSyncProcessor::new(KVServer { ..Default::default() });

    // create the server and start listening
    let mut server = TServer::new(i_tran_fact,
                                        i_prot_fact,
                                        o_tran_fact,
                                        o_prot_fact,
                                        processor,
                                        10);

    server.listen(&listen_address)
}

struct KVStore {
    store: HashMap<String, String>,
}

impl KVStore{
    fn new() -> KVStore {
        KVStore{store: HashMap::new()}
    }
}

struct KVServer {
    store: RwLock<KVStore>
}

impl Default for KVServer {
    fn default() -> KVServer {
        KVServer { store: RwLock::new(KVStore::new()) }
    }
}

impl KVServerSyncHandler for KVServer {
    fn handle_set_key(&self, kv: KVObject) -> Result<bool, thrift::Error> {
        let key = kv.key.unwrap();
        let value = kv.value.unwrap();
        println!("Storing value: {}  into key: {}", value, key);
        let mut store = self.store.write().unwrap();
        {
            let w_store = store.deref_mut();
            w_store.store.insert(key, value);
        }
        Ok(true)
    }

    fn handle_get_val(&self, key: String)  -> Result<std::string::String, thrift::Error>{
         let store = self.store.read().unwrap();
         let r_store = store.deref();
         if r_store.store.contains_key(&key) {
             let val = r_store.store.get(&key).unwrap().clone();
             Ok(val)
         } else {
             Err(thrift::Error::from(KeyNotFound{ key: Some(key) }))
         }
    }

    fn handle_get_obj(&self, key: String)  -> Result<kv_server::KVObject, thrift::Error> {
        let store = self.store.read().unwrap();
        let r_store = store.deref();
        if r_store.store.contains_key(&key) {
            let val = r_store.store.get(&key).unwrap().clone();
            let obj = kv_server::KVObject{key: Some(key), value: Some(val)};
            Ok(obj)
        } else {
            Err(thrift::Error::from(KeyNotFound{ key: Some(key) }))
        }
    }

    fn handle_del_key(&self, key: String) -> Result<(), thrift::Error> {
        let mut store = self.store.write().unwrap();
        {
            println!("Removing key: {}", key);
            let w_store = store.deref_mut();
            w_store.store.remove(&key);
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>//!
//! # WebSocket Serial Server
//!
//! WebSocket Serial Server is a program that allows
//! that allows browsers to access serial ports
//! on localhost
//!
//! ## Running
//!
//! ```./wsss```
//!
//! You can also specift a port:
//!
//! ```./wsss -p PORT_NUM``` or ```./wsss --port PORT_NUM```
//!
//! When you specify a port, a simple http server will
//! be bound at "/" on PORT_NUM, and a websocket bound at "/"
//! on PORT_NUM + 1
//!
//! The webpage served at "/" on PORT_NUM provides a convenient
//! way for testing serial port connectivity
//!
//! You can open/close ports, read and write data, and see the
//! responses. All messages are in JSON format

extern crate argparse;
extern crate base64;
extern crate env_logger;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate rand;
extern crate serde_json;
extern crate serialport;
extern crate websocket;

extern crate serial_support;

use std::io::Write;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender};
use std::thread;

use argparse::{ArgumentParser, Store};
use websocket::client::Writer;
use websocket::result::WebSocketError;
use websocket::message::Type;
use websocket::{Server, Message};
use websocket::server::upgrade::WsUpgrade;
use hyper::Server as HttpServer;
use hyper::net::Fresh;
use hyper::server::request::Request;
use hyper::server::response::Response;
use rand::{Rng, thread_rng};

use serial_support::dynamic_sleep::DynamicSleep;
use serial_support::errors as e;
use serial_support::manage::Manager;
use serial_support::messages::*;

/// Max number of failures we allow when trying to send
/// data to client before exiting
/// TODO: Make configurable
pub const MAX_SEND_ERROR_COUNT: u32 = 5;

/// Launches wsss
pub fn main() {

  // Init logger
  env_logger::init().unwrap();

  // Default port number
  let mut port = 8080;
  // Parse cmdline args
  {
    let mut ap = ArgumentParser::new();
    ap.set_description("Provide access to serial ports over JSON Websockets");
    ap.refer(&mut port)
      .add_option(&["-p", "--port"], Store, "Http Port");
    ap.parse_args_or_exit();
  }

  // websocket port
  let ws_port = port + 1;

  // html file for landing page
  let websocket_html = include_str!("websockets.html").replace(
    "__WS_PORT__ = 8081",
    &format!("__WS_PORT__ = {}", ws_port),
  );

  // The HTTP server handler
  let http_handler = move |_: Request, response: Response<Fresh>| {
    let mut response = response.start().expect(&"Could not start response");
    // Send a client webpage
    response
      .write_all(websocket_html.as_bytes())
      .expect(&"Could not get template as bytes");
    response.end().expect(&"Send response failed");
  };

  info!("Using ports {} {}", port, ws_port);

  // Set up channels and Manager
  let (sub_tx, sub_rx) = channel::<SubscriptionRequest>();
  let (sreq_tx, sreq_rx) = channel::<(String, SerialRequest)>();
  Manager::spawn(sreq_rx, sub_rx);

  // Start listening for http connections
  let http_server = HttpServer::http(format!("127.0.0.1:{}", port)).expect(
    &format!(
      "Failed to create http server on port {}",
      port
    ),
  );

  thread::spawn(
    move || {
      http_server
        .handle(http_handler)
        .expect(&"Failed to listen");
    },
  );

  // Start listening for WebSocket connections
  let ws_server = Server::bind(format!("127.0.0.1:{}", ws_port)).expect(
    &format!(
      "Failed bind on websocket port {}",
      ws_port
    ),
  );

  // Continuously iterate over connections,
  // spawning handlers
  for connection in ws_server.filter_map(Result::ok) {
    // Set up subscription id
    // let ts = SystemTime::now() - UNIX_EPOCH
    let prefix: String = thread_rng().gen_ascii_chars().take(8).collect();
    let sub_id = format!("thread-{}-{}", prefix, rand::random::<u16>());
    debug!("{}: spawned.", sub_id);

    // Spawn a new thread for each connection.
    let sub_tx_clone = sub_tx.clone();
    let sreq_tx_clone = sreq_tx.clone();
    spawn_ws_handler(sub_id, sub_tx_clone, sreq_tx_clone, connection);
  }
}

/// Spawn a websocket handler into its own thread
fn spawn_ws_handler(
  sub_id: String,
  sub_tx_clone: Sender<SubscriptionRequest>,
  sreq_tx_clone: Sender<(String, SerialRequest)>,
  connection: WsUpgrade<TcpStream>,
) {
  thread::spawn(move || ws_handler(sub_id, &sub_tx_clone, &sreq_tx_clone, connection),);
}

/// Websocket handler
fn ws_handler(
  sub_id: String,
  sub_tx: &Sender<SubscriptionRequest>,
  sreq_tx: &Sender<(String, SerialRequest)>,
  connection: WsUpgrade<TcpStream>,
) {

  if !connection
        .protocols()
        .contains(&"websocket-serial-json".to_string()) {
    connection
      .reject()
      .expect(&"Connection rejection failed.");
    return;
  }

  connection
    .tcp_stream()
    .set_nonblocking(true)
    .expect(&"Setting stream non-blocking failed.");

  // Create response channel
  let (sub_resp_tx, sub_resp_rx) = channel::<SerialResponse>();

  // Register sub_id with manager
  sub_tx
    .send(
      SubscriptionRequest {
        sub_id: sub_id.clone(),
        subscriber: sub_resp_tx,
      },
    )
    .expect(&format!("{}: Registering with manager failed.", sub_id));

  let client = connection
    .use_protocol(format!("websocket-serial-json"))
    .accept()
    .expect(&format!("{}: Accept protocol failed.", sub_id));

  let ip = client
    .peer_addr()
    .expect(&format!("{}: Could not get peer address", sub_id));

  info!("{}: Connection from {}", sub_id, ip);

  let (mut receiver, mut sender) = client
    .split()
    .expect(&format!("{}: WS client error", sub_id));

  let mut send_error_count = 0;

  let mut dynamic_sleep = DynamicSleep::new("main");

  'msg_loop: loop {

    dynamic_sleep.sleep();

    // Try and read a WS message
    match receiver.recv_message::<Message, _, _>() {
      Ok(message) => {
        match message.opcode {

          Type::Close => {
            let message = Message::close();
            sender
              .send_message(&message)
              .unwrap_or(info!("{}: Client {} hung up!", sub_id, ip));
            // Send close request to cleanup resources
            sreq_tx
              .send((sub_id.clone(), SerialRequest::Close { port: None }))
              .unwrap_or_else(
                |e| {
                  warn!(
                    "Client exit cleanup failed for sub_id '{}', cause '{}'",
                    sub_id,
                    e
                  )
                },
              );
            info!("{}: Client {} disconnected", sub_id, ip);
            break 'msg_loop;
          }

          Type::Ping => {
            let message = Message::pong(message.payload);
            sender
              .send_message(&message)
              .unwrap_or(info!("{}:  Could not ping client {}!", sub_id, ip));
          }

          _ => {

            // Get the payload, in a lossy manner
            let msg = String::from_utf8_lossy(&message.payload);

            // So we will get a result <SerialRequest::*,SerialResponse::Error> back
            match serde_json::from_str(&msg) {
              Ok(req) => {
                match sreq_tx.send((sub_id.clone(), req)) {
                  Err(err) => {
                    let error = e::ErrorKind::SendRequest(err).into();
                    send_serial_response_error(&sub_id, &mut sender, error);

                  }
                  _ => {}
                };
              }
              Err(err) => {
                let error = e::ErrorKind::Json(err).into();
                send_serial_response_error(&sub_id, &mut sender, error);
              }
            };
          }
        };
      }
      Err(e) => {
        match e {
          WebSocketError::NoDataAvailable => { /*Logging?*/ }
          _ => { /*Logging?*/ }
        };
      }
    }

    // Send on any serial responses
    match sub_resp_rx.try_recv() {
      Ok(resp) => {
        match serde_json::to_string(&resp) {
          Ok(json) => {
            let reply = Message::text(json.clone());
            sender
              .send_message(&reply)
              .unwrap_or_else(
                |e| {
                  send_error_count += 1;
                  info!(
                    "{}: Could not send message '{}' to client '{}', cause '{}'",
                    sub_id,
                    json,
                    ip,
                    e
                  )
                },
              );
          }
          Err(_) => {}
        }
      }
      _ => { /*Logging*/ }
    };

    if send_error_count > MAX_SEND_ERROR_COUNT {
      warn!(
        "{}: Client send error count exceeded! Shutting down msg loop.",
        &sub_id
      );
      break 'msg_loop;
    }
  }

  info!("{}: Shutting down!", sub_id);

}

/// Send an error to the given subscriber
/// Log a warning if the message can't be sent
/// This is usually ok as it means the client
/// has simply disconnected
fn send_serial_response_error(sub_id: &String, sender: &mut Writer<TcpStream>, error: e::Error) {
  let error = e::to_serial_response_error(error);
  serde_json::to_string(&error)
    .map_err(|err| e::ErrorKind::Json(err))
    .map(|json| Message::text(json))
    .map(
      |msg| {
        sender
          .send_message::<Message, _>(&msg)
          .map_err::<e::Error, _>(|err| e::ErrorKind::SendWsMessage(err).into())
      },
    )
    .unwrap_or_else(
      |_| {
        warn!("{}: Problem sending bad json error response", sub_id);
        Ok(())
      },
    )
    .is_ok(); // This shouldn't be needed?

}
<commit_msg>Switch main to use new config library support<commit_after>//!
//! # WebSocket Serial Server
//!
//! WebSocket Serial Server is a program that allows
//! that allows browsers to access serial ports
//! on localhost
//!
//! ## Running
//!
//! ```./wsss```
//!
//! You can also specift a port:
//!
//! ```./wsss -p PORT_NUM``` or ```./wsss --port PORT_NUM```
//!
//! When you specify a port, a simple http server will
//! be bound at "/" on PORT_NUM, and a websocket bound at "/"
//! on PORT_NUM + 1
//!
//! The webpage served at "/" on PORT_NUM provides a convenient
//! way for testing serial port connectivity
//!
//! You can open/close ports, read and write data, and see the
//! responses. All messages are in JSON format

extern crate argparse;
extern crate base64;
extern crate env_logger;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate rand;
extern crate serde_json;
extern crate serialport;
extern crate websocket;

extern crate serial_support;

use std::io::Write;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender};
use std::thread;

use websocket::client::Writer;
use websocket::result::WebSocketError;
use websocket::message::Type;
use websocket::{Server, Message};
use websocket::server::upgrade::WsUpgrade;
use hyper::Server as HttpServer;
use hyper::net::Fresh;
use hyper::server::request::Request;
use hyper::server::response::Response;
use rand::{Rng, thread_rng};

use serial_support::dynamic_sleep::DynamicSleep;
use serial_support::errors as e;
use serial_support::manage::Manager;
use serial_support::messages::*;
use serial_support::cfg::*;

/// Max number of failures we allow when trying to send
/// data to client before exiting
/// TODO: Make configurable
pub const MAX_SEND_ERROR_COUNT: u32 = 5;

/// Launches wsss
pub fn main() {

  // Init logger
  env_logger::init().expect("Initialization of logging system failed!");

  // Grab config
  let cfg = WsssConfig::load();

  // html file for landing page
  let websocket_html = include_str!("websockets.html").replace(
    "__WS_PORT__ = 8081",
    &format!("__WS_PORT__ = {}", cfg.ws_port),
  );

  // The HTTP server handler
  let http_handler = move |_: Request, response: Response<Fresh>| {
    let mut response = response.start().expect(&"Could not start response");
    // Send a client webpage
    response
      .write_all(websocket_html.as_bytes())
      .expect(&"Could not get template as bytes");
    response.end().expect(&"Send response failed");
  };

  info!("Using ports {} {}", cfg.http_port, cfg.ws_port);

  // Set up channels and Manager
  let (sub_tx, sub_rx) = channel::<SubscriptionRequest>();
  let (sreq_tx, sreq_rx) = channel::<(String, SerialRequest)>();
  Manager::spawn(sreq_rx, sub_rx);

  // Start listening for http connections
  let http_server = HttpServer::http(format!("{}:{}", cfg.bind_address, cfg.http_port)).expect(
    &format!(
      "Failed to create http server on port {}",
      cfg.http_port
    ),
  );

  thread::spawn(
    move || {
      http_server
        .handle(http_handler)
        .expect(&"Failed to listen");
    },
  );

  // Start listening for WebSocket connections
  let ws_server = Server::bind(format!("{}:{}", cfg.bind_address, cfg.ws_port)).expect(
    &format!(
      "Failed bind on websocket port {}",
      cfg.ws_port
    ),
  );

  // Continuously iterate over connections,
  // spawning handlers
  for connection in ws_server.filter_map(Result::ok) {
    // Set up subscription id
    // let ts = SystemTime::now() - UNIX_EPOCH
    let prefix: String = thread_rng().gen_ascii_chars().take(8).collect();
    let sub_id = format!("thread-{}-{}", prefix, rand::random::<u16>());
    debug!("{}: spawned.", sub_id);

    // Spawn a new thread for each connection.
    let sub_tx_clone = sub_tx.clone();
    let sreq_tx_clone = sreq_tx.clone();
    spawn_ws_handler(sub_id, sub_tx_clone, sreq_tx_clone, connection);
  }
}

/// Spawn a websocket handler into its own thread
fn spawn_ws_handler(
  sub_id: String,
  sub_tx_clone: Sender<SubscriptionRequest>,
  sreq_tx_clone: Sender<(String, SerialRequest)>,
  connection: WsUpgrade<TcpStream>,
) {
  thread::spawn(move || ws_handler(sub_id, &sub_tx_clone, &sreq_tx_clone, connection),);
}

/// Websocket handler
fn ws_handler(
  sub_id: String,
  sub_tx: &Sender<SubscriptionRequest>,
  sreq_tx: &Sender<(String, SerialRequest)>,
  connection: WsUpgrade<TcpStream>,
) {

  if !connection
        .protocols()
        .contains(&"websocket-serial-json".to_string()) {
    connection
      .reject()
      .expect(&"Connection rejection failed.");
    return;
  }

  connection
    .tcp_stream()
    .set_nonblocking(true)
    .expect(&"Setting stream non-blocking failed.");

  // Create response channel
  let (sub_resp_tx, sub_resp_rx) = channel::<SerialResponse>();

  // Register sub_id with manager
  sub_tx
    .send(
      SubscriptionRequest {
        sub_id: sub_id.clone(),
        subscriber: sub_resp_tx,
      },
    )
    .expect(&format!("{}: Registering with manager failed.", sub_id));

  let client = connection
    .use_protocol(format!("websocket-serial-json"))
    .accept()
    .expect(&format!("{}: Accept protocol failed.", sub_id));

  let ip = client
    .peer_addr()
    .expect(&format!("{}: Could not get peer address", sub_id));

  info!("{}: Connection from {}", sub_id, ip);

  let (mut receiver, mut sender) = client
    .split()
    .expect(&format!("{}: WS client error", sub_id));

  let mut send_error_count = 0;

  let mut dynamic_sleep = DynamicSleep::new("main");

  'msg_loop: loop {

    dynamic_sleep.sleep();

    // Try and read a WS message
    match receiver.recv_message::<Message, _, _>() {
      Ok(message) => {
        match message.opcode {

          Type::Close => {
            let message = Message::close();
            sender
              .send_message(&message)
              .unwrap_or(info!("{}: Client {} hung up!", sub_id, ip));
            // Send close request to cleanup resources
            sreq_tx
              .send((sub_id.clone(), SerialRequest::Close { port: None }))
              .unwrap_or_else(
                |e| {
                  warn!(
                    "Client exit cleanup failed for sub_id '{}', cause '{}'",
                    sub_id,
                    e
                  )
                },
              );
            info!("{}: Client {} disconnected", sub_id, ip);
            break 'msg_loop;
          }

          Type::Ping => {
            let message = Message::pong(message.payload);
            sender
              .send_message(&message)
              .unwrap_or(info!("{}:  Could not ping client {}!", sub_id, ip));
          }

          _ => {

            // Get the payload, in a lossy manner
            let msg = String::from_utf8_lossy(&message.payload);

            // So we will get a result <SerialRequest::*,SerialResponse::Error> back
            match serde_json::from_str(&msg) {
              Ok(req) => {
                match sreq_tx.send((sub_id.clone(), req)) {
                  Err(err) => {
                    let error = e::ErrorKind::SendRequest(err).into();
                    send_serial_response_error(&sub_id, &mut sender, error);

                  }
                  _ => {}
                };
              }
              Err(err) => {
                let error = e::ErrorKind::Json(err).into();
                send_serial_response_error(&sub_id, &mut sender, error);
              }
            };
          }
        };
      }
      Err(e) => {
        match e {
          WebSocketError::NoDataAvailable => { /*Logging?*/ }
          _ => { /*Logging?*/ }
        };
      }
    }

    // Send on any serial responses
    match sub_resp_rx.try_recv() {
      Ok(resp) => {
        match serde_json::to_string(&resp) {
          Ok(json) => {
            let reply = Message::text(json.clone());
            sender
              .send_message(&reply)
              .unwrap_or_else(
                |e| {
                  send_error_count += 1;
                  info!(
                    "{}: Could not send message '{}' to client '{}', cause '{}'",
                    sub_id,
                    json,
                    ip,
                    e
                  )
                },
              );
          }
          Err(_) => {}
        }
      }
      _ => { /*Logging*/ }
    };

    if send_error_count > MAX_SEND_ERROR_COUNT {
      warn!(
        "{}: Client send error count exceeded! Shutting down msg loop.",
        &sub_id
      );
      break 'msg_loop;
    }
  }

  info!("{}: Shutting down!", sub_id);

}

/// Send an error to the given subscriber
/// Log a warning if the message can't be sent
/// This is usually ok as it means the client
/// has simply disconnected
fn send_serial_response_error(sub_id: &String, sender: &mut Writer<TcpStream>, error: e::Error) {
  let error = e::to_serial_response_error(error);
  serde_json::to_string(&error)
    .map_err(|err| e::ErrorKind::Json(err))
    .map(|json| Message::text(json))
    .map(
      |msg| {
        sender
          .send_message::<Message, _>(&msg)
          .map_err::<e::Error, _>(|err| e::ErrorKind::SendWsMessage(err).into())
      },
    )
    .unwrap_or_else(
      |_| {
        warn!("{}: Problem sending bad json error response", sub_id);
        Ok(())
      },
    )
    .is_ok(); // This shouldn't be needed?

}
<|endoftext|>


<commit_before>extern crate xcb;
extern crate xcb_util;
extern crate cairo;
extern crate cairo_sys;
extern crate pango;
extern crate pangocairo;

use std::rc::Rc;

use cairo::{Context, Surface, XCBConnection, XCBDrawable, XCBSurface, XCBVisualType};
use pango::LayoutExt;
use pangocairo::CairoContextExt;
use xcb::ffi::*;

fn get_root_visual_type(conn: &xcb::Connection, screen: &xcb::Screen) -> xcb::Visualtype {
    for root in conn.get_setup().roots() {
        for allowed_depth in root.allowed_depths() {
            for visual in allowed_depth.visuals() {
                if visual.visual_id() == screen.root_visual() {
                    return visual;
                }
            }
        }
    }
    panic!("No visual type found");
}

#[derive(Clone, Debug)]
struct Color {
    red: f64,
    green: f64,
    blue: f64,
}

impl Color {
    fn white() -> Color {
        Color {
            red: 1.0,
            green: 1.0,
            blue: 1.0,
        }
    }

    fn red() -> Color {
        Color {
            red: 1.0,
            green: 0.0,
            blue: 0.0,
        }
    }

    fn blue() -> Color {
        Color {
            red: 0.0,
            green: 0.0,
            blue: 1.0,
        }
    }

    fn apply_to_context(&self, cr: &Context) {
        cr.set_source_rgb(self.red, self.green, self.blue);
    }
}

#[derive(Clone, Debug)]
struct Padding {
    left: f64,
    right: f64,
    top: f64,
    bottom: f64,
}

impl Padding {
    fn none() -> Padding {
        Padding {
            left: 0.0,
            right: 0.0,
            top: 0.0,
            bottom: 0.0,
        }
    }
    fn new(left: f64, right: f64, top: f64, bottom: f64) -> Padding {
        Padding {
            left,
            right,
            top,
            bottom,
        }
    }

    fn uniform(value: f64) -> Padding {
        Padding {
            left: value,
            right: value,
            top: value,
            bottom: value,
        }
    }
}

#[derive(Clone)]
struct TextAttributes {
    font: pango::FontDescription,
    fg_color: Color,
    bg_color: Option<Color>,
    padding: Padding,
}

struct Text {
    attr: TextAttributes,
    text: String,
    stretch: bool,
}

impl Text {
    fn layout(self, surface: &Surface) -> TextLayout {
        let context = Context::new(&surface);

        let layout = context.create_pango_layout();
        layout.set_text(&self.text, self.text.len() as i32);
        layout.set_font_description(Some(&self.attr.font));

        TextLayout {
            attr: self.attr.clone(),
            stretch: self.stretch,
            width: None,
            height: None,
            context: context,
            layout: layout,
        }
    }
}

struct TextLayout {
    attr: TextAttributes,
    stretch: bool,
    width: Option<f64>,
    height: Option<f64>,
    context: Context,
    layout: pango::Layout,
}

impl TextLayout {
    fn width(&self) -> f64 {
        self.width
            .unwrap_or_else(|| {
                                let text_width = self.layout.get_pixel_size().0 as f64;
                                text_width + self.attr.padding.left + self.attr.padding.right
                            })
    }

    fn height(&self) -> f64 {
        self.height
            .unwrap_or_else(|| {
                                let text_height = self.layout.get_pixel_size().1 as f64;
                                text_height + self.attr.padding.top + self.attr.padding.bottom
                            })
    }

    fn set_width(&mut self, width: f64) {
        self.width = Some(width);
    }

    fn set_height(&mut self, height: f64) {
        self.height = Some(height);
    }

    fn stretch(&self) -> bool {
        self.stretch
    }

    fn render(&self, x: f64, y: f64) {
        self.context.save();
        self.context.translate(x, y + self.attr.padding.top);

        if let Some(ref bg_color) = self.attr.bg_color {
            bg_color.apply_to_context(&self.context);
            // FIXME: The use of `height` isnt' right here: we want to do the
            // full height of the bar, not the full height of the text. It
            // would be useful if we could do Surface.get_height(), but that
            // doesn't seem to be available in cairo-rs for some reason?
            self.context
                .rectangle(0.0, 0.0, self.width(), self.height());
            self.context.fill();
        }

        self.attr.fg_color.apply_to_context(&self.context);
        self.context
            .translate(self.attr.padding.left, self.attr.padding.top);
        self.context.show_pango_layout(&self.layout);

        self.context.restore();
    }
}

struct Pager {
    conn: xcb_util::ewmh::Connection,
    screen_idx: i32,

    active_attr: TextAttributes,
    inactive_attr: TextAttributes,
}

impl Pager {
    fn new(active_attr: TextAttributes, inactive_attr: TextAttributes) -> Pager {
        let (conn, screen_idx) = xcb::Connection::connect_with_xlib_display().unwrap();
        let ewmh_conn = xcb_util::ewmh::Connection::connect(conn)
            .map_err(|_| ())
            .unwrap();

        Pager {
            conn: ewmh_conn,
            screen_idx: screen_idx,
            active_attr: active_attr,
            inactive_attr: inactive_attr,
        }
    }

    fn get_desktops_info(&self) -> Vec<(bool, String)> {
        let number = xcb_util::ewmh::get_number_of_desktops(&self.conn, self.screen_idx)
            .get_reply()
            .unwrap() as usize;
        let current = xcb_util::ewmh::get_current_desktop(&self.conn, self.screen_idx)
            .get_reply()
            .unwrap() as usize;
        let names_reply = xcb_util::ewmh::get_desktop_names(&self.conn, self.screen_idx)
            .get_reply()
            .unwrap();
        let mut names = names_reply.strings();

        // EWMH states that `number` may not equal `names.len()`, as there may
        // be unnamed desktops, or more desktops than are currently in use.
        if names.len() > number {
            names.truncate(number);
        } else if number > names.len() {
            for i in 0..(number - names.len()) {
                names.push("?");
            }
        }

        names
            .into_iter()
            .enumerate()
            .map(|(i, name)| (i == current, name.to_owned()))
            .collect()
    }

    fn compute_text(&self) -> Vec<Text> {
        let desktops = self.get_desktops_info();
        self.get_desktops_info()
            .into_iter()
            .map(|(active, name)| {
                Text {
                    attr: if active {
                        self.active_attr.clone()
                    } else {
                        self.inactive_attr.clone()
                    },
                    text: name,
                    stretch: false,
                }
            })
            .collect()
    }
}

// TODO: impl Drop?
struct Window {
    conn: Rc<xcb::Connection>,
    screen_idx: usize,
    id: u32,
    surface: Surface,
}

impl Window {
    fn new(conn: Rc<xcb::Connection>, screen_idx: usize) -> Window {
        let id = conn.generate_id();

        let surface = {
            let screen = conn.get_setup()
                .roots()
                .nth(screen_idx)
                .expect("invalid screen");
            let values = [(xcb::CW_BACK_PIXEL, screen.black_pixel()),
                          (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE)];

            let (width, height) = (screen.width_in_pixels(), 100);

            xcb::create_window(&conn,
                               xcb::COPY_FROM_PARENT as u8,
                               id,
                               screen.root(),
                               0,
                               0,
                               width,
                               height,
                               10,
                               xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
                               screen.root_visual(),
                               &values);

            let surface = unsafe {
                let cairo_conn = XCBConnection::from_raw_none(conn.get_raw_conn() as
                                                              *mut cairo_sys::xcb_connection_t);
                let visual =
                    XCBVisualType::from_raw_none(&mut get_root_visual_type(&conn, &screen).base as
                                                 *mut xcb::ffi::xcb_visualtype_t as
                                                 *mut cairo_sys::xcb_visualtype_t);
                let drawable = XCBDrawable(id);
                Surface::create(&cairo_conn, &drawable, &visual, width as i32, height as i32)
                // TODO: Update surface width/height when window size changes.
            };

            surface
        };

        xcb::map_window(&conn, id);
        conn.flush();

        Window {
            conn,
            screen_idx,
            id,
            surface,
        }
    }

    fn screen<'a>(&'a self) -> xcb::Screen<'a> {
        self.conn
            .get_setup()
            .roots()
            .nth(self.screen_idx)
            .expect("Invalid screen")
    }

    fn expose(&self) {
        let font = pango::FontDescription::from_string("Envy Code R 27");

        let attr1 = TextAttributes {
            font: font.clone(),
            fg_color: Color::red(),
            bg_color: None,
            padding: Padding::uniform(5.0),
        };
        let attr2 = TextAttributes {
            font: font.clone(),
            fg_color: Color::blue(),
            bg_color: Some(Color::red()),
            padding: Padding::uniform(5.0),
        };
        let texts = vec![Text {
                             attr: attr1.clone(),
                             text: "Hello, world!".to_owned(),
                             stretch: false,
                         },
                         Text {
                             attr: attr2.clone(),
                             text: "Again".to_owned(),
                             stretch: true,
                         },
                         Text {
                             attr: attr1,
                             text: "Stretched".to_owned(),
                             stretch: true,
                         },
                         Text {
                             attr: attr2,
                             text: "Not Stretched".to_owned(),
                             stretch: false,
                         }];

        let inactive_attr = TextAttributes {
            font: pango::FontDescription::from_string("Envy Code R 27"),
            fg_color: Color::white(),
            bg_color: None,
            padding: Padding::new(10.0, 10.0, 5.0, 5.0),
        };
        let mut active_attr = inactive_attr.clone();
        active_attr.bg_color = Some(Color::blue());

        self.render_text_blocks(Pager::new(active_attr, inactive_attr).compute_text());

        self.conn.flush();
    }

    fn render_text_blocks(&self, texts: Vec<Text>) {
        // Layout each block of text. After this, we can query the width of each
        // block, which will allow us to do more complex layout below.
        let mut layouts: Vec<_> = texts.into_iter().map(|t| t.layout(&self.surface)).collect();

        // Calculate how much free space we have after laying out all the
        // non-stretch blocks. Split the remaining space (if any) between the
        // stretch blocks. If there isn't enough space for the non-stretch blocks
        // do nothing and allow it to overflow.
        {
            let mut width = 0.0;
            let mut stretched = Vec::new();
            for layout in layouts.iter_mut() {
                if !layout.stretch() {
                    width += layout.width();
                } else {
                    stretched.push(layout);
                }
            }

            let remaining_width = self.screen().width_in_pixels() as f64 - width;
            let remaining_width = if remaining_width < 0.0 {
                0.0
            } else {
                remaining_width
            };
            let width_per_stretched = remaining_width / (stretched.len() as f64);
            for layout in stretched.iter_mut() {
                layout.set_width(width_per_stretched);
            }
        }

        // TODO: Set the height of the window and the height of each text block(?)
        // to the height of the largest bit of text.

        // Finally, just render each block of text in turn.
        let mut x = 0.0;
        for layout in &layouts {
            layout.render(x, 0.0);
            x += layout.width();
        }
    }
}

fn main() {
    let (conn, screen_idx) = xcb::Connection::connect_with_xlib_display().unwrap();
    let conn = Rc::new(conn);

    let w = Window::new(conn.clone(), screen_idx as usize);

    loop {
        let event = conn.wait_for_event();
        match event {
            None => {
                break;
            }
            Some(event) => {
                let r = event.response_type() & !0x80;
                match r {
                    xcb::EXPOSE => w.expose(),
                    _ => {}
                }
            }
        }
    }
}
<commit_msg>Convenience methods for producing similar attrs.<commit_after>extern crate xcb;
extern crate xcb_util;
extern crate cairo;
extern crate cairo_sys;
extern crate pango;
extern crate pangocairo;

use std::rc::Rc;

use cairo::{Context, Surface, XCBConnection, XCBDrawable, XCBSurface, XCBVisualType};
use pango::LayoutExt;
use pangocairo::CairoContextExt;
use xcb::ffi::*;

fn get_root_visual_type(conn: &xcb::Connection, screen: &xcb::Screen) -> xcb::Visualtype {
    for root in conn.get_setup().roots() {
        for allowed_depth in root.allowed_depths() {
            for visual in allowed_depth.visuals() {
                if visual.visual_id() == screen.root_visual() {
                    return visual;
                }
            }
        }
    }
    panic!("No visual type found");
}

#[derive(Clone, Debug)]
struct Color {
    red: f64,
    green: f64,
    blue: f64,
}

impl Color {
    fn white() -> Color {
        Color {
            red: 1.0,
            green: 1.0,
            blue: 1.0,
        }
    }

    fn red() -> Color {
        Color {
            red: 1.0,
            green: 0.0,
            blue: 0.0,
        }
    }

    fn blue() -> Color {
        Color {
            red: 0.0,
            green: 0.0,
            blue: 1.0,
        }
    }

    fn apply_to_context(&self, cr: &Context) {
        cr.set_source_rgb(self.red, self.green, self.blue);
    }
}

#[derive(Clone, Debug)]
struct Padding {
    left: f64,
    right: f64,
    top: f64,
    bottom: f64,
}

impl Padding {
    fn none() -> Padding {
        Padding {
            left: 0.0,
            right: 0.0,
            top: 0.0,
            bottom: 0.0,
        }
    }
    fn new(left: f64, right: f64, top: f64, bottom: f64) -> Padding {
        Padding {
            left,
            right,
            top,
            bottom,
        }
    }

    fn uniform(value: f64) -> Padding {
        Padding {
            left: value,
            right: value,
            top: value,
            bottom: value,
        }
    }
}

#[derive(Clone)]
struct TextAttributes {
    font: pango::FontDescription,
    fg_color: Color,
    bg_color: Option<Color>,
    padding: Padding,
}

impl TextAttributes {
    fn with_font(&self, font: pango::FontDescription) -> TextAttributes {
        let mut new = self.clone();
        new.font = font;
        new
    }

    fn with_fg_color(&self, fg_color: Color) -> TextAttributes {
        let mut new = self.clone();
        new.fg_color = fg_color;
        new
    }

    fn with_bg_color(&self, bg_color: Option<Color>) -> TextAttributes {
        let mut new = self.clone();
        new.bg_color = bg_color;
        new
    }

    fn with_padding(&self, padding: Padding) -> TextAttributes {
        let mut new = self.clone();
        new.padding = padding;
        new
    }
}

struct Text {
    attr: TextAttributes,
    text: String,
    stretch: bool,
}

impl Text {
    fn layout(self, surface: &Surface) -> TextLayout {
        let context = Context::new(&surface);

        let layout = context.create_pango_layout();
        layout.set_text(&self.text, self.text.len() as i32);
        layout.set_font_description(Some(&self.attr.font));

        TextLayout {
            attr: self.attr.clone(),
            stretch: self.stretch,
            width: None,
            height: None,
            context: context,
            layout: layout,
        }
    }
}

struct TextLayout {
    attr: TextAttributes,
    stretch: bool,
    width: Option<f64>,
    height: Option<f64>,
    context: Context,
    layout: pango::Layout,
}

impl TextLayout {
    fn width(&self) -> f64 {
        self.width
            .unwrap_or_else(|| {
                                let text_width = self.layout.get_pixel_size().0 as f64;
                                text_width + self.attr.padding.left + self.attr.padding.right
                            })
    }

    fn height(&self) -> f64 {
        self.height
            .unwrap_or_else(|| {
                                let text_height = self.layout.get_pixel_size().1 as f64;
                                text_height + self.attr.padding.top + self.attr.padding.bottom
                            })
    }

    fn set_width(&mut self, width: f64) {
        self.width = Some(width);
    }

    fn set_height(&mut self, height: f64) {
        self.height = Some(height);
    }

    fn stretch(&self) -> bool {
        self.stretch
    }

    fn render(&self, x: f64, y: f64) {
        self.context.save();
        self.context.translate(x, y + self.attr.padding.top);

        if let Some(ref bg_color) = self.attr.bg_color {
            bg_color.apply_to_context(&self.context);
            // FIXME: The use of `height` isnt' right here: we want to do the
            // full height of the bar, not the full height of the text. It
            // would be useful if we could do Surface.get_height(), but that
            // doesn't seem to be available in cairo-rs for some reason?
            self.context
                .rectangle(0.0, 0.0, self.width(), self.height());
            self.context.fill();
        }

        self.attr.fg_color.apply_to_context(&self.context);
        self.context
            .translate(self.attr.padding.left, self.attr.padding.top);
        self.context.show_pango_layout(&self.layout);

        self.context.restore();
    }
}

struct Pager {
    conn: xcb_util::ewmh::Connection,
    screen_idx: i32,

    active_attr: TextAttributes,
    inactive_attr: TextAttributes,
}

impl Pager {
    fn new(active_attr: TextAttributes, inactive_attr: TextAttributes) -> Pager {
        let (conn, screen_idx) = xcb::Connection::connect_with_xlib_display().unwrap();
        let ewmh_conn = xcb_util::ewmh::Connection::connect(conn)
            .map_err(|_| ())
            .unwrap();

        Pager {
            conn: ewmh_conn,
            screen_idx: screen_idx,
            active_attr: active_attr,
            inactive_attr: inactive_attr,
        }
    }

    fn get_desktops_info(&self) -> Vec<(bool, String)> {
        let number = xcb_util::ewmh::get_number_of_desktops(&self.conn, self.screen_idx)
            .get_reply()
            .unwrap() as usize;
        let current = xcb_util::ewmh::get_current_desktop(&self.conn, self.screen_idx)
            .get_reply()
            .unwrap() as usize;
        let names_reply = xcb_util::ewmh::get_desktop_names(&self.conn, self.screen_idx)
            .get_reply()
            .unwrap();
        let mut names = names_reply.strings();

        // EWMH states that `number` may not equal `names.len()`, as there may
        // be unnamed desktops, or more desktops than are currently in use.
        if names.len() > number {
            names.truncate(number);
        } else if number > names.len() {
            for i in 0..(number - names.len()) {
                names.push("?");
            }
        }

        names
            .into_iter()
            .enumerate()
            .map(|(i, name)| (i == current, name.to_owned()))
            .collect()
    }

    fn compute_text(&self) -> Vec<Text> {
        let desktops = self.get_desktops_info();
        self.get_desktops_info()
            .into_iter()
            .map(|(active, name)| {
                Text {
                    attr: if active {
                        self.active_attr.clone()
                    } else {
                        self.inactive_attr.clone()
                    },
                    text: name,
                    stretch: false,
                }
            })
            .collect()
    }
}

// TODO: impl Drop?
struct Window {
    conn: Rc<xcb::Connection>,
    screen_idx: usize,
    id: u32,
    surface: Surface,
}

impl Window {
    fn new(conn: Rc<xcb::Connection>, screen_idx: usize) -> Window {
        let id = conn.generate_id();

        let surface = {
            let screen = conn.get_setup()
                .roots()
                .nth(screen_idx)
                .expect("invalid screen");
            let values = [(xcb::CW_BACK_PIXEL, screen.black_pixel()),
                          (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE)];

            let (width, height) = (screen.width_in_pixels(), 100);

            xcb::create_window(&conn,
                               xcb::COPY_FROM_PARENT as u8,
                               id,
                               screen.root(),
                               0,
                               0,
                               width,
                               height,
                               10,
                               xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
                               screen.root_visual(),
                               &values);

            let surface = unsafe {
                let cairo_conn = XCBConnection::from_raw_none(conn.get_raw_conn() as
                                                              *mut cairo_sys::xcb_connection_t);
                let visual =
                    XCBVisualType::from_raw_none(&mut get_root_visual_type(&conn, &screen).base as
                                                 *mut xcb::ffi::xcb_visualtype_t as
                                                 *mut cairo_sys::xcb_visualtype_t);
                let drawable = XCBDrawable(id);
                Surface::create(&cairo_conn, &drawable, &visual, width as i32, height as i32)
                // TODO: Update surface width/height when window size changes.
            };

            surface
        };

        xcb::map_window(&conn, id);
        conn.flush();

        Window {
            conn,
            screen_idx,
            id,
            surface,
        }
    }

    fn screen<'a>(&'a self) -> xcb::Screen<'a> {
        self.conn
            .get_setup()
            .roots()
            .nth(self.screen_idx)
            .expect("Invalid screen")
    }

    fn expose(&self) {
        let font = pango::FontDescription::from_string("Envy Code R 27");

        let attr1 = TextAttributes {
            font: font.clone(),
            fg_color: Color::red(),
            bg_color: None,
            padding: Padding::uniform(5.0),
        };
        let attr2 = TextAttributes {
            font: font.clone(),
            fg_color: Color::blue(),
            bg_color: Some(Color::red()),
            padding: Padding::uniform(5.0),
        };
        let texts = vec![Text {
                             attr: attr1.clone(),
                             text: "Hello, world!".to_owned(),
                             stretch: false,
                         },
                         Text {
                             attr: attr2.clone(),
                             text: "Again".to_owned(),
                             stretch: true,
                         },
                         Text {
                             attr: attr1,
                             text: "Stretched".to_owned(),
                             stretch: true,
                         },
                         Text {
                             attr: attr2,
                             text: "Not Stretched".to_owned(),
                             stretch: false,
                         }];

        let inactive_attr = TextAttributes {
            font: pango::FontDescription::from_string("Envy Code R 27"),
            fg_color: Color::white(),
            bg_color: None,
            padding: Padding::new(10.0, 10.0, 5.0, 5.0),
        };
        let active_attr = inactive_attr.with_bg_color(Some(Color::blue()));

        self.render_text_blocks(Pager::new(active_attr, inactive_attr).compute_text());

        self.conn.flush();
    }

    fn render_text_blocks(&self, texts: Vec<Text>) {
        // Layout each block of text. After this, we can query the width of each
        // block, which will allow us to do more complex layout below.
        let mut layouts: Vec<_> = texts.into_iter().map(|t| t.layout(&self.surface)).collect();

        // Calculate how much free space we have after laying out all the
        // non-stretch blocks. Split the remaining space (if any) between the
        // stretch blocks. If there isn't enough space for the non-stretch blocks
        // do nothing and allow it to overflow.
        {
            let mut width = 0.0;
            let mut stretched = Vec::new();
            for layout in layouts.iter_mut() {
                if !layout.stretch() {
                    width += layout.width();
                } else {
                    stretched.push(layout);
                }
            }

            let remaining_width = self.screen().width_in_pixels() as f64 - width;
            let remaining_width = if remaining_width < 0.0 {
                0.0
            } else {
                remaining_width
            };
            let width_per_stretched = remaining_width / (stretched.len() as f64);
            for layout in stretched.iter_mut() {
                layout.set_width(width_per_stretched);
            }
        }

        // TODO: Set the height of the window and the height of each text block(?)
        // to the height of the largest bit of text.

        // Finally, just render each block of text in turn.
        let mut x = 0.0;
        for layout in &layouts {
            layout.render(x, 0.0);
            x += layout.width();
        }
    }
}

fn main() {
    let (conn, screen_idx) = xcb::Connection::connect_with_xlib_display().unwrap();
    let conn = Rc::new(conn);

    let w = Window::new(conn.clone(), screen_idx as usize);

    loop {
        let event = conn.wait_for_event();
        match event {
            None => {
                break;
            }
            Some(event) => {
                let r = event.response_type() & !0x80;
                match r {
                    xcb::EXPOSE => w.expose(),
                    _ => {}
                }
            }
        }
    }
}
<|endoftext|>