<commit_before>use alloc::borrow::Cow;
use alloc::string::String;
use core::fmt::{self, Debug, Display};
use core::marker::{PhantomData, PhantomPinned};
use core::pin::Pin;
use core::slice;
use core::str::{self, Utf8Error};

extern "C" {
    #[link_name = "cxxbridge05$cxx_string$data"]
    fn string_data(this: &CxxString) -> *const u8;
    #[link_name = "cxxbridge05$cxx_string$length"]
    fn string_length(this: &CxxString) -> usize;
    #[link_name = "cxxbridge05$cxx_string$push"]
    fn string_push(this: &mut CxxString, ptr: *const u8, len: usize);
}

/// Binding to C++ `std::string`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxString` by value. C++'s string
/// requires a move constructor and may hold internal pointers, which is not
/// compatible with Rust's move behavior. Instead in Rust code we will only ever
/// look at a CxxString through a reference or smart pointer, as in `&CxxString`
/// or `UniquePtr<CxxString>`.
#[repr(C)]
pub struct CxxString {
    _private: [u8; 0],
    _pinned: PhantomData<PhantomPinned>,
}

impl CxxString {
    /// Returns the length of the string in bytes.
    ///
    /// Matches the behavior of C++ [std::string::size][size].
    ///
    /// [size]: https://en.cppreference.com/w/cpp/string/basic_string/size
    pub fn len(&self) -> usize {
        unsafe { string_length(self) }
    }

    /// Returns true if `self` has a length of zero bytes.
    ///
    /// Matches the behavior of C++ [std::string::empty][empty].
    ///
    /// [empty]: https://en.cppreference.com/w/cpp/string/basic_string/empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a byte slice of this string's contents.
    pub fn as_bytes(&self) -> &[u8] {
        let data = self.as_ptr();
        let len = self.len();
        unsafe { slice::from_raw_parts(data, len) }
    }

    /// Produces a pointer to the first character of the string.
    ///
    /// Matches the behavior of C++ [std::string::data][data].
    ///
    /// Note that the return type may look like `const char *` but is not a
    /// `const char *` in the typical C sense, as C++ strings may contain
    /// internal null bytes. As such, the returned pointer only makes sense as a
    /// string in combination with the length returned by [`len()`][len].
    ///
    /// [data]: https://en.cppreference.com/w/cpp/string/basic_string/data
    /// [len]: #method.len
    pub fn as_ptr(&self) -> *const u8 {
        unsafe { string_data(self) }
    }

    /// Validates that the C++ string contains UTF-8 data and produces a view of
    /// it as a Rust &str, otherwise an error.
    pub fn to_str(&self) -> Result<&str, Utf8Error> {
        str::from_utf8(self.as_bytes())
    }

    /// If the contents of the C++ string are valid UTF-8, this function returns
    /// a view as a Cow::Borrowed &str. Otherwise replaces any invalid UTF-8
    /// sequences with the U+FFFD [replacement character] and returns a
    /// Cow::Owned String.
    ///
    /// [replacement character]: https://doc.rust-lang.org/std/char/constant.REPLACEMENT_CHARACTER.html
    pub fn to_string_lossy(&self) -> Cow<str> {
        String::from_utf8_lossy(self.as_bytes())
    }

    /// Appends a given string slice onto the end of this C++ string.
    pub fn push_str(self: Pin<&mut Self>, s: &str) {
        self.push_bytes(s.as_bytes());
    }

    /// Appends arbitrary bytes onto the end of this C++ string.
    pub fn push_bytes(self: Pin<&mut Self>, bytes: &[u8]) {
        unsafe {
            let this = Pin::into_inner_unchecked(self);
            string_push(this, bytes.as_ptr(), bytes.len())
        }
    }
}

impl Display for CxxString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(self.to_string_lossy().as_ref(), f)
    }
}

impl Debug for CxxString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self.to_string_lossy().as_ref(), f)
    }
}

impl PartialEq for CxxString {
    fn eq(&self, other: &CxxString) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl PartialEq<CxxString> for str {
    fn eq(&self, other: &CxxString) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl PartialEq<str> for CxxString {
    fn eq(&self, other: &str) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}
<commit_msg>Simplify CxxString push_bytes implementation<commit_after>use alloc::borrow::Cow;
use alloc::string::String;
use core::fmt::{self, Debug, Display};
use core::marker::{PhantomData, PhantomPinned};
use core::pin::Pin;
use core::slice;
use core::str::{self, Utf8Error};

extern "C" {
    #[link_name = "cxxbridge05$cxx_string$data"]
    fn string_data(this: &CxxString) -> *const u8;
    #[link_name = "cxxbridge05$cxx_string$length"]
    fn string_length(this: &CxxString) -> usize;
    #[link_name = "cxxbridge05$cxx_string$push"]
    fn string_push(this: Pin<&mut CxxString>, ptr: *const u8, len: usize);
}

/// Binding to C++ `std::string`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxString` by value. C++'s string
/// requires a move constructor and may hold internal pointers, which is not
/// compatible with Rust's move behavior. Instead in Rust code we will only ever
/// look at a CxxString through a reference or smart pointer, as in `&CxxString`
/// or `UniquePtr<CxxString>`.
#[repr(C)]
pub struct CxxString {
    _private: [u8; 0],
    _pinned: PhantomData<PhantomPinned>,
}

impl CxxString {
    /// Returns the length of the string in bytes.
    ///
    /// Matches the behavior of C++ [std::string::size][size].
    ///
    /// [size]: https://en.cppreference.com/w/cpp/string/basic_string/size
    pub fn len(&self) -> usize {
        unsafe { string_length(self) }
    }

    /// Returns true if `self` has a length of zero bytes.
    ///
    /// Matches the behavior of C++ [std::string::empty][empty].
    ///
    /// [empty]: https://en.cppreference.com/w/cpp/string/basic_string/empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a byte slice of this string's contents.
    pub fn as_bytes(&self) -> &[u8] {
        let data = self.as_ptr();
        let len = self.len();
        unsafe { slice::from_raw_parts(data, len) }
    }

    /// Produces a pointer to the first character of the string.
    ///
    /// Matches the behavior of C++ [std::string::data][data].
    ///
    /// Note that the return type may look like `const char *` but is not a
    /// `const char *` in the typical C sense, as C++ strings may contain
    /// internal null bytes. As such, the returned pointer only makes sense as a
    /// string in combination with the length returned by [`len()`][len].
    ///
    /// [data]: https://en.cppreference.com/w/cpp/string/basic_string/data
    /// [len]: #method.len
    pub fn as_ptr(&self) -> *const u8 {
        unsafe { string_data(self) }
    }

    /// Validates that the C++ string contains UTF-8 data and produces a view of
    /// it as a Rust &str, otherwise an error.
    pub fn to_str(&self) -> Result<&str, Utf8Error> {
        str::from_utf8(self.as_bytes())
    }

    /// If the contents of the C++ string are valid UTF-8, this function returns
    /// a view as a Cow::Borrowed &str. Otherwise replaces any invalid UTF-8
    /// sequences with the U+FFFD [replacement character] and returns a
    /// Cow::Owned String.
    ///
    /// [replacement character]: https://doc.rust-lang.org/std/char/constant.REPLACEMENT_CHARACTER.html
    pub fn to_string_lossy(&self) -> Cow<str> {
        String::from_utf8_lossy(self.as_bytes())
    }

    /// Appends a given string slice onto the end of this C++ string.
    pub fn push_str(self: Pin<&mut Self>, s: &str) {
        self.push_bytes(s.as_bytes());
    }

    /// Appends arbitrary bytes onto the end of this C++ string.
    pub fn push_bytes(self: Pin<&mut Self>, bytes: &[u8]) {
        unsafe { string_push(self, bytes.as_ptr(), bytes.len()) }
    }
}

impl Display for CxxString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(self.to_string_lossy().as_ref(), f)
    }
}

impl Debug for CxxString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self.to_string_lossy().as_ref(), f)
    }
}

