<commit_before>#![feature(core)]
#![feature(std_misc)]

extern crate time;
extern crate "rustc-serialize" as rustc_serialize;

use std::io::prelude::*;
use std::os::unix::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::fs::create_dir_all;
use std::path::Path;
use std::thread;
use std::process::{Command, Stdio};
use std::collections::HashMap;
use std::sync::mpsc::{Receiver, Sender, channel};

use rustc_serialize::json;

#[derive(Debug)]
#[derive(Clone)]
pub enum LogSource {
  ControlSystem,
  StdOut,
  StdErr,
  BuildSystem,
}

impl LogSource {
  pub fn to_string(&self) -> String {
    match *self {
      LogSource::ControlSystem => "Control System",
      LogSource::StdOut => "stdout",
      LogSource::StdErr => "stderr",
      LogSource::BuildSystem => "Log System",
    }.to_string()
  }
}

pub fn to_string_ts(ti: time::Tm) -> String {
    let format = "%Y-%m-%d %T.%f";
    let mut ts = time::strftime(format, &ti).ok().unwrap();
    let l = ts.len();
    ts.truncate(l-6);
    ts
}

#[derive(Debug)]
pub struct TimestampedLine {
  source: LogSource,
  time: time::Tm,
  content: String,
}

impl TimestampedLine {
  pub fn tsl(source: LogSource, time: time::Tm, content: String) -> HashMap<String, String> {
    let mut line = HashMap::new();
    line.insert("source".to_string(), source.to_string());
    line.insert("time".to_string(), to_string_ts(time.to_utc()));
    line.insert("content".to_string(), content);

    line
  }

  pub fn msg(reason: String) -> HashMap<String, String> {
    TimestampedLine::tsl(LogSource::BuildSystem, time::now(), reason)
  }
  pub fn stop_writer() -> HashMap<String, String> {
    TimestampedLine::tsl(LogSource::ControlSystem, time::now(), "stop".to_string())
  }
}

pub struct Writer;

impl Writer {
  fn run(&self, destination_file:String,  receiver: Receiver<HashMap<String, String>> ) {
    let destination = Path::new(destination_file.as_slice());
    std::fs::create_dir_all(destination.parent().unwrap()).ok();
    println!("Writing to {}.", destination_file);
    match File::create(destination) {
      Ok(mut file) => {
        let mut stop = 3;
        while stop != 0 {
          match receiver.recv() {
            Ok(tl) => {
              // This is a stop command, decrement counter. We need to wait for main, stderr, stdout before stopping
              if tl.get("source") == Some(&LogSource::ControlSystem.to_string()) && tl.get("content") == Some(&"stop".to_string()) {
                  stop = stop - 1;
              } else {
                let encoded = json::encode(&tl).unwrap();
                println!("{:?}", tl);
                file.write_all(&encoded.into_bytes()).ok();
                file.write_all(b"\n").ok();
              }
            }
            Err(e) => println!("Receive error: {}", e),
          }
        }
      },
      Err(e) => panic!("Unable to open output file {}: {}", destination_file, e.to_string())
    }
  }
}

pub struct Runner;

impl Runner {
	fn run(&self, cmd: &str, parms: Vec<String>)  {
    let start = time::now();

    let cmd_path = Path::new(cmd);
    let fname = match cmd_path.file_name() {
      Some(f) => {
        let mut pth = time::strftime("./logs/%Y/%m/%d/", &start).ok().unwrap();
        let postfix = time::strftime("-%T.ajson", &start).ok().unwrap();
        let osname = f.to_string_lossy().into_owned();
        pth.push_str(&osname);
        pth.push_str(&postfix);
        pth
      },
      None => panic!("Unable to find file name for {}", cmd),
    };

    let (sender, receiver) = channel();
    let writer = Writer;
    let th = thread::spawn(move || {
      writer.run(fname, receiver);
    });

    sender.send(TimestampedLine::msg(format!("Processing {}", cmd))).unwrap();

    let mut child = match Command::new(&cmd)
      .args(parms.as_slice())
      .current_dir(".")
      .stdin(Stdio::null())
      .stdout(Stdio::piped())
      .stderr(Stdio::piped())
      .spawn() {
        Err(why) => panic!("couldn't spawn {}: {}", &cmd, why.to_string()),
        Ok(child) => child,
    };

    //https://github.com/rust-lang/rust/blob/b83b26bacb6371173cdec6bf68c7ffa69f858c84/src/libstd/process.rs
    fn read_timestamped_lines<T: Read + Send + 'static>(stream: Option<T>, source: LogSource, sender: Sender<HashMap<String, String>>) {
      match stream {
        Some(stream) => {
          thread::spawn(move || {
            let mut br = BufReader::with_capacity(64, stream);
            while {
              let mut line = String::new();
              let ok = match br.read_line(&mut line) {
                Ok(0) => false,
                Ok(_) => true,
                Err(e) => {println!("Something went wrong while reading the data: {}", e.to_string()); false}
              };
              if ok {
                let now = time::now();
                sender.send(TimestampedLine::tsl(source.clone(), now, line[0..line.len()-1].to_string())).unwrap();
              }
              ok
            } {}
            sender.send(TimestampedLine::stop_writer()).unwrap();
          });
        }
        None => sender.send(TimestampedLine::msg("Stream is None, not reading anything.".to_string())).unwrap()
      }
    }
    read_timestamped_lines(child.stdout.take(), LogSource::StdOut, sender.clone());
    read_timestamped_lines(child.stderr.take(), LogSource::StdErr, sender.clone());
    let status = child.wait();
    let end = time::now();

    let duration = (end-start).num_milliseconds().to_string();

    let mut end_line = match status {
    Ok(es) => if es.success() {
        let mut msg = TimestampedLine::msg("Process completed successfully.".to_string());
        msg.insert("completed".to_string(), "0".to_string());
        msg
      } else if let Some(ecode) = es.code() {
        TimestampedLine::msg(format!("Process completed with error code {}.", ecode))
      } else if let Some(esignal) = es.signal() {
        TimestampedLine::msg(format!("Process aborted with signal {}.", esignal))
      } else {
        TimestampedLine::msg("Non-reachable condition reached. Something's wrong".to_string())
      },
      Err(run_error) => TimestampedLine::msg(format!("Something went wrong while getting the command output: {:?}", run_error)),
    };

    end_line.insert("duration".to_string(), duration);
    sender.send(end_line).unwrap();

    sender.send(TimestampedLine::stop_writer()).unwrap();
    // Wait for writer thread to complete its writes
    let _ = th.join();
	}
}

fn main() {
  let r = Runner;

  r.run("/bin/ls", Vec::<String>::new());
}
<commit_msg>Read command to run in command line.<commit_after>#![feature(core)]
#![feature(std_misc)]

extern crate time;
extern crate "rustc-serialize" as rustc_serialize;

use std::io::prelude::*;
use std::os::unix::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::fs::create_dir_all;
use std::path::Path;
use std::thread;
use std::process::{Command, Stdio};
use std::collections::HashMap;
use std::sync::mpsc::{Receiver, Sender, channel};

use rustc_serialize::json;

#[derive(Debug)]
#[derive(Clone)]
pub enum LogSource {
  ControlSystem,
  StdOut,
  StdErr,
  BuildSystem,
}

impl LogSource {
  pub fn to_string(&self) -> String {
    match *self {
      LogSource::ControlSystem => "Control System",
      LogSource::StdOut => "stdout",
      LogSource::StdErr => "stderr",
      LogSource::BuildSystem => "Log System",
    }.to_string()
  }
}

pub fn to_string_ts(ti: time::Tm) -> String {
    let format = "%Y-%m-%d %T.%f";
    let mut ts = time::strftime(format, &ti).ok().unwrap();
    let l = ts.len();
    ts.truncate(l-6);
    ts
}

#[derive(Debug)]
pub struct TimestampedLine {
  source: LogSource,
  time: time::Tm,
  content: String,
}

impl TimestampedLine {
  pub fn tsl(source: LogSource, time: time::Tm, content: String) -> HashMap<String, String> {
    let mut line = HashMap::new();
    line.insert("source".to_string(), source.to_string());
    line.insert("time".to_string(), to_string_ts(time.to_utc()));
    line.insert("content".to_string(), content);

    line
  }

  pub fn msg(reason: String) -> HashMap<String, String> {
    TimestampedLine::tsl(LogSource::BuildSystem, time::now(), reason)
  }
  pub fn stop_writer() -> HashMap<String, String> {
    TimestampedLine::tsl(LogSource::ControlSystem, time::now(), "stop".to_string())
  }
}

pub struct Writer;

impl Writer {
  fn run(&self, destination_file:String,  receiver: Receiver<HashMap<String, String>> ) {
    let destination = Path::new(destination_file.as_slice());
    std::fs::create_dir_all(destination.parent().unwrap()).ok();
    println!("Writing to {}.", destination_file);
    match File::create(destination) {
      Ok(mut file) => {
        let mut stop = 3;
        while stop != 0 {
          match receiver.recv() {
            Ok(tl) => {
              // This is a stop command, decrement counter. We need to wait for main, stderr, stdout before stopping
              if tl.get("source") == Some(&LogSource::ControlSystem.to_string()) && tl.get("content") == Some(&"stop".to_string()) {
                  stop = stop - 1;
              } else {
                let encoded = json::encode(&tl).unwrap();
                println!("{:?}", tl);
                file.write_all(&encoded.into_bytes()).ok();
                file.write_all(b"\n").ok();
              }
            }
            Err(e) => println!("Receive error: {}", e),
          }
        }
      },
      Err(e) => panic!("Unable to open output file {}: {}", destination_file, e.to_string())
    }
  }
}

pub struct Runner;

impl Runner {
	fn run(&self, cmd: &str, parms: Vec<String>)  {
    let start = time::now();

    let cmd_path = Path::new(cmd);
    let fname = match cmd_path.file_name() {
      Some(f) => {
        let mut pth = time::strftime("./logs/%Y/%m/%d/", &start).ok().unwrap();
        let postfix = time::strftime("-%T.ajson", &start).ok().unwrap();
        let osname = f.to_string_lossy().into_owned();
        pth.push_str(&osname);
        pth.push_str(&postfix);
        pth
      },
      None => panic!("Unable to find file name for {}", cmd),
    };

    let (sender, receiver) = channel();
    let writer = Writer;
    let th = thread::spawn(move || {
      writer.run(fname, receiver);
    });

    sender.send(TimestampedLine::msg(format!("Processing {}", cmd))).unwrap();

    let mut child = match Command::new(&cmd)
      .args(parms.as_slice())
      .current_dir(".")
      .stdin(Stdio::null())
      .stdout(Stdio::piped())
      .stderr(Stdio::piped())
      .spawn() {
        Err(why) => panic!("couldn't spawn {}: {}", &cmd, why.to_string()),
        Ok(child) => child,
    };

    //https://github.com/rust-lang/rust/blob/b83b26bacb6371173cdec6bf68c7ffa69f858c84/src/libstd/process.rs
    fn read_timestamped_lines<T: Read + Send + 'static>(stream: Option<T>, source: LogSource, sender: Sender<HashMap<String, String>>) {
      match stream {
        Some(stream) => {
          thread::spawn(move || {
            let mut br = BufReader::with_capacity(64, stream);
            while {
              let mut line = String::new();
              let ok = match br.read_line(&mut line) {
                Ok(0) => false,
                Ok(_) => true,
                Err(e) => {println!("Something went wrong while reading the data: {}", e.to_string()); false}
              };
              if ok {
                let now = time::now();
                sender.send(TimestampedLine::tsl(source.clone(), now, line[0..line.len()-1].to_string())).unwrap();
              }
              ok
            } {}
            sender.send(TimestampedLine::stop_writer()).unwrap();
          });
        }
        None => sender.send(TimestampedLine::msg("Stream is None, not reading anything.".to_string())).unwrap()
      }
    }
    read_timestamped_lines(child.stdout.take(), LogSource::StdOut, sender.clone());
    read_timestamped_lines(child.stderr.take(), LogSource::StdErr, sender.clone());
    let status = child.wait();
    let end = time::now();

