<commit_before>#![crate_id = "rustyredis#0.1"]
#![desc = "A Rust client library for Redis based off hiredis"]
#![crate_type = "lib"]

use std::io::net::tcp::TcpStream;

enum Global {
  RedisReaderMaxBuf = 1024 * 16
}

#[deriving(Clone)]
pub enum RedisReply {
  RedisString(String),
  RedisInteger(int),
  RedisNil,
  RedisStatus(String),
  RedisError(String)
}

enum RedisError {
  RedisNoError,
  RedisIoError,
  RedisProcessError
}

struct RedisReadTask {
  kind: int,
  elm: int,
  idx: int,
  obj: String, // this prob isn't right
}

struct RedisReader {
  err: RedisError,
  errstr: String,
  buf: String,
  reply: RedisReply,
  pos: int,
  len: int,
  rstack: [RedisReadTask, ..9],
  ridx: int
}

pub struct RedisContext {
  err: RedisError,
  errstr: String,
  tcpstream: TcpStream,
  flags: int,
  obuf: String,
  reader: RedisReader
}

impl RedisReadTask {
  fn new() -> RedisReadTask {
    RedisReadTask {
      kind: -1,
      elm: -1,
      idx: -1,
      obj: String::new(),
    }
  }
}

impl RedisReader {
  fn process_item(&self) -> Result<(), String> {
    unimplemented!();
  }

  fn process_reply(&mut self) -> Result<Option<RedisReply>, String> {
    if self.len == 0 {
      return Ok(Some(RedisNil))
    }

    if self.ridx == -1 {
      self.ridx = 0;
    }

    while self.ridx >= 0 {
      match self.process_item(){
        Err(s) => { self.set_error(RedisProcessError, s.as_slice()); return Err(s) },
        _ => ()
      }
    }

    Ok(Some(self.reply.clone()))
  }

  fn feed(&mut self, buf: &mut [u8], len: uint){
    let mut i = 0;
    while i < len {
      let c = buf[i].to_ascii();
      self.buf.push_char(c.to_char());
      i = i + 1;
    }
    println!("{}", self.buf);
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_str();
  }

  fn new() -> RedisReader {
    RedisReader {
      err: RedisNoError,
      errstr: String::new(),
      buf: String::new(),
      reply: RedisNil,
      pos: 0,
      len: 0,
      rstack: [RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new()],
      ridx: -1
    }
  }
}

impl RedisContext {
  fn format_command(&self, format: &str) -> String {
    let mut argc: uint = 0;
    let mut c = String::new();
    let mut finalc = String::new();

    for arg in format.split(' '){
      let arglen = arg.len();
      c = c.append("$");
      c = c.append(arglen.to_str().as_slice());
      c = c.append("\r\n");
      c = c.append(arg);
      c = c.append("\r\n");
      argc = argc + 1;
    }
    finalc = finalc.append("*");
    finalc = finalc.append(argc.to_str().as_slice());
    finalc = finalc.append("\r\n");
    finalc = finalc.append(c.as_slice());
    finalc
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_str();
  }

  fn get_reply_reader(&mut self) -> Result<Option<RedisReply>, String> {
    self.reader.process_reply()
  }

  fn buffer_write(&mut self) -> int {
    println!("{}", self.obuf);
    match self.tcpstream.write_str(self.obuf.as_slice()){
      Err(e) => { self.set_error(RedisIoError, e.desc ); 1 }
      _ => 0
    }
  }

  fn buffer_read(&mut self) -> int {
    let mut buf = [0, ..RedisReaderMaxBuf as uint];
    let res = self.tcpstream.read(buf);
    match res {
      Ok(s) => { self.reader.feed(buf, s); 0 },
      Err(e) => { self.set_error(RedisIoError, e.desc); 1 }
    }

  }

  fn block_for_reply(&mut self) -> Result<Option<RedisReply>, String> {
    let o = try!(self.get_reply_reader());
    match o {
      Some(s) => Ok(Some(s)),
      None => {
        self.buffer_write();
        self.buffer_read();
        let o2 = try!(self.get_reply_reader());
        match o2{
          Some(s) => Ok(Some(s)),
          None => Err("Error".to_str())
        }
      }
    }
  }

  pub fn connect(ip: &str, port: u16) -> RedisContext {
    RedisContext {
      err: RedisNoError,
      errstr: String::new(),
      tcpstream: match TcpStream::connect(ip, port) {
        Ok(s) => s,
        Err(e) => fail!(e.desc)
      },
      flags: 0,
      obuf: String::new(),
      reader: RedisReader::new()
    }
  }

  pub fn command(&mut self, command: &str) -> Result<Option<RedisReply>, String> {
    self.obuf = self.format_command(command);
    self.block_for_reply()
  }
}

<commit_msg>Supports sync RedisError, RedisStatus, RedisInteger reply types<commit_after>#![crate_id = "rustyredis#0.1"]
#![desc = "A Rust client library for Redis based off hiredis"]
#![crate_type = "lib"]

use std::io::net::tcp::TcpStream;
use std::io::BufReader;
use std::int::parse_bytes;

enum Global {
  RedisReaderMaxBuf = 1024 * 16
}

enum RedisReplyType {
  RedisReplyString,
  RedisReplyInteger,
  RedisReplyArray,
  RedisReplyNil,
  RedisReplyStatus,
  RedisReplyError
}

#[deriving(Clone)]
pub enum RedisObject {
  RedisString(String),
  RedisInteger(int),
  RedisArray(Vec<RedisObject>),
  RedisNil,
  RedisStatus(String),
  RedisError(String)
}

enum RedisError {
  RedisNoError,
  RedisIoError,
  RedisProcessError
}

struct RedisReadTask {
  kind: RedisReplyType,
  elm: int,
  idx: int,
  obj: RedisObject
}

struct RedisReader {
  err: RedisError,
  errstr: String,
  buf: String,
  reply: RedisObject,
  pos: uint,
  len: uint,
  rstack: [RedisReadTask, ..9],
  ridx: int
}

pub struct RedisContext {
  err: RedisError,
  errstr: String,
  tcpstream: TcpStream,
  flags: int,
  obuf: String,
  reader: RedisReader
}

impl RedisReadTask {
  fn new() -> RedisReadTask {
    RedisReadTask {
      kind: RedisReplyNil,
      elm: -1,
      idx: -1,
      obj: RedisNil,
    }
  }
}

impl RedisReader {
  fn create_integer(&self, s: &str) -> Result<RedisObject, &str> {
    match parse_bytes(s.as_bytes(), 10) {
      Some(n) => Ok(RedisInteger(n)),
      None => Err("Invalid integer for create_integer")
    }
  }

  fn process_line_item(&mut self) -> Result<(), &str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    match reader.read_line() {
      Ok(s) => {
        let mut ns = s.clone();
        ns.shift_char(); // this is dirty and quick
        let nns = ns.as_slice().trim();

        match self.rstack[self.ridx as uint].kind {
          RedisReplyStatus => self.reply = RedisStatus(nns.to_str()),
          RedisReplyError => self.reply = RedisError(nns.to_str()),
          RedisReplyInteger => match self.create_integer(nns) {
            Ok(n) => self.reply = n,
            Err(e) => return Err(e)
          },
          _ => return Err("Invalid type for process_line_item")
        };
        Ok(())
      },
      Err(e) => Err(e.desc)
    }
  }

  fn process_bulk_item(&mut self) -> Result<(), &str> {
    unimplemented!();
  }

  fn process_multi_bulk_item(&mut self) -> Result<(), &str> {
    unimplemented!();
  }

  fn process_item(&mut self) -> Result<(), &str> {
    match self.rstack[self.ridx as uint].kind {
      RedisReplyError => self.process_line_item(),
      RedisReplyStatus => self.process_line_item(),
      RedisReplyInteger => self.process_line_item(),
      RedisReplyString => self.process_bulk_item(),
      RedisReplyArray => self.process_multi_bulk_item(),
      _ => Err("This should never happen")
    }
  }

  fn check_reply_type(&mut self) -> Result<(), &str> {
    let mut kind: RedisReplyType;
    let slice = self.buf.as_slice();
    match slice.char_at(0) {
      '-' => kind = RedisReplyError,
      '+' => kind = RedisReplyStatus,
      ':' => kind = RedisReplyInteger,
      '$' => kind = RedisReplyString,
      '*' => kind = RedisReplyArray,
      _ =>  return Err("Failed reading control byte")
    }

    self.rstack[self.ridx as uint].kind = kind;
    Ok(())
  }

  fn process_reply(&mut self) -> Result<Option<RedisObject>, &str> {
    if self.len == 0 {
      return Ok(None)
    }

    if self.ridx == -1 {
      self.ridx = 0;
    }

    while self.ridx >= 0 {
      match self.check_reply_type(){
        Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
        _ => match self.process_item() {
               Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
               _ => self.ridx = self.ridx - 1
             }
      }
    }

    Ok(Some(self.reply.clone()))
  }

  fn feed(&mut self, buf: &mut [u8], len: uint){
    let mut i = 0;
    while i < len {
      let c = buf[i].to_ascii();
      self.buf.push_char(c.to_char());
      i = i + 1;
    }
    self.len = len;
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_str();
  }

  fn new() -> RedisReader {
    RedisReader {
      err: RedisNoError,
      errstr: String::new(),
      buf: String::new(),
      reply: RedisNil,
      pos: 0,
      len: 0,
      rstack: [RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new()],
      ridx: -1
    }
  }
}

impl RedisContext {
  fn format_command(&self, format: &str) -> String {
    let mut argc: uint = 0;
    let mut c = String::new();
    let mut finalc = String::new();

    for arg in format.split(' '){
      let arglen = arg.len();
      c = c.append("$");
      c = c.append(arglen.to_str().as_slice());
      c = c.append("\r\n");
      c = c.append(arg);
      c = c.append("\r\n");
      argc = argc + 1;
    }
    finalc = finalc.append("*");
    finalc = finalc.append(argc.to_str().as_slice());
    finalc = finalc.append("\r\n");
    finalc = finalc.append(c.as_slice());
    finalc
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_str();
  }

  fn get_reply_reader(&mut self) -> Result<Option<RedisObject>, &str> {
    self.reader.process_reply()
  }

  fn buffer_write(&mut self) -> int {
    match self.tcpstream.write_str(self.obuf.as_slice()){
      Err(e) => { self.set_error(RedisIoError, e.desc ); 1 }
      _ => 0
    }
  }

  fn buffer_read(&mut self) -> int {
    let mut buf = [0, ..RedisReaderMaxBuf as uint];
    let res = self.tcpstream.read(buf);
    match res {
      Ok(s) => { self.reader.feed(buf, s); 0 },
      Err(e) => { self.set_error(RedisIoError, e.desc); 1 }
    }

  }

  fn block_for_reply(&mut self) -> Result<Option<RedisObject>, &str> {
    let o = try!(self.get_reply_reader());
    match o {
      Some(s) => Ok(Some(s)),
      None => {
        self.buffer_write();
        self.buffer_read();
        let o2 = try!(self.get_reply_reader());
        match o2{
          Some(s) => Ok(Some(s)),
          None => Err("No reply was found")
        }
      }
    }
  }