impl PartialEq for CxxString {
    fn eq(&self, other: &CxxString) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl PartialEq<CxxString> for str {
    fn eq(&self, other: &CxxString) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl PartialEq<str> for CxxString {
    fn eq(&self, other: &str) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}
<|endoftext|>


<commit_before>use super::book::{Book, BookAccounting};
use std::collections::HashMap;
use std::fmt;
use std::cmp::Ordering;
use ::error::PoloError;
use super::timeseries::Timeseries;
use super::tradestats::{TradeStats, TimeStats};
use time;

#[derive(Clone, Debug, PartialEq)]
pub struct Record {
  pub rate: f64,
  pub amount: f64
}

#[derive(Clone, Debug, PartialEq)]
pub struct BookStats {
  pub min_sell: f64,
  pub max_buy: f64,
  pub sum_sell: f64,
  pub sum_buy: f64,
  pub vec_buy: Vec<Record>,
  pub vec_sell: Vec<Record>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct BookWithStats {
  book: Book,
  pub stats: BookStats,
  pub trade_series_1s: Timeseries<TradeStats>,
  pub trade_stats_1m: TradeStats,
}

// BookStats operations

impl BookStats {
  pub fn new(book: &Book) -> BookStats {
    let (sum_buy, mut vec_buy) = hash_to_vec(&book.buy);
    vec_buy.sort_unstable_by(|rec1, rec2| f64cmp(&rec2.rate, &rec1.rate));
    let (sum_sell, mut vec_sell) = hash_to_vec(&book.sell);
    vec_sell.sort_unstable_by(|rec1, rec2| f64cmp(&rec1.rate, &rec2.rate));

    BookStats {
      min_sell: vec_sell.first().map_or(0.0, |rec| rec.rate),
      max_buy: vec_buy.first().map_or(0.0, |rec| rec.rate),
      sum_sell,
      sum_buy,
      vec_buy,
      vec_sell,
    }
  }

  pub fn update_sell(&mut self, rate: f64, amount: f64, prev_amount: Option<f64>) {
    let idx_r = self.vec_sell.binary_search_by(|rec| f64cmp(&rec.rate, &rate));
    let stat_cmp = self.min_sell > rate;
    update_sorted_vec(idx_r, &mut self.vec_sell, &mut self.min_sell, rate, amount, stat_cmp);
    self.sum_sell = self.sum_sell + amount - prev_amount.unwrap_or(0.0);
  }

  pub fn update_buy(&mut self, rate: f64, amount: f64, prev_amount: Option<f64>) {
    let idx_r = self.vec_buy.binary_search_by(|rec| f64cmp(&rate, &rec.rate));
    let stat_cmp = self.max_buy < rate;
    update_sorted_vec(idx_r, &mut self.vec_buy, &mut self.max_buy, rate, amount, stat_cmp);
    self.sum_buy = self.sum_buy + amount - prev_amount.unwrap_or(0.0);
  }
}

impl fmt::Display for BookStats {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "(BUY min {} sum {} | SELL max {} sum {})", self.max_buy, self.sum_buy, self.min_sell, self.sum_sell)
  }
}

// BookWithStats operations

impl BookWithStats {
  pub fn new(book: Book) -> BookWithStats {
    BookWithStats {
      stats: BookStats::new(&book),
      trade_series_1s: Timeseries::new(),
      trade_stats_1m: TradeStats::default(),
      book
    }
  }
}

impl fmt::Display for BookWithStats {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "  ** STATS ")?;
    self.stats.fmt(f)?;
    if let Some(last_sec) = self.trade_series_1s.data.front() {
      write!(f, "\n  >> T1s: ")?;
      last_sec.fmt(f)?;
    }
    write!(f, "\n  >> T1m: ")?;
    self.trade_stats_1m.fmt(f)
  }
}

impl BookAccounting for BookWithStats {
  fn update_sell(&mut self, rate: String, amount: f64) -> Option<f64> {
    let rate_f64 = rate.parse::<f64>();
    let prev_amount = self.book.update_sell(rate, amount);
    if let Ok(rate_f64) = rate_f64 {
      self.stats.update_sell(rate_f64, amount, prev_amount);
    };
    prev_amount
  }

  fn update_buy(&mut self, rate: String, amount: f64) -> Option<f64> {
    let rate_f64 = rate.parse::<f64>();
    let prev_amount = self.book.update_buy(rate, amount);
    if let Ok(rate_f64) = rate_f64 {
      self.stats.update_buy(rate_f64, amount, prev_amount);
    };
    prev_amount
  }

  fn new_deal(&mut self, id: u64, rate: String, amount: f64) -> Result<f64, PoloError> {
    let rate_f64 = self.book.new_deal(id, rate, amount)?;
    Ok(rate_f64)
  }

  fn book_ref(&self) -> &Book {
    &self.book
  }
}

impl TimeStats for BookWithStats {
  fn update_stats_1s(&mut self) {
    let timestamp = time::get_time();
    // cleanup deals time series
    self.book.deals.drain_until(time::Timespec { sec: timestamp.sec - 600, nsec: 0 });
    // update stats with last second of data
    let last_second = self.book.deals.vec_after(time::Timespec { sec: timestamp.sec - 1, nsec: timestamp.nsec });
    let stats = TradeStats::new(last_second);
    self.trade_stats_1m = self.trade_stats_1m + &stats;
    self.trade_series_1s.add(stats);
    if self.trade_series_1s.data.len() > 60 {
      let stats_1m_ago = &self.trade_series_1s.data[self.trade_series_1s.data.len() - 60];
      println!("stats_1m_ago {:?}", stats_1m_ago);
      self.trade_stats_1m = self.trade_stats_1m - stats_1m_ago;
    }
  }
}

/**
 ** Library functions
 **/

fn f64cmp(f1: &f64, f2: &f64) -> Ordering {
  f1.partial_cmp(f2).unwrap_or(Ordering::Equal)
}

fn hash_to_vec(hash: &HashMap<String, f64>) -> (f64, Vec<Record>) {
  let mut sum = 0.0;
  let vec = hash.iter().filter_map(|(rate_s, amount)| {
    rate_s.parse::<f64>()
      .and_then(|rate| {
        sum += *amount;
        Ok(Record { rate, amount: *amount })
      }).ok()
  }).collect();
  (sum, vec)
}

fn update_sorted_vec(idx_r: Result<usize, usize>, vec: &mut Vec<Record>, stat: &mut f64, rate: f64, amount: f64, stat_cmp: bool) {
  if amount == 0.0 {
    if let Ok(idx) = idx_r {
      vec.remove(idx);
    };
    if *stat == rate || *stat == 0.0 {
      *stat = vec.first().map_or(*stat, |rec| rec.rate);
    }
  } else if amount > 0.0  {
    match idx_r {
      Ok(idx) => vec[idx].amount = amount,
      Err(idx) => vec.insert(idx, Record { rate, amount })
    };
    if stat_cmp || *stat == 0.0 {
      *stat = rate
    }
  };
}

/**
 ** TESTS TESTS TESTS
 **/

#[cfg(test)]
mod tests {
  use super::BookWithStats;
  use ::data::book::Book;
  use json;
  use std::convert::TryFrom;

  #[test]
  fn stats_init() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let book_stats = BookWithStats::new(book).stats;
    assert_eq!(book_stats.min_sell, 0.13161901);
    assert_eq!(book_stats.max_buy, 0.13109621);
  }

  #[test]
  fn stats_init_wrong_order() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13361901": 0.23709568, "0.13164313": "0.17328089"}, {"0.12909621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let book_stats = BookWithStats::new(book).stats;
    assert_eq!(book_stats.min_sell, 0.13164313);
    assert_eq!(book_stats.max_buy, 0.13069621);
  }

  #[test]
  fn stats_update_sell_zero() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let mut book_stats = BookWithStats::new(book).stats;
    book_stats.update_sell(0.1, 0.0, None);
    assert_eq!(book_stats.min_sell, 0.13161901);
  }

  #[test]
  fn stats_update_sell_shift_zero() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let mut book_stats = BookWithStats::new(book).stats;
    book_stats.update_sell(0.13161901, 0.0, Some(0.23709568));
    assert_eq!(book_stats.min_sell, 0.13164313);
  }

  #[test]
  fn stats_update_sell() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let mut book_stats = BookWithStats::new(book).stats;
    book_stats.update_sell(0.1, 1.0, None);
    assert_eq!(book_stats.min_sell, 0.1);
  }

  #[test]
  fn stats_update_buy_zero() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let mut book_stats = BookWithStats::new(book).stats;
    book_stats.update_buy(100.0, 0.0, None);
    assert_eq!(book_stats.max_buy, 0.13109621);
  }

  #[test]
  fn stats_update_buy_shift_zero() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let mut book_stats = BookWithStats::new(book).stats;
    book_stats.update_buy(0.13109621, 0.0, Some(0.2331));
    assert_eq!(book_stats.max_buy, 0.13069621);
  }

  #[test]
  fn stats_update_buy() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let mut book_stats = BookWithStats::new(book).stats;
    book_stats.update_buy(100.0, 1.0, None);
    assert_eq!(book_stats.max_buy, 100.0);
  }

}<commit_msg>fix 1m ago stat update<commit_after>use super::book::{Book, BookAccounting};
use std::collections::HashMap;
use std::fmt;
use std::cmp::Ordering;
use ::error::PoloError;
use super::timeseries::Timeseries;
use super::tradestats::{TradeStats, TimeStats};
use time;

#[derive(Clone, Debug, PartialEq)]
pub struct Record {
  pub rate: f64,
  pub amount: f64
}

#[derive(Clone, Debug, PartialEq)]
pub struct BookStats {
  pub min_sell: f64,
  pub max_buy: f64,
  pub sum_sell: f64,
  pub sum_buy: f64,
  pub vec_buy: Vec<Record>,
  pub vec_sell: Vec<Record>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct BookWithStats {
  book: Book,
  pub stats: BookStats,
  pub trade_series_1s: Timeseries<TradeStats>,
  pub trade_stats_1m: TradeStats,
}

// BookStats operations

impl BookStats {
  pub fn new(book: &Book) -> BookStats {
    let (sum_buy, mut vec_buy) = hash_to_vec(&book.buy);
    vec_buy.sort_unstable_by(|rec1, rec2| f64cmp(&rec2.rate, &rec1.rate));
    let (sum_sell, mut vec_sell) = hash_to_vec(&book.sell);
    vec_sell.sort_unstable_by(|rec1, rec2| f64cmp(&rec1.rate, &rec2.rate));

    BookStats {
      min_sell: vec_sell.first().map_or(0.0, |rec| rec.rate),
      max_buy: vec_buy.first().map_or(0.0, |rec| rec.rate),
      sum_sell,
      sum_buy,
      vec_buy,
      vec_sell,
    }
  }