    let duration = (end-start).num_milliseconds().to_string();

    let mut end_line = match status {
    Ok(es) => if es.success() {
        let mut msg = TimestampedLine::msg("Process completed successfully.".to_string());
        msg.insert("completed".to_string(), "0".to_string());
        msg
      } else if let Some(ecode) = es.code() {
        TimestampedLine::msg(format!("Process completed with error code {}.", ecode))
      } else if let Some(esignal) = es.signal() {
        TimestampedLine::msg(format!("Process aborted with signal {}.", esignal))
      } else {
        TimestampedLine::msg("Non-reachable condition reached. Something's wrong".to_string())
      },
      Err(run_error) => TimestampedLine::msg(format!("Something went wrong while getting the command output: {:?}", run_error)),
    };

    end_line.insert("duration".to_string(), duration);
    sender.send(end_line).unwrap();

    sender.send(TimestampedLine::stop_writer()).unwrap();
    // Wait for writer thread to complete its writes
    let _ = th.join();
	}
}

fn main() {
  let r = Runner;

  let mut args = std::env::args();
  let _ = args.next().unwrap();
  let cmd = args.next().unwrap();

  r.run(cmd.as_slice(), args.collect());
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate walkdir;

use walkdir::WalkDir;
use rand::{Rng, thread_rng};
use std::env;
use std::fs::File;
use std::fs;
use std::io::prelude::*;
use std::io::Error;
use std::cmp;

fn main() {
    let mut recursive: bool = false;
    let mut file: String = String::from("");

    for argument in env::args().skip(1) {
        if argument.to_lowercase() == "--help" || argument.to_lowercase() == "-help" {
            help();
            return;
        } else if argument.to_lowercase() == "--v" || argument.to_lowercase() == "-v" ||
           argument.to_lowercase() == "-version" ||
           argument.to_lowercase() == "--version" {
            version();
            return;
        } else if argument.to_lowercase() == "-r" {
            recursive = true;
        } else {
            file = argument;
            break;
        }
    }
    if file == "" {
        help();
        return;
    }
    file = get_path(&file);

    if recursive {
        for entry in WalkDir::new(file) {
            let entry = entry.unwrap();
            trumpify(entry.path().display().to_string());
        }
    } else {
        trumpify(file)
    }
}

fn get_path2(file: &str) -> Result<String, Error> {
    let path = try!(fs::canonicalize(file));
    Ok(path.display().to_string())
}

fn get_path(file: &str) -> String {
    get_path2(file).unwrap_or(file.to_owned())
}

fn read_file(file: &str) -> Result<String, Error> {
    let mut file = try!(File::open(file));
    let mut contents = String::new();
    try!(file.read_to_string(&mut contents));
    Ok(contents)
}

fn write_file(file: &str, content: String) -> Result<(), Error> {
    let mut f = try!(File::create(file));
    try!(f.write_all(content.as_bytes()));

    try!(f.sync_data());
    Ok(())
}

fn version() {
    println!("\x1b[32mVersion:");
    println!("\x1b[0m    trump-0.1.0");
    println!("\x1b[32mWebsite:");
    println!("\x1b[0m    https://github.com/x13machine/trump/");
    println!("\x1b[32mCreator:");
    println!("\x1b[0m    <Googolplexking/x13machine> https://googolplex.ninja/");
}
fn help() {
    println!("\x1b[32mHelp:");
    println!("\x1b[0m    trump --help");
    println!("\x1b[32mVersion:");
    println!("\x1b[0m    trump -v");
    println!("\x1b[32mFiles:");
    println!("\x1b[0m    trump <File>");
    println!("\x1b[32mDirectories:");
    println!("\x1b[0m    trump -r <Directory>");
}

fn trumpify(file: String) {
    let dirs: Vec<&str> = file.split('/').collect::<Vec<&str>>();
    let mut name: String = String::from(dirs[dirs.len() - 1]);
    name = format!("{}{}",
                   &name[0..1].to_uppercase(),
                   &name[1..name.len()].to_lowercase());
    // Ansi Color Codes!!!
    println!("\x1b[32mMaking Great Again:\x1b[0m {}", file);

    let text = format!("Make {} Great Again!", name);

    let mut content = match read_file(&file) {
        Ok(content) => content,
        Err(_) => return,
    };

    let loops = cmp::max(content.len() / text.len() / 2, 1);
    let mut rng = thread_rng();
    for _ in 0..loops {
        let place: usize = rng.gen_range(0, content.len() as u32) as usize;
        let part1: String = String::from(&content[0..place]);
        let part2: String =
            String::from(&content[cmp::min(place + text.len(), content.len())..content.len()]);
        content = format!("{}{}{}", part1, text, part2);
    }
    let _ = write_file(&file, content);
}
<commit_msg>Update main.rs<commit_after>extern crate rand;
extern crate walkdir;

use walkdir::WalkDir;
use rand::{Rng, thread_rng};
use std::env;
use std::fs::File;
use std::fs;
use std::io::prelude::*;
use std::io::Error;
use std::cmp;

fn main() {
    let mut recursive: bool = false;
    let mut file: String = String::from("");

    for argument in env::args().skip(1) {
        if argument.to_lowercase() == "--help" || argument.to_lowercase() == "-help" {
            help();
            return;
        } else if argument.to_lowercase() == "--v" || argument.to_lowercase() == "-v" ||
           argument.to_lowercase() == "-version" ||
           argument.to_lowercase() == "--version" {
            version();
            return;
        } else if argument.to_lowercase() == "-r" {
            recursive = true;
        } else {
            file = argument;
            break;
        }
    }
    if file == "" {
        help();
        return;
    }
    file = get_path(&file);

    if recursive {
        for entry in WalkDir::new(file) {
            let entry = entry.unwrap();
            trumpify(entry.path().display().to_string());
        }
    } else {
        trumpify(file)
    }
}

fn get_path2(file: &str) -> Result<String, Error> {
    let path = try!(fs::canonicalize(file));
    Ok(path.display().to_string())
}

fn get_path(file: &str) -> String {
    get_path2(file).unwrap_or(file.to_owned())
}

fn read_file(file: &str) -> Result<String, Error> {
    let mut file = try!(File::open(file));
    let mut contents = String::new();
    try!(file.read_to_string(&mut contents));
    Ok(contents)
}

fn write_file(file: &str, content: String) -> Result<(), Error> {
    let mut f = try!(File::create(file));
    try!(f.write_all(content.as_bytes()));

    try!(f.sync_data());
    Ok(())
}

fn version() {
    println!("\x1b[32mVersion:");
    println!("\x1b[0m    trump-0.1.0");
    println!("\x1b[32mWebsite:");
    println!("\x1b[0m    https://github.com/x13machine/trump/");
    println!("\x1b[32mCreator:");
    println!("\x1b[0m    <Googolplexking/x13machine> https://googolplex.ninja/");
}
fn help() {
    println!("\x1b[32mHelp:");
    println!("\x1b[0m    trump --help");
    println!("\x1b[32mVersion:");
    println!("\x1b[0m    trump -v");
    println!("\x1b[32mFiles:");
    println!("\x1b[0m    trump <File>");
    println!("\x1b[32mDirectories:");
    println!("\x1b[0m    trump -r <Directory>");
}

fn trumpify(file: String) {
    let dirs: Vec<&str> = file.split('/').collect::<Vec<&str>>();
    let mut name: String = String::from(dirs[dirs.len() - 1]);
    name = format!("{}{}",
                   &name[0..1].to_uppercase(),
                   &name[1..name.len()].to_lowercase());
    // Ansi Color Codes!!!
    println!("\x1b[32mMaking Great Again:\x1b[0m {}", file);

    let text = format!("Make {} Great Again!", name);

    let mut content = match read_file(&file) {
        Ok(content) => content,
        Err(_) => return,
    };
    if content == ""{
        return ;
    }

    let loops = cmp::max(content.len() / text.len() / 2, 1);
    let mut rng = thread_rng();
    for _ in 0..loops {
        let place: usize = rng.gen_range(0, content.len() as u32) as usize;
        let part1: String = String::from(&content[0..place]);
        let part2: String =
            String::from(&content[cmp::min(place + text.len(), content.len())..content.len()]);
        content = format!("{}{}{}", part1, text, part2);
    }
    let _ = write_file(&file, content);
}
<|endoftext|>


<commit_before>use std::path::Path;

#[macro_use] extern crate clap;

extern crate image;

extern crate onmf;

// `name` and `long` have the same lifetime
fn named_usize_arg<'n, 'h, 'g, 'p, 'r>(name: &'n str, help: &'h str) -> clap::Arg<'n, 'n, 'h, 'g, 'p, 'r> {
    // we don't own `name` but we now own `error_message`
    // which contains `name`.
    let error_message = format!(
        "value provided for argument `{}` is not a valid unsigned integer number",
        name);
    clap::Arg::with_name(name)
         .long(name)
         .help(help)
         // `move` makes it such that the  closure owns `error_message`
         .validator(move |val| {
             match val.parse::<usize>() {
                 Ok(_) => Ok(()),
                 // the closure owns `error_message`.
                 // we can't move `error_message` out of the closure.
                 // we have to clone it instead.
                 Err(_) => Err(error_message.clone())
             }
         })
         .takes_value(true)
}

fn main() {
    let default_nhidden: usize = 10;
    let help_nhidden = format!("number of hidden (latent) variables to find (defaults to `{}`)", default_nhidden);

    let help_input_image_path = "path to image on the the grayscale amounts in the columns of which the NMF should be applied";

    let matches =
        clap::App::new("image-columns-nmf")
            .version(&crate_version!()[..])
            .about("applies NMF on the grayscale amounts of the columns of an image")
            .arg(clap::Arg::with_name("input-image-path")
                 .index(1)
                 .help(&help_input_image_path)
                 .required(true))
            .arg(named_usize_arg("nhidden", &help_nhidden))
            .get_matches();

    let nhidden: usize = value_t!(matches.value_of("nhidden"), usize).unwrap_or(default_nhidden);
    let input_image_path_string = matches.value_of("input-image-path").unwrap();
    let input_image_path = Path::new(input_image_path_string);

    println!("nhidden = {}", nhidden);
    println!("input_image_path = {:?}", input_image_path);
    println!("input_image_path.parent() = {:?}", input_image_path.parent());
    println!("input_image_path.file_name() = {:?}", input_image_path.file_name());
    println!("input_image_path.file_stem() = {:?}", input_image_path.file_stem());
    println!("input_image_path.extension() = {:?}", input_image_path.extension());

    // let mut input_image_file = std::fs::File::open(&input_image_path).unwrap();

    let image = image::open(&input_image_path).unwrap();

    // TODO read the file into an array you can pass into nmf

    // TODO
    // let mut ortho_nmf = onmf::OrthogonalNMFBlas::new_random01(
    //     nhidden, nobserved, nsamples);

    // TODO iterate nmf
}
<commit_msg>convert image to grayscale<commit_after>use std::path::Path;

#[macro_use] extern crate clap;

extern crate image;

extern crate onmf;