  pub fn connect(ip: &str, port: u16) -> RedisContext {
    RedisContext {
      err: RedisNoError,
      errstr: String::new(),
      tcpstream: match TcpStream::connect(ip, port) {
        Ok(s) => s,
        Err(e) => fail!(e.desc)
      },
      flags: 0,
      obuf: String::new(),
      reader: RedisReader::new()
    }
  }

  pub fn command(&mut self, command: &str) -> Result<Option<RedisObject>, &str> {
    self.obuf = self.format_command(command);
    self.block_for_reply()
  }
}

<|endoftext|>


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

use id::Id;
use resource::{Cache, Load, Get, Reload};

/// The scene type.
///
/// This type gathers all the required objects a scene needs to correctly handle and render all
/// visual effects.
pub struct Scene<'a> {
  /// Cache.
  cache: Cache<'a>
}

impl<'a> Scene<'a> {
  pub fn new<P>(root: P) -> Self where P: AsRef<Path>{
    Scene {
      cache: Cache::new(root),
    }
  }

  pub fn get_id<T>(&mut self, name: &str, args: <T as Load<'a>>::Args) -> Option<Id<'a, T>> where Cache<'a>: Get<'a, T>, T: 'a + Reload<'a> {
    self.cache.get_id(name, args)
  }

  pub fn get_by_id<T>(&mut self, id: &Id<'a, T>) -> Option<&T> where Cache<'a>: Get<'a, T>, T: 'a + Reload<'a> {
    self.cache.get_by_id(id)
  }

  pub fn get<T>(&mut self, name: &str, args: <T as Load<'a>>::Args) -> Option<&T> where Cache<'a>: Get<'a, T>, T: 'a + Reload<'a> {
    self.cache.get(name, args)
  }
}

#[macro_export]
macro_rules! get_id {
  ($scene:ident, $name:expr) => {
    $scene.get_id($name, ())
  };

  ($scene:ident, $name:expr, $($arg:expr),*) => {
    $scene.get_id($name, ($($arg),*))
  }
}

#[macro_export]
macro_rules! get {
  ($scene:ident, $name:expr) => {
    $scene.get($name, ())
  };

  ($scene:ident, $name:expr, $($arg:expr),*) => {
    $scene.get($name, ($($arg),*))
  }
}
<commit_msg>Expose the cache from scene.<commit_after>use std::path::Path;

use id::Id;
use resource::{Cache, Load, Get, Reload};

/// The scene type.
///
/// This type gathers all the required objects a scene needs to correctly handle and render all
/// visual effects.
pub struct Scene<'a> {
  /// Cache.
  pub cache: Cache<'a>
}

impl<'a> Scene<'a> {
  pub fn new<P>(root: P) -> Self where P: AsRef<Path>{
    Scene {
      cache: Cache::new(root),
    }
  }

  pub fn get_id<T>(&mut self, name: &str, args: <T as Load<'a>>::Args) -> Option<Id<'a, T>> where Cache<'a>: Get<'a, T>, T: 'a + Reload<'a> {
    self.cache.get_id(name, args)
  }

  pub fn get_by_id<T>(&mut self, id: &Id<'a, T>) -> Option<&T> where Cache<'a>: Get<'a, T>, T: 'a + Reload<'a> {
    self.cache.get_by_id(id)
  }

  pub fn get<T>(&mut self, name: &str, args: <T as Load<'a>>::Args) -> Option<&T> where Cache<'a>: Get<'a, T>, T: 'a + Reload<'a> {
    self.cache.get(name, args)
  }
}

#[macro_export]
macro_rules! get_id {
  ($scene:ident, $name:expr) => {
    $scene.get_id($name, ())
  };

  ($scene:ident, $name:expr, $($arg:expr),*) => {
    $scene.get_id($name, ($($arg),*))
  }
}

#[macro_export]
macro_rules! get {
  ($scene:ident, $name:expr) => {
    $scene.get($name, ())
  };

  ($scene:ident, $name:expr, $($arg:expr),*) => {
    $scene.get($name, ($($arg),*))
  }
}
<|endoftext|>


<commit_before>use rusqlite::{params, Connection};
use std::collections::HashMap;
use std::path::Path;
use std::result::Result as Result_;
use thiserror::Error;

pub type Result<T, E = StoreError> = Result_<T, E>;

#[derive(Error, Debug)]
pub enum StoreError {
    #[error("database error")]
    Sqlite(#[from] rusqlite::Error),

    #[error("could not de/serialize object")]
    Serialization(#[from] serde_json::Error),
}

trait AsStoreResult<T> {
    fn as_store_result(self) -> Result<T>;
}

impl<T, E> AsStoreResult<T> for Result_<T, E>
where
    E: Into<StoreError>,
{
    fn as_store_result(self) -> Result<T> {
        self.map_err(|e| e.into())
    }
}

pub type Object = HashMap<String, serde_json::Value>;

pub struct Store {
    conn: Connection,
}

impl Store {
    pub fn open(path: impl AsRef<Path>) -> Result<Store> {
        let mut store = Store {
            conn: Connection::open(path)?,
        };

        // Make SQLite use a write-ahead instead of a delete-based journal; see
        // [the SQLite documentation](https://www.sqlite.org/wal.html) for more info.
        store.conn.pragma_update(None, "journal_mode", &"WAL")?;

        // Check that the JSON1 extension is working.
        store
            .conn
            .prepare("SELECT json(\"{}\")")?
            .query(params![])
            // Explicitly ignore the value.
            .map(|_| {})?;

        store.upgrade_if_needed()?;

        Ok(store)
    }

    fn upgrade_if_needed(&mut self) -> Result<()> {
        // We check the version of the database and upgrade it if necessary.
        // Conveniently, this starts at 0 in an empty database.
        let version = self
            .conn
            .prepare("SELECT user_version from pragma_user_version")?
            .query_row(params![], |row| row.get::<usize, i64>(0))? as usize;

        // We use `AUTOINCREMENT` on the objects table so that IDs are not reused.
        let updates = [
            "
                        CREATE TABLE objects (
                                object_id INTEGER PRIMARY KEY AUTOINCREMENT,
                                properties TEXT
                        );
                ",
            "
                        CREATE TABLE object_changes (
                                serial INTEGER PRIMARY KEY,
                                timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                                object_id INTEGER,
                                action TEXT,
                                previous TEXT
                        );
                        CREATE TABLE checkpoints (
                                checkpoint_id INTEGER PRIMARY KEY,
                                timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                                serial INTEGER
                        );
                ",
        ];

        // We set the `user_version` after each update to ensure updates are not applied twice if one
        // in a sequence of updates fails.
        for (version, update) in updates.iter().enumerate().skip(version) {
            self.conn.execute_batch(update)?;
            self.conn
                .pragma_update(None, "user_version", &(version as i64))?;
        }

        Ok(())
    }

    pub fn all(&self) -> Collection {
        Collection { conn: &self.conn }
    }

    pub fn add(&mut self, object: Object) -> Result<()> {
        let object_serialized = serde_json::to_string(&object)?;

        self.conn
            .prepare("INSERT INTO objects(properties) VALUES(?)")?
            .execute(params![object_serialized])?;

        Ok(())
    }
}

pub struct Collection<'a> {
    conn: &'a Connection,
}

impl<'a> Collection<'a> {
    pub fn len(&self) -> Result<usize> {
        Ok(self
            .conn
            .prepare("SELECT COUNT(*) FROM objects")?
            .query_row(params![], |row| row.get::<usize, i64>(0))? as usize)
    }

    pub fn iter(&self) -> Result<impl Iterator<Item = Object> + 'a> {
        Ok(self
            .conn
            .prepare("SELECT properties FROM objects")?
            .query_and_then(params![], |row| row.get::<usize, String>(0))?
            .map(|r| {
                r.as_store_result().and_then(|serialized_object| {
                    serde_json::from_str(&serialized_object).as_store_result()
                })
            })
            .collect::<Result<Vec<Object>>>()?
            .into_iter())
    }
}

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

    fn open_store(tempdir: &TempDir, name: &str) -> Store {
        Store::open(tempdir.path().join(name)).unwrap()
    }

    fn test_dir() -> TempDir {
        TempDir::new("qualia-store").unwrap()
    }

    fn mkobject<'a>(proplist: &'a [(&'a str, &'a str)]) -> Object {
        proplist
            .iter()
            .cloned()
            .map(|(k, v)| (k.to_string(), serde_json::Value::String(v.to_string())))
            .collect()
    }

    #[test]
    fn new_store_is_empty() {
        assert_eq!(
            open_store(&test_dir(), "store.qualia").all().len().unwrap(),
            0
        );
    }

    #[test]
    fn added_object_can_be_found() {
        let test_dir = test_dir();
        let mut store = open_store(&test_dir, "store.qualia");

        store.add(mkobject(&[("a", "b"), ("c", "d")])).unwrap();

        let all = store.all();

        assert_eq!(all.len().unwrap(), 1);
        assert_eq!(
            all.iter().unwrap().collect::<Vec<Object>>(),
            vec![mkobject(&[("a", "b"), ("c", "d")])]
        );
    }
}
<commit_msg>Flesh out object retrieval testing<commit_after>use rusqlite::{params, Connection};
use std::collections::HashMap;
use std::path::Path;
use std::result::Result as Result_;
use thiserror::Error;

pub type Result<T, E = StoreError> = Result_<T, E>;