  pub fn update_sell(&mut self, rate: f64, amount: f64, prev_amount: Option<f64>) {
    let idx_r = self.vec_sell.binary_search_by(|rec| f64cmp(&rec.rate, &rate));
    let stat_cmp = self.min_sell > rate;
    update_sorted_vec(idx_r, &mut self.vec_sell, &mut self.min_sell, rate, amount, stat_cmp);
    self.sum_sell = self.sum_sell + amount - prev_amount.unwrap_or(0.0);
  }

  pub fn update_buy(&mut self, rate: f64, amount: f64, prev_amount: Option<f64>) {
    let idx_r = self.vec_buy.binary_search_by(|rec| f64cmp(&rate, &rec.rate));
    let stat_cmp = self.max_buy < rate;
    update_sorted_vec(idx_r, &mut self.vec_buy, &mut self.max_buy, rate, amount, stat_cmp);
    self.sum_buy = self.sum_buy + amount - prev_amount.unwrap_or(0.0);
  }
}

impl fmt::Display for BookStats {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "(BUY min {} sum {} | SELL max {} sum {})", self.max_buy, self.sum_buy, self.min_sell, self.sum_sell)
  }
}

// BookWithStats operations

impl BookWithStats {
  pub fn new(book: Book) -> BookWithStats {
    BookWithStats {
      stats: BookStats::new(&book),
      trade_series_1s: Timeseries::new(),
      trade_stats_1m: TradeStats::default(),
      book
    }
  }
}

impl fmt::Display for BookWithStats {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "  ** STATS ")?;
    self.stats.fmt(f)?;
    if let Some(last_sec) = self.trade_series_1s.data.front() {
      write!(f, "\n  >> T1s: ")?;
      last_sec.fmt(f)?;
    }
    write!(f, "\n  >> T1m: ")?;
    self.trade_stats_1m.fmt(f)
  }
}

impl BookAccounting for BookWithStats {
  fn update_sell(&mut self, rate: String, amount: f64) -> Option<f64> {
    let rate_f64 = rate.parse::<f64>();
    let prev_amount = self.book.update_sell(rate, amount);
    if let Ok(rate_f64) = rate_f64 {
      self.stats.update_sell(rate_f64, amount, prev_amount);
    };
    prev_amount
  }

  fn update_buy(&mut self, rate: String, amount: f64) -> Option<f64> {
    let rate_f64 = rate.parse::<f64>();
    let prev_amount = self.book.update_buy(rate, amount);
    if let Ok(rate_f64) = rate_f64 {
      self.stats.update_buy(rate_f64, amount, prev_amount);
    };
    prev_amount
  }

  fn new_deal(&mut self, id: u64, rate: String, amount: f64) -> Result<f64, PoloError> {
    let rate_f64 = self.book.new_deal(id, rate, amount)?;
    Ok(rate_f64)
  }

  fn book_ref(&self) -> &Book {
    &self.book
  }
}

impl TimeStats for BookWithStats {
  fn update_stats_1s(&mut self) {
    let timestamp = time::get_time();
    // cleanup deals time series
    self.book.deals.drain_until(time::Timespec { sec: timestamp.sec - 600, nsec: 0 });
    // update stats with last second of data
    let last_second = self.book.deals.vec_after(time::Timespec { sec: timestamp.sec - 1, nsec: timestamp.nsec });
    let stats = TradeStats::new(last_second);
    self.trade_stats_1m = self.trade_stats_1m + &stats;
    self.trade_series_1s.add(stats);
    if let Some(stats_1m_ago) = self.trade_series_1s.data.get(60) {
      println!("stats_1m_ago {:?}", stats_1m_ago);
      self.trade_stats_1m = self.trade_stats_1m - stats_1m_ago;
    }
  }
}

/**
 ** Library functions
 **/

fn f64cmp(f1: &f64, f2: &f64) -> Ordering {
  f1.partial_cmp(f2).unwrap_or(Ordering::Equal)
}

fn hash_to_vec(hash: &HashMap<String, f64>) -> (f64, Vec<Record>) {
  let mut sum = 0.0;
  let vec = hash.iter().filter_map(|(rate_s, amount)| {
    rate_s.parse::<f64>()
      .and_then(|rate| {
        sum += *amount;
        Ok(Record { rate, amount: *amount })
      }).ok()
  }).collect();
  (sum, vec)
}

fn update_sorted_vec(idx_r: Result<usize, usize>, vec: &mut Vec<Record>, stat: &mut f64, rate: f64, amount: f64, stat_cmp: bool) {
  if amount == 0.0 {
    if let Ok(idx) = idx_r {
      vec.remove(idx);
    };
    if *stat == rate || *stat == 0.0 {
      *stat = vec.first().map_or(*stat, |rec| rec.rate);
    }
  } else if amount > 0.0  {
    match idx_r {
      Ok(idx) => vec[idx].amount = amount,
      Err(idx) => vec.insert(idx, Record { rate, amount })
    };
    if stat_cmp || *stat == 0.0 {
      *stat = rate
    }
  };
}

/**
 ** TESTS TESTS TESTS
 **/

#[cfg(test)]
mod tests {
  use super::BookWithStats;
  use ::data::book::Book;
  use json;
  use std::convert::TryFrom;

  #[test]
  fn stats_init() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let book_stats = BookWithStats::new(book).stats;
    assert_eq!(book_stats.min_sell, 0.13161901);
    assert_eq!(book_stats.max_buy, 0.13109621);
  }

  #[test]
  fn stats_init_wrong_order() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13361901": 0.23709568, "0.13164313": "0.17328089"}, {"0.12909621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let book_stats = BookWithStats::new(book).stats;
    assert_eq!(book_stats.min_sell, 0.13164313);
    assert_eq!(book_stats.max_buy, 0.13069621);
  }

  #[test]
  fn stats_update_sell_zero() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let mut book_stats = BookWithStats::new(book).stats;
    book_stats.update_sell(0.1, 0.0, None);
    assert_eq!(book_stats.min_sell, 0.13161901);
  }

  #[test]
  fn stats_update_sell_shift_zero() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let mut book_stats = BookWithStats::new(book).stats;
    book_stats.update_sell(0.13161901, 0.0, Some(0.23709568));
    assert_eq!(book_stats.min_sell, 0.13164313);
  }

  #[test]
  fn stats_update_sell() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let mut book_stats = BookWithStats::new(book).stats;
    book_stats.update_sell(0.1, 1.0, None);
    assert_eq!(book_stats.min_sell, 0.1);
  }

  #[test]
  fn stats_update_buy_zero() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let mut book_stats = BookWithStats::new(book).stats;
    book_stats.update_buy(100.0, 0.0, None);
    assert_eq!(book_stats.max_buy, 0.13109621);
  }

  #[test]
  fn stats_update_buy_shift_zero() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let mut book_stats = BookWithStats::new(book).stats;
    book_stats.update_buy(0.13109621, 0.0, Some(0.2331));
    assert_eq!(book_stats.max_buy, 0.13069621);
  }

  #[test]
  fn stats_update_buy() {
    let book_init = r#"{"currencyPair": "BTC_BCH", "orderBook": [{"0.13161901": 0.23709568, "0.13164313": "0.17328089"}, {"0.13109621": 0.2331, "0.13069621": 0.2331}]}"#;
    let book = Book::try_from(&json::parse(book_init).unwrap()).unwrap();
    let mut book_stats = BookWithStats::new(book).stats;
    book_stats.update_buy(100.0, 1.0, None);
    assert_eq!(book_stats.max_buy, 100.0);
  }

}<|endoftext|>


<commit_before>use std;

use manager;
use manager::NetworkManager;

#[derive(Debug)]
pub struct Device {
    pub interface: String,
    pub path: String,
    pub device_type: DeviceType,
    pub state: DeviceState,
    pub real: bool,
}

impl Device {
    pub fn from_path(manager: &NetworkManager, path: &String) -> Result<Device, String> {
        let interface = try!(manager.get_device_interface(&path));

        let device_type = try!(manager.get_device_type(&path));

        let state = try!(manager.get_device_state(&path));

        let real = try!(manager.is_device_real(&path));

        Ok(Device {
               interface: interface,
               path: path.clone(),
               device_type: device_type,
               state: state,
               real: real,
           })
    }
}

#[derive(Debug, PartialEq)]
pub enum DeviceType {
    Unknown,
    Generic,
    Ethernet,
    WiFi,
    Bridge,
}

impl From<i64> for DeviceType {
    fn from(state: i64) -> Self {
        match state {
            0 => DeviceType::Unknown,
            14 => DeviceType::Generic,
            1 => DeviceType::Ethernet,
            2 => DeviceType::WiFi,
            13 => DeviceType::Bridge,
            _ => DeviceType::Unknown,

        }
    }
}

#[derive(Debug, PartialEq)]
pub enum DeviceState {
    Unknown,
    Unmanaged,
    Unavailable,
    Disconnected,
    Activated,
    Deactivating,
    Failed,
}