// `name` and `long` have the same lifetime
fn named_usize_arg<'n, 'h, 'g, 'p, 'r>(name: &'n str, help: &'h str) -> clap::Arg<'n, 'n, 'h, 'g, 'p, 'r> {
    // we don't own `name` but we now own `error_message`
    // which contains `name`.
    let error_message = format!(
        "value provided for argument `{}` is not a valid unsigned integer number",
        name);
    clap::Arg::with_name(name)
         .long(name)
         .help(help)
         // `move` makes it such that the  closure owns `error_message`
         .validator(move |val| {
             match val.parse::<usize>() {
                 Ok(_) => Ok(()),
                 // the closure owns `error_message`.
                 // we can't move `error_message` out of the closure.
                 // we have to clone it instead.
                 Err(_) => Err(error_message.clone())
             }
         })
         .takes_value(true)
}

fn main() {
    let default_nhidden: usize = 10;
    let help_nhidden = format!("number of hidden (latent) variables to find (defaults to `{}`)", default_nhidden);

    let help_input_image_path = "path to image on the the grayscale amounts in the columns of which the NMF should be applied";

    let matches =
        clap::App::new("image-columns-nmf")
            .version(&crate_version!()[..])
            .about("applies NMF on the grayscale amounts of the columns of an image")
            .arg(clap::Arg::with_name("input-image-path")
                 .index(1)
                 .help(&help_input_image_path)
                 .required(true))
            .arg(named_usize_arg("nhidden", &help_nhidden))
            .get_matches();

    let nhidden: usize = value_t!(matches.value_of("nhidden"), usize).unwrap_or(default_nhidden);
    let input_image_path_string = matches.value_of("input-image-path").unwrap();
    let input_image_path = Path::new(input_image_path_string);

    println!("nhidden = {}", nhidden);
    println!("input_image_path = {:?}", input_image_path);
    println!("input_image_path.parent() = {:?}", input_image_path.parent());
    println!("input_image_path.file_name() = {:?}", input_image_path.file_name());
    println!("input_image_path.file_stem() = {:?}", input_image_path.file_stem());
    println!("input_image_path.extension() = {:?}", input_image_path.extension());

    // let mut input_image_file = std::fs::File::open(&input_image_path).unwrap();

    let image = image::open(&input_image_path).unwrap();

    // to grayscale
    let image_luma = image.to_luma();

    // TODO read the file into an array you can pass into nmf

    // TODO
    // let mut ortho_nmf = onmf::OrthogonalNMFBlas::new_random01(
    //     nhidden, nobserved, nsamples);

    // TODO iterate nmf
}
<|endoftext|>


<commit_before>use std::io::Write;
use std::io::Read;
use std::fmt;
use std::cmp;
use std::io;

const DEFAULT_NUMBER_OF_SAMPLES:usize = 31;
const DEFAULT_NUMBER_OF_ROWS_PER_PATTERN:usize = 64;
const DEFAULT_NUMBER_OF_CHANNELS_PER_ROW:usize = 4;
const MAGIC_MK:[u8; 4] =['M' as u8, '.' as u8, 'K' as u8, '.' as u8];

#[derive(Debug)]
pub struct SampleInfo {
	pub name: String, // [char; 22],
	pub length: u16, // In words, so multiply by 2
	pub finetune: u8,
	pub volume: u8, // 0-64
	pub repeat_start: u16, // In words from start of sample data, so multiply by 2
	pub repeat_length: u16, // Number of words to loop, multiply by 2
}

impl SampleInfo {
	pub fn new() -> SampleInfo {
		SampleInfo{name: String::new(), length:0, finetune:0, volume:0, repeat_start:0, repeat_length:0}
	}
}

#[derive(Debug)]
pub struct Channel {
	pub period: u16, // Really u12
	pub sample_number: u8,
	pub effect: u16 // Really u12
}

impl Channel {
	pub fn new() -> Channel {
		Channel{period: 0, sample_number: 0, effect: 0}
	}
}

#[derive(Debug)]
pub struct Row {
	pub channels: Vec<Channel>
}

impl Row {
	pub fn new() -> Row {
		let mut row = Row{channels: Vec::new()};
		for _ in 0..DEFAULT_NUMBER_OF_CHANNELS_PER_ROW {
			row.channels.push(Channel::new());
		}

		row
	}
}

#[derive(Debug)]
pub struct Pattern {
	pub rows: Vec<Row>
}

impl Pattern {
	pub fn new() -> Pattern {
		let mut p = Pattern{rows: Vec::new()};

		for _ in 0..DEFAULT_NUMBER_OF_ROWS_PER_PATTERN {
			p.rows.push(Row::new());
		}

		p
	}
}

pub struct Positions {
	pub data: [u8; 128]
}

impl fmt::Debug for Positions {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.data[..].fmt(formatter)
    }
}

#[derive(Debug)]
pub struct PTModule {
	pub name: String, // [char; 20],
	pub sample_info: Vec<SampleInfo>, // [SampleInfo; DEFAULT_NUMBER_OF_SAMPLES]
	pub length: u8, // Length 1-128
	pub nt_restart: u8, // Set to 127
	pub positions: Positions, // The order in which to play patterns
	pub mk: [u8; 4], // Set to M.K.
	pub patterns: Vec<Pattern>,
	pub sample_data: Vec<Vec<u8>> // The bytes in the samples -127 - 127
}

impl PTModule {
	pub fn new() -> PTModule {
		let mut ptmod = PTModule{name: String::new(), sample_info: Vec::new(), length:0,
			nt_restart: 127, positions: Positions{data: [0; 128]}, mk: MAGIC_MK,
			patterns: Vec::new(), sample_data: Vec::new() };

		for _ in 0..DEFAULT_NUMBER_OF_SAMPLES {
			ptmod.sample_info.push(SampleInfo::new());
		}

		ptmod
	}
}

fn read_all(reader: &mut Read, data: &mut [u8]) -> io::Result<usize> {
	let mut pos = 0;
	while pos < data.len() {
		let slice = &mut data[pos..];
		let n = try!(reader.read(slice));
		pos += n;
	}

	Ok(pos)
}

fn write_or_panic(writer: &mut Write, data: &[u8]) {
	match writer.write_all(&data) {
		Ok(_) => (),
		_ => panic!("Failed to write bytes")
	};
}

fn read_0_padded_string(reader: &mut Read, len: usize) -> Result<String, io::Error> {
	let mut data = vec![0u8; len];
	try!(read_all(reader,&mut data));
	let mut str = String::new();
	for byte in data {
		if byte != 0 {
			str.push(byte as char);
		}
	}

	Ok(str)
}

fn write_0_padded_string(writer: &mut Write, str: &String, len: usize) {
	let mut data = vec![0u8; len];
	let str_buf = str.as_bytes();
	let m = cmp::min(data.len(),str_buf.len());
	for i in 0..m {
		data[i] = str_buf[i];
	}

	write_or_panic(writer, &data);
}

fn read_big_endian_u16(reader: &mut Read) -> Result<u16, io::Error> {
	let mut data_arr = [0u8; 2];
	try!(read_all(reader,&mut data_arr));

	let mut data:u16 = 0;

	for n in data_arr.iter() {
		data = (data << 8) + *n as u16;
	}

	Ok(data)
}

fn write_big_endian_u16(writer: &mut Write, val: u16) {
	let mut data = [0u8; 2];
	data[0] = (val >> 8) as u8;
	data[1] = (val & 0xff) as u8;

	write_or_panic(writer, &data);
}

fn read_u8(reader: &mut Read) -> Result<u8, io::Error> {
	let mut data = [0u8; 1];

	try!(read_all(reader, &mut data));

	Ok(data[0])
}

fn write_u8(writer: &mut Write, val: u8) {
	let mut data = [0u8; 1];
	data[0] = val;

	write_or_panic(writer, &data);
}

/// Write a 31 sample Amiga ProTracker mod-file
/// Panics on all errors
pub fn write_mod(writer: &mut Write, module: &mut PTModule) {

	// First write songname, 20 bytes, pad with 0
	write_0_padded_string(writer,&module.name,20);
	// Then write all 32 samples
	// TODO Handle the case when the vector has less than 31 samples
	let mut num_samples = 0;
	for i in 0..DEFAULT_NUMBER_OF_SAMPLES {
		let ref si = module.sample_info[i];
		// Sample name
		write_0_padded_string(writer, &si.name, 22);
		// Sample length
		write_big_endian_u16(writer, si.length);
		if si.length > 0 {
			num_samples += 1;
		}
		// Finetune
		write_u8(writer, si.finetune);
		// Volume
		write_u8(writer, si.volume);
		// Repeat start
		write_big_endian_u16(writer, si.repeat_start);
		// Repeat length
		write_big_endian_u16(writer, si.repeat_length);
	}

	let num_samples = num_samples;
	// Songlength
	write_u8(writer, module.length);
	// nt_restart
	write_u8(writer, module.nt_restart);
	// Song positions
	write_or_panic(writer,&module.positions.data);
	// M.K.
	write_or_panic(writer,&module.mk);

	// All patterns
	for pattern_it in module.patterns.iter() {
		// All rows
		for row_it in pattern_it.rows.iter() {
			// All channels
			for channel_it in row_it.channels.iter() {
				let mut data = [0u8; 4];

				data[0] = (channel_it.sample_number & 0xf0) | ((channel_it.period & 0xf00) >> 8) as u8;
				data[1] = (channel_it.period & 0xff) as u8;
				data[2] = ((channel_it.sample_number & 0x0f) << 4) | ((channel_it.effect & 0xf00) >> 8) as u8;
				data[3] = (channel_it.effect & 0xff) as u8;

				write_or_panic(writer,&data);
			}
		}
	}

	// And finally all samples
	for sample_it in module.sample_data.iter() {
		write_or_panic(writer,sample_it);
	}

	if num_samples != module.sample_data.len() {
		panic!("Warning! Number of samples does not match sample data");
	}
}

/// Read a 31 sample Amiga ProTracker mod-file
/// Panics on all errors
pub fn read_mod(reader: &mut Read) -> Result<PTModule, io::Error> {
	let mut module = PTModule::new();

	// First read 20 bytes songname
	module.name = try!(read_0_padded_string(reader, 20));
	// Read all sample info
	// TODO Handle 15 sample files
	for i in 0..DEFAULT_NUMBER_OF_SAMPLES {
		let si = &mut module.sample_info[i];
		// Sample name
		si.name = try!(read_0_padded_string(reader, 22));
		si.length = try!(read_big_endian_u16(reader));
		// Finetune
		si.finetune = try!(read_u8(reader));
		// Volume
		si.volume = try!(read_u8(reader));
		// Repeat start
		si.repeat_start = try!(read_big_endian_u16(reader));
		// Repeat length
		si.repeat_length = try!(read_big_endian_u16(reader));
	}

	// Songlength
	module.length = try!(read_u8(reader));
	// nt_restart
	module.nt_restart = try!(read_u8(reader));
	// Song positions
	try!(read_all(reader,&mut module.positions.data));
	// M.K.
	try!(read_all(reader,&mut module.mk));
	if module.mk != MAGIC_MK {
		panic!("Unknown format {:?}", module.mk);
	}

	// Read all patterns
	let mut num_patterns = 0;
	for n in module.positions.data.iter() {
		num_patterns = cmp::max(num_patterns,*n);
	}
	num_patterns += 1;
	for _ in 0..num_patterns {
		let mut pattern = Pattern::new();
		for mut row in &mut pattern.rows {
			for channel in &mut row.channels {
				let mut data  = [0u8;4];
				try!(read_all(reader,&mut data));
				channel.sample_number = (data[0] & 0xf0) | ((data[2] & 0xf0) >> 4);
				channel.period = (((data[0] & 0x0f) as u16) << 8) | (data[1] as u16);
				channel.effect = (((data[2] & 0x0f) as u16) << 8) | (data[3] as u16);
			}
		}
		module.patterns.push(pattern);
	}

	// Read all samples
	for si in &module.sample_info {
		if si.length > 0 {
			let length_in_bytes = si.length * 2;
			let mut data = vec![0u8; length_in_bytes as usize];
			try!(read_all(reader,&mut data));
			module.sample_data.push(data);
		}
	}

	// Now we have read all data.
	// Sanity check that the reader is empty
	let mut data = [0u8; 1];
	match reader.read(&mut data) {
		Ok(n) if n == data.len() => panic!("Unread data left in file"),
		_ => ()
	};

	Ok(module)
}
<commit_msg>Removed all panic<commit_after>use std::io::Write;
use std::io::Read;
use std::fmt;
use std::cmp;
use std::io;