#[derive(Error, Debug)]
pub enum StoreError {
    #[error("database error")]
    Sqlite(#[from] rusqlite::Error),

    #[error("could not de/serialize object")]
    Serialization(#[from] serde_json::Error),
}

trait AsStoreResult<T> {
    fn as_store_result(self) -> Result<T>;
}

impl<T, E> AsStoreResult<T> for Result_<T, E>
where
    E: Into<StoreError>,
{
    fn as_store_result(self) -> Result<T> {
        self.map_err(|e| e.into())
    }
}

pub type Object = HashMap<String, serde_json::Value>;

pub struct Store {
    conn: Connection,
}

impl Store {
    pub fn open(path: impl AsRef<Path>) -> Result<Store> {
        let mut store = Store {
            conn: Connection::open(path)?,
        };

        // Make SQLite use a write-ahead instead of a delete-based journal; see
        // [the SQLite documentation](https://www.sqlite.org/wal.html) for more info.
        store.conn.pragma_update(None, "journal_mode", &"WAL")?;

        // Check that the JSON1 extension is working.
        store
            .conn
            .prepare("SELECT json(\"{}\")")?
            .query(params![])
            // Explicitly ignore the value.
            .map(|_| {})?;

        store.upgrade_if_needed()?;

        Ok(store)
    }

    fn upgrade_if_needed(&mut self) -> Result<()> {
        // We check the version of the database and upgrade it if necessary.
        // Conveniently, this starts at 0 in an empty database.
        let version = self
            .conn
            .prepare("SELECT user_version from pragma_user_version")?
            .query_row(params![], |row| row.get::<usize, i64>(0))? as usize;

        // We use `AUTOINCREMENT` on the objects table so that IDs are not reused.
        let updates = [
            "
                        CREATE TABLE objects (
                                object_id INTEGER PRIMARY KEY AUTOINCREMENT,
                                properties TEXT
                        );
                ",
            "
                        CREATE TABLE object_changes (
                                serial INTEGER PRIMARY KEY,
                                timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                                object_id INTEGER,
                                action TEXT,
                                previous TEXT
                        );
                        CREATE TABLE checkpoints (
                                checkpoint_id INTEGER PRIMARY KEY,
                                timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                                serial INTEGER
                        );
                ",
        ];

        // We set the `user_version` after each update to ensure updates are not applied twice if one
        // in a sequence of updates fails.
        for (version, update) in updates.iter().enumerate().skip(version) {
            self.conn.execute_batch(update)?;
            self.conn
                .pragma_update(None, "user_version", &(version as i64))?;
        }

        Ok(())
    }

    pub fn all(&self) -> Collection {
        Collection { conn: &self.conn }
    }

    pub fn add(&mut self, object: Object) -> Result<()> {
        let object_serialized = serde_json::to_string(&object)?;

        self.conn
            .prepare("INSERT INTO objects(properties) VALUES(?)")?
            .execute(params![object_serialized])?;

        Ok(())
    }
}

pub struct Collection<'a> {
    conn: &'a Connection,
}

impl<'a> Collection<'a> {
    pub fn len(&self) -> Result<usize> {
        Ok(self
            .conn
            .prepare("SELECT COUNT(*) FROM objects")?
            // This workaround can be removed when https://github.com/rusqlite/rusqlite/issues/700
            // is closed
            .query_row(params![], |row| row.get::<usize, i64>(0))? as usize)
    }

    pub fn iter(&self) -> Result<impl Iterator<Item = Object> + 'a> {
        Ok(self
            .conn
            .prepare("SELECT properties FROM objects")?
            .query_and_then(params![], |row| row.get::<usize, String>(0))?
            .map(|r| {
                r.as_store_result().and_then(|serialized_object| {
                    serde_json::from_str(&serialized_object).as_store_result()
                })
            })
            .collect::<Result<Vec<Object>>>()?
            .into_iter())
    }
}

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

    fn open_store(tempdir: &TempDir, name: &str) -> Store {
        Store::open(tempdir.path().join(name)).unwrap()
    }

    fn test_dir() -> TempDir {
        TempDir::new("qualia-store").unwrap()
    }

    fn mkobject<'a>(proplist: &'a [(&'a str, &'a str)]) -> Object {
        proplist
            .iter()
            .cloned()
            .map(|(k, v)| (k.to_string(), serde_json::Value::String(v.to_string())))
            .collect()
    }

    fn sort_objects(objects: &mut Vec<Object>) {
        objects.sort_by_key(|o| {
            o.get("name")
                .and_then(|v| Some(v.as_str().unwrap_or("")))
                .unwrap_or("")
                .to_string()
        })
    }

    #[test]
    fn new_store_is_empty() {
        assert_eq!(
            open_store(&test_dir(), "store.qualia").all().len().unwrap(),
            0
        );
    }

    #[test]
    fn added_objects_can_be_found() {
        let test_dir = test_dir();
        let mut store = open_store(&test_dir, "store.qualia");

        store.add(mkobject(&[("name", "b"), ("c", "d")])).unwrap();
        store.add(mkobject(&[("name", "d"), ("c", "f")])).unwrap();
        store.add(mkobject(&[("name", "c"), ("c", "e")])).unwrap();

        let all = store.all();

        assert_eq!(all.len().unwrap(), 3);
        let mut all_objects = all.iter().unwrap().collect::<Vec<Object>>();
        sort_objects(&mut all_objects);
        assert_eq!(
            all_objects,
            vec![
                mkobject(&[("name", "b"), ("c", "d")]),
                mkobject(&[("name", "c"), ("c", "e")]),
                mkobject(&[("name", "d"), ("c", "f")])
            ],
        );
    }
}
<|endoftext|>


<commit_before>/// A style is a collection of properties that can format a string
/// using ANSI escape codes.
#[derive(PartialEq, Clone, Copy)]
pub struct Style {

    /// The style's foreground colour, if it has one.
    pub foreground: Option<Colour>,

    /// The style's background colour, if it has one.
    pub background: Option<Colour>,

    /// Whether this style is bold.
    pub is_bold: bool,

    /// Whether this style is dimmed.
    pub is_dimmed: bool,

    /// Whether this style is italic.
    pub is_italic: bool,

    /// Whether this style is underlined.
    pub is_underline: bool,

    /// Whether this style is blinking.
    pub is_blink: bool,

    /// Whether this style has reverse colours.
    pub is_reverse: bool,

    /// Whether this style is hidden.
    pub is_hidden: bool,

    /// Whether this style is struckthrough.
    pub is_strikethrough: bool
}

impl Style {
    /// Creates a new Style with no differences.
    pub fn new() -> Style {
        Style::default()
    }

    /// Returns a Style with the bold property set.
    pub fn bold(&self) -> Style {
        Style { is_bold: true, .. *self }
    }

    /// Returns a Style with the dimmed property set.
    pub fn dimmed(&self) -> Style {
        Style { is_dimmed: true, .. *self }
    }

    /// Returns a Style with the italic property set.
    pub fn italic(&self) -> Style {
        Style { is_italic: true, .. *self }
    }

    /// Returns a Style with the underline property set.
    pub fn underline(&self) -> Style {
        Style { is_underline: true, .. *self }
    }

    /// Returns a Style with the blink property set.
    pub fn blink(&self) -> Style {
        Style { is_blink: true, .. *self }
    }

    /// Returns a Style with the reverse property set.
    pub fn reverse(&self) -> Style {
        Style { is_reverse: true, .. *self }
    }

    /// Returns a Style with the hidden property set.
    pub fn hidden(&self) -> Style {
        Style { is_hidden: true, .. *self }
    }

    /// Returns a Style with the hidden property set.
    pub fn strikethrough(&self) -> Style {
        Style { is_strikethrough: true, .. *self }
    }

    /// Returns a Style with the foreground colour property set.
    pub fn fg(&self, foreground: Colour) -> Style {
        Style { foreground: Some(foreground), .. *self }
    }

    /// Returns a Style with the background colour property set.
    pub fn on(&self, background: Colour) -> Style {
        Style { background: Some(background), .. *self }
    }

    /// Return true if this `Style` has no actual styles, and can be written
    /// without any control characters.
    pub fn is_plain(self) -> bool {
        self == Style::default()
    }
}

impl Default for Style {
    fn default() -> Style {
        Style {
            foreground: None,
            background: None,
            is_bold: false,
            is_dimmed: false,
            is_italic: false,
            is_underline: false,
            is_blink: false,
            is_reverse: false,
            is_hidden: false,
            is_strikethrough: false,
        }
    }
}

// ---- colours ----

/// A colour is one specific type of ANSI escape code, and can refer
/// to either the foreground or background colour.
///
/// These use the standard numeric sequences.
/// See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum Colour {

    /// Colour #0 (foreground code `30`, background code `40`).
    ///
    /// This is not necessarily the background colour, and using it as one may
    /// render the text hard to read on terminals with dark backgrounds.
    Black,

    /// Colour #1 (foreground code `31`, background code `41`).
    Red,

    /// Colour #2 (foreground code `32`, background code `42`).
    Green,

    /// Colour #3 (foreground code `33`, background code `43`).
    Yellow,

    /// Colour #4 (foreground code `34`, background code `44`).
    Blue,

    /// Colour #5 (foreground code `35`, background code `45`).
    Purple,

    /// Colour #6 (foreground code `36`, background code `46`).
    Cyan,

    /// Colour #7 (foreground code `37`, background code `47`).
    ///
    /// As above, this is not necessarily the foreground colour, and may be
    /// hard to read on terminals with light backgrounds.
    White,

    /// A colour number from 0 to 255, for use in 256-colour terminal
    /// environments.
    ///
    /// - Colours 0 to 7 are the `Black` to `White` variants respectively.
    ///   These colours can usually be changed in the terminal emulator.
    /// - Colours 8 to 15 are brighter versions of the eight colours above.
    ///   These can also usually be changed in the terminal emulator, or it
    ///   could be configured to use the original colours and show the text in
    ///   bold instead. It varies depending on the program.
    /// - Colours 16 to 231 contain several palettes of bright colours,
    ///   arranged in six squares measuring six by six each.
    /// - Colours 232 to 255 are shades of grey from black to white.
    ///
    /// It might make more sense to look at a [colour chart][cc].
    /// [cc]: https://upload.wikimedia.org/wikipedia/en/1/15/Xterm_256color_chart.svg
    Fixed(u8),

    /// A 24-bit RGB color, as specified by ISO-8613-3.
    RGB(u8, u8, u8),
}

impl Colour {
    /// Return a Style with the foreground colour set to this colour.
    pub fn normal(self) -> Style {
        Style { foreground: Some(self), .. Style::default() }
    }

    /// Returns a Style with the bold property set.
    pub fn bold(self) -> Style {
        Style { foreground: Some(self), is_bold: true, .. Style::default() }
    }

    /// Returns a Style with the dimmed property set.
    pub fn dimmed(self) -> Style {
        Style { foreground: Some(self), is_dimmed: true, .. Style::default() }
    }

    /// Returns a Style with the italic property set.
    pub fn italic(self) -> Style {
        Style { foreground: Some(self), is_italic: true, .. Style::default() }
    }

    /// Returns a Style with the underline property set.
    pub fn underline(self) -> Style {
        Style { foreground: Some(self), is_underline: true, .. Style::default() }
    }

    /// Returns a Style with the blink property set.
    pub fn blink(self) -> Style {
        Style { foreground: Some(self), is_blink: true, .. Style::default() }
    }

    /// Returns a Style with the reverse property set.
    pub fn reverse(self) -> Style {
        Style { foreground: Some(self), is_reverse: true, .. Style::default() }
    }

    /// Returns a Style with the hidden property set.
    pub fn hidden(self) -> Style {
        Style { foreground: Some(self), is_hidden: true, .. Style::default() }
    }

    /// Returns a Style with the strikethrough property set.
    pub fn strikethrough(self) -> Style {
        Style { foreground: Some(self), is_strikethrough: true, .. Style::default() }
    }

    /// Returns a Style with the background colour property set.
    pub fn on(self, background: Colour) -> Style {
        Style { foreground: Some(self), background: Some(background), .. Style::default() }
    }
}
<commit_msg>impl From<Colour> for Style<commit_after>/// A style is a collection of properties that can format a string
/// using ANSI escape codes.
#[derive(PartialEq, Clone, Copy)]
pub struct Style {

    /// The style's foreground colour, if it has one.
    pub foreground: Option<Colour>,

    /// The style's background colour, if it has one.
    pub background: Option<Colour>,

    /// Whether this style is bold.
    pub is_bold: bool,

    /// Whether this style is dimmed.
    pub is_dimmed: bool,

    /// Whether this style is italic.
    pub is_italic: bool,

    /// Whether this style is underlined.
    pub is_underline: bool,