impl From<i64> for DeviceState {
    fn from(state: i64) -> Self {
        match state {
            0 => DeviceState::Unknown,
            10 => DeviceState::Unmanaged,
            20 => DeviceState::Unavailable,
            30 => DeviceState::Disconnected,
            100 => DeviceState::Activated,
            110 => DeviceState::Deactivating,
            120 => DeviceState::Failed,
            _ => DeviceState::Unknown,

        }
    }
}

/// Get a list of Network Manager devices.
///
/// # Examples
///
/// ```
/// use network_manager::device;
/// use network_manager::manager;
/// let manager = manager::new();
/// let devices = device::list(&manager).unwrap();
/// println!("{:?}", devices);
/// ```
pub fn list(manager: &NetworkManager) -> Result<Vec<Device>, String> {
    let device_paths = try!(manager.get_devices());

    let mut result = Vec::new();

    for path in device_paths {
        let device = try!(Device::from_path(manager, &path));

        result.push(device);
    }

    Ok(result)
}

#[test]
fn test_list_function() {
    let manager = manager::new();
    let devices = list(&manager).unwrap();
    assert!(devices.len() > 0);
}

/// Connects a Network Manager device.
///
/// # Examples
///
/// # ```
/// # use network_manager::device;
/// # use network_manager::manager;
/// # let manager = manager::new();
/// # let mut devices = device::list(&manager).unwrap();
/// # let i = devices.iter().position(|ref d| d.device_type == device::DeviceType::WiFi).unwrap();
/// # let device = &mut devices[i];
/// # device::connect(&manager, device, 10).unwrap();
/// # ```
pub fn connect(manager: &NetworkManager, device: &mut Device, time_out: i32) -> Result<(), String> {
    match device.state {
        DeviceState::Activated => Ok(()),
        _ => {
            try!(manager.activate_device(&device.path));

            wait(manager, device, time_out, DeviceState::Activated)
        }
    }
}

/// Disconnect a Network Manager device.
///
/// # Examples
///
/// ```
/// use network_manager::device;
/// use network_manager::manager;
/// let manager = manager::new();
/// let mut devices = device::list(&manager).unwrap();
/// let i = devices.iter().position(|ref d| d.device_type == device::DeviceType::WiFi).unwrap();
/// let device = &mut devices[i];
/// device::disconnect(&manager, device, 10).unwrap();
/// ```
pub fn disconnect(manager: &NetworkManager,
                  device: &mut Device,
                  time_out: i32)
                  -> Result<(), String> {
    match device.state {
        DeviceState::Disconnected => Ok(()),
        _ => {
            try!(manager.disconnect_device(&device.path));

            wait(manager, device, time_out, DeviceState::Disconnected)
        }
    }
}

fn wait(manager: &NetworkManager,
        device: &mut Device,
        time_out: i32,
        target_state: DeviceState)
        -> Result<(), String> {
    if time_out == 0 {
        return Ok(());
    }

    let mut total_time = 0;

    while total_time < time_out {
        device.state = try!(manager.get_device_state(&device.path));

        if device.state == target_state {
            return Ok(());
        }

        std::thread::sleep(std::time::Duration::from_secs(1));

        total_time += 1;
    }

    Err("service timed out".to_string())
}

#[test]
fn test_connect_disconnect_functions() {
    let manager = manager::new();

    let mut devices = list(&manager).unwrap();

    let i = devices.iter().position(|ref d| d.device_type == DeviceType::WiFi).unwrap();
    let device = &mut devices[i];

    if device.state == DeviceState::Activated {
        disconnect(&manager, device, 10).unwrap();
        assert_eq!(DeviceState::Disconnected, device.state);

        connect(&manager, device, 10).unwrap();
        assert_eq!(DeviceState::Activated, device.state);
    } else {
        connect(&manager, device, 10).unwrap();
        assert_eq!(DeviceState::Activated, device.state);

        disconnect(&manager, device, 10).unwrap();
        assert_eq!(DeviceState::Disconnected, device.state);
    }
}
<commit_msg>Formatting fix for the device module<commit_after>use std;

use manager;
use manager::NetworkManager;

#[derive(Debug)]
pub struct Device {
    pub interface: String,
    pub path: String,
    pub device_type: DeviceType,
    pub state: DeviceState,
    pub real: bool,
}

impl Device {
    pub fn from_path(manager: &NetworkManager, path: &String) -> Result<Device, String> {
        let interface = try!(manager.get_device_interface(&path));

        let device_type = try!(manager.get_device_type(&path));

        let state = try!(manager.get_device_state(&path));

        let real = try!(manager.is_device_real(&path));

        Ok(Device {
               interface: interface,
               path: path.clone(),
               device_type: device_type,
               state: state,
               real: real,
           })
    }
}

#[derive(Debug, PartialEq)]
pub enum DeviceType {
    Unknown,
    Generic,
    Ethernet,
    WiFi,
    Bridge,
}

impl From<i64> for DeviceType {
    fn from(state: i64) -> Self {
        match state {
            0 => DeviceType::Unknown,
            14 => DeviceType::Generic,
            1 => DeviceType::Ethernet,
            2 => DeviceType::WiFi,
            13 => DeviceType::Bridge,
            _ => DeviceType::Unknown,

        }
    }
}

#[derive(Debug, PartialEq)]
pub enum DeviceState {
    Unknown,
    Unmanaged,
    Unavailable,
    Disconnected,
    Activated,
    Deactivating,
    Failed,
}

impl From<i64> for DeviceState {
    fn from(state: i64) -> Self {
        match state {
            0 => DeviceState::Unknown,
            10 => DeviceState::Unmanaged,
            20 => DeviceState::Unavailable,
            30 => DeviceState::Disconnected,
            100 => DeviceState::Activated,
            110 => DeviceState::Deactivating,
            120 => DeviceState::Failed,
            _ => DeviceState::Unknown,

        }
    }
}

/// Get a list of Network Manager devices.
///
/// # Examples
///
/// ```
/// use network_manager::device;
/// use network_manager::manager;
/// let manager = manager::new();
/// let devices = device::list(&manager).unwrap();
/// println!("{:?}", devices);
/// ```
pub fn list(manager: &NetworkManager) -> Result<Vec<Device>, String> {
    let device_paths = try!(manager.get_devices());

    let mut result = Vec::new();

    for path in device_paths {
        let device = try!(Device::from_path(manager, &path));

        result.push(device);
    }

    Ok(result)
}

#[test]
fn test_list_function() {
    let manager = manager::new();
    let devices = list(&manager).unwrap();
    assert!(devices.len() > 0);
}

/// Connects a Network Manager device.
///
/// # Examples
///
/// # ```
/// # use network_manager::device;
/// # use network_manager::manager;
/// # let manager = manager::new();
/// # let mut devices = device::list(&manager).unwrap();
/// # let i = devices.iter().position(|ref d| d.device_type == device::DeviceType::WiFi).unwrap();
/// # let device = &mut devices[i];
/// # device::connect(&manager, device, 10).unwrap();
/// # ```
pub fn connect(manager: &NetworkManager, device: &mut Device, time_out: i32) -> Result<(), String> {
    match device.state {
        DeviceState::Activated => Ok(()),
        _ => {
            try!(manager.activate_device(&device.path));

            wait(manager, device, time_out, DeviceState::Activated)
        }
    }
}

/// Disconnect a Network Manager device.
///
/// # Examples
///
/// ```
/// use network_manager::device;
/// use network_manager::manager;
/// let manager = manager::new();
/// let mut devices = device::list(&manager).unwrap();
/// let i = devices.iter().position(|ref d| d.device_type == device::DeviceType::WiFi).unwrap();
/// let device = &mut devices[i];
/// device::disconnect(&manager, device, 10).unwrap();
/// ```
pub fn disconnect(manager: &NetworkManager,
                  device: &mut Device,
                  time_out: i32)
                  -> Result<(), String> {
    match device.state {
        DeviceState::Disconnected => Ok(()),
        _ => {
            try!(manager.disconnect_device(&device.path));

            wait(manager, device, time_out, DeviceState::Disconnected)
        }
    }
}

fn wait(manager: &NetworkManager,
        device: &mut Device,
        time_out: i32,
        target_state: DeviceState)
        -> Result<(), String> {
    if time_out == 0 {
        return Ok(());
    }

    let mut total_time = 0;

    while total_time < time_out {
        device.state = try!(manager.get_device_state(&device.path));

        if device.state == target_state {
            return Ok(());
        }

        std::thread::sleep(std::time::Duration::from_secs(1));

        total_time += 1;
    }

    Err("service timed out".to_string())
}