const DEFAULT_NUMBER_OF_SAMPLES:usize = 31;
const DEFAULT_NUMBER_OF_ROWS_PER_PATTERN:usize = 64;
const DEFAULT_NUMBER_OF_CHANNELS_PER_ROW:usize = 4;
const MAGIC_MK:[u8; 4] =['M' as u8, '.' as u8, 'K' as u8, '.' as u8];

#[derive(Debug)]
pub enum PTMFError {
	Io(io::Error),
	Parse(String)
}

impl From<io::Error> for PTMFError {
    fn from(err: io::Error) -> PTMFError {
        PTMFError::Io(err)
    }
}

#[derive(Debug)]
pub struct SampleInfo {
	pub name: String, // [char; 22],
	pub length: u16, // In words, so multiply by 2
	pub finetune: u8,
	pub volume: u8, // 0-64
	pub repeat_start: u16, // In words from start of sample data, so multiply by 2
	pub repeat_length: u16, // Number of words to loop, multiply by 2
}

impl SampleInfo {
	pub fn new() -> SampleInfo {
		SampleInfo{name: String::new(), length:0, finetune:0, volume:0, repeat_start:0, repeat_length:0}
	}
}

#[derive(Debug)]
pub struct Channel {
	pub period: u16, // Really u12
	pub sample_number: u8,
	pub effect: u16 // Really u12
}

impl Channel {
	pub fn new() -> Channel {
		Channel{period: 0, sample_number: 0, effect: 0}
	}
}

#[derive(Debug)]
pub struct Row {
	pub channels: Vec<Channel>
}

impl Row {
	pub fn new() -> Row {
		let mut row = Row{channels: Vec::new()};
		for _ in 0..DEFAULT_NUMBER_OF_CHANNELS_PER_ROW {
			row.channels.push(Channel::new());
		}

		row
	}
}

#[derive(Debug)]
pub struct Pattern {
	pub rows: Vec<Row>
}

impl Pattern {
	pub fn new() -> Pattern {
		let mut p = Pattern{rows: Vec::new()};

		for _ in 0..DEFAULT_NUMBER_OF_ROWS_PER_PATTERN {
			p.rows.push(Row::new());
		}

		p
	}
}

pub struct Positions {
	pub data: [u8; 128]
}

impl fmt::Debug for Positions {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.data[..].fmt(formatter)
    }
}

#[derive(Debug)]
pub struct PTModule {
	pub name: String, // [char; 20],
	pub sample_info: Vec<SampleInfo>, // [SampleInfo; DEFAULT_NUMBER_OF_SAMPLES]
	pub length: u8, // Length 1-128
	pub nt_restart: u8, // Set to 127
	pub positions: Positions, // The order in which to play patterns
	pub mk: [u8; 4], // Set to M.K.
	pub patterns: Vec<Pattern>,
	pub sample_data: Vec<Vec<u8>> // The bytes in the samples -127 - 127
}

impl PTModule {
	pub fn new() -> PTModule {
		let mut ptmod = PTModule{name: String::new(), sample_info: Vec::new(), length:0,
			nt_restart: 127, positions: Positions{data: [0; 128]}, mk: MAGIC_MK,
			patterns: Vec::new(), sample_data: Vec::new() };

		for _ in 0..DEFAULT_NUMBER_OF_SAMPLES {
			ptmod.sample_info.push(SampleInfo::new());
		}

		ptmod
	}
}

fn read_all(reader: &mut Read, data: &mut [u8]) -> io::Result<usize> {
	let mut pos = 0;
	while pos < data.len() {
		let slice = &mut data[pos..];
		let n = try!(reader.read(slice));
		pos += n;
	}

	Ok(pos)
}

fn write_all(writer: &mut Write, data: &[u8]) -> io::Result<()> {
	let n = try!{writer.write_all(&data)};

	Ok(n)
}

fn read_0_padded_string(reader: &mut Read, len: usize) -> Result<String, io::Error> {
	let mut data = vec![0u8; len];
	try!(read_all(reader,&mut data));
	let mut str = String::new();
	for byte in data {
		if byte != 0 {
			str.push(byte as char);
		}
	}

	Ok(str)
}

fn write_0_padded_string(writer: &mut Write, str: &String, len: usize) -> io::Result<()> {
	let mut data = vec![0u8; len];
	let str_buf = str.as_bytes();
	let m = cmp::min(data.len(),str_buf.len());
	for i in 0..m {
		data[i] = str_buf[i];
	}

	let n = try!(write_all(writer, &data));

	Ok(n)
}

fn read_big_endian_u16(reader: &mut Read) -> Result<u16, io::Error> {
	let mut data_arr = [0u8; 2];
	try!(read_all(reader,&mut data_arr));

	let mut data:u16 = 0;

	for n in data_arr.iter() {
		data = (data << 8) + *n as u16;
	}

	Ok(data)
}

fn write_big_endian_u16(writer: &mut Write, val: u16)  -> io::Result<()> {
	let mut data = [0u8; 2];
	data[0] = (val >> 8) as u8;
	data[1] = (val & 0xff) as u8;

	let n = try!(write_all(writer, &data));

	Ok(n)
}

fn read_u8(reader: &mut Read) -> Result<u8, io::Error> {
	let mut data = [0u8; 1];

	try!(read_all(reader, &mut data));

	Ok(data[0])
}

fn write_u8(writer: &mut Write, val: u8)  -> io::Result<()> {
	let mut data = [0u8; 1];
	data[0] = val;

	let n = try!(write_all(writer, &data));

	Ok(n)
}

/// Write a 31 sample Amiga ProTracker mod-file
pub fn write_mod(writer: &mut Write, module: &mut PTModule) -> Result<(),PTMFError> {

	// First write songname, 20 bytes, pad with 0
	try!(write_0_padded_string(writer,&module.name,20));
	// Then write all 32 samples
	// TODO Handle the case when the vector has less than 31 samples
	let mut num_samples = 0;
	for i in 0..DEFAULT_NUMBER_OF_SAMPLES {
		let ref si = module.sample_info[i];
		// Sample name
		try!(write_0_padded_string(writer, &si.name, 22));
		// Sample length
		try!(write_big_endian_u16(writer, si.length));
		if si.length > 0 {
			num_samples += 1;
		}
		// Finetune
		try!(write_u8(writer, si.finetune));
		// Volume
		try!(write_u8(writer, si.volume));
		// Repeat start
		try!(write_big_endian_u16(writer, si.repeat_start));
		// Repeat length
		try!(write_big_endian_u16(writer, si.repeat_length));
	}

	let num_samples = num_samples;
	// Songlength
	try!(write_u8(writer, module.length));
	// nt_restart
	try!(write_u8(writer, module.nt_restart));
	// Song positions
	try!(write_all(writer,&module.positions.data));
	// M.K.
	try!(write_all(writer,&module.mk));

	// All patterns
	for pattern_it in module.patterns.iter() {
		// All rows
		for row_it in pattern_it.rows.iter() {
			// All channels
			for channel_it in row_it.channels.iter() {
				let mut data = [0u8; 4];

				data[0] = (channel_it.sample_number & 0xf0) | ((channel_it.period & 0xf00) >> 8) as u8;
				data[1] = (channel_it.period & 0xff) as u8;
				data[2] = ((channel_it.sample_number & 0x0f) << 4) | ((channel_it.effect & 0xf00) >> 8) as u8;
				data[3] = (channel_it.effect & 0xff) as u8;

				try!(write_all(writer,&data));
			}
		}
	}

	// And finally all samples
	for sample_it in module.sample_data.iter() {
		try!(write_all(writer,sample_it));
	}

	if num_samples != module.sample_data.len() {
		return Err(PTMFError::Parse(format!("Warning! Number of samples '{}' does not match sample data '{}'", num_samples, module.sample_data.len())));
	}

	Ok(())
}

/// Read a 31 sample Amiga ProTracker mod-file
pub fn read_mod(reader: &mut Read) -> Result<PTModule, PTMFError> {
	let mut module = PTModule::new();

	// First read 20 bytes songname
	module.name = try!(read_0_padded_string(reader, 20));
	// Read all sample info
	// TODO Handle 15 sample files
	for i in 0..DEFAULT_NUMBER_OF_SAMPLES {
		let si = &mut module.sample_info[i];
		// Sample name
		si.name = try!(read_0_padded_string(reader, 22));
		si.length = try!(read_big_endian_u16(reader));
		// Finetune
		si.finetune = try!(read_u8(reader));
		// Volume
		si.volume = try!(read_u8(reader));
		// Repeat start
		si.repeat_start = try!(read_big_endian_u16(reader));
		// Repeat length
		si.repeat_length = try!(read_big_endian_u16(reader));
	}

	// Songlength
	module.length = try!(read_u8(reader));
	// nt_restart
	module.nt_restart = try!(read_u8(reader));
	// Song positions
	try!(read_all(reader,&mut module.positions.data));
	// M.K.
	try!(read_all(reader,&mut module.mk));
	if module.mk != MAGIC_MK {
		return Err(PTMFError::Parse(format!("Unknown format {:?}", module.mk)));
	}

	// Read all patterns
	let mut num_patterns = 0;
	for n in module.positions.data.iter() {
		num_patterns = cmp::max(num_patterns,*n);
	}
	num_patterns += 1;
	for _ in 0..num_patterns {
		let mut pattern = Pattern::new();
		for mut row in &mut pattern.rows {
			for channel in &mut row.channels {
				let mut data  = [0u8;4];
				try!(read_all(reader,&mut data));
				channel.sample_number = (data[0] & 0xf0) | ((data[2] & 0xf0) >> 4);
				channel.period = (((data[0] & 0x0f) as u16) << 8) | (data[1] as u16);
				channel.effect = (((data[2] & 0x0f) as u16) << 8) | (data[3] as u16);
			}
		}
		module.patterns.push(pattern);
	}

	// Read all samples
	for si in &module.sample_info {
		if si.length > 0 {
			let length_in_bytes = si.length * 2;
			let mut data = vec![0u8; length_in_bytes as usize];
			try!(read_all(reader,&mut data));
			module.sample_data.push(data);
		}
	}

	// Now we have read all data.
	// Sanity check that the reader is empty
	let mut data = [0u8; 1];
	match reader.read(&mut data) {
		Ok(n) if n == data.len() => return Err(PTMFError::Parse(format!("Unread data left in file"))),
		_ => ()
	};

	Ok(module)
}
<|endoftext|>


<commit_before>/// The Toml Read extensions

use toml::Value;

use tokenizer::tokenize_with_seperator;
use error::*;