    /// Whether this style is blinking.
    pub is_blink: bool,

    /// Whether this style has reverse colours.
    pub is_reverse: bool,

    /// Whether this style is hidden.
    pub is_hidden: bool,

    /// Whether this style is struckthrough.
    pub is_strikethrough: bool
}

impl Style {
    /// Creates a new Style with no differences.
    pub fn new() -> Style {
        Style::default()
    }

    /// Returns a Style with the bold property set.
    pub fn bold(&self) -> Style {
        Style { is_bold: true, .. *self }
    }

    /// Returns a Style with the dimmed property set.
    pub fn dimmed(&self) -> Style {
        Style { is_dimmed: true, .. *self }
    }

    /// Returns a Style with the italic property set.
    pub fn italic(&self) -> Style {
        Style { is_italic: true, .. *self }
    }

    /// Returns a Style with the underline property set.
    pub fn underline(&self) -> Style {
        Style { is_underline: true, .. *self }
    }

    /// Returns a Style with the blink property set.
    pub fn blink(&self) -> Style {
        Style { is_blink: true, .. *self }
    }

    /// Returns a Style with the reverse property set.
    pub fn reverse(&self) -> Style {
        Style { is_reverse: true, .. *self }
    }

    /// Returns a Style with the hidden property set.
    pub fn hidden(&self) -> Style {
        Style { is_hidden: true, .. *self }
    }

    /// Returns a Style with the hidden property set.
    pub fn strikethrough(&self) -> Style {
        Style { is_strikethrough: true, .. *self }
    }

    /// Returns a Style with the foreground colour property set.
    pub fn fg(&self, foreground: Colour) -> Style {
        Style { foreground: Some(foreground), .. *self }
    }

    /// Returns a Style with the background colour property set.
    pub fn on(&self, background: Colour) -> Style {
        Style { background: Some(background), .. *self }
    }

    /// Return true if this `Style` has no actual styles, and can be written
    /// without any control characters.
    pub fn is_plain(self) -> bool {
        self == Style::default()
    }
}

impl Default for Style {
    fn default() -> Style {
        Style {
            foreground: None,
            background: None,
            is_bold: false,
            is_dimmed: false,
            is_italic: false,
            is_underline: false,
            is_blink: false,
            is_reverse: false,
            is_hidden: false,
            is_strikethrough: false,
        }
    }
}

// ---- colours ----

/// A colour is one specific type of ANSI escape code, and can refer
/// to either the foreground or background colour.
///
/// These use the standard numeric sequences.
/// See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum Colour {

    /// Colour #0 (foreground code `30`, background code `40`).
    ///
    /// This is not necessarily the background colour, and using it as one may
    /// render the text hard to read on terminals with dark backgrounds.
    Black,

    /// Colour #1 (foreground code `31`, background code `41`).
    Red,

    /// Colour #2 (foreground code `32`, background code `42`).
    Green,

    /// Colour #3 (foreground code `33`, background code `43`).
    Yellow,

    /// Colour #4 (foreground code `34`, background code `44`).
    Blue,

    /// Colour #5 (foreground code `35`, background code `45`).
    Purple,

    /// Colour #6 (foreground code `36`, background code `46`).
    Cyan,

    /// Colour #7 (foreground code `37`, background code `47`).
    ///
    /// As above, this is not necessarily the foreground colour, and may be
    /// hard to read on terminals with light backgrounds.
    White,

    /// A colour number from 0 to 255, for use in 256-colour terminal
    /// environments.
    ///
    /// - Colours 0 to 7 are the `Black` to `White` variants respectively.
    ///   These colours can usually be changed in the terminal emulator.
    /// - Colours 8 to 15 are brighter versions of the eight colours above.
    ///   These can also usually be changed in the terminal emulator, or it
    ///   could be configured to use the original colours and show the text in
    ///   bold instead. It varies depending on the program.
    /// - Colours 16 to 231 contain several palettes of bright colours,
    ///   arranged in six squares measuring six by six each.
    /// - Colours 232 to 255 are shades of grey from black to white.
    ///
    /// It might make more sense to look at a [colour chart][cc].
    /// [cc]: https://upload.wikimedia.org/wikipedia/en/1/15/Xterm_256color_chart.svg
    Fixed(u8),

    /// A 24-bit RGB color, as specified by ISO-8613-3.
    RGB(u8, u8, u8),
}

impl Colour {
    /// Return a Style with the foreground colour set to this colour.
    pub fn normal(self) -> Style {
        Style { foreground: Some(self), .. Style::default() }
    }

    /// Returns a Style with the bold property set.
    pub fn bold(self) -> Style {
        Style { foreground: Some(self), is_bold: true, .. Style::default() }
    }

    /// Returns a Style with the dimmed property set.
    pub fn dimmed(self) -> Style {
        Style { foreground: Some(self), is_dimmed: true, .. Style::default() }
    }

    /// Returns a Style with the italic property set.
    pub fn italic(self) -> Style {
        Style { foreground: Some(self), is_italic: true, .. Style::default() }
    }

    /// Returns a Style with the underline property set.
    pub fn underline(self) -> Style {
        Style { foreground: Some(self), is_underline: true, .. Style::default() }
    }

    /// Returns a Style with the blink property set.
    pub fn blink(self) -> Style {
        Style { foreground: Some(self), is_blink: true, .. Style::default() }
    }

    /// Returns a Style with the reverse property set.
    pub fn reverse(self) -> Style {
        Style { foreground: Some(self), is_reverse: true, .. Style::default() }
    }

    /// Returns a Style with the hidden property set.
    pub fn hidden(self) -> Style {
        Style { foreground: Some(self), is_hidden: true, .. Style::default() }
    }

    /// Returns a Style with the strikethrough property set.
    pub fn strikethrough(self) -> Style {
        Style { foreground: Some(self), is_strikethrough: true, .. Style::default() }
    }

    /// Returns a Style with the background colour property set.
    pub fn on(self, background: Colour) -> Style {
        Style { foreground: Some(self), background: Some(background), .. Style::default() }
    }
}

impl From<Colour> for Style {

    /// You can turn a `Colour` into a `Style` with the foreground colour set
    /// with the `From` trait.
    ///
    /// ```
    /// use ansi_term::{Style, Colour};
    /// let green_foreground = Style::default().fg(Colour::Green);
    /// assert_eq!(green_foreground, Colour::Green.normal());
    /// assert_eq!(green_foreground, Colour::Green.into());
    /// assert_eq!(green_foreground, Style::from(Colour::Green));
    /// ```
    fn from(colour: Colour) -> Style {
        colour.normal()
    }
}
<|endoftext|>


<commit_before>/// Represents a term
#[derive(Debug)]
pub struct Term<'a>(pub &'a str);

/// Represents TF-IDF struct
#[derive(Debug)]
pub struct TfIdf<'a> {
    pub documents: Vec<Vec<Term<'a>>>
}

impl<'a> PartialEq for Term<'a> {
    fn eq(&self, other: &Term) -> bool {
        self.0 == other.0
    }
}

impl<'a> TfIdf<'a> {
    /// Returns a TF-IDF object
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// let tfidf = TfIdf::new();
    /// ```
    pub fn new() -> TfIdf<'a> {
        TfIdf { documents: vec![] }
    }

    /// Adding a vector of Terms
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// use tfidf::tfidf::Term;
    ///
    /// let mut terms: Vec<Term> = vec![];
    /// terms.push(Term("Hello world"));
    ///
    /// let mut tfidf = TfIdf::new();
    /// tfidf.add_vec(terms);
    /// ```
    pub fn add_vec(&mut self, document: Vec<Term<'a>>) {
        self.documents.push(document);
    }

    /// Adding a new document
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    ///
    /// let mut tfidf = TfIdf::new();
    /// tfidf.add("hello world");
    /// ```
    pub fn add(&mut self, document: &'a str) {
        let mut terms: Vec<Term<'a>> = vec![];

        for word in document.split(' ') {
            terms.push(Term(word));
        }

        self.add_vec(terms);
    }

    /// Returns the count of documents containing a specific Term
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// use tfidf::tfidf::Term;
    ///
    /// let tfidf = TfIdf::new();
    /// tfidf.count(&Term("hello"));
    /// ```
    pub fn count(&self, term: &'a Term) -> i32 {
        let mut count: i32 = 0;

        for document in &self.documents {
            let inner_count = document.into_iter().filter(
                |&tx| tx == term
            ).count();

            if inner_count > 0 {
                count += 1;
            }
        }

        count
    }

    /// Returns the IDF of a specific Term
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// use tfidf::tfidf::Term;
    ///
    /// let mut tfidf = TfIdf::new();
    /// tfidf.add("hello world");
    ///
    /// tfidf.idf(&Term("hello"));
    /// ```
    pub fn idf(&self, term: &Term) -> f32 {
        let docs = &self.documents;

        if self.count(term) > 0 {
            (docs.len() as f32 / self.count(term) as f32).log10()
        } else {
            0f32
        }
    }

    /// Returns the TF of a specific Term
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// use tfidf::tfidf::Term;
    ///
    /// let mut tfidf = TfIdf::new();
    /// tfidf.add("hello world");
    ///
    /// tfidf.tf(&Term("hello"), 0);
    /// ```
    pub fn tf(&self, term: &'a Term, document_index: usize) -> f32 {
        let ref document: Vec<Term<'a>> = self.documents[document_index];

        let counts: f32 = document.into_iter().filter(
            |&dx| dx == term
        ).count() as f32;

        return match counts {
            0.0f32 => 0.0f32,
            _ => {
                counts.log10() + 1.0f32
            }
        };
    }

    /// Returns a specific TF-IDF of a Term
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// use tfidf::tfidf::Term;
    ///
    /// let mut tfidf = TfIdf::new();
    /// tfidf.add("hello world");
    ///
    /// tfidf.tfidf(&Term("hello"), 0);
    /// ```
    pub fn tfidf(&self, term: &'a Term, document_index: usize) -> f32 {
        self.tf(term, document_index) * self.idf(term)
    }

    /// Returns the similarities of a Term among all inserted documents
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// use tfidf::tfidf::Term;
    ///
    /// let mut tfidf = TfIdf::new();
    /// tfidf.add("China has a strong economy that is growing at a rapid pace. However politically it differs greatly from the US Economy.");
    /// tfidf.add("At last, China seems serious about confronting an endemic problem: domestic violence and corruption.");
    ///
    /// tfidf.similarities(&Term("China"));
    /// ```
    pub fn similarities(&self, term: &'a Term) -> Vec<f32> {
        let mut values: Vec<f32> = vec![];

        for i in 0usize..self.documents.len() {
            values.push(self.tfidf(term, i));
        }

        values
    }
}
<commit_msg>adding "to lowercase" to Term compare<commit_after>/// Represents a term
#[derive(Debug)]
pub struct Term<'a>(pub &'a str);

/// Represents TF-IDF struct
#[derive(Debug)]
pub struct TfIdf<'a> {
    pub documents: Vec<Vec<Term<'a>>>
}

/// To compare two Terms
impl<'a> PartialEq for Term<'a> {
    fn eq(&self, other: &Term) -> bool {
        self.0.to_lowercase() == other.0.to_lowercase()
    }
}