#[test]
fn test_connect_disconnect_functions() {
    let manager = manager::new();

    let mut devices = list(&manager).unwrap();

    let i = devices
        .iter()
        .position(|ref d| d.device_type == DeviceType::WiFi)
        .unwrap();
    let device = &mut devices[i];

    if device.state == DeviceState::Activated {
        disconnect(&manager, device, 10).unwrap();
        assert_eq!(DeviceState::Disconnected, device.state);

        connect(&manager, device, 10).unwrap();
        assert_eq!(DeviceState::Activated, device.state);
    } else {
        connect(&manager, device, 10).unwrap();
        assert_eq!(DeviceState::Activated, device.state);

        disconnect(&manager, device, 10).unwrap();
        assert_eq!(DeviceState::Disconnected, device.state);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::sync::{Arc, mpsc};

use objects::Update;
use command::Command;
use bot::Bot;

/// A `Dispatcher` which will receive updates from the `Updater` and dispatches
/// them to the registered handlers.
///
/// You can add your command and message handlers to the `Dispatcher`.
pub struct Dispatcher {
    command_handlers: HashMap<String, (Box<Command>, bool)>,
    message_handlers: Vec<Box<Command>>,
}

impl Dispatcher {
    /// Constructs a new `Dispatcher`.
    pub fn new() -> Self {
        debug!("Going to construct a new Dispatcher...");
        Dispatcher {
            command_handlers: HashMap::new(),
            message_handlers: Vec::new(),
        }
    }

    /// Add a function which implements the `Command` trait to the `Dispatcher.command_handlers`.
    pub fn add_command_handler<C: Command>(&mut self, command_name: &str, command: C, args: bool) {
        self.command_handlers
            .insert(command_name.to_string(), (Box::new(command), args));
    }

    /// Add a function which implements the `Command` trait to the `Dispatcher.message_handlers`.
    pub fn add_message_handler<C: Command>(&mut self, command: C) {
        self.message_handlers.push(Box::new(command));
    }

    /// Starts the update handling process and dispatches all the updates to the assigned handlers.
    pub fn start_handling(&mut self, rx: mpsc::Receiver<Update>, bot: Arc<Bot>) {
        debug!("Going to start dispatcher thread...");
        loop {
            let update = rx.recv().unwrap();

            if let Some(t) = update.clone().message.and_then(|t| t.text) {
                if t.starts_with("/") {
                    let msg = t.split_whitespace().collect::<Vec<&str>>();
                    let (_, bot_command) = msg[0].split_at(1);
                    let name_command = bot_command.split("@").collect::<Vec<&str>>();

                    if name_command.len() == 1 ||
                       name_command.len() == 2 && name_command[1] == bot.username {
                        let command = self.command_handlers.get_mut(name_command[0]);

                        if let Some(c) = command {
                            debug!("Going to execute the {} command", name_command[0]);
                            if c.1 {
                                let args = msg.clone().split_off(1);
                                c.0.execute(&bot, update, Some(args));
                            } else {
                                c.0.execute(&bot, update, None);
                            }
                            continue;
                        }
                    }
                }
            }
            for message_handler in self.message_handlers.iter_mut() {
                message_handler.execute(&bot, update.clone(), None);
            }
        }
    }
}
<commit_msg>Adding new debug message and modifying old one<commit_after>use std::collections::HashMap;
use std::sync::{Arc, mpsc};

use objects::Update;
use command::Command;
use bot::Bot;

/// A `Dispatcher` which will receive updates from the `Updater` and dispatches
/// them to the registered handlers.
///
/// You can add your command and message handlers to the `Dispatcher`.
pub struct Dispatcher {
    command_handlers: HashMap<String, (Box<Command>, bool)>,
    message_handlers: Vec<Box<Command>>,
}

impl Dispatcher {
    /// Constructs a new `Dispatcher`.
    pub fn new() -> Self {
        debug!("Going to construct a new Dispatcher...");
        Dispatcher {
            command_handlers: HashMap::new(),
            message_handlers: Vec::new(),
        }
    }

    /// Add a function which implements the `Command` trait to the `Dispatcher.command_handlers`.
    pub fn add_command_handler<C: Command>(&mut self, command_name: &str, command: C, args: bool) {
        self.command_handlers
            .insert(command_name.to_string(), (Box::new(command), args));
    }

    /// Add a function which implements the `Command` trait to the `Dispatcher.message_handlers`.
    pub fn add_message_handler<C: Command>(&mut self, command: C) {
        self.message_handlers.push(Box::new(command));
    }

    /// Starts the update handling process and dispatches all the updates to the assigned handlers.
    pub fn start_handling(&mut self, rx: mpsc::Receiver<Update>, bot: Arc<Bot>) {
        debug!("Going to start dispatcher thread...");
        loop {
            let update = rx.recv().unwrap();

            if let Some(t) = update.clone().message.and_then(|t| t.text) {
                if t.starts_with("/") {
                    let msg = t.split_whitespace().collect::<Vec<&str>>();
                    let (_, bot_command) = msg[0].split_at(1);
                    let name_command = bot_command.split("@").collect::<Vec<&str>>();

                    if name_command.len() == 1 ||
                       name_command.len() == 2 && name_command[1] == bot.username {
                        let command = self.command_handlers.get_mut(name_command[0]);

                        if let Some(c) = command {
                            debug!("Going to execute the {} command...", name_command[0]);
                            if c.1 {
                                let args = msg.clone().split_off(1);
                                debug!("With these arguments: {:?}", args);
                                c.0.execute(&bot, update, Some(args));
                            } else {
                                c.0.execute(&bot, update, None);
                            }
                            continue;
                        }
                    }
                }
            }
            for message_handler in self.message_handlers.iter_mut() {
                message_handler.execute(&bot, update.clone(), None);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::string::*;
use std::slice;
use std::fmt;

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum RGBSubmodel {
    RGB,
    SRGB,
}

impl fmt::Display for RGBSubmodel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = match *self {
            RGBSubmodel::RGB => "RGB".to_string(),
            RGBSubmodel::SRGB => "sRGB".to_string(),
        };
        write!(f, "{}", name)
    }
}

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum YUVSubmodel {
    YCbCr,
    YIQ,
    YUVJ,
}

impl fmt::Display for YUVSubmodel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = match *self {
            YUVSubmodel::YCbCr => "YCbCr".to_string(),
            YUVSubmodel::YIQ => "YIQ".to_string(),
            YUVSubmodel::YUVJ => "YUVJ".to_string(),
        };
        write!(f, "{}", name)
    }
}

#[derive(Debug, Clone,Copy,PartialEq)]
pub enum ColorModel {
    RGB(RGBSubmodel),
    YUV(YUVSubmodel),
    CMYK,
    HSV,
    LAB,
    XYZ,
}

impl ColorModel {
    pub fn get_default_components(&self) -> usize {
        match *self {
            ColorModel::CMYK => 4,
            _ => 3,
        }
    }
}

impl fmt::Display for ColorModel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = match *self {
            ColorModel::RGB(fmt) => format!("RGB({})", fmt).to_string(),
            ColorModel::YUV(fmt) => format!("YUV({})", fmt).to_string(),
            ColorModel::CMYK => "CMYK".to_string(),
            ColorModel::HSV => "HSV".to_string(),
            ColorModel::LAB => "LAB".to_string(),
            ColorModel::XYZ => "XYZ".to_string(),
        };
        write!(f, "{}", name)
    }
}

#[derive(Clone,Copy,PartialEq)]
pub struct Chromaton {
    h_ss: u8,
    v_ss: u8,
    packed: bool,
    depth: u8,
    shift: u8,
    comp_offs: u8,
    next_elem: u8,
}

impl Chromaton {
    pub fn get_subsampling(&self) -> (u8, u8) {
        (self.h_ss, self.v_ss)
    }
    pub fn is_packed(&self) -> bool {
        self.packed
    }
    pub fn get_depth(&self) -> u8 {
        self.depth
    }
    pub fn get_shift(&self) -> u8 {
        self.shift
    }
    pub fn get_offset(&self) -> u8 {
        self.comp_offs
    }
    pub fn get_step(&self) -> u8 {
        self.next_elem
    }

    pub fn get_width(&self, width: usize) -> usize {
        (width + ((1 << self.h_ss) - 1)) >> self.h_ss
    }
    pub fn get_height(&self, height: usize) -> usize {
        (height + ((1 << self.v_ss) - 1)) >> self.v_ss
    }
    pub fn get_linesize(&self, width: usize) -> usize {
        let d = self.depth as usize;
        (self.get_width(width) * d + d - 1) >> 3
    }
    pub fn get_data_size(&self, width: usize, height: usize) -> usize {
        let nh = (height + ((1 << self.v_ss) - 1)) >> self.v_ss;
        self.get_linesize(width) * nh
    }
}

impl fmt::Display for Chromaton {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let pfmt = if self.packed {
            let mask = ((1 << self.depth) - 1) << self.shift;
            format!("packed(+{},{:X}, step {})",
                    self.comp_offs,
                    mask,
                    self.next_elem)
        } else {
            format!("planar({},{})", self.comp_offs, self.next_elem)
        };
        write!(f, "({}x{}, {})", self.h_ss, self.v_ss, pfmt)
    }
}

#[derive(Clone,Copy,PartialEq)]
pub struct Formaton {
    model: ColorModel,
    components: u8,
    comp_info: [Option<Chromaton>; 5],
    elem_size: u8,
    be: bool,
    alpha: bool,
    palette: bool,
}

bitflags! {
    pub flags Flags: u8 {
        const BE       = 0x01,
        const ALPHA    = 0x02,
        const PALETTE  = 0x04,
    }
}