pub trait TomlValueReadExt<'doc> {

    /// Extension function for reading a value from the current toml::Value document
    /// using a custom seperator
    fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>>;

    /// Extension function for reading a value from the current toml::Value document mutably
    /// using a custom seperator
    fn read_mut_with_seperator(&'doc mut self, query: &str, sep: char) -> Result<Option<&'doc mut Value>>;

    /// Extension function for reading a value from the current toml::Value document
    fn read(&'doc self, query: &str) -> Result<Option<&'doc Value>> {
        self.read_with_seperator(query, '.')
    }

    /// Extension function for reading a value from the current toml::Value document mutably
    fn read_mut(&'doc mut self, query: &str) -> Result<Option<&'doc mut Value>> {
        self.read_mut_with_seperator(query, '.')
    }

}

impl<'doc> TomlValueReadExt<'doc> for Value {

    fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>> {
        use resolver::non_mut_resolver::resolve;

        tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
    }

    fn read_mut_with_seperator(&'doc mut self, query: &str, sep: char) -> Result<Option<&'doc mut Value>> {
        use resolver::mut_resolver::resolve;

        tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
    }

}

pub trait TomlValueReadTypeExt<'doc> {
    fn read_string(&'doc self, query: &str) -> Result<String>;
    fn read_int(&'doc self, query: &str) -> Result<i64>;
    fn read_float(&'doc self, query: &str) -> Result<f64>;
    fn read_bool(&'doc self, query: &str) -> Result<bool>;
}

macro_rules! make_type_getter {
    ($fnname:ident, $rettype:ty, $typename:expr, $matcher:pat => $implementation:expr) => {
        fn $fnname(&'doc self, query: &str) -> Result<$rettype> {
            self.read_with_seperator(query, '.').and_then(|o| match o {
                $matcher => $implementation,
                Some(o)  => Err(ErrorKind::TypeError($typename, ::util::name_of_val(&o)).into()),
                None     => Err(ErrorKind::NotAvailable(String::from(query)).into()),
            })
        }
    };
}

impl<'doc, T> TomlValueReadTypeExt<'doc> for T
    where T: TomlValueReadExt<'doc>
{
    make_type_getter!(read_string, String, "String",
                      Some(&Value::String(ref obj)) => Ok(obj.clone()));

    make_type_getter!(read_int, i64, "Integer",
                      Some(&Value::Integer(obj)) => Ok(obj));

    make_type_getter!(read_float, f64, "Float",
                      Some(&Value::Float(obj)) => Ok(obj));

    make_type_getter!(read_bool, bool, "Boolean",
                      Some(&Value::Boolean(obj)) => Ok(obj));
}

#[cfg(test)]
mod test {
    use super::*;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_read_empty() {
        let toml : Value = toml_from_str("").unwrap();

        let val  = toml.read_with_seperator(&String::from("a"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Table(_)));
        match val {
            &Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_read_table_value() {
        let toml : Value = toml_from_str(r#"
        [table]
        a = 1
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table.a"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Integer(1)));
    }

    #[test]
    fn test_read_empty_table_value() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table.a"), '.');
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_index() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table.[0]"), '.');
        assert!(val.is_err());
        let err = val.unwrap_err();

        assert!(is_match!(err.kind(), &ErrorKind::NoIndexInTable(_)));
    }

    ///
    ///
    /// Querying without specifying the seperator
    ///
    ///

    #[test]
    fn test_read_empty_without_seperator() {
        let toml : Value = toml_from_str("").unwrap();

        let val  = toml.read(&String::from("a"));
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read(&String::from("table"));

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Table(_)));
        match val {
            &Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_read_table_value_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        a = 1
        "#).unwrap();

        let val  = toml.read(&String::from("table.a"));

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Integer(1)));
    }

    #[test]
    fn test_read_empty_table_value_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read(&String::from("table.a"));
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_index_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read(&String::from("table.[0]"));
        assert!(val.is_err());
        let err = val.unwrap_err();

        assert!(is_match!(err.kind(), &ErrorKind::NoIndexInTable(_)));
    }

}

#[cfg(test)]
mod high_level_fn_test {
    use super::*;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_read_table_value() {
        let toml : Value = toml_from_str(r#"
        [table]
        a = 1
        "#).unwrap();

        let val  = toml.read_int(&String::from("table.a"));

        assert!(val.is_ok());
        assert_eq!(val.unwrap(), 1);
    }

}

<commit_msg>Add trait requirements: TomlValueReadTypeExt : TomlValueReadExt<commit_after>/// The Toml Read extensions

use toml::Value;

use tokenizer::tokenize_with_seperator;
use error::*;

pub trait TomlValueReadExt<'doc> {

    /// Extension function for reading a value from the current toml::Value document
    /// using a custom seperator
    fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>>;

    /// Extension function for reading a value from the current toml::Value document mutably
    /// using a custom seperator
    fn read_mut_with_seperator(&'doc mut self, query: &str, sep: char) -> Result<Option<&'doc mut Value>>;

    /// Extension function for reading a value from the current toml::Value document
    fn read(&'doc self, query: &str) -> Result<Option<&'doc Value>> {
        self.read_with_seperator(query, '.')
    }

    /// Extension function for reading a value from the current toml::Value document mutably
    fn read_mut(&'doc mut self, query: &str) -> Result<Option<&'doc mut Value>> {
        self.read_mut_with_seperator(query, '.')
    }

}

impl<'doc> TomlValueReadExt<'doc> for Value {

    fn read_with_seperator(&'doc self, query: &str, sep: char) -> Result<Option<&'doc Value>> {
        use resolver::non_mut_resolver::resolve;

        tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
    }

    fn read_mut_with_seperator(&'doc mut self, query: &str, sep: char) -> Result<Option<&'doc mut Value>> {
        use resolver::mut_resolver::resolve;

        tokenize_with_seperator(query, sep).and_then(move |tokens| resolve(self, &tokens, false))
    }

}

pub trait TomlValueReadTypeExt<'doc> : TomlValueReadExt<'doc> {
    fn read_string(&'doc self, query: &str) -> Result<String>;
    fn read_int(&'doc self, query: &str) -> Result<i64>;
    fn read_float(&'doc self, query: &str) -> Result<f64>;
    fn read_bool(&'doc self, query: &str) -> Result<bool>;
}

macro_rules! make_type_getter {
    ($fnname:ident, $rettype:ty, $typename:expr, $matcher:pat => $implementation:expr) => {
        fn $fnname(&'doc self, query: &str) -> Result<$rettype> {
            self.read_with_seperator(query, '.').and_then(|o| match o {
                $matcher => $implementation,
                Some(o)  => Err(ErrorKind::TypeError($typename, ::util::name_of_val(&o)).into()),
                None     => Err(ErrorKind::NotAvailable(String::from(query)).into()),
            })
        }
    };
}

impl<'doc, T> TomlValueReadTypeExt<'doc> for T
    where T: TomlValueReadExt<'doc>
{
    make_type_getter!(read_string, String, "String",
                      Some(&Value::String(ref obj)) => Ok(obj.clone()));

    make_type_getter!(read_int, i64, "Integer",
                      Some(&Value::Integer(obj)) => Ok(obj));

    make_type_getter!(read_float, f64, "Float",
                      Some(&Value::Float(obj)) => Ok(obj));

    make_type_getter!(read_bool, bool, "Boolean",
                      Some(&Value::Boolean(obj)) => Ok(obj));
}

#[cfg(test)]
mod test {
    use super::*;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_read_empty() {
        let toml : Value = toml_from_str("").unwrap();

        let val  = toml.read_with_seperator(&String::from("a"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Table(_)));
        match val {
            &Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_read_table_value() {
        let toml : Value = toml_from_str(r#"
        [table]
        a = 1
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table.a"), '.');

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Integer(1)));
    }

    #[test]
    fn test_read_empty_table_value() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table.a"), '.');
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_index() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read_with_seperator(&String::from("table.[0]"), '.');
        assert!(val.is_err());
        let err = val.unwrap_err();

        assert!(is_match!(err.kind(), &ErrorKind::NoIndexInTable(_)));
    }

    ///
    ///
    /// Querying without specifying the seperator
    ///
    ///

    #[test]
    fn test_read_empty_without_seperator() {
        let toml : Value = toml_from_str("").unwrap();

        let val  = toml.read(&String::from("a"));
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read(&String::from("table"));

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Table(_)));
        match val {
            &Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_read_table_value_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        a = 1
        "#).unwrap();

        let val  = toml.read(&String::from("table.a"));

        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_some());
        let val = val.unwrap();

        assert!(is_match!(val, &Value::Integer(1)));
    }

    #[test]
    fn test_read_empty_table_value_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read(&String::from("table.a"));
        assert!(val.is_ok());
        let val = val.unwrap();

        assert!(val.is_none());
    }

    #[test]
    fn test_read_table_index_without_seperator() {
        let toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let val  = toml.read(&String::from("table.[0]"));
        assert!(val.is_err());
        let err = val.unwrap_err();

        assert!(is_match!(err.kind(), &ErrorKind::NoIndexInTable(_)));
    }

}

#[cfg(test)]
mod high_level_fn_test {
    use super::*;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_read_table_value() {
        let toml : Value = toml_from_str(r#"
        [table]
        a = 1
        "#).unwrap();

        let val  = toml.read_int(&String::from("table.a"));

        assert!(val.is_ok());
        assert_eq!(val.unwrap(), 1);
    }

}

<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/SHA-1
// straight port from golang crypto/sha1
// library implementation

use std::io::IoResult;
use std::slice::bytes::copy_memory;

// The size of a SHA1 checksum in bytes.
static size: uint = 20;

// The blocksize of SHA1 in bytes.
static chunk:uint = 64;
static init:[u32,..5] = [0x67452301,0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];

#[cfg(not(test))]
fn main() {
	let mut d = Digest::new();
	d.write(b"The quick brown fox jumps over the lazy dog").unwrap();
    let sha1=d.sha1();

    for h in sha1.iter() {
        print!("{:x} ", *h);
    }
 }

// digest represents the partial evaluation of a checksum.
struct Digest {
	h:      [u32, ..5],
	x:      [u8, ..chunk],
	nx:     uint,
	len:    u64
}

impl Digest {
    fn new() -> Digest {
        Digest {
            h:  init,
            x:  [0u8, ..chunk],
            nx: 0u,
            len:0u64
        }
    }

    fn sha1(&mut self) -> [u8,..size] {
        let mut len = self.len;
        // Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
        let mut tmp : [u8,..64] = [0u8,..64];
        tmp[0] = 0x80u8;

        let m:uint=(len%64u64) as uint;
        if m < 56 {
            self.write(tmp.slice(0u, 56-m)).unwrap();
        } else {
            self.write(tmp.slice(0u, 64+56-m)).unwrap();
        }

        // Length in bits (=lengh in bytes*8=shift 3 bits to the right).
        len = len << 3;
        for i in range (0u, 8) {
            tmp[i] = (len >> (56u - 8*i)) as u8;
        }
        self.write(tmp.slice(0,8)).unwrap();

        assert!(self.nx == 0);

        let mut digest : [u8,..size]=[0u8,..size];
        for (i, s) in self.h.iter().enumerate() {
            digest[i*4] = (*s >> 24) as u8;
            digest[i*4+1] = (*s >> 16) as u8;
            digest[i*4+2] = (*s >> 8) as u8;
            digest[i*4+3] = *s as u8;
        }
        digest
    }

    fn process_block(&self, data:&[u8]) ->  [u32, ..5]{
        let k:[u32,..4] = [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6];

        #[inline]
        fn part(a: u32, b: u32) -> (u32, u32) {
            (a<<5 | a>>(32-5), b<<30 | b>>(32-30))
        }

        let mut w :[u32, ..16] = [0u32, ..16];

        let (mut h0, mut h1, mut h2, mut h3, mut h4) =
            (self.h[0], self.h[1], self.h[2], self.h[3], self.h[4]);

        let mut p = data;

        while p.len() >= chunk {
            for i in range(0u, 16) {
                let j = i * 4;
                w[i] =  (p[j]   as u32)<<24 |
                        (p[j+1] as u32)<<16 |
                        (p[j+2] as u32) <<8 |
                         p[j+3] as u32;
            }

            let (mut a, mut b, mut c, mut d, mut e) = (h0, h1, h2, h3, h4);

            for i in range(0u, 16) {
                let f = b & c | (!b) & d;
                let (a5, b30) = part(a, b);
                let t = a5 + f + e + w[i&0xf] + k[0];
                 b=a; a=t; e=d; d=c; c=b30;
            }
            for i in range(16u, 20) {
                let tmp = w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf];
                w[i&0xf] = tmp<<1 | tmp>>(32-1);
                let f = b & c | (!b) & d;
                let (a5, b30) = part(a, b);
                let t = a5 + f + e + w[i&0xf] + k[0];
                b=a; a=t; e=d; d=c; c=b30;
            }
            for i in range(20u, 40) {
                let tmp = w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf];
                w[i&0xf] = tmp<<1 | tmp>>(32-1);
                let f = b ^ c ^ d;
                let (a5, b30) = part(a, b);
                let t = a5 + f + e + w[i&0xf] + k[1];
                b=a; a=t; e=d; d=c; c=b30;
            }
            for i in range(40u, 60) {
                let tmp = w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf];
                w[i&0xf] = tmp<<1 | tmp>>(32-1);
                let f = ((b | c) & d) | (b & c);
                let (a5, b30) = part(a, b);
                let t = a5 + f + e + w[i&0xf] + k[2];
                b=a; a=t; e=d; d=c; c=b30;
            }
            for i in range(60u, 80) {
                let tmp = w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf];
                w[i&0xf] = tmp<<1 | tmp>>(32-1);
                let f = b ^ c ^ d;
                let (a5, b30) = part(a, b);
                let t = a5 + f + e + w[i&0xf] + k[3];
                b=a; a=t; e=d; d=c; c=b30;
            }
            h0 += a;
            h1 += b;
            h2 += c;
            h3 += d;
            h4 += e;

            p = p.tailn(chunk);
        }
        [h0, h1, h2, h3, h4]
    }
}

impl Writer for Digest {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let mut buf_m = buf;

        self.len += buf_m.len() as u64;

        if self.nx > 0 {
            let mut n = buf_m.len();
            if n > chunk - self.nx {
                n = chunk - self.nx;
            }
            for i in range(0,n) {
                self.x[self.nx + i] = *buf_m.get(i).unwrap();
            }
            self.nx += n;
            if self.nx == chunk {
                let x = self.x.as_slice();
                self.h=self.process_block(x);
                self.nx = 0;
            }
            buf_m = buf_m.tailn(n);
        }
        if buf_m.len() >= chunk {
            let n = buf_m.len() &!(chunk - 1);
            let x = self.x.slice_from(n);
            self.h=self.process_block(x);
            buf_m = buf_m.tailn(n);
        }
        let ln=buf_m.len();
        if ln > 0 {
            assert!(self.x.len() >= ln);
            copy_memory(self.x, buf_m);
            self.nx = ln;
        }
        Ok(())
    }
}

#[test]
fn known_sha1s() {
   let input_output = vec![
        (
            "His money is twice tainted: 'taint yours and 'taint mine.",
            vec!(0x59u8, 0x7f, 0x6a, 0x54, 0x0, 0x10, 0xf9, 0x4c,
                0x15, 0xd7, 0x18, 0x6, 0xa9, 0x9a, 0x2c, 0x87, 0x10,
                0xe7, 0x47, 0xbd)
         ),
        (
            "The quick brown fox jumps over the lazy dog",
            vec!(0x2fu8, 0xd4, 0xe1, 0xc6, 0x7a, 0x2d,
            0x28, 0xfc, 0xed, 0x84, 0x9e, 0xe1, 0xbb, 0x76
            , 0xe7, 0x39, 0x1b, 0x93, 0xeb, 0x12)
         ),
        (
            "The quick brown fox jumps over the lazy cog",
            vec!(0xdeu8 ,0x9f ,0x2c ,0x7f ,0xd2 ,0x5e ,0x1b ,0x3a
            ,0xfa ,0xd3 ,0xe8 ,0x5a ,0x0b ,0xd1 ,0x7d ,0x9b
            ,0x10 ,0x0d ,0xb4,0xb3)
         )];

    for &(ref i, ref o) in input_output.iter() {
        let i = i.as_slice();
        let o = o.as_slice();

        let mut d = Digest::new();
        d.write_str(i).unwrap();
        let sha1=d.sha1();

        assert_eq!(sha1.as_slice(), o);
    }
}
<commit_msg>Fix calls to deprecated tailn function<commit_after>// Implements http://rosettacode.org/wiki/SHA-1
// straight port from golang crypto/sha1
// library implementation

use std::io::IoResult;
use std::slice::bytes::copy_memory;

// The size of a SHA1 checksum in bytes.
static size: uint = 20;

// The blocksize of SHA1 in bytes.
static chunk:uint = 64;
static init:[u32,..5] = [0x67452301,0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];

#[cfg(not(test))]
fn main() {
	let mut d = Digest::new();
	d.write(b"The quick brown fox jumps over the lazy dog").unwrap();
    let sha1=d.sha1();

    for h in sha1.iter() {
        print!("{:x} ", *h);
    }
 }

// digest represents the partial evaluation of a checksum.
struct Digest {
	h:      [u32, ..5],
	x:      [u8, ..chunk],
	nx:     uint,
	len:    u64
}

impl Digest {
    fn new() -> Digest {
        Digest {
            h:  init,
            x:  [0u8, ..chunk],
            nx: 0u,
            len:0u64
        }
    }

    fn sha1(&mut self) -> [u8,..size] {
        let mut len = self.len;
        // Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
        let mut tmp : [u8,..64] = [0u8,..64];
        tmp[0] = 0x80u8;

        let m:uint=(len%64u64) as uint;
        if m < 56 {
            self.write(tmp.slice(0u, 56-m)).unwrap();
        } else {
            self.write(tmp.slice(0u, 64+56-m)).unwrap();
        }

        // Length in bits (=lengh in bytes*8=shift 3 bits to the right).
        len = len << 3;
        for i in range (0u, 8) {
            tmp[i] = (len >> (56u - 8*i)) as u8;
        }
        self.write(tmp.slice(0,8)).unwrap();

        assert!(self.nx == 0);

        let mut digest : [u8,..size]=[0u8,..size];
        for (i, s) in self.h.iter().enumerate() {
            digest[i*4] = (*s >> 24) as u8;
            digest[i*4+1] = (*s >> 16) as u8;
            digest[i*4+2] = (*s >> 8) as u8;
            digest[i*4+3] = *s as u8;
        }
        digest
    }

    fn process_block(&self, data:&[u8]) ->  [u32, ..5]{
        let k:[u32,..4] = [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6];

        #[inline]
        fn part(a: u32, b: u32) -> (u32, u32) {
            (a<<5 | a>>(32-5), b<<30 | b>>(32-30))
        }

        let mut w :[u32, ..16] = [0u32, ..16];

        let (mut h0, mut h1, mut h2, mut h3, mut h4) =
            (self.h[0], self.h[1], self.h[2], self.h[3], self.h[4]);

        let mut p = data;

        while p.len() >= chunk {
            for i in range(0u, 16) {
                let j = i * 4;
                w[i] =  (p[j]   as u32)<<24 |
                        (p[j+1] as u32)<<16 |
                        (p[j+2] as u32) <<8 |
                         p[j+3] as u32;
            }

            let (mut a, mut b, mut c, mut d, mut e) = (h0, h1, h2, h3, h4);

            for i in range(0u, 16) {
                let f = b & c | (!b) & d;
                let (a5, b30) = part(a, b);
                let t = a5 + f + e + w[i&0xf] + k[0];
                 b=a; a=t; e=d; d=c; c=b30;
            }
            for i in range(16u, 20) {
                let tmp = w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf];
                w[i&0xf] = tmp<<1 | tmp>>(32-1);
                let f = b & c | (!b) & d;
                let (a5, b30) = part(a, b);
                let t = a5 + f + e + w[i&0xf] + k[0];
                b=a; a=t; e=d; d=c; c=b30;
            }
            for i in range(20u, 40) {
                let tmp = w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf];
                w[i&0xf] = tmp<<1 | tmp>>(32-1);
                let f = b ^ c ^ d;
                let (a5, b30) = part(a, b);
                let t = a5 + f + e + w[i&0xf] + k[1];
                b=a; a=t; e=d; d=c; c=b30;
            }
            for i in range(40u, 60) {
                let tmp = w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf];
                w[i&0xf] = tmp<<1 | tmp>>(32-1);
                let f = ((b | c) & d) | (b & c);
                let (a5, b30) = part(a, b);
                let t = a5 + f + e + w[i&0xf] + k[2];
                b=a; a=t; e=d; d=c; c=b30;
            }
            for i in range(60u, 80) {
                let tmp = w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf];
                w[i&0xf] = tmp<<1 | tmp>>(32-1);
                let f = b ^ c ^ d;
                let (a5, b30) = part(a, b);
                let t = a5 + f + e + w[i&0xf] + k[3];
                b=a; a=t; e=d; d=c; c=b30;
            }
            h0 += a;
            h1 += b;
            h2 += c;
            h3 += d;
            h4 += e;

            p = p.slice_from(chunk);
        }
        [h0, h1, h2, h3, h4]
    }
}

impl Writer for Digest {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let mut buf_m = buf;

        self.len += buf_m.len() as u64;

        if self.nx > 0 {
            let mut n = buf_m.len();
            if n > chunk - self.nx {
                n = chunk - self.nx;
            }
            for i in range(0,n) {
                self.x[self.nx + i] = *buf_m.get(i).unwrap();
            }
            self.nx += n;
            if self.nx == chunk {
                let x = self.x.as_slice();
                self.h=self.process_block(x);
                self.nx = 0;
            }
            buf_m = buf_m.slice_from(n);
        }
        if buf_m.len() >= chunk {
            let n = buf_m.len() &!(chunk - 1);
            let x = self.x.slice_from(n);
            self.h=self.process_block(x);
            buf_m = buf_m.slice_from(n);
        }
        let ln=buf_m.len();
        if ln > 0 {
            assert!(self.x.len() >= ln);
            copy_memory(self.x, buf_m);
            self.nx = ln;
        }
        Ok(())
    }
}

#[test]
fn known_sha1s() {
   let input_output = vec![
        (
            "His money is twice tainted: 'taint yours and 'taint mine.",
            vec!(0x59u8, 0x7f, 0x6a, 0x54, 0x0, 0x10, 0xf9, 0x4c,
                0x15, 0xd7, 0x18, 0x6, 0xa9, 0x9a, 0x2c, 0x87, 0x10,
                0xe7, 0x47, 0xbd)
         ),
        (
            "The quick brown fox jumps over the lazy dog",
            vec!(0x2fu8, 0xd4, 0xe1, 0xc6, 0x7a, 0x2d,
            0x28, 0xfc, 0xed, 0x84, 0x9e, 0xe1, 0xbb, 0x76
            , 0xe7, 0x39, 0x1b, 0x93, 0xeb, 0x12)
         ),
        (
            "The quick brown fox jumps over the lazy cog",
            vec!(0xdeu8 ,0x9f ,0x2c ,0x7f ,0xd2 ,0x5e ,0x1b ,0x3a
            ,0xfa ,0xd3 ,0xe8 ,0x5a ,0x0b ,0xd1 ,0x7d ,0x9b
            ,0x10 ,0x0d ,0xb4,0xb3)
         )];

    for &(ref i, ref o) in input_output.iter() {
        let i = i.as_slice();
        let o = o.as_slice();

        let mut d = Digest::new();
        d.write_str(i).unwrap();
        let sha1=d.sha1();

        assert_eq!(sha1.as_slice(), o);
    }
}
<|endoftext|>


<commit_before>use std::time::Duration;
use std::cmp::min;
use std::thread;

use rustc_serialize::json::ToJson;

use super::{BosonNLP, Result};
use rep::{TextCluster, CommentsCluster, TaskStatusResp, TaskStatus, ClusterContent};
use errors::Error;

/// 聚类任务
pub trait Task {
    type Output;

    /// 批量上传需要处理的文本序列
    fn push(&mut self, contents: &[ClusterContent]) -> Result<bool>;
    /// 启动分析任务
    fn analysis(&self, alpha: f32, beta: f32) -> Result<()>;
    /// 获取任务状态
    fn status(&self) -> Result<TaskStatus>;
    /// 获取任务结果
    fn result(&self) -> Result<Self::Output>;
    /// 清空服务器端缓存的文本和结果
    fn clear(&self) -> Result<()>;
    /// 等待任务完成
    fn wait(&self, timeout: Option<u64>) -> Result<()>;
}

/// 文本聚类任务
pub struct ClusterTask<'a> {
    pub task_id: String,
    contents: Vec<ClusterContent>,
    nlp: &'a BosonNLP,
}