impl<'a> TfIdf<'a> {
    /// Returns a TF-IDF object
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// let tfidf = TfIdf::new();
    /// ```
    pub fn new() -> TfIdf<'a> {
        TfIdf { documents: vec![] }
    }

    /// Adding a vector of Terms
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// use tfidf::tfidf::Term;
    ///
    /// let mut terms: Vec<Term> = vec![];
    /// terms.push(Term("Hello world"));
    ///
    /// let mut tfidf = TfIdf::new();
    /// tfidf.add_vec(terms);
    /// ```
    pub fn add_vec(&mut self, document: Vec<Term<'a>>) {
        self.documents.push(document);
    }

    /// Adding a new document
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    ///
    /// let mut tfidf = TfIdf::new();
    /// tfidf.add("hello world");
    /// ```
    pub fn add(&mut self, document: &'a str) {
        let mut terms: Vec<Term<'a>> = vec![];

        for word in document.split(' ') {
            terms.push(Term(word));
        }

        self.add_vec(terms);
    }

    /// Returns the count of documents containing a specific Term
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// use tfidf::tfidf::Term;
    ///
    /// let tfidf = TfIdf::new();
    /// tfidf.count(&Term("hello"));
    /// ```
    pub fn count(&self, term: &'a Term) -> i32 {
        let mut count: i32 = 0;

        for document in &self.documents {
            let inner_count = document.into_iter().filter(
                |&tx| tx == term
            ).count();

            if inner_count > 0 {
                count += 1;
            }
        }

        count
    }

    /// Returns the IDF of a specific Term
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// use tfidf::tfidf::Term;
    ///
    /// let mut tfidf = TfIdf::new();
    /// tfidf.add("hello world");
    ///
    /// tfidf.idf(&Term("hello"));
    /// ```
    pub fn idf(&self, term: &Term) -> f32 {
        let docs = &self.documents;

        if self.count(term) > 0 {
            (docs.len() as f32 / self.count(term) as f32).log10()
        } else {
            0f32
        }
    }

    /// Returns the TF of a specific Term
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// use tfidf::tfidf::Term;
    ///
    /// let mut tfidf = TfIdf::new();
    /// tfidf.add("hello world");
    ///
    /// tfidf.tf(&Term("hello"), 0);
    /// ```
    pub fn tf(&self, term: &'a Term, document_index: usize) -> f32 {
        let ref document: Vec<Term<'a>> = self.documents[document_index];

        let counts: f32 = document.into_iter().filter(
            |&dx| dx == term
        ).count() as f32;

        return match counts {
            0.0f32 => 0.0f32,
            _ => {
                counts.log10() + 1.0f32
            }
        };
    }

    /// Returns a specific TF-IDF of a Term
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// use tfidf::tfidf::Term;
    ///
    /// let mut tfidf = TfIdf::new();
    /// tfidf.add("hello world");
    ///
    /// tfidf.tfidf(&Term("hello"), 0);
    /// ```
    pub fn tfidf(&self, term: &'a Term, document_index: usize) -> f32 {
        self.tf(term, document_index) * self.idf(term)
    }

    /// Returns the similarities of a Term among all inserted documents
    ///
    /// # Examples
    ///
    /// ```
    /// use tfidf::tfidf::TfIdf;
    /// use tfidf::tfidf::Term;
    ///
    /// let mut tfidf = TfIdf::new();
    /// tfidf.add("China has a strong economy that is growing at a rapid pace. However politically it differs greatly from the US Economy.");
    /// tfidf.add("At last, China seems serious about confronting an endemic problem: domestic violence and corruption.");
    ///
    /// tfidf.similarities(&Term("China"));
    /// ```
    pub fn similarities(&self, term: &'a Term) -> Vec<f32> {
        let mut values: Vec<f32> = vec![];

        for i in 0usize..self.documents.len() {
            values.push(self.tfidf(term, i));
        }

        values
    }
}
<|endoftext|>


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

use crate::traits::*;

pub type NewRootContext = fn(context_id: u32) -> Box<dyn RootContext>;
pub type NewStreamContext = fn(context_id: u32, root_context_id: u32) -> Box<dyn StreamContext>;
pub type NewHttpContext = fn(context_id: u32, root_context_id: u32) -> Box<dyn HttpContext>;

#[repr(u32)]
#[derive(Debug)]
pub enum LogLevel {
    Trace = 0,
    Debug = 1,
    Info = 2,
    Warn = 3,
    Error = 4,
    Critical = 5,
}

#[repr(u32)]
#[derive(Debug)]
pub enum Action {
    Continue = 0,
    Pause = 1,
}

#[repr(u32)]
#[derive(Debug)]
pub enum Status {
    Ok = 0,
    NotFound = 1,
    BadArgument = 2,
    ParseFailure = 4,
    Empty = 7,
    CasMismatch = 8,
    InternalFailure = 10,
}

#[repr(u32)]
#[derive(Debug)]
pub enum ContextType {
    HttpContext = 0,
    StreamContext = 1,
}

#[repr(u32)]
#[derive(Debug)]
pub enum BufferType {
    HttpRequestBody = 0,
    HttpResponseBody = 1,
    DownstreamData = 2,
    UpstreamData = 3,
    HttpCallResponseBody = 4,
    GrpcReceiveBuffer = 5,
}

#[repr(u32)]
#[derive(Debug)]
pub enum MapType {
    HttpRequestHeaders = 0,
    HttpRequestTrailers = 1,
    HttpResponseHeaders = 2,
    HttpResponseTrailers = 3,
    GrpcReceiveInitialMetadata = 4,
    GrpcReceiveTrailingMetadata = 5,
    HttpCallResponseHeaders = 6,
    HttpCallResponseTrailers = 7,
}

#[repr(u32)]
#[derive(Debug)]
pub enum PeerType {
    Unknown = 0,
    Local = 1,
    Remote = 2,
}

#[repr(u32)]
#[derive(Debug)]
pub enum MetricType {
    Counter = 0,
    Gauge = 1,
    Histogram = 2,
}

pub type Bytes = Vec<u8>;
<commit_msg>Add standard Rust attributes. (#24)<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::traits::*;

pub type NewRootContext = fn(context_id: u32) -> Box<dyn RootContext>;
pub type NewStreamContext = fn(context_id: u32, root_context_id: u32) -> Box<dyn StreamContext>;
pub type NewHttpContext = fn(context_id: u32, root_context_id: u32) -> Box<dyn HttpContext>;

#[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum LogLevel {
    Trace = 0,
    Debug = 1,
    Info = 2,
    Warn = 3,
    Error = 4,
    Critical = 5,
}

#[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum Action {
    Continue = 0,
    Pause = 1,
}

#[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum Status {
    Ok = 0,
    NotFound = 1,
    BadArgument = 2,
    ParseFailure = 4,
    Empty = 7,
    CasMismatch = 8,
    InternalFailure = 10,
}

#[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum ContextType {
    HttpContext = 0,
    StreamContext = 1,
}

#[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum BufferType {
    HttpRequestBody = 0,
    HttpResponseBody = 1,
    DownstreamData = 2,
    UpstreamData = 3,
    HttpCallResponseBody = 4,
    GrpcReceiveBuffer = 5,
}

#[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum MapType {
    HttpRequestHeaders = 0,
    HttpRequestTrailers = 1,
    HttpResponseHeaders = 2,
    HttpResponseTrailers = 3,
    GrpcReceiveInitialMetadata = 4,
    GrpcReceiveTrailingMetadata = 5,
    HttpCallResponseHeaders = 6,
    HttpCallResponseTrailers = 7,
}

#[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum PeerType {
    Unknown = 0,
    Local = 1,
    Remote = 2,
}

#[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum MetricType {
    Counter = 0,
    Gauge = 1,
    Histogram = 2,
}

pub type Bytes = Vec<u8>;
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use clap::{App, Arg, SubCommand};
use time;
use self::DataType::{F32, I16};
use self::Mode::{ConstMode, TrackMode};

use std::fmt;
use std::process::exit;

pub enum Mode {
    ConstMode,
    TrackMode,
}

#[derive(Clone, Copy)]
pub enum DataType {
    F32,
    I16,
}

impl fmt::Display for DataType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DataType::F32 => {write!(f, "f32")},
            DataType::I16 => {write!(f, "i16")},
        }
    }
}

#[derive(Debug)]
#[derive(Clone, Copy)]
pub struct Location {
    pub lat: f64,
    pub lon: f64,
    pub alt: i32,
}

pub struct ConstModeArgs {
    pub shift: Option<i32>,
}

pub struct TrackModeArgs {
    pub tlefile: Option<String>,
    pub tlename: Option<String>,
    pub location: Option<Location>,
    pub time: Option<time::Tm>,
    pub frequency: Option<u32>,
    pub offset: Option<i32>,
}

pub struct CommandArgs {
    pub mode: Option<Mode>,

    pub samplerate: Option<u32>,
    pub inputtype: Option<DataType>,
    pub outputtype: Option<DataType>,

    pub constargs: ConstModeArgs,
    pub trackargs: TrackModeArgs,
}

fn parse_location(location: &str) -> Result<Location, String> {
    if location.contains("lat") && location.contains("lon") && location.contains("alt"){
        let split = location.split(",");

        let mut lat: Option<f64> = None;
        let mut lon: Option<f64> = None;
        let mut alt: Option<i32> = None;

        for s in split {
            if s.contains("lat") && s.contains("=") {
                lat = s.split("=").nth(1).unwrap().parse::<f64>().ok();
            }
            else if s.contains("lon") && s.contains("=") {
                lon = s.split("=").nth(1).unwrap().parse::<f64>().ok();
            }
            else if s.contains("alt") && s.contains("=") {
                alt = s.split("=").nth(1).unwrap().parse::<i32>().ok();
            }
        }

        if lat.is_some() && lon.is_some() && alt.is_some() {
            Ok(Location{lat: lat.unwrap(), lon: lon.unwrap(), alt: alt.unwrap()})
        }
        else {
            Err(format!("{} isn't a valid value for --location\n\t[use as: lat=58.64560,lon=23.15163,alt=8]", location).to_string())
        }
    }
    else {
        Err("--location should be defined as: lat=58.64560,lon=23.15163,alt=8".to_string())
    }
}