impl Formaton {
    pub fn new(model: ColorModel,
               comp1: Option<Chromaton>,
               comp2: Option<Chromaton>,
               comp3: Option<Chromaton>,
               comp4: Option<Chromaton>,
               comp5: Option<Chromaton>,
               flags: Flags,
               elem_size: u8)
               -> Self {
        let mut chromatons: [Option<Chromaton>; 5] = [None; 5];
        let mut ncomp = 0;
        let be = flags.contains(BE);
        let alpha = flags.contains(ALPHA);
        let palette = flags.contains(PALETTE);
        if let Some(c) = comp1 {
            chromatons[0] = Some(c);
            ncomp += 1;
        }
        if let Some(c) = comp2 {
            chromatons[1] = Some(c);
            ncomp += 1;
        }
        if let Some(c) = comp3 {
            chromatons[2] = Some(c);
            ncomp += 1;
        }
        if let Some(c) = comp4 {
            chromatons[3] = Some(c);
            ncomp += 1;
        }
        if let Some(c) = comp5 {
            chromatons[4] = Some(c);
            ncomp += 1;
        }

        Formaton {
            model: model,
            components: ncomp,
            comp_info: chromatons,
            elem_size: elem_size,
            be: be,
            alpha: alpha,
            palette: palette,
        }
    }

    pub fn get_model(&self) -> ColorModel {
        self.model
    }
    pub fn get_num_comp(&self) -> usize {
        self.components as usize
    }
    pub fn get_chromaton(&self, idx: usize) -> Option<Chromaton> {
        if idx < self.comp_info.len() {
            return self.comp_info[idx];
        }
        None
    }
    pub fn is_be(&self) -> bool {
        self.be
    }
    pub fn has_alpha(&self) -> bool {
        self.alpha
    }
    pub fn is_paletted(&self) -> bool {
        self.palette
    }
    pub fn get_elem_size(&self) -> u8 {
        self.elem_size
    }
}

impl<'a> IntoIterator for &'a Formaton {
    type Item = &'a Option<Chromaton>;
    type IntoIter = slice::Iter<'a, Option<Chromaton>>;

    fn into_iter(self) -> Self::IntoIter {
        self.comp_info.iter()
    }
}

impl fmt::Display for Formaton {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let end = if self.be {
            "BE"
        } else {
            "LE"
        };
        let palstr = if self.palette {
            "palette "
        } else {
            ""
        };
        let astr = if self.alpha {
            "alpha "
        } else {
            ""
        };
        let mut str = format!("Formaton for {} ({}{}elem {} size {}): ",
                              self.model,
                              palstr,
                              astr,
                              end,
                              self.elem_size);
        for &i in self.into_iter() {
            if let Some(chr) = i {
                str = format!("{} {}", str, chr);
            }
        }
        write!(f, "[{}]", str)
    }
}

macro_rules! chromaton {
    ($hs: expr, $vs: expr, $pck: expr, $d: expr, $sh: expr, $co: expr, $ne: expr) => ({
        Some(Chromaton {
                h_ss: $hs,
                v_ss: $vs,
                packed: $pck,
                depth: $d,
                shift: $sh,
                comp_offs: $co,
                next_elem: $ne })
    });
    (yuv8; $hs: expr, $vs: expr, $co: expr) => ({
        chromaton!($hs, $vs, false, 8, 0, $co, 1)
    });
    (packrgb; $d: expr, $s: expr, $co: expr, $ne: expr) => ({
        chromaton!(0, 0, true, $d, $s, $co, $ne)
    });
    (pal8; $co: expr) => ({
        chromaton!(0, 0, true, 8, 0, $co, 3)
    });
}

pub mod formats {
    use data::pixel::*;

    pub const YUV420: Formaton = Formaton {
        model: ColorModel::YUV(YUVSubmodel::YUVJ),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 1, 1, 1),
                    chromaton!(yuv8; 1, 1, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV410: Formaton = Formaton {
        model: ColorModel::YUV(YUVSubmodel::YUVJ),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 2, 2, 1),
                    chromaton!(yuv8; 2, 2, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const PAL8: Formaton = Formaton {
        model: ColorModel::RGB(RGBSubmodel::RGB),
        components: 3,
        comp_info: [chromaton!(pal8; 0), chromaton!(pal8; 1), chromaton!(pal8; 2), None, None],
        elem_size: 3,
        be: false,
        alpha: false,
        palette: true,
    };

    pub const RGB565: Formaton = Formaton {
        model: ColorModel::RGB(RGBSubmodel::RGB),
        components: 3,
        comp_info: [chromaton!(packrgb; 5, 11, 0, 2),
                    chromaton!(packrgb; 6,  5, 0, 2),
                    chromaton!(packrgb; 5,  0, 0, 2),
                    None,
                    None],
        elem_size: 2,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const RGB24: Formaton = Formaton {
        model: ColorModel::RGB(RGBSubmodel::RGB),
        components: 3,
        comp_info: [chromaton!(packrgb; 8, 0, 2, 3),
                    chromaton!(packrgb; 8, 0, 1, 3),
                    chromaton!(packrgb; 8, 0, 0, 3),
                    None,
                    None],
        elem_size: 3,
        be: false,
        alpha: false,
        palette: false,
    };
}

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

    #[test]
    fn fmt() {
        println!("formaton yuv- {}", formats::YUV420);
        println!("formaton pal- {}", formats::PAL8);
        println!("formaton rgb565- {}", formats::RGB565);
    }
}
<commit_msg>pixel: Add the Index syntactic sugar<commit_after>use std::string::*;
use std::slice;
use std::fmt;
use std::ops::Index;

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum RGBSubmodel {
    RGB,
    SRGB,
}

impl fmt::Display for RGBSubmodel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = match *self {
            RGBSubmodel::RGB => "RGB".to_string(),
            RGBSubmodel::SRGB => "sRGB".to_string(),
        };
        write!(f, "{}", name)
    }
}

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum YUVSubmodel {
    YCbCr,
    YIQ,
    YUVJ,
}

impl fmt::Display for YUVSubmodel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = match *self {
            YUVSubmodel::YCbCr => "YCbCr".to_string(),
            YUVSubmodel::YIQ => "YIQ".to_string(),
            YUVSubmodel::YUVJ => "YUVJ".to_string(),
        };
        write!(f, "{}", name)
    }
}

#[derive(Debug, Clone,Copy,PartialEq)]
pub enum ColorModel {
    RGB(RGBSubmodel),
    YUV(YUVSubmodel),
    CMYK,
    HSV,
    LAB,
    XYZ,
}

impl ColorModel {
    pub fn get_default_components(&self) -> usize {
        match *self {
            ColorModel::CMYK => 4,
            _ => 3,
        }
    }
}

impl fmt::Display for ColorModel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = match *self {
            ColorModel::RGB(fmt) => format!("RGB({})", fmt).to_string(),
            ColorModel::YUV(fmt) => format!("YUV({})", fmt).to_string(),
            ColorModel::CMYK => "CMYK".to_string(),
            ColorModel::HSV => "HSV".to_string(),
            ColorModel::LAB => "LAB".to_string(),
            ColorModel::XYZ => "XYZ".to_string(),
        };
        write!(f, "{}", name)
    }
}

#[derive(Clone,Copy,PartialEq)]
pub struct Chromaton {
    h_ss: u8,
    v_ss: u8,
    packed: bool,
    depth: u8,
    shift: u8,
    comp_offs: u8,
    next_elem: u8,
}

impl Chromaton {
    pub fn get_subsampling(&self) -> (u8, u8) {
        (self.h_ss, self.v_ss)
    }
    pub fn is_packed(&self) -> bool {
        self.packed
    }
    pub fn get_depth(&self) -> u8 {
        self.depth
    }
    pub fn get_shift(&self) -> u8 {
        self.shift
    }
    pub fn get_offset(&self) -> u8 {
        self.comp_offs
    }
    pub fn get_step(&self) -> u8 {
        self.next_elem
    }

    pub fn get_width(&self, width: usize) -> usize {
        (width + ((1 << self.h_ss) - 1)) >> self.h_ss
    }
    pub fn get_height(&self, height: usize) -> usize {
        (height + ((1 << self.v_ss) - 1)) >> self.v_ss
    }
    pub fn get_linesize(&self, width: usize) -> usize {
        let d = self.depth as usize;
        (self.get_width(width) * d + d - 1) >> 3
    }
    pub fn get_data_size(&self, width: usize, height: usize) -> usize {
        let nh = (height + ((1 << self.v_ss) - 1)) >> self.v_ss;
        self.get_linesize(width) * nh
    }
}

impl fmt::Display for Chromaton {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let pfmt = if self.packed {
            let mask = ((1 << self.depth) - 1) << self.shift;
            format!("packed(+{},{:X}, step {})",
                    self.comp_offs,
                    mask,
                    self.next_elem)
        } else {
            format!("planar({},{})", self.comp_offs, self.next_elem)
        };
        write!(f, "({}x{}, {})", self.h_ss, self.v_ss, pfmt)
    }
}

#[derive(Clone,Copy,PartialEq)]
pub struct Formaton {
    model: ColorModel,
    components: u8,
    comp_info: [Option<Chromaton>; 5],
    elem_size: u8,
    be: bool,
    alpha: bool,
    palette: bool,
}

bitflags! {
    pub flags Flags: u8 {
        const BE       = 0x01,
        const ALPHA    = 0x02,
        const PALETTE  = 0x04,
    }
}