impl<'a> ClusterTask<'a> {
    pub fn new<T: Into<String>>(nlp: &'a BosonNLP, task_id: T) -> ClusterTask<'a> {
        ClusterTask {
            task_id: task_id.into(),
            contents: vec![],
            nlp: nlp,
        }
    }
}

impl<'a> Task for ClusterTask<'a> {
    type Output = Vec<TextCluster>;

    /// 批量上传需要处理的文本序列
    fn push(&mut self, contents: &[ClusterContent]) -> Result<bool> {
        let endpoint = format!("/cluster/push/{}", self.task_id);
        if contents.len() == 0 {
            return Ok(false);
        }
        for parts in contents.chunks(100) {
            let data = parts.to_json();
            try!(self.nlp.post(&endpoint, vec![], &data));
        }
        self.contents.extend_from_slice(contents);
        Ok(true)
    }

    /// 启动分析任务
    fn analysis(&self, alpha: f32, beta: f32) -> Result<()> {
        let endpoint = format!("/cluster/analysis/{}", self.task_id);
        let alpha_str = alpha.to_string();
        let beta_str = beta.to_string();
        let params = vec![("alpha", alpha_str.as_ref()), ("beta", beta_str.as_ref())];
        try!(self.nlp.get(&endpoint, params));
        Ok(())
    }