pub fn args() -> CommandArgs {
    let datatypes = ["i16", "f32"];

    let matches = App::new("doppler")
                .author("Andres Vahter <andres.vahter@gmail.com>")
                .version(env!("CARGO_PKG_VERSION"))
                .about("Compensates IQ data stream doppler shift based on TLE information, also can be used for doing constant baseband shifting")

                .subcommand(SubCommand::new("const")
                    .about("Constant shift mode")

                    .arg(Arg::with_name("SAMPLERATE")
                       .long("samplerate")
                       .short("s")
                       .help("IQ data samplerate")
                       .required(true)
                       .takes_value(true))

                    .arg(Arg::with_name("INTYPE")
                       .long("intype")
                       .short("i")
                       .help("IQ data input type")
                       .required(true)
                       .possible_values(&datatypes)
                       .takes_value(true))

                   .arg(Arg::with_name("OUTTYPE")
                       .long("outtype")
                       .short("o")
                       .help("IQ data output type")
                       .required(false)
                       .possible_values(&datatypes)
                       .takes_value(true))

                    .arg(Arg::with_name("SHIFT")
                       .long("shift")
                       .help("frequency shift in Hz")
                       .required(true)
                       .takes_value(true)))

                .subcommand(SubCommand::new("track")
                    .about("Doppler tracking mode")

                    .arg(Arg::with_name("SAMPLERATE")
                       .long("samplerate")
                       .short("s")
                       .help("IQ data samplerate")
                       .required(true)
                       .takes_value(true))

                    .arg(Arg::with_name("INTYPE")
                       .long("intype")
                       .short("i")
                       .help("IQ data type")
                       .required(true)
                       .possible_values(&datatypes)
                       .takes_value(true))

                   .arg(Arg::with_name("OUTTYPE")
                       .long("outtype")
                       .short("o")
                       .help("IQ data output type")
                       .required(false)
                       .possible_values(&datatypes)
                       .takes_value(true))

                    .arg(Arg::with_name("TLEFILE")
                       .long("tlefile")
                       .help("TLE file: eg. http://www.celestrak.com/NORAD/elements/cubesat.txt")
                       .required(true)
                       .takes_value(true))

                    .arg(Arg::with_name("TLENAME")
                       .long("tlename")
                       .help("TLE name in TLE file: eg. ESTCUBE 1")
                       .required(true)
                       .takes_value(true))

                    .arg(Arg::with_name("LOCATION")
                       .long("location")
                       .help("Observer location (lat=<deg>,lon=<deg>,alt=<m>): eg. lat=58.64560,lon=23.15163,alt=8")
                       .required(true)
                       .takes_value(true))

                    .arg(Arg::with_name("TIME")
                       .long("time")
                       .help("Observation start time in UTC Y-m-dTH:M:S: eg. 2015-05-13T14:28:48. If not specified current time is used")
                       .required(false)
                       .takes_value(true))

                    .arg(Arg::with_name("FREQUENCY")
                       .long("frequency")
                       .help("Satellite transmitter frequency in Hz")
                       .required(true)
                       .takes_value(true))

                    .arg(Arg::with_name("OFFSET")
                       .long("offset")
                       .help("Constant frequency shift in Hz. Can be used to compensate constant offset")
                       .required(false)
                       .takes_value(true)))

                .get_matches();

    let mut args = CommandArgs {
                    mode : None,

                    samplerate : None,
                    inputtype : None,
                    outputtype: None,

                    constargs : ConstModeArgs {
                        shift: None,
                    },

                    trackargs : TrackModeArgs {
                        tlefile : None,
                        tlename : None,
                        location: None,
                        time : None,
                        frequency : None,
                        offset : None,
                    },
                };

    match matches.subcommand_name() {
        Some("const")   => {
            args.mode = Some(ConstMode);
            let submatches = matches.subcommand_matches("const").unwrap();
            args.samplerate = Some(value_t_or_exit!(submatches.value_of("SAMPLERATE"), u32));

            match submatches.value_of("INTYPE").unwrap() {
                "f32" => {args.inputtype = Some(F32);},
                "i16" => {args.inputtype = Some(I16);},
                _ => unreachable!()
            }

            if submatches.is_present("OUTTYPE") {
                match submatches.value_of("OUTTYPE").unwrap() {
                    "f32" => {args.outputtype = Some(F32);},
                    "i16" => {args.outputtype = Some(I16);},
                    _ => unreachable!()
                }
            }
            else {
                args.outputtype = args.inputtype;
            }

            args.constargs.shift = Some(value_t_or_exit!(submatches.value_of("SHIFT"), i32));
        },

        Some("track") => {
            args.mode = Some(TrackMode);
            let submatches = matches.subcommand_matches("track").unwrap();
            args.samplerate = Some(value_t_or_exit!(submatches.value_of("SAMPLERATE"), u32));

            match submatches.value_of("INTYPE").unwrap() {
                "f32" => {args.inputtype = Some(F32);},
                "i16" => {args.inputtype = Some(I16);},
                _ => unreachable!()
            }

            if submatches.is_present("OUTTYPE") {
                match submatches.value_of("OUTTYPE").unwrap() {
                    "f32" => {args.outputtype = Some(F32);},
                    "i16" => {args.outputtype = Some(I16);},
                    _ => unreachable!()
                }
            }
            else {
                args.outputtype = args.inputtype;
            }

            if submatches.is_present("OFFSET") {
                args.trackargs.offset = Some(value_t_or_exit!(submatches.value_of("OFFSET"), i32));
            }

            if submatches.is_present("TIME") {
                let tm = time::strptime(submatches.value_of("TIME").unwrap(), "%Y-%m-%dT%H:%M:%S");
                match tm {
                    Ok(_) => {},
                    Err(e) => {
                        error!("{}.", e);
                        error!("--time should be defined in Y-m-dTH:M:S format: eg. 2015-05-13T14:28:48");
                        exit(1);
                    },
                };

                args.trackargs.time = Some(tm.unwrap());
            }

            args.trackargs.tlefile = Some(submatches.value_of("TLEFILE").unwrap().to_string());
            args.trackargs.tlename = Some(submatches.value_of("TLENAME").unwrap().to_string());
            args.trackargs.frequency = Some(value_t_or_exit!(submatches.value_of("FREQUENCY"), u32));

            let location = parse_location(&submatches.value_of("LOCATION").unwrap().to_string());
            match location {
                Ok(loc) => { args.trackargs.location = Some(loc);},
                Err(e) => {
                    error!("{}.", e);
                    exit(1);
                }
            }
        },

        _ => {
            info!("no arguments provided, try with doppler -h");
            exit(1);
        }
    }

    args
}
<commit_msg>fix negative numbers support eg. --shift -5600 now works<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use clap::{App, AppSettings, Arg, SubCommand};
use time;
use self::DataType::{F32, I16};
use self::Mode::{ConstMode, TrackMode};

use std::fmt;
use std::process::exit;

pub enum Mode {
    ConstMode,
    TrackMode,
}

#[derive(Clone, Copy)]
pub enum DataType {
    F32,
    I16,
}

impl fmt::Display for DataType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DataType::F32 => {write!(f, "f32")},
            DataType::I16 => {write!(f, "i16")},
        }
    }
}

#[derive(Debug)]
#[derive(Clone, Copy)]
pub struct Location {
    pub lat: f64,
    pub lon: f64,
    pub alt: i32,
}

pub struct ConstModeArgs {
    pub shift: Option<i32>,
}

pub struct TrackModeArgs {
    pub tlefile: Option<String>,
    pub tlename: Option<String>,
    pub location: Option<Location>,
    pub time: Option<time::Tm>,
    pub frequency: Option<u32>,
    pub offset: Option<i32>,
}

pub struct CommandArgs {
    pub mode: Option<Mode>,

    pub samplerate: Option<u32>,
    pub inputtype: Option<DataType>,
    pub outputtype: Option<DataType>,

    pub constargs: ConstModeArgs,
    pub trackargs: TrackModeArgs,
}

fn parse_location(location: &str) -> Result<Location, String> {
    if location.contains("lat") && location.contains("lon") && location.contains("alt"){
        let split = location.split(",");

        let mut lat: Option<f64> = None;
        let mut lon: Option<f64> = None;
        let mut alt: Option<i32> = None;

        for s in split {
            if s.contains("lat") && s.contains("=") {
                lat = s.split("=").nth(1).unwrap().parse::<f64>().ok();
            }
            else if s.contains("lon") && s.contains("=") {
                lon = s.split("=").nth(1).unwrap().parse::<f64>().ok();
            }
            else if s.contains("alt") && s.contains("=") {
                alt = s.split("=").nth(1).unwrap().parse::<i32>().ok();
            }
        }

        if lat.is_some() && lon.is_some() && alt.is_some() {
            Ok(Location{lat: lat.unwrap(), lon: lon.unwrap(), alt: alt.unwrap()})
        }
        else {
            Err(format!("{} isn't a valid value for --location\n\t[use as: lat=58.64560,lon=23.15163,alt=8]", location).to_string())
        }
    }
    else {
        Err("--location should be defined as: lat=58.64560,lon=23.15163,alt=8".to_string())
    }
}