impl Formaton {
    pub fn new(model: ColorModel,
               comp1: Option<Chromaton>,
               comp2: Option<Chromaton>,
               comp3: Option<Chromaton>,
               comp4: Option<Chromaton>,
               comp5: Option<Chromaton>,
               flags: Flags,
               elem_size: u8)
               -> Self {
        let mut chromatons: [Option<Chromaton>; 5] = [None; 5];
        let mut ncomp = 0;
        let be = flags.contains(BE);
        let alpha = flags.contains(ALPHA);
        let palette = flags.contains(PALETTE);
        if let Some(c) = comp1 {
            chromatons[0] = Some(c);
            ncomp += 1;
        }
        if let Some(c) = comp2 {
            chromatons[1] = Some(c);
            ncomp += 1;
        }
        if let Some(c) = comp3 {
            chromatons[2] = Some(c);
            ncomp += 1;
        }
        if let Some(c) = comp4 {
            chromatons[3] = Some(c);
            ncomp += 1;
        }
        if let Some(c) = comp5 {
            chromatons[4] = Some(c);
            ncomp += 1;
        }

        Formaton {
            model: model,
            components: ncomp,
            comp_info: chromatons,
            elem_size: elem_size,
            be: be,
            alpha: alpha,
            palette: palette,
        }
    }

    pub fn get_model(&self) -> ColorModel {
        self.model
    }
    pub fn get_num_comp(&self) -> usize {
        self.components as usize
    }
    pub fn get_chromaton(&self, idx: usize) -> Option<Chromaton> {
        if idx < self.comp_info.len() {
            return self.comp_info[idx];
        }
        None
    }
    pub fn is_be(&self) -> bool {
        self.be
    }
    pub fn has_alpha(&self) -> bool {
        self.alpha
    }
    pub fn is_paletted(&self) -> bool {
        self.palette
    }
    pub fn get_elem_size(&self) -> u8 {
        self.elem_size
    }
}

impl<'a> Index<usize> for &'a Formaton {
    type Output = Option<Chromaton>;

    fn index(&self, index: usize) -> &Self::Output {
        self.comp_info.index(index)
    }
}

impl<'a> IntoIterator for &'a Formaton {
    type Item = &'a Option<Chromaton>;
    type IntoIter = slice::Iter<'a, Option<Chromaton>>;

    fn into_iter(self) -> Self::IntoIter {
        self.comp_info.iter()
    }
}

impl fmt::Display for Formaton {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let end = if self.be {
            "BE"
        } else {
            "LE"
        };
        let palstr = if self.palette {
            "palette "
        } else {
            ""
        };
        let astr = if self.alpha {
            "alpha "
        } else {
            ""
        };
        let mut str = format!("Formaton for {} ({}{}elem {} size {}): ",
                              self.model,
                              palstr,
                              astr,
                              end,
                              self.elem_size);
        for &i in self.into_iter() {
            if let Some(chr) = i {
                str = format!("{} {}", str, chr);
            }
        }
        write!(f, "[{}]", str)
    }
}

macro_rules! chromaton {
    ($hs: expr, $vs: expr, $pck: expr, $d: expr, $sh: expr, $co: expr, $ne: expr) => ({
        Some(Chromaton {
                h_ss: $hs,
                v_ss: $vs,
                packed: $pck,
                depth: $d,
                shift: $sh,
                comp_offs: $co,
                next_elem: $ne })
    });
    (yuv8; $hs: expr, $vs: expr, $co: expr) => ({
        chromaton!($hs, $vs, false, 8, 0, $co, 1)
    });
    (packrgb; $d: expr, $s: expr, $co: expr, $ne: expr) => ({
        chromaton!(0, 0, true, $d, $s, $co, $ne)
    });
    (pal8; $co: expr) => ({
        chromaton!(0, 0, true, 8, 0, $co, 3)
    });
}

pub mod formats {
    use data::pixel::*;