    /// 获取任务状态
    fn status(&self) -> Result<TaskStatus> {
        let endpoint = format!("/cluster/status/{}", self.task_id);
        let status_resp = try!(self.nlp.get::<TaskStatusResp>(&endpoint, vec![]));
        let status_str = status_resp.status.to_lowercase();
        let ret = match status_str.as_ref() {
            "received" => TaskStatus::Received,
            "running" => TaskStatus::Running,
            "done" => TaskStatus::Done,
            "error" => TaskStatus::Error,
            "not found" => return Err(Error::TaskNotFound { task_id: self.task_id.clone() }),
            _ => unreachable!(),
        };
        Ok(ret)
    }

    /// 获取任务结果
    fn result(&self) -> Result<Vec<TextCluster>> {
        let endpoint = format!("/cluster/result/{}", self.task_id);
        self.nlp.get::<Vec<TextCluster>>(&endpoint, vec![])
    }

    /// 清空服务器端缓存的文本和结果
    fn clear(&self) -> Result<()> {
        let endpoint = format!("/cluster/clear/{}", self.task_id);
        try!(self.nlp.get(&endpoint, vec![]));
        Ok(())
    }

    /// 等待任务完成
    fn wait(&self, timeout: Option<u64>) -> Result<()> {
        let mut elapsed = Duration::from_secs(0u64);
        let mut seconds_to_sleep = Duration::from_secs(0u64);
        if let Some(_timeout) = timeout {
            seconds_to_sleep = min(seconds_to_sleep, Duration::from_secs(_timeout));
        }
        let mut i = 0usize;
        loop {
            thread::sleep(seconds_to_sleep);
            let status = try!(self.status());
            if status == TaskStatus::Done {
                return Ok(());
            }
            elapsed = elapsed + seconds_to_sleep;
            if let Some(_timeout) = timeout {
                if elapsed >= Duration::from_secs(_timeout) {
                    return Err(Error::Timeout { task_id: self.task_id.clone() });
                }
            }
            i += 1usize;
            if i % 3usize == 0usize && seconds_to_sleep < Duration::from_secs(64u64) {
                seconds_to_sleep = seconds_to_sleep + seconds_to_sleep;
            }
        }
    }
}

/// 典型意见任务
pub struct CommentsTask<'a> {
    pub task_id: String,
    contents: Vec<ClusterContent>,
    nlp: &'a BosonNLP,
}

impl<'a> CommentsTask<'a> {
    pub fn new<T: Into<String>>(nlp: &'a BosonNLP, task_id: T) -> CommentsTask<'a> {
        CommentsTask {
            task_id: task_id.into(),
            contents: vec![],
            nlp: nlp,
        }
    }
}

impl<'a> Task for CommentsTask<'a> {
    type Output = Vec<CommentsCluster>;

    /// 批量上传需要处理的文本序列
    fn push(&mut self, contents: &[ClusterContent]) -> Result<bool> {
        let endpoint = format!("/comments/push/{}", self.task_id);
        if contents.len() == 0 {
            return Ok(false);
        }
        for parts in contents.chunks(100) {
            let data = parts.to_json();
            try!(self.nlp.post(&endpoint, vec![], &data));
        }
        self.contents.extend_from_slice(contents);
        Ok(true)
    }

    /// 启动分析任务
    fn analysis(&self, alpha: f32, beta: f32) -> Result<()> {
        let endpoint = format!("/comments/analysis/{}", self.task_id);
        let alpha_str = alpha.to_string();
        let beta_str = beta.to_string();
        let params = vec![("alpha", alpha_str.as_ref()), ("beta", beta_str.as_ref())];
        try!(self.nlp.get(&endpoint, params));
        Ok(())
    }

    /// 获取任务状态
    fn status(&self) -> Result<TaskStatus> {
        let endpoint = format!("/comments/status/{}", self.task_id);
        let status_resp = try!(self.nlp.get::<TaskStatusResp>(&endpoint, vec![]));
        let status_str = status_resp.status.to_lowercase();
        let ret = match status_str.as_ref() {
            "received" => TaskStatus::Received,
            "running" => TaskStatus::Running,
            "done" => TaskStatus::Done,
            "error" => TaskStatus::Error,
            "not found" => return Err(Error::TaskNotFound { task_id: self.task_id.clone() }),
            _ => unreachable!(),
        };
        Ok(ret)
    }

    /// 获取任务结果
    fn result(&self) -> Result<Vec<CommentsCluster>> {
        let endpoint = format!("/comments/result/{}", self.task_id);
        self.nlp.get::<Vec<CommentsCluster>>(&endpoint, vec![])
    }

    /// 清空服务器端缓存的文本和结果
    fn clear(&self) -> Result<()> {
        let endpoint = format!("/comments/clear/{}", self.task_id);
        try!(self.nlp.get(&endpoint, vec![]));
        Ok(())
    }

    /// 等待任务完成
    fn wait(&self, timeout: Option<u64>) -> Result<()> {
        let mut elapsed = Duration::from_secs(0u64);
        let mut seconds_to_sleep = Duration::from_secs(0u64);
        if let Some(_timeout) = timeout {
            seconds_to_sleep = min(seconds_to_sleep, Duration::from_secs(_timeout));
        }
        let mut i = 0usize;
        loop {
            thread::sleep(seconds_to_sleep);
            let status = try!(self.status());
            if status == TaskStatus::Done {
                return Ok(());
            }
            elapsed = elapsed + seconds_to_sleep;
            if let Some(_timeout) = timeout {
                if elapsed >= Duration::from_secs(_timeout) {
                    return Err(Error::Timeout { task_id: self.task_id.clone() });
                }
            }
            i += 1usize;
            if i % 3usize == 0usize && seconds_to_sleep < Duration::from_secs(64u64) {
                seconds_to_sleep = seconds_to_sleep + seconds_to_sleep;
            }
        }
    }
}
<commit_msg>Add some loggings on task module<commit_after>use std::time::Duration;
use std::cmp::min;
use std::thread;

use rustc_serialize::json::ToJson;

use super::{BosonNLP, Result};
use rep::{TextCluster, CommentsCluster, TaskStatusResp, TaskStatus, ClusterContent};
use errors::Error;

/// 聚类任务
pub trait Task {
    type Output;

    /// 批量上传需要处理的文本序列
    fn push(&mut self, contents: &[ClusterContent]) -> Result<bool>;
    /// 启动分析任务
    fn analysis(&self, alpha: f32, beta: f32) -> Result<()>;
    /// 获取任务状态
    fn status(&self) -> Result<TaskStatus>;
    /// 获取任务结果
    fn result(&self) -> Result<Self::Output>;
    /// 清空服务器端缓存的文本和结果
    fn clear(&self) -> Result<()>;
    /// 等待任务完成
    fn wait(&self, timeout: Option<u64>) -> Result<()>;
}

/// 文本聚类任务
pub struct ClusterTask<'a> {
    pub task_id: String,
    contents: Vec<ClusterContent>,
    nlp: &'a BosonNLP,
}

impl<'a> ClusterTask<'a> {
    pub fn new<T: Into<String>>(nlp: &'a BosonNLP, task_id: T) -> ClusterTask<'a> {
        ClusterTask {
            task_id: task_id.into(),
            contents: vec![],
            nlp: nlp,
        }
    }
}

impl<'a> Task for ClusterTask<'a> {
    type Output = Vec<TextCluster>;

    /// 批量上传需要处理的文本序列
    fn push(&mut self, contents: &[ClusterContent]) -> Result<bool> {
        let endpoint = format!("/cluster/push/{}", self.task_id);
        if contents.len() == 0 {
            return Ok(false);
        }
        for parts in contents.chunks(100) {
            let data = parts.to_json();
            try!(self.nlp.post(&endpoint, vec![], &data));
            info!("Pushed {} of {} documents for clustering", parts.len(), contents.len());
        }
        self.contents.extend_from_slice(contents);
        Ok(true)
    }

    /// 启动分析任务
    fn analysis(&self, alpha: f32, beta: f32) -> Result<()> {
        let endpoint = format!("/cluster/analysis/{}", self.task_id);
        let alpha_str = alpha.to_string();
        let beta_str = beta.to_string();
        let params = vec![("alpha", alpha_str.as_ref()), ("beta", beta_str.as_ref())];
        try!(self.nlp.get(&endpoint, params));
        info!("Cluster task {} analysis started", self.task_id);
        Ok(())
    }

    /// 获取任务状态
    fn status(&self) -> Result<TaskStatus> {
        let endpoint = format!("/cluster/status/{}", self.task_id);
        let status_resp = try!(self.nlp.get::<TaskStatusResp>(&endpoint, vec![]));
        let status_str = status_resp.status.to_lowercase();
        info!("Cluster task {} status: {}", self.task_id, status_str);
        let ret = match status_str.as_ref() {
            "received" => TaskStatus::Received,
            "running" => TaskStatus::Running,
            "done" => TaskStatus::Done,
            "error" => TaskStatus::Error,
            "not found" => return Err(Error::TaskNotFound { task_id: self.task_id.clone() }),
            _ => unreachable!(),
        };
        Ok(ret)
    }

    /// 获取任务结果
    fn result(&self) -> Result<Vec<TextCluster>> {
        let endpoint = format!("/cluster/result/{}", self.task_id);
        self.nlp.get::<Vec<TextCluster>>(&endpoint, vec![])
    }

    /// 清空服务器端缓存的文本和结果
    fn clear(&self) -> Result<()> {
        let endpoint = format!("/cluster/clear/{}", self.task_id);
        try!(self.nlp.get(&endpoint, vec![]));
        info!("Cluster task {} cleared", self.task_id);
        Ok(())
    }