pub fn args() -> CommandArgs {
    let datatypes = ["i16", "f32"];

    let matches = App::new("doppler")
                .author("Andres Vahter <andres.vahter@gmail.com>")
                .version(env!("CARGO_PKG_VERSION"))
                .about("Compensates IQ data stream doppler shift based on TLE information, also can be used for doing constant baseband shifting")

                .subcommand(SubCommand::with_name("const")
                    .setting(AppSettings::AllowLeadingHyphen) // allow negative values like --shift -5000
                    .about("Constant shift mode")

                    .arg(Arg::with_name("SAMPLERATE")
                       .long("samplerate")
                       .short("s")
                       .help("IQ data samplerate")
                       .required(true)
                       .takes_value(true))

                    .arg(Arg::with_name("INTYPE")
                       .long("intype")
                       .short("i")
                       .help("IQ data input type")
                       .required(true)
                       .possible_values(&datatypes)
                       .takes_value(true))

                   .arg(Arg::with_name("OUTTYPE")
                       .long("outtype")
                       .short("o")
                       .help("IQ data output type")
                       .required(false)
                       .possible_values(&datatypes)
                       .takes_value(true))

                    .arg(Arg::with_name("SHIFT")
                       .long("shift")
                       .help("frequency shift in Hz")
                       .required(true)
                       .takes_value(true)))

                .subcommand(SubCommand::with_name("track")
                    .setting(AppSettings::AllowLeadingHyphen) // allow negative values like --offset -5000
                    .about("Doppler tracking mode")

                    .arg(Arg::with_name("SAMPLERATE")
                       .long("samplerate")
                       .short("s")
                       .help("IQ data samplerate")
                       .required(true)
                       .takes_value(true))

                    .arg(Arg::with_name("INTYPE")
                       .long("intype")
                       .short("i")
                       .help("IQ data type")
                       .required(true)
                       .possible_values(&datatypes)
                       .takes_value(true))

                   .arg(Arg::with_name("OUTTYPE")
                       .long("outtype")
                       .short("o")
                       .help("IQ data output type")
                       .required(false)
                       .possible_values(&datatypes)
                       .takes_value(true))

                    .arg(Arg::with_name("TLEFILE")
                       .long("tlefile")
                       .help("TLE file: eg. http://www.celestrak.com/NORAD/elements/cubesat.txt")
                       .required(true)
                       .takes_value(true))

                    .arg(Arg::with_name("TLENAME")
                       .long("tlename")
                       .help("TLE name in TLE file: eg. ESTCUBE 1")
                       .required(true)
                       .takes_value(true))

                    .arg(Arg::with_name("LOCATION")
                       .long("location")
                       .help("Observer location (lat=<deg>,lon=<deg>,alt=<m>): eg. lat=58.64560,lon=23.15163,alt=8")
                       .required(true)
                       .takes_value(true))

                    .arg(Arg::with_name("TIME")
                       .long("time")
                       .help("Observation start time in UTC Y-m-dTH:M:S: eg. 2015-05-13T14:28:48. If not specified current time is used")
                       .required(false)
                       .takes_value(true))

                    .arg(Arg::with_name("FREQUENCY")
                       .long("frequency")
                       .help("Satellite transmitter frequency in Hz")
                       .required(true)
                       .takes_value(true))

                    .arg(Arg::with_name("OFFSET")
                       .long("offset")
                       .help("Constant frequency shift in Hz. Can be used to compensate constant offset")
                       .required(false)
                       .takes_value(true)))

                .get_matches();

    let mut args = CommandArgs {
                    mode : None,

                    samplerate : None,
                    inputtype : None,
                    outputtype: None,

                    constargs : ConstModeArgs {
                        shift: None,
                    },

                    trackargs : TrackModeArgs {
                        tlefile : None,
                        tlename : None,
                        location: None,
                        time : None,
                        frequency : None,
                        offset : None,
                    },
                };

    match matches.subcommand_name() {
        Some("const")   => {
            args.mode = Some(ConstMode);
            let submatches = matches.subcommand_matches("const").unwrap();
            args.samplerate = Some(value_t_or_exit!(submatches.value_of("SAMPLERATE"), u32));

            match submatches.value_of("INTYPE").unwrap() {
                "f32" => {args.inputtype = Some(F32);},
                "i16" => {args.inputtype = Some(I16);},
                _ => unreachable!()
            }

            if submatches.is_present("OUTTYPE") {
                match submatches.value_of("OUTTYPE").unwrap() {
                    "f32" => {args.outputtype = Some(F32);},
                    "i16" => {args.outputtype = Some(I16);},
                    _ => unreachable!()
                }
            }
            else {
                args.outputtype = args.inputtype;
            }

            args.constargs.shift = Some(value_t_or_exit!(submatches.value_of("SHIFT"), i32));
        },

        Some("track") => {
            args.mode = Some(TrackMode);
            let submatches = matches.subcommand_matches("track").unwrap();
            args.samplerate = Some(value_t_or_exit!(submatches.value_of("SAMPLERATE"), u32));

            match submatches.value_of("INTYPE").unwrap() {
                "f32" => {args.inputtype = Some(F32);},
                "i16" => {args.inputtype = Some(I16);},
                _ => unreachable!()
            }

            if submatches.is_present("OUTTYPE") {
                match submatches.value_of("OUTTYPE").unwrap() {
                    "f32" => {args.outputtype = Some(F32);},
                    "i16" => {args.outputtype = Some(I16);},
                    _ => unreachable!()
                }
            }
            else {
                args.outputtype = args.inputtype;
            }

            if submatches.is_present("OFFSET") {
                args.trackargs.offset = Some(value_t_or_exit!(submatches.value_of("OFFSET"), i32));
            }

            if submatches.is_present("TIME") {
                let tm = time::strptime(submatches.value_of("TIME").unwrap(), "%Y-%m-%dT%H:%M:%S");
                match tm {
                    Ok(_) => {},
                    Err(e) => {
                        error!("{}.", e);
                        error!("--time should be defined in Y-m-dTH:M:S format: eg. 2015-05-13T14:28:48");
                        exit(1);
                    },
                };

                args.trackargs.time = Some(tm.unwrap());
            }

            args.trackargs.tlefile = Some(submatches.value_of("TLEFILE").unwrap().to_string());
            args.trackargs.tlename = Some(submatches.value_of("TLENAME").unwrap().to_string());
            args.trackargs.frequency = Some(value_t_or_exit!(submatches.value_of("FREQUENCY"), u32));

            let location = parse_location(&submatches.value_of("LOCATION").unwrap().to_string());
            match location {
                Ok(loc) => { args.trackargs.location = Some(loc);},
                Err(e) => {
                    error!("{}.", e);
                    exit(1);
                }
            }
        },

        _ => {
            info!("no arguments provided, try with doppler -h");
            exit(1);
        }
    }

    args
}
<|endoftext|>


<commit_before>//! Internal utilities

use itertools::FoldWhile::{Continue, Done};

use itertools::Itertools;
use std;

/// Map across the iterator, terminating early if a mapping returns None
pub fn map_while_some<A, E>(iter: &mut Iterator<Item = E>, f: &Fn(E) -> Option<A>) -> Option<Vec<A>> {
    let mut results: Vec<A> = Vec::new();
    for x in iter {
        if let Some(result) = f(x) {
            results.push(result);
        } else {
            return None;
        }
    }
    return Some(results);
}

pub fn fold_while_some<A, E>(init_acc: A, iter: &mut Iterator<Item = E>, f: &Fn(A, E) -> Option<A>) -> Option<A> {
    iter.fold_while(Some(init_acc), |acc, x| match f(acc.unwrap(), x) {
        Some(value) => Continue(Some(value)),
        None => Done(None),
    })
}
<commit_msg>Fixed warning<commit_after>//! Internal utilities

use itertools::FoldWhile::{Continue, Done};

use itertools::Itertools;

/// Map across the iterator, terminating early if a mapping returns None
pub fn map_while_some<A, E>(iter: &mut Iterator<Item = E>, f: &Fn(E) -> Option<A>) -> Option<Vec<A>> {
    let mut results: Vec<A> = Vec::new();
    for x in iter {
        if let Some(result) = f(x) {
            results.push(result);
        } else {
            return None;
        }
    }
    return Some(results);
}

pub fn fold_while_some<A, E>(init_acc: A, iter: &mut Iterator<Item = E>, f: &Fn(A, E) -> Option<A>) -> Option<A> {
    iter.fold_while(Some(init_acc), |acc, x| match f(acc.unwrap(), x) {
        Some(value) => Continue(Some(value)),
        None => Done(None),
    })
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::io;
use std::io::Write;
use std::net;
use error::MemcacheError;

pub enum Flags {
    Bytes = 0,
}

/// determine how the value is serialize to memcache
pub trait ToMemcacheValue {
    fn get_flags(&self) -> u16;
    fn get_exptime(&self) -> u32;
    fn get_length(&self) -> usize;
    fn write_to(&self, stream: &net::TcpStream) -> io::Result<()>;
}

impl<'a> ToMemcacheValue for (&'a [u8], u16) {
    fn get_flags(&self) -> u16 {
        return self.1;
    }

    fn get_exptime(&self) -> u32 {
        return 0;
    }

    fn get_length(&self) -> usize {
        return self.0.len();
    }

    fn write_to(&self, mut stream: &net::TcpStream) -> io::Result<()> {
        match stream.write(self.0) {
            Ok(_) => Ok(()),
            Err(e) => Err(e),
        }
    }
}

impl<'a> ToMemcacheValue for &'a [u8] {
    fn get_flags(&self) -> u16 {
        return Flags::Bytes as u16;
    }

    fn get_exptime(&self) -> u32 {
        return 0;
    }

    fn get_length(&self) -> usize {
        return self.len();
    }

    fn write_to(&self, mut stream: &net::TcpStream) -> io::Result<()> {
        match stream.write(self) {
            Ok(_) => Ok(()),
            Err(e) => Err(e),
        }
    }
}

impl ToMemcacheValue for String {
    fn get_flags(&self) -> u16 {
        return Flags::Bytes as u16;
    }

    fn get_exptime(&self) -> u32 {
        return 0;
    }

    fn get_length(&self) -> usize {
        return self.as_bytes().len();
    }

    fn write_to(&self, mut stream: &net::TcpStream) -> io::Result<()> {
        match stream.write(self.as_bytes()) {
            Ok(_) => Ok(()),
            Err(e) => Err(e),
        }
    }
}

impl<'a> ToMemcacheValue for &'a str {
    fn get_flags(&self) -> u16 {
        return Flags::Bytes as u16;
    }

    fn get_exptime(&self) -> u32 {
        return 0;
    }

    fn get_length(&self) -> usize {
        return self.as_bytes().len();
    }

    fn write_to(&self, mut stream: &net::TcpStream) -> io::Result<()> {
        match stream.write(self.as_bytes()) {
            Ok(_) => Ok(()),
            Err(e) => Err(e),
        }
    }
}

macro_rules! impl_to_memcache_value_for_number{
    ($ty:ident) => {
        impl ToMemcacheValue for $ty {
            fn get_flags(&self) -> u16 {
                return Flags::Bytes as u16;
            }

    fn get_exptime(&self) -> u32 {
        return 0;
    }

            fn get_length(&self) -> usize {
                return self.to_string().as_bytes().len();
            }

            fn write_to(&self, mut stream: &net::TcpStream) -> io::Result<()> {
                match stream.write(self.to_string().as_bytes()) {
                    Ok(_) => Ok(()),
                    Err(e) => Err(e),
                }
            }
        }
    }
}

impl_to_memcache_value_for_number!(bool);
impl_to_memcache_value_for_number!(u8);
impl_to_memcache_value_for_number!(u16);
impl_to_memcache_value_for_number!(u32);
impl_to_memcache_value_for_number!(u64);
impl_to_memcache_value_for_number!(i8);
impl_to_memcache_value_for_number!(i16);
impl_to_memcache_value_for_number!(i32);
impl_to_memcache_value_for_number!(i64);
impl_to_memcache_value_for_number!(f32);
impl_to_memcache_value_for_number!(f64);

type MemcacheValue<T> = Result<T, MemcacheError>;

/// determine how the value is unserialize to memcache
pub trait FromMemcacheValue: Sized {
    fn from_memcache_value(Vec<u8>, u16) -> MemcacheValue<Self>;
}

impl FromMemcacheValue for (Vec<u8>, u16) {
    fn from_memcache_value(value: Vec<u8>, flags: u16) -> MemcacheValue<Self> {
        return Ok((value, flags));
    }
}

impl FromMemcacheValue for Vec<u8> {
    fn from_memcache_value(value: Vec<u8>, _: u16) -> MemcacheValue<Self> {
        return Ok(value);
    }
}

impl FromMemcacheValue for String {
    fn from_memcache_value(value: Vec<u8>, _: u16) -> MemcacheValue<Self> {
        return Ok(String::from_utf8(value)?);
    }
}

macro_rules! impl_from_memcache_value_for_number{
    ($ty:ident) => {
        impl FromMemcacheValue for $ty {
            fn from_memcache_value(value: Vec<u8>, _: u16) -> MemcacheValue<Self> {
                let s: String = String::from_memcache_value(value, 0)?;
                match Self::from_str(s.as_str()) {
                    Ok(v) => return Ok(v),
                    Err(_) => Err(MemcacheError::Error),
                }
            }
        }
    }
}

impl_from_memcache_value_for_number!(bool);
impl_from_memcache_value_for_number!(u8);
impl_from_memcache_value_for_number!(u16);
impl_from_memcache_value_for_number!(u32);
impl_from_memcache_value_for_number!(u64);
impl_from_memcache_value_for_number!(i8);
impl_from_memcache_value_for_number!(i16);
impl_from_memcache_value_for_number!(i32);
impl_from_memcache_value_for_number!(i64);
impl_from_memcache_value_for_number!(f32);
impl_from_memcache_value_for_number!(f64);
<commit_msg>refactor: remove implement ToMemcacheValue trait for ([u8], u16)<commit_after>use std::str::FromStr;
use std::io;
use std::io::Write;
use std::net;
use error::MemcacheError;