    pub const YUV420: Formaton = Formaton {
        model: ColorModel::YUV(YUVSubmodel::YUVJ),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 1, 1, 1),
                    chromaton!(yuv8; 1, 1, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const YUV410: Formaton = Formaton {
        model: ColorModel::YUV(YUVSubmodel::YUVJ),
        components: 3,
        comp_info: [chromaton!(0, 0, false, 8, 0, 0, 1),
                    chromaton!(yuv8; 2, 2, 1),
                    chromaton!(yuv8; 2, 2, 2),
                    None,
                    None],
        elem_size: 0,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const PAL8: Formaton = Formaton {
        model: ColorModel::RGB(RGBSubmodel::RGB),
        components: 3,
        comp_info: [chromaton!(pal8; 0), chromaton!(pal8; 1), chromaton!(pal8; 2), None, None],
        elem_size: 3,
        be: false,
        alpha: false,
        palette: true,
    };

    pub const RGB565: Formaton = Formaton {
        model: ColorModel::RGB(RGBSubmodel::RGB),
        components: 3,
        comp_info: [chromaton!(packrgb; 5, 11, 0, 2),
                    chromaton!(packrgb; 6,  5, 0, 2),
                    chromaton!(packrgb; 5,  0, 0, 2),
                    None,
                    None],
        elem_size: 2,
        be: false,
        alpha: false,
        palette: false,
    };

    pub const RGB24: Formaton = Formaton {
        model: ColorModel::RGB(RGBSubmodel::RGB),
        components: 3,
        comp_info: [chromaton!(packrgb; 8, 0, 2, 3),
                    chromaton!(packrgb; 8, 0, 1, 3),
                    chromaton!(packrgb; 8, 0, 0, 3),
                    None,
                    None],
        elem_size: 3,
        be: false,
        alpha: false,
        palette: false,
    };
}

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

    #[test]
    fn fmt() {
        println!("formaton yuv- {}", formats::YUV420);
        println!("formaton pal- {}", formats::PAL8);
        println!("formaton rgb565- {}", formats::RGB565);
    }
}
<|endoftext|>


<commit_before>mod cmd;

use semck;
use parser::ast;
use parser::Parser;

use std::process::exit;

pub fn compile() {
    let cmd = match cmd::parse() {
        Ok(cmd) => cmd,

        Err(msg) => {
            println!("{}\n", msg);
            cmd::usage();

            exit(1);
        }
    };

    let mut parser = match Parser::from_file(cmd.filename()) {
        Err(_) => {
            println!("unable to read file `{}`", cmd.filename());
            exit(1);
        }

        Ok(parser) => parser
    };

    let (ast, mut interner) = match parser.parse() {
        Ok(ret) => ret,

        Err(error) => {
            error.print();
            exit(1);
        }
    };

    ast::dump::dump(&ast, &interner);

    if let Err(errors) = semck::check(&ast, &mut interner) {
        for err in &errors {
            err.print();
        }

        println!("\n{} errors found", errors.len());
        exit(1);
    }
}
<commit_msg>driver: replaced exits with panics<commit_after>mod cmd;

use semck;
use parser::ast;
use parser::Parser;

pub fn compile() {
    let cmd = match cmd::parse() {
        Ok(cmd) => cmd,

        Err(msg) => {
            println!("{}\n", msg);
            cmd::usage();

            panic!();
        }
    };

    let mut parser = match Parser::from_file(cmd.filename()) {
        Err(_) => {
            println!("unable to read file `{}`", cmd.filename());
            panic!();
        }

        Ok(parser) => parser
    };

    let (ast, mut interner) = match parser.parse() {
        Ok(ret) => ret,

        Err(error) => {
            error.print();
            panic!();
        }
    };

    ast::dump::dump(&ast, &interner);

    if let Err(errors) = semck::check(&ast, &mut interner) {
        for err in &errors {
            err.print();
        }

        println!("\n{} errors found", errors.len());
        panic!();
    }
}
<|endoftext|>


<commit_before>use std::process::exit;
use std::path::{Path, PathBuf};

use package::{
    PrebuiltPackage,
    download_package
};
use utils::find_cmd;

fn emscripten_package() -> Option< PrebuiltPackage > {
    let package =
        if cfg!( target_os = "linux" ) && cfg!( target_arch = "x86_64" ) {
            PrebuiltPackage {
                url: "https://github.com/koute/emscripten-build/releases/download/emscripten-1.38.19-1/emscripten-1.38.19-1-x86_64-unknown-linux-gnu.tgz",
                name: "emscripten",
                version: "1.38.19-1",
                arch: "x86_64-unknown-linux-gnu",
                hash: "baab5f1162901bfa220cb009dc628300c5e67b91cf58656ab6bf392d513bff9c",
                size: 211505607
            }
        } else if cfg!( target_os = "linux" ) && cfg!( target_arch = "x86" ) {
            PrebuiltPackage {
                url: "https://github.com/koute/emscripten-build/releases/download/emscripten-1.38.19-1/emscripten-1.38.19-1-i686-unknown-linux-gnu.tgz",
                name: "emscripten",
                version: "1.38.19-1",
                arch: "i686-unknown-linux-gnu",
                hash: "6d211eb0e9bbf82a1bf0dcc336486aa5191952f3938b7c0cf76b8d6946d4c117",
                size: 223770839
            }
        } else {
            return None;
        };

    Some( package )
}

fn binaryen_package() -> Option< PrebuiltPackage > {
    let package =
        if cfg!( target_os = "linux" ) && cfg!( target_arch = "x86_64" ) {
            PrebuiltPackage {
                url: "https://github.com/koute/emscripten-build/releases/download/emscripten-1.38.19-1/binaryen-1.38.19-1-x86_64-unknown-linux-gnu.tgz",
                name: "binaryen",
                version: "1.38.19-1",
                arch: "x86_64-unknown-linux-gnu",
                hash: "af079258c6f13234541d932b873762910951779c4682fc917255716637383dc9",
                size: 15818455
            }
        } else if cfg!( target_os = "linux" ) && cfg!( target_arch = "x86" ) {
            PrebuiltPackage {
                url: "https://github.com/koute/emscripten-build/releases/download/emscripten-1.38.19-1/binaryen-1.38.19-1-i686-unknown-linux-gnu.tgz",
                name: "binaryen",
                version: "1.38.19-1",
                arch: "i686-unknown-linux-gnu",
                hash: "9fd0e30d1760d29e3c96fa24592a35629876316fadb7ef882b9c6d8b2eafb0d8",
                size: 15951181
            }
        } else {
            return None;
        };

    Some( package )
}

fn check_emscripten() {
    let possible_commands =
        if cfg!( windows ) {
            &[ "emcc.bat" ]
        } else {
            &[ "emcc" ]
        };

    if find_cmd( possible_commands ).is_some() {
        return;
    }

    eprintln!( "error: you don't have Emscripten installed!" );
    eprintln!( "" );

    if Path::new( "/usr/bin/pacman" ).exists() {
        eprintln!( "You can most likely install it like this:" );
        eprintln!( "  sudo pacman -S emscripten" );
    } else if Path::new( "/usr/bin/apt-get" ).exists() {
        eprintln!( "You can most likely install it like this:" );
        eprintln!( "  sudo apt-get install emscripten" );
    } else if cfg!( target_os = "linux" ) {
        eprintln!( "You can most likely find it in your distro's repositories." );
    } else if cfg!( target_os = "windows" ) {
        eprintln!( "Download and install emscripten from the official site: http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html" );
    }

    if cfg!( unix ) {
        if cfg!( target_os = "linux" ) {
            eprintln!( "If not you can install it manually like this:" );
        } else {
            eprintln!( "You can install it manually like this:" );
        }
        eprintln!( "  curl -O https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz" );
        eprintln!( "  tar -xzf emsdk-portable.tar.gz" );
        eprintln!( "  source emsdk_portable/emsdk_env.sh" );
        eprintln!( "  emsdk update" );
        eprintln!( "  emsdk install sdk-incoming-64bit" );
        eprintln!( "  emsdk activate sdk-incoming-64bit" );
    }

    exit( 101 );
}

pub struct Emscripten {
    pub binaryen_path: Option< PathBuf >,
    pub emscripten_path: PathBuf,
    pub emscripten_llvm_path: PathBuf
}

pub fn initialize_emscripten(
    use_system_emscripten: bool,
    targeting_webasm: bool
) -> Option< Emscripten > {

    if use_system_emscripten {
        check_emscripten();
        return None;
    }

    let emscripten_package = match emscripten_package() {
        Some( pkg ) => pkg,
        None => {
            check_emscripten();
            return None;
        }
    };

    let binaryen_package = if targeting_webasm {
        match binaryen_package() {
            Some( pkg ) => Some( pkg ),
            None => {
                check_emscripten();
                return None;
            }
        }
    } else {
        None
    };

    let emscripten_root = download_package( &emscripten_package );
    let emscripten_path = emscripten_root.join( "emscripten" );
    let emscripten_llvm_path = emscripten_root.join( "emscripten-fastcomp" );
    let binaryen_path = if let Some( binaryen_package ) = binaryen_package {
        let binaryen_root = download_package( &binaryen_package );
        Some( binaryen_root.join( "binaryen" ) )
    } else {
        None
    };

    Some( Emscripten {
        binaryen_path,
        emscripten_path,
        emscripten_llvm_path
    })
}
<commit_msg>Correct Emscripten SDK installation instructions (#163)<commit_after>use std::process::exit;
use std::path::{Path, PathBuf};

use package::{
    PrebuiltPackage,
    download_package
};
use utils::find_cmd;

fn emscripten_package() -> Option< PrebuiltPackage > {
    let package =
        if cfg!( target_os = "linux" ) && cfg!( target_arch = "x86_64" ) {
            PrebuiltPackage {
                url: "https://github.com/koute/emscripten-build/releases/download/emscripten-1.38.19-1/emscripten-1.38.19-1-x86_64-unknown-linux-gnu.tgz",
                name: "emscripten",
                version: "1.38.19-1",
                arch: "x86_64-unknown-linux-gnu",
                hash: "baab5f1162901bfa220cb009dc628300c5e67b91cf58656ab6bf392d513bff9c",
                size: 211505607
            }
        } else if cfg!( target_os = "linux" ) && cfg!( target_arch = "x86" ) {
            PrebuiltPackage {
                url: "https://github.com/koute/emscripten-build/releases/download/emscripten-1.38.19-1/emscripten-1.38.19-1-i686-unknown-linux-gnu.tgz",
                name: "emscripten",
                version: "1.38.19-1",
                arch: "i686-unknown-linux-gnu",
                hash: "6d211eb0e9bbf82a1bf0dcc336486aa5191952f3938b7c0cf76b8d6946d4c117",
                size: 223770839
            }
        } else {
            return None;
        };

    Some( package )
}

fn binaryen_package() -> Option< PrebuiltPackage > {
    let package =
        if cfg!( target_os = "linux" ) && cfg!( target_arch = "x86_64" ) {
            PrebuiltPackage {
                url: "https://github.com/koute/emscripten-build/releases/download/emscripten-1.38.19-1/binaryen-1.38.19-1-x86_64-unknown-linux-gnu.tgz",
                name: "binaryen",
                version: "1.38.19-1",
                arch: "x86_64-unknown-linux-gnu",
                hash: "af079258c6f13234541d932b873762910951779c4682fc917255716637383dc9",
                size: 15818455
            }
        } else if cfg!( target_os = "linux" ) && cfg!( target_arch = "x86" ) {
            PrebuiltPackage {
                url: "https://github.com/koute/emscripten-build/releases/download/emscripten-1.38.19-1/binaryen-1.38.19-1-i686-unknown-linux-gnu.tgz",
                name: "binaryen",
                version: "1.38.19-1",
                arch: "i686-unknown-linux-gnu",
                hash: "9fd0e30d1760d29e3c96fa24592a35629876316fadb7ef882b9c6d8b2eafb0d8",
                size: 15951181
            }
        } else {
            return None;
        };

    Some( package )
}

fn check_emscripten() {
    let possible_commands =
        if cfg!( windows ) {
            &[ "emcc.bat" ]
        } else {
            &[ "emcc" ]
        };

    if find_cmd( possible_commands ).is_some() {
        return;
    }

    eprintln!( "error: you don't have Emscripten installed!" );
    eprintln!( "" );

    if Path::new( "/usr/bin/pacman" ).exists() {
        eprintln!( "You can most likely install it like this:" );
        eprintln!( "  sudo pacman -S emscripten" );
    } else if Path::new( "/usr/bin/apt-get" ).exists() {
        eprintln!( "You can most likely install it like this:" );
        eprintln!( "  sudo apt-get install emscripten" );
    } else if cfg!( target_os = "linux" ) {
        eprintln!( "You can most likely find it in your distro's repositories." );
    } else if cfg!( target_os = "windows" ) {
        eprintln!( "Download and install emscripten from the official site: http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html" );
    }

    if cfg!( unix ) {
        if cfg!( target_os = "linux" ) {
            eprintln!( "If not you can install it manually like this:" );
        } else {
            eprintln!( "You can install it manually like this:" );
        }
        eprintln!( "  curl -O https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz" );
        eprintln!( "  tar -xzf emsdk-portable.tar.gz" );
        eprintln!( "  source emsdk-portable/emsdk_env.sh" );
        eprintln!( "  emsdk update" );
        eprintln!( "  emsdk install sdk-incoming-64bit" );
        eprintln!( "  emsdk activate sdk-incoming-64bit" );
    }

    exit( 101 );
}

pub struct Emscripten {
    pub binaryen_path: Option< PathBuf >,
    pub emscripten_path: PathBuf,
    pub emscripten_llvm_path: PathBuf
}

pub fn initialize_emscripten(
    use_system_emscripten: bool,
    targeting_webasm: bool
) -> Option< Emscripten > {

    if use_system_emscripten {
        check_emscripten();
        return None;
    }

    let emscripten_package = match emscripten_package() {
        Some( pkg ) => pkg,
        None => {
            check_emscripten();
            return None;
        }
    };

    let binaryen_package = if targeting_webasm {
        match binaryen_package() {
            Some( pkg ) => Some( pkg ),
            None => {
                check_emscripten();
                return None;
            }
        }
    } else {
        None
    };

    let emscripten_root = download_package( &emscripten_package );
    let emscripten_path = emscripten_root.join( "emscripten" );
    let emscripten_llvm_path = emscripten_root.join( "emscripten-fastcomp" );
    let binaryen_path = if let Some( binaryen_package ) = binaryen_package {
        let binaryen_root = download_package( &binaryen_package );
        Some( binaryen_root.join( "binaryen" ) )
    } else {
        None
    };

    Some( Emscripten {
        binaryen_path,
        emscripten_path,
        emscripten_llvm_path
    })
}
<|endoftext|>