    /// 等待任务完成
    fn wait(&self, timeout: Option<u64>) -> Result<()> {
        let mut elapsed = Duration::from_secs(0u64);
        let mut seconds_to_sleep = Duration::from_secs(0u64);
        if let Some(_timeout) = timeout {
            seconds_to_sleep = min(seconds_to_sleep, Duration::from_secs(_timeout));
        }
        let mut i = 0usize;
        loop {
            thread::sleep(seconds_to_sleep);
            let status = try!(self.status());
            if status == TaskStatus::Done {
                return Ok(());
            }
            elapsed = elapsed + seconds_to_sleep;
            if let Some(_timeout) = timeout {
                if elapsed >= Duration::from_secs(_timeout) {
                    return Err(Error::Timeout { task_id: self.task_id.clone() });
                }
            }
            i += 1usize;
            if i % 3usize == 0usize && seconds_to_sleep < Duration::from_secs(64u64) {
                seconds_to_sleep = seconds_to_sleep + seconds_to_sleep;
            }
        }
    }
}

/// 典型意见任务
pub struct CommentsTask<'a> {
    pub task_id: String,
    contents: Vec<ClusterContent>,
    nlp: &'a BosonNLP,
}

impl<'a> CommentsTask<'a> {
    pub fn new<T: Into<String>>(nlp: &'a BosonNLP, task_id: T) -> CommentsTask<'a> {
        CommentsTask {
            task_id: task_id.into(),
            contents: vec![],
            nlp: nlp,
        }
    }
}

impl<'a> Task for CommentsTask<'a> {
    type Output = Vec<CommentsCluster>;

    /// 批量上传需要处理的文本序列
    fn push(&mut self, contents: &[ClusterContent]) -> Result<bool> {
        let endpoint = format!("/comments/push/{}", self.task_id);
        if contents.len() == 0 {
            return Ok(false);
        }
        for parts in contents.chunks(100) {
            let data = parts.to_json();
            try!(self.nlp.post(&endpoint, vec![], &data));
            info!("Pushed {} of {} documents for comments clustering", parts.len(), contents.len());
        }
        self.contents.extend_from_slice(contents);
        Ok(true)
    }

    /// 启动分析任务
    fn analysis(&self, alpha: f32, beta: f32) -> Result<()> {
        let endpoint = format!("/comments/analysis/{}", self.task_id);
        let alpha_str = alpha.to_string();
        let beta_str = beta.to_string();
        let params = vec![("alpha", alpha_str.as_ref()), ("beta", beta_str.as_ref())];
        try!(self.nlp.get(&endpoint, params));
        info!("Comments task {} analysis started", self.task_id);
        Ok(())
    }

    /// 获取任务状态
    fn status(&self) -> Result<TaskStatus> {
        let endpoint = format!("/comments/status/{}", self.task_id);
        let status_resp = try!(self.nlp.get::<TaskStatusResp>(&endpoint, vec![]));
        let status_str = status_resp.status.to_lowercase();
        info!("Comments task {} status: {}", self.task_id, status_str);
        let ret = match status_str.as_ref() {
            "received" => TaskStatus::Received,
            "running" => TaskStatus::Running,
            "done" => TaskStatus::Done,
            "error" => TaskStatus::Error,
            "not found" => return Err(Error::TaskNotFound { task_id: self.task_id.clone() }),
            _ => unreachable!(),
        };
        Ok(ret)
    }

    /// 获取任务结果
    fn result(&self) -> Result<Vec<CommentsCluster>> {
        let endpoint = format!("/comments/result/{}", self.task_id);
        self.nlp.get::<Vec<CommentsCluster>>(&endpoint, vec![])
    }

    /// 清空服务器端缓存的文本和结果
    fn clear(&self) -> Result<()> {
        let endpoint = format!("/comments/clear/{}", self.task_id);
        try!(self.nlp.get(&endpoint, vec![]));
        info!("Comments task {} cleared", self.task_id);
        Ok(())
    }

    /// 等待任务完成
    fn wait(&self, timeout: Option<u64>) -> Result<()> {
        let mut elapsed = Duration::from_secs(0u64);
        let mut seconds_to_sleep = Duration::from_secs(0u64);
        if let Some(_timeout) = timeout {
            seconds_to_sleep = min(seconds_to_sleep, Duration::from_secs(_timeout));
        }
        let mut i = 0usize;
        loop {
            thread::sleep(seconds_to_sleep);
            let status = try!(self.status());
            if status == TaskStatus::Done {
                return Ok(());
            }
            elapsed = elapsed + seconds_to_sleep;
            if let Some(_timeout) = timeout {
                if elapsed >= Duration::from_secs(_timeout) {
                    return Err(Error::Timeout { task_id: self.task_id.clone() });
                }
            }
            i += 1usize;
            if i % 3usize == 0usize && seconds_to_sleep < Duration::from_secs(64u64) {
                seconds_to_sleep = seconds_to_sleep + seconds_to_sleep;
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

use serde_json::value::Value;

use priority::TaskPriority;

pub type DateTime= String; // FIXME
pub type Project = String;
pub type Status  = String;
pub type Tag     = String;
pub type UUID    = String; // FIXME
pub type Urgency = f64;

pub struct Task {
    id: u64,
    desc: String,
    entry: DateTime,
    modified: DateTime,
    priority: TaskPriority,
    project: Project,
    status: Status,
    tags: Vec<Tag>,
    uuid: UUID,
    urgency: Urgency,
}

/*
 * TODO: We do not fail if the JSON parsing fails. This panics. We rely on taskwarrior to be nice
 * to us. I guess this should be fixed.
 */
impl Task {

    pub fn new(id: u64, desc: String, entry: DateTime, modified: DateTime,
        priority: TaskPriority, project: Project, status: Status,
        tags: Vec<Tag>, uuid: UUID, urgency: Urgency)
        -> Task
    {
        Task {
            id       : id,
            desc     : desc,
            entry    : entry,
            modified : modified,
            priority : priority,
            project  : project,
            status   : status,
            tags     : tags,
            uuid     : uuid,
            urgency  : urgency,
        }
    }

    pub fn from_value(v: Value) -> Option<Task> {
        if !v.is_object() {
            return None;
        }

        let map = v.as_object().unwrap();

        let keys = [ "id", "description", "modified", "priority", "project",
            "status", "tags", "uuid", "urgency"];

        if keys.iter().any(|x| map.contains_key(*x)) {
            return None
        }

        Some(Task {
            id       : get_id(&map),
            desc     : get_desc(&map),
            entry    : get_entry(&map),
            modified : get_modified(&map),
            priority : TaskPriority::from(get_priority(&map)),
            project  : get_project(&map),
            status   : get_status(&map),
            tags     : get_tags(&map),
            uuid     : get_uuid(&map),
            urgency  : get_urgency(&map),
        })
    }

}

fn get_id(map: &BTreeMap<String, Value>) -> u64 {
    map.get("id").unwrap().as_u64().unwrap()
}

fn get_desc(map: &BTreeMap<String, Value>) -> String {
    map.get("description").unwrap().as_string().map(String::from).unwrap()
}

fn get_entry(map: &BTreeMap<String, Value>) -> String {
    map.get("entry").unwrap().as_string().map(String::from).unwrap()
}

fn get_modified(map: &BTreeMap<String, Value>) -> String {
    map.get("modified").unwrap().as_string().map(String::from).unwrap()
}

fn get_priority(map: &BTreeMap<String, Value>) -> &str {
    map.get("priority").unwrap().as_string().unwrap()
}

fn get_project(map: &BTreeMap<String, Value>) -> String {
    map.get("project").unwrap().as_string().map(String::from).unwrap()
}

fn get_status(map: &BTreeMap<String, Value>) -> String {
    map.get("status").unwrap().as_string().map(String::from).unwrap()
}

fn get_tags(map: &BTreeMap<String, Value>) -> Vec<Tag> {
    map.get("tags")
        .unwrap()
        .as_array()
        .unwrap()
        .clone()
        .into_iter()
        .map(|item| item.as_string().map(String::from).unwrap())
        .collect()
}

fn get_uuid(map: &BTreeMap<String, Value>) -> String {
    map.get("uuid").unwrap().as_string().map(String::from).unwrap()
}

fn get_urgency(map: &BTreeMap<String, Value>) -> f64 {
    map.get("urgency").unwrap().as_f64().unwrap()
}

<commit_msg>Task should derive Debug and Clone<commit_after>use std::collections::BTreeMap;

use serde_json::value::Value;

use priority::TaskPriority;

pub type DateTime= String; // FIXME
pub type Project = String;
pub type Status  = String;
pub type Tag     = String;
pub type UUID    = String; // FIXME
pub type Urgency = f64;

#[derive(Debug, Clone)]
pub struct Task {
    id: u64,
    desc: String,
    entry: DateTime,
    modified: DateTime,
    priority: TaskPriority,
    project: Project,
    status: Status,
    tags: Vec<Tag>,
    uuid: UUID,
    urgency: Urgency,
}

/*
 * TODO: We do not fail if the JSON parsing fails. This panics. We rely on taskwarrior to be nice
 * to us. I guess this should be fixed.
 */
impl Task {

    pub fn new(id: u64, desc: String, entry: DateTime, modified: DateTime,
        priority: TaskPriority, project: Project, status: Status,
        tags: Vec<Tag>, uuid: UUID, urgency: Urgency)
        -> Task
    {
        Task {
            id       : id,
            desc     : desc,
            entry    : entry,
            modified : modified,
            priority : priority,
            project  : project,
            status   : status,
            tags     : tags,
            uuid     : uuid,
            urgency  : urgency,
        }
    }

    pub fn from_value(v: Value) -> Option<Task> {
        if !v.is_object() {
            return None;
        }

        let map = v.as_object().unwrap();

        let keys = [ "id", "description", "modified", "priority", "project",
            "status", "tags", "uuid", "urgency"];

        if keys.iter().any(|x| map.contains_key(*x)) {
            return None
        }

        Some(Task {
            id       : get_id(&map),
            desc     : get_desc(&map),
            entry    : get_entry(&map),
            modified : get_modified(&map),
            priority : TaskPriority::from(get_priority(&map)),
            project  : get_project(&map),
            status   : get_status(&map),
            tags     : get_tags(&map),
            uuid     : get_uuid(&map),
            urgency  : get_urgency(&map),
        })
    }

}

fn get_id(map: &BTreeMap<String, Value>) -> u64 {
    map.get("id").unwrap().as_u64().unwrap()
}

fn get_desc(map: &BTreeMap<String, Value>) -> String {
    map.get("description").unwrap().as_string().map(String::from).unwrap()
}

fn get_entry(map: &BTreeMap<String, Value>) -> String {
    map.get("entry").unwrap().as_string().map(String::from).unwrap()
}

fn get_modified(map: &BTreeMap<String, Value>) -> String {
    map.get("modified").unwrap().as_string().map(String::from).unwrap()
}

fn get_priority(map: &BTreeMap<String, Value>) -> &str {
    map.get("priority").unwrap().as_string().unwrap()
}

fn get_project(map: &BTreeMap<String, Value>) -> String {
    map.get("project").unwrap().as_string().map(String::from).unwrap()
}

fn get_status(map: &BTreeMap<String, Value>) -> String {
    map.get("status").unwrap().as_string().map(String::from).unwrap()
}

fn get_tags(map: &BTreeMap<String, Value>) -> Vec<Tag> {
    map.get("tags")
        .unwrap()
        .as_array()
        .unwrap()
        .clone()
        .into_iter()
        .map(|item| item.as_string().map(String::from).unwrap())
        .collect()
}

fn get_uuid(map: &BTreeMap<String, Value>) -> String {
    map.get("uuid").unwrap().as_string().map(String::from).unwrap()
}

fn get_urgency(map: &BTreeMap<String, Value>) -> f64 {
    map.get("urgency").unwrap().as_f64().unwrap()
}

<|endoftext|>