pub enum Flags {
    Bytes = 0,
}

/// determine how the value is serialize to memcache
pub trait ToMemcacheValue {
    fn get_flags(&self) -> u16;
    fn get_exptime(&self) -> u32;
    fn get_length(&self) -> usize;
    fn write_to(&self, stream: &net::TcpStream) -> io::Result<()>;
}

impl<'a> ToMemcacheValue for &'a [u8] {
    fn get_flags(&self) -> u16 {
        return Flags::Bytes as u16;
    }

    fn get_exptime(&self) -> u32 {
        return 0;
    }

    fn get_length(&self) -> usize {
        return self.len();
    }

    fn write_to(&self, mut stream: &net::TcpStream) -> io::Result<()> {
        match stream.write(self) {
            Ok(_) => Ok(()),
            Err(e) => Err(e),
        }
    }
}

impl ToMemcacheValue for String {
    fn get_flags(&self) -> u16 {
        return Flags::Bytes as u16;
    }

    fn get_exptime(&self) -> u32 {
        return 0;
    }

    fn get_length(&self) -> usize {
        return self.as_bytes().len();
    }

    fn write_to(&self, mut stream: &net::TcpStream) -> io::Result<()> {
        match stream.write(self.as_bytes()) {
            Ok(_) => Ok(()),
            Err(e) => Err(e),
        }
    }
}

impl<'a> ToMemcacheValue for &'a str {
    fn get_flags(&self) -> u16 {
        return Flags::Bytes as u16;
    }

    fn get_exptime(&self) -> u32 {
        return 0;
    }

    fn get_length(&self) -> usize {
        return self.as_bytes().len();
    }

    fn write_to(&self, mut stream: &net::TcpStream) -> io::Result<()> {
        match stream.write(self.as_bytes()) {
            Ok(_) => Ok(()),
            Err(e) => Err(e),
        }
    }
}

macro_rules! impl_to_memcache_value_for_number{
    ($ty:ident) => {
        impl ToMemcacheValue for $ty {
            fn get_flags(&self) -> u16 {
                return Flags::Bytes as u16;
            }

    fn get_exptime(&self) -> u32 {
        return 0;
    }

            fn get_length(&self) -> usize {
                return self.to_string().as_bytes().len();
            }

            fn write_to(&self, mut stream: &net::TcpStream) -> io::Result<()> {
                match stream.write(self.to_string().as_bytes()) {
                    Ok(_) => Ok(()),
                    Err(e) => Err(e),
                }
            }
        }
    }
}

impl_to_memcache_value_for_number!(bool);
impl_to_memcache_value_for_number!(u8);
impl_to_memcache_value_for_number!(u16);
impl_to_memcache_value_for_number!(u32);
impl_to_memcache_value_for_number!(u64);
impl_to_memcache_value_for_number!(i8);
impl_to_memcache_value_for_number!(i16);
impl_to_memcache_value_for_number!(i32);
impl_to_memcache_value_for_number!(i64);
impl_to_memcache_value_for_number!(f32);
impl_to_memcache_value_for_number!(f64);

type MemcacheValue<T> = Result<T, MemcacheError>;

/// determine how the value is unserialize to memcache
pub trait FromMemcacheValue: Sized {
    fn from_memcache_value(Vec<u8>, u16) -> MemcacheValue<Self>;
}

impl FromMemcacheValue for (Vec<u8>, u16) {
    fn from_memcache_value(value: Vec<u8>, flags: u16) -> MemcacheValue<Self> {
        return Ok((value, flags));
    }
}

impl FromMemcacheValue for Vec<u8> {
    fn from_memcache_value(value: Vec<u8>, _: u16) -> MemcacheValue<Self> {
        return Ok(value);
    }
}

impl FromMemcacheValue for String {
    fn from_memcache_value(value: Vec<u8>, _: u16) -> MemcacheValue<Self> {
        return Ok(String::from_utf8(value)?);
    }
}

macro_rules! impl_from_memcache_value_for_number{
    ($ty:ident) => {
        impl FromMemcacheValue for $ty {
            fn from_memcache_value(value: Vec<u8>, _: u16) -> MemcacheValue<Self> {
                let s: String = String::from_memcache_value(value, 0)?;
                match Self::from_str(s.as_str()) {
                    Ok(v) => return Ok(v),
                    Err(_) => Err(MemcacheError::Error),
                }
            }
        }
    }
}

impl_from_memcache_value_for_number!(bool);
impl_from_memcache_value_for_number!(u8);
impl_from_memcache_value_for_number!(u16);
impl_from_memcache_value_for_number!(u32);
impl_from_memcache_value_for_number!(u64);
impl_from_memcache_value_for_number!(i8);
impl_from_memcache_value_for_number!(i16);
impl_from_memcache_value_for_number!(i32);
impl_from_memcache_value_for_number!(i64);
impl_from_memcache_value_for_number!(f32);
impl_from_memcache_value_for_number!(f64);
<|endoftext|>


<commit_before>use crate::{poll, sys, Registry, Token};

use std::io;

/// Waker allows cross-thread waking of [`Poll`].
///
/// When created it will cause events with [`readable`] readiness and the
/// provided `token` if [`wake`] is called, possibly from another thread.
///
/// [`Poll`]: crate::Poll
/// [`readable`]: crate::event::Event::is_readable
/// [`wake`]: Waker::wake
///
/// # Notes
///
/// `Waker` events are only guaranteed to be delivered while the `Waker` value
/// is alive.
///
/// Only a single `Waker` should active per [`Poll`], if multiple threads need
/// access to the `Waker` it can be shared via for example an `Arc`. What
/// happens if multiple `Waker`s are registered with the same `Poll` is
/// undefined.
///
/// # Implementation notes
///
/// On platforms that support kqueue this will use the `EVFILT_USER` event
/// filter, see [implementation notes of `Poll`] to see what platforms support
/// kqueue. On Linux it uses [eventfd].
///
/// [implementation notes of `Poll`]: struct.Poll.html#implementation-notes
/// [eventfd]: http://man7.org/linux/man-pages/man2/eventfd.2.html
///
/// # Examples
///
/// Wake a [`Poll`] instance from another thread.
///
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use std::thread;
/// use std::time::Duration;
/// use std::sync::Arc;
///
/// use mio::{Events, Token, Poll, Waker};
///
/// const WAKE_TOKEN: Token = Token(10);
///
/// let mut poll = Poll::new()?;
/// let mut events = Events::with_capacity(2);
///
/// let waker = Arc::new(Waker::new(poll.registry(), WAKE_TOKEN)?);
///
/// // We need to keep the Waker alive, so we'll create a clone for the
/// // thread we create below.
/// let waker1 = waker.clone();
/// let handle = thread::spawn(move || {
///     // Working hard, or hardly working?
///     thread::sleep(Duration::from_millis(500));
///
///     // Now we'll wake the queue on the other thread.
///     waker1.wake().expect("unable to wake");
/// });
///
/// // On our current thread we'll poll for events, without a timeout.
/// poll.poll(&mut events, None)?;
///
/// // After about 500 milliseconds we should we awoken by the other thread we
/// // started, getting a single event.
/// assert!(!events.is_empty());
/// let waker_event = events.iter().next().unwrap();
/// assert!(waker_event.is_readable());
/// assert_eq!(waker_event.token(), WAKE_TOKEN);
/// # handle.join().unwrap();
/// #     Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct Waker {
    inner: sys::Waker,
}

impl Waker {
    /// Create a new `Waker`.
    pub fn new(registry: &Registry, token: Token) -> io::Result<Waker> {
        sys::Waker::new(poll::selector(&registry), token).map(|inner| Waker { inner })
    }

    /// Wake up the [`Poll`] associated with this `Waker`.
    ///
    /// [`Poll`]: crate::Poll
    pub fn wake(&self) -> io::Result<()> {
        self.inner.wake()
    }
}
<commit_msg>Fix comment typo<commit_after>use crate::{poll, sys, Registry, Token};

use std::io;

/// Waker allows cross-thread waking of [`Poll`].
///
/// When created it will cause events with [`readable`] readiness and the
/// provided `token` if [`wake`] is called, possibly from another thread.
///
/// [`Poll`]: crate::Poll
/// [`readable`]: crate::event::Event::is_readable
/// [`wake`]: Waker::wake
///
/// # Notes
///
/// `Waker` events are only guaranteed to be delivered while the `Waker` value
/// is alive.
///
/// Only a single `Waker` should active per [`Poll`], if multiple threads need
/// access to the `Waker` it can be shared via for example an `Arc`. What
/// happens if multiple `Waker`s are registered with the same `Poll` is
/// undefined.
///
/// # Implementation notes
///
/// On platforms that support kqueue this will use the `EVFILT_USER` event
/// filter, see [implementation notes of `Poll`] to see what platforms support
/// kqueue. On Linux it uses [eventfd].
///
/// [implementation notes of `Poll`]: struct.Poll.html#implementation-notes
/// [eventfd]: http://man7.org/linux/man-pages/man2/eventfd.2.html
///
/// # Examples
///
/// Wake a [`Poll`] instance from another thread.
///
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use std::thread;
/// use std::time::Duration;
/// use std::sync::Arc;
///
/// use mio::{Events, Token, Poll, Waker};
///
/// const WAKE_TOKEN: Token = Token(10);
///
/// let mut poll = Poll::new()?;
/// let mut events = Events::with_capacity(2);
///
/// let waker = Arc::new(Waker::new(poll.registry(), WAKE_TOKEN)?);
///
/// // We need to keep the Waker alive, so we'll create a clone for the
/// // thread we create below.
/// let waker1 = waker.clone();
/// let handle = thread::spawn(move || {
///     // Working hard, or hardly working?
///     thread::sleep(Duration::from_millis(500));
///
///     // Now we'll wake the queue on the other thread.
///     waker1.wake().expect("unable to wake");
/// });
///
/// // On our current thread we'll poll for events, without a timeout.
/// poll.poll(&mut events, None)?;
///
/// // After about 500 milliseconds we should be awoken by the other thread and
/// // get a single event.
/// assert!(!events.is_empty());
/// let waker_event = events.iter().next().unwrap();
/// assert!(waker_event.is_readable());
/// assert_eq!(waker_event.token(), WAKE_TOKEN);
/// # handle.join().unwrap();
/// #     Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct Waker {
    inner: sys::Waker,
}

impl Waker {
    /// Create a new `Waker`.
    pub fn new(registry: &Registry, token: Token) -> io::Result<Waker> {
        sys::Waker::new(poll::selector(&registry), token).map(|inner| Waker { inner })
    }

    /// Wake up the [`Poll`] associated with this `Waker`.
    ///
    /// [`Poll`]: crate::Poll
    pub fn wake(&self) -> io::Result<()> {
        self.inner.wake()
    }
}
<|endoftext|>