<commit_before>#![feature(core_intrinsics)]
#![doc(html_root_url="https://samfoo.github.io/oxidize/")]
#![cfg_attr(test, deny(warnings))]

//! # Oxidize
//!
//! Oxidize lets you set expected outcomes on objects in unit tests (or
//! anywhere). This allows for more fluid expression than with assertions alone
//! and yields more readable error messages.
//!
//! For example:
//!
//!     use oxidize::dsl::*;
//!
//!     expect("optimus prime").to(contain("prime"));
//!
//! Any expectation can also be negated:
//!
//!     use oxidize::dsl::*;
//!
//!     expect("megatron").to_not(contain("prime"));
//!
//! ## Built-in Matchers
//!
//! Oxidize has of built-in [matchers](matchers/index.html) that you can
//! use for all kinds of data.
//!
//! ### Equality
//!
//!     use oxidize::dsl::*;
//!
//!     expect(1).to(equal(1));
//!     expect(6).is(greater_than(0));
//!     expect(-120).is(less_than(5));
//!
//! ### Truthiness
//!
//!     use oxidize::dsl::*;
//!
//!     struct Transformer { is_prime: bool };
//!     let optimus = Transformer { is_prime: true };
//!
//!     expect(optimus.is_prime).to(be_true());
//!
//!     struct Paradox;
//!     impl Paradox {
//!         fn can_fly(&self) -> bool {
//!             false
//!         }
//!     }
//!     let pigs = Paradox;
//!
//!     expect(pigs.can_fly()).to(be_false());
//!
//! ### Substrings / Containers
//!
//!     use oxidize::dsl::*;
//!
//!     expect(vec![1, 2, 3]).to(contain(2));
//!     expect("Energon Cube").to(contain("Cube"));
//!
//! ### Length
//!
//!     use oxidize::dsl::*;
//!
//!     expect(vec![1, 2, 3, 4]).is_not(empty());
//!
//! ### Options / Existence
//!
//!     use oxidize::dsl::*;
//!
//!     let mut big: Vec<u64> = vec![1337u64];
//!
//!     expect(big.pop()).is(some());
//!     expect(big.pop()).is(none());
//!
//! ### Regex
//!
//!     use oxidize::dsl::*;
//!
//!     expect("sam").to(match_regex("..."));
//!
//! ## Inspiration
//!
//! These projects were inspirational in oxidize's design (maybe they'll inspire
//! you, too!):
//!
//! * [rspec-expectations](https://github.com/rspec/rspec-expectations/)
//! * [hamcrest](http://hamcrest.org/)
//! * [assertj](https://joel-costigliola.github.io/assertj/)

extern crate regex;

use matchers::Matcher;

/// Contains all built in matchers.
pub mod matchers;

/// Contains functions wrapping creating matchers in a more pleasant syntax.
pub mod dsl;

use std::fmt::Debug;

/// Holds an expectation's left hand side (LHS). This LHS can then be matched by
/// any `Matcher`.
pub struct Expectation<Lhs: Debug>(Lhs);

impl<Lhs: Debug> Expectation<Lhs> {
    pub fn is<T>(&self, matcher: Box<T>) where T: Matcher<Lhs> {
        self.to(matcher)
    }

    pub fn is_not<T>(&self, matcher: Box<T>) where T: Matcher<Lhs> {
        self.to_not(matcher)
    }

    pub fn to<T>(&self, matcher: Box<T>) where T: Matcher<Lhs> {
        if !matcher.matches(&self.0) {
            panic!(matcher.fail_msg(&self.0))
        }
    }

    pub fn to_not<T>(&self, matcher: Box<T>) where T: Matcher<Lhs> {
        if matcher.matches(&self.0) {
            panic!(matcher.negated_fail_msg(&self.0))
        }
    }
}

<commit_msg>Remove core_intrinsics<commit_after>#![doc(html_root_url="https://samfoo.github.io/oxidize/")]
#![cfg_attr(test, deny(warnings))]

//! # Oxidize
//!
//! Oxidize lets you set expected outcomes on objects in unit tests (or
//! anywhere). This allows for more fluid expression than with assertions alone
//! and yields more readable error messages.
//!
//! For example:
//!
//!     use oxidize::dsl::*;
//!
//!     expect("optimus prime").to(contain("prime"));
//!
//! Any expectation can also be negated:
//!
//!     use oxidize::dsl::*;
//!
//!     expect("megatron").to_not(contain("prime"));
//!
//! ## Built-in Matchers
//!
//! Oxidize has of built-in [matchers](matchers/index.html) that you can
//! use for all kinds of data.
//!
//! ### Equality
//!
//!     use oxidize::dsl::*;
//!
//!     expect(1).to(equal(1));
//!     expect(6).is(greater_than(0));
//!     expect(-120).is(less_than(5));
//!
//! ### Truthiness
//!
//!     use oxidize::dsl::*;
//!
//!     struct Transformer { is_prime: bool };
//!     let optimus = Transformer { is_prime: true };
//!
//!     expect(optimus.is_prime).to(be_true());
//!
//!     struct Paradox;
//!     impl Paradox {
//!         fn can_fly(&self) -> bool {
//!             false
//!         }
//!     }
//!     let pigs = Paradox;
//!
//!     expect(pigs.can_fly()).to(be_false());
//!
//! ### Substrings / Containers
//!
//!     use oxidize::dsl::*;
//!
//!     expect(vec![1, 2, 3]).to(contain(2));
//!     expect("Energon Cube").to(contain("Cube"));
//!
//! ### Length
//!
//!     use oxidize::dsl::*;
//!
//!     expect(vec![1, 2, 3, 4]).is_not(empty());
//!
//! ### Options / Existence
//!
//!     use oxidize::dsl::*;
//!
//!     let mut big: Vec<u64> = vec![1337u64];
//!
//!     expect(big.pop()).is(some());
//!     expect(big.pop()).is(none());
//!
//! ### Regex
//!
//!     use oxidize::dsl::*;
//!
//!     expect("sam").to(match_regex("..."));
//!
//! ## Inspiration
//!
//! These projects were inspirational in oxidize's design (maybe they'll inspire
//! you, too!):
//!
//! * [rspec-expectations](https://github.com/rspec/rspec-expectations/)
//! * [hamcrest](http://hamcrest.org/)
//! * [assertj](https://joel-costigliola.github.io/assertj/)

extern crate regex;

use matchers::Matcher;

/// Contains all built in matchers.
pub mod matchers;

/// Contains functions wrapping creating matchers in a more pleasant syntax.
pub mod dsl;

use std::fmt::Debug;

/// Holds an expectation's left hand side (LHS). This LHS can then be matched by
/// any `Matcher`.
pub struct Expectation<Lhs: Debug>(Lhs);

impl<Lhs: Debug> Expectation<Lhs> {
    pub fn is<T>(&self, matcher: Box<T>) where T: Matcher<Lhs> {
        self.to(matcher)
    }

    pub fn is_not<T>(&self, matcher: Box<T>) where T: Matcher<Lhs> {
        self.to_not(matcher)
    }

    pub fn to<T>(&self, matcher: Box<T>) where T: Matcher<Lhs> {
        if !matcher.matches(&self.0) {
            panic!(matcher.fail_msg(&self.0))
        }
    }

    pub fn to_not<T>(&self, matcher: Box<T>) where T: Matcher<Lhs> {
        if matcher.matches(&self.0) {
            panic!(matcher.negated_fail_msg(&self.0))
        }
    }
}

<|endoftext|>


<commit_before>#[crate_type = "lib"];
#[crate_id = "strain#0.0.1"];
#[feature(globs,phase)];
#[phase(syntax, link)] extern crate log;

extern crate leveldb;

#[deriving(Show)]
pub enum Errors {
  PreConditionNotMet(~str),
  PostConditionNotMet(~str),
  ActionFailed(~str)
}

pub trait State {
}

pub trait Event<T: State> {
  fn precondition(&self, state: &T) -> Result<(), Errors>;

  fn postcondition(&self, state: &T) -> Result<(), Errors>;

  fn action(&self, state: &mut T) -> Result<(), Errors>;
}

pub struct Strain<T> {
  state: ~T,
}

impl<T: State> Strain<T> {
  pub fn new<T: State>(state: ~T) -> Strain<T> {
    Strain { state: state }
  }

  pub fn feed(&mut self, event: &Event<T>) -> Result<(), Errors>{
    event.precondition(self.state).and_then(|_| {
      event.action(self.state).and_then(|_| {
        event.postcondition(self.state)
      })
    })
  }

  pub fn state(self) -> ~T {
    self.state
  }
}

#[cfg(test)]
mod tests {
  use super::{State, Event, Strain, Errors, PreConditionNotMet, PostConditionNotMet};

  struct Counter {
    count: int,
  }
  impl State for Counter {}

  struct Increment;
  struct Decrement;

  impl Event<Counter> for Increment {
    fn precondition(&self, state: &Counter) -> Result<(), Errors> {
      if state.count < 0 {
        Err(PreConditionNotMet(~"I cannot count to negatives"))
      } else {
        Ok(())
      }
    }

    fn action(&self, state: &mut Counter) -> Result<(), Errors>  {
      state.count = state.count + 1;
      Ok(())
    }

    fn postcondition(&self, state: &Counter) -> Result<(), Errors> {
      if state.count < 0 {
        Err(PostConditionNotMet(~"I shouldn't have counted to negatives"))
      } else {
        Ok(())
      }
    }
  }

  impl Event<Counter> for Decrement {
    fn precondition(&self, state: &Counter) -> Result<(), Errors> {
      if state.count < 1 {
        Err(PreConditionNotMet(~"I cannot count to negatives"))
      } else {
        Ok(())
      }
    }

    fn action(&self, state: &mut Counter) -> Result<(), Errors>  {
      state.count = state.count - 1;
      Ok(())
    }

    fn postcondition(&self, state: &Counter) -> Result<(), Errors> {
      if state.count < 0 {
        Err(PostConditionNotMet(~"I shouldn't have counted to negatives"))
      } else {
        Ok(())
      }
    }

  }

  #[test]
  fn test_state_changes() {
    let mut strain : Strain<Counter> = Strain { state: ~Counter { count: 0 } };
    let res = strain.feed(&Increment).and_then(|_| {
      strain.feed(&Increment).and_then(|_| {
        strain.feed(&Decrement)
      })
    });
    assert!(res.is_ok());
    assert_eq!(strain.state().count, 1);
  }
}
<commit_msg>Add a test for unmet pre-condition<commit_after>#[crate_type = "lib"];
#[crate_id = "strain#0.0.1"];
#[feature(globs,phase)];
#[phase(syntax, link)] extern crate log;

extern crate leveldb;

#[deriving(Show)]
pub enum Errors {
  PreConditionNotMet(~str),
  PostConditionNotMet(~str),
  ActionFailed(~str)
}

pub trait State {
}

pub trait Event<T: State> {
  fn precondition(&self, state: &T) -> Result<(), Errors>;

  fn postcondition(&self, state: &T) -> Result<(), Errors>;

  fn action(&self, state: &mut T) -> Result<(), Errors>;
}

pub struct Strain<T> {
  state: ~T,
}

impl<T: State> Strain<T> {
  pub fn new<T: State>(state: ~T) -> Strain<T> {
    Strain { state: state }
  }

  pub fn feed(&mut self, event: &Event<T>) -> Result<(), Errors>{
    event.precondition(self.state).and_then(|_| {
      event.action(self.state).and_then(|_| {
        event.postcondition(self.state)
      })
    })
  }

  pub fn state(self) -> ~T {
    self.state
  }
}

#[cfg(test)]
mod tests {
  use super::{State, Event, Strain, Errors, PreConditionNotMet, PostConditionNotMet};

  struct Counter {
    count: int,
  }
  impl State for Counter {}

  struct Increment;
  struct Decrement;

  impl Event<Counter> for Increment {
    fn precondition(&self, state: &Counter) -> Result<(), Errors> {
      if state.count < 0 {
        Err(PreConditionNotMet(~"I cannot count to negatives"))
      } else {
        Ok(())
      }
    }

    fn action(&self, state: &mut Counter) -> Result<(), Errors>  {
      state.count = state.count + 1;
      Ok(())
    }

    fn postcondition(&self, state: &Counter) -> Result<(), Errors> {
      if state.count < 0 {
        Err(PostConditionNotMet(~"I shouldn't have counted to negatives"))
      } else {
        Ok(())
      }
    }
  }

  impl Event<Counter> for Decrement {
    fn precondition(&self, state: &Counter) -> Result<(), Errors> {
      if state.count < 1 {
        Err(PreConditionNotMet(~"I cannot count to negatives"))
      } else {
        Ok(())
      }
    }

    fn action(&self, state: &mut Counter) -> Result<(), Errors>  {
      state.count = state.count - 1;
      Ok(())
    }

    fn postcondition(&self, state: &Counter) -> Result<(), Errors> {
      if state.count < 0 {
        Err(PostConditionNotMet(~"I shouldn't have counted to negatives"))
      } else {
        Ok(())
      }
    }

  }

  #[test]
  fn test_state_changes() {
    let mut strain : Strain<Counter> = Strain { state: ~Counter { count: 0 } };
    let res = strain.feed(&Increment).and_then(|_| {
      strain.feed(&Increment).and_then(|_| {
        strain.feed(&Decrement)
      })
    });
    assert!(res.is_ok());
    assert_eq!(strain.state().count, 1);
  }

  #[test]
  fn test_unmet_pre_condition() {
    let mut strain : Strain<Counter> = Strain { state: ~Counter { count: -1 } };
    let res = strain.feed(&Increment);
    assert!(res.is_err());
    assert_eq!(strain.state().count, -1);
  }
}
<|endoftext|>


<commit_before>// use std::marker::PhantomData;
// use std::slice;

pub struct StrCursor<'a> {
    s: &'a str,
    at: *const u8,
}

impl<'a> StrCursor<'a> {
    pub fn new_at_start(s: &'a str) -> StrCursor<'a> {
        StrCursor {
            s: s,
            at: s.as_ptr(),
        }
    }

    pub fn new_at_end(s: &'a str) -> StrCursor<'a> {
        unsafe {
            StrCursor {
                s: s,
                at: s.as_ptr().offset(s.len() as isize),
            }
        }
    }

    pub fn new_left_of_byte_pos(s: &'a str, byte_pos: usize) -> StrCursor<'a> {
        unsafe {
            StrCursor {
                s: s,
                at: seek_utf8_cp_start_left(s, &s.as_bytes()[byte_pos]),
            }
        }
    }

    pub fn new_right_of_byte_pos(s: &'a str, byte_pos: usize) -> StrCursor<'a> {
        unsafe {
            StrCursor {
                s: s,
                at: seek_utf8_cp_start_right(s, &s.as_bytes()[byte_pos]),
            }
        }
    }

    pub fn at_prev_cp(mut self) -> Option<StrCursor<'a>> {
        match self.try_seek_left() {
            true => Some(self),
            false => None
        }
    }

    pub fn at_next_cp(mut self) -> Option<StrCursor<'a>> {
        match self.try_seek_right() {
            true => Some(self),
            false => None
        }
    }

    pub fn seek_prev_cp(&mut self) {
        if !self.try_seek_left() {
            panic!("cannot seek past the beginning of a string");
        }
    }

    pub fn seek_next_cp(&mut self) {
        if !self.try_seek_right() {
            panic!("cannot seek past the end of a string");
        }
    }

    pub fn slice_before(&self) -> &str {
        unsafe {
            self.s.slice_unchecked(0, self.byte_pos())
        }
    }

    pub fn slice_after(&self) -> &str {
        unsafe {
            self.s.slice_unchecked(self.byte_pos(), self.s.len())
        }
    }

    pub fn char_before(&self) -> Option<char> {
        self.at_prev_cp().and_then(|cur| cur.char_after())
    }

    pub fn char_after(&self) -> Option<char> {
        self.slice_after().chars().next()
    }

    pub fn byte_pos(&self) -> usize {
        self.at as usize - self.s.as_ptr() as usize
    }

    fn try_seek_left(&mut self) -> bool {
        unsafe {
            // We just have to ensure that offsetting the `at` pointer *at all* is safe.
            if self.byte_pos() == 0 {
                return false;
            }
            self.at = seek_utf8_cp_start_left(self.s, self.at.offset(-1));
            true
        }
    }

    fn try_seek_right(&mut self) -> bool {
        unsafe {
            // We just have to ensure that offsetting the `at` pointer *at all* is safe.
            if self.byte_pos() == self.s.len() {
                return false;
            }
            self.at = seek_utf8_cp_start_right(self.s, self.at.offset(1));
            true
        }
    }
}

impl<'a> Copy for StrCursor<'a> {}

impl<'a> Clone for StrCursor<'a> {
    fn clone(&self) -> StrCursor<'a> {
        *self
    }
}

impl<'a> std::fmt::Debug for StrCursor<'a> {
	fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after())
    }
}

#[cfg(test)]
#[test]
fn test_new_at_start() {
    let cur = StrCursor::new_at_start("abcdef");
    assert_eq!(cur.slice_before(), "");
    assert_eq!(cur.slice_after(), "abcdef");
}

#[cfg(test)]
#[test]
fn test_new_at_end() {
    let cur = StrCursor::new_at_end("abcdef");
    assert_eq!(cur.slice_before(), "abcdef");
    assert_eq!(cur.slice_after(), "");
}

#[cfg(test)]
#[test]
fn test_new_left_of_byte_pos() {
    let s = "This is a 本当 test.";
    let cur = StrCursor::new_left_of_byte_pos(s, 11);
    assert_eq!(cur.slice_before(), "This is a ");
    assert_eq!(cur.slice_after(), "本当 test.");
}

#[cfg(test)]
#[test]
fn test_new_right_of_byte_pos() {
    let s = "This is a 本当 test.";
    let cur = StrCursor::new_right_of_byte_pos(s, 11);
    assert_eq!(cur.slice_before(), "This is a 本");
    assert_eq!(cur.slice_after(), "当 test.");
}

#[cfg(test)]
#[test]
fn test_at_prev_cp() {
    let s = "大嫌い,💪❤";
    let cur = StrCursor::new_at_end(s);
    let bps = test_util::finite_iterate(cur, StrCursor::at_prev_cp)
        .map(|cur| cur.byte_pos())
        .collect::<Vec<_>>();
    assert_eq!(bps, vec![14, 10, 9, 6, 3, 0]);
}

#[cfg(test)]
#[test]
fn test_at_next_cp() {
    let s = "大嫌い,💪❤";
    let cur = StrCursor::new_at_start(s);
    let bps = test_util::finite_iterate(cur, StrCursor::at_next_cp)
        .map(|cur| cur.byte_pos())
        .collect::<Vec<_>>();
    assert_eq!(bps, vec![3, 6, 9, 10, 14, 17]);
}

#[cfg(test)]
#[test]
fn test_char_before_and_after() {
    let s = "大嫌い,💪❤";
    let cur = StrCursor::new_at_start(s);
    let r = test_util::finite_iterate_lead(cur, StrCursor::at_next_cp)
        .map(|cur| (cur.byte_pos(), cur.char_before(), cur.char_after()))
        .collect::<Vec<_>>();
    assert_eq!(r, vec![
        (0, None, Some('大')),
        (3, Some('大'), Some('嫌')),
        (6, Some('嫌'), Some('い')),
        (9, Some('い'), Some(',')),
        (10, Some(','), Some('💪')),
        (14, Some('💪'), Some('❤')),
        (17, Some('❤'), None)
    ]);
}

unsafe fn seek_utf8_cp_start_left(s: &str, mut from: *const u8) -> *const u8 {
    let beg = s.as_ptr();
    while from > beg && (*from & 0b11_00_0000 == 0b10_00_0000) {
        from = from.offset(-1);
    }
    from
}

#[cfg(test)]
#[test]
fn test_seek_utf8_cp_start_left() {
    let s = "カブム！";
    let b = s.as_bytes();
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[0]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[1]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[2]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[3]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[4]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[5]) }, &b[3]);
}

unsafe fn seek_utf8_cp_start_right(s: &str, mut from: *const u8) -> *const u8 {
    let end = s.as_ptr().offset(s.len() as isize);
    while from < end && (*from & 0b11_00_0000 == 0b10_00_0000) {
        from = from.offset(1);
    }
    from
}

#[cfg(test)]
#[test]
fn test_seek_utf8_cp_start_right() {
    let s = "カブム！";
    let b = s.as_bytes();
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[0]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[1]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[2]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[3]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[4]) }, &b[6]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[5]) }, &b[6]);
}

#[cfg(test)]
mod test_util {
    pub struct FiniteIter<T, F>(Option<T>, F);

    impl<T, F> Iterator for FiniteIter<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        type Item = T;

        fn next(&mut self) -> Option<Self::Item> {
            self.0.take().and_then(|last| {
                match (self.1)(last) {
                    Some(e) => {
                        self.0 = Some(e);
                        self.0.clone()
                    },
                    None => None
                }
            })
        }
    }

    pub fn finite_iterate<T, F>(seed: T, f: F) -> FiniteIter<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        FiniteIter(Some(seed), f)
    }
    pub struct FiniteIterLead<T, F>(Option<T>, F, bool);

    impl<T, F> Iterator for FiniteIterLead<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        type Item = T;

        fn next(&mut self) -> Option<Self::Item> {
            if !self.2 {
                self.2 = true;
                return self.0.clone();
            }

            self.0.take().and_then(|last| {
                match (self.1)(last) {
                    Some(e) => {
                        self.0 = Some(e);
                        self.0.clone()
                    },
                    None => None
                }
            })
        }
    }

    pub fn finite_iterate_lead<T, F>(seed: T, f: F) -> FiniteIterLead<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        FiniteIterLead(Some(seed), f, false)
    }
}<commit_msg>Some cleanup.<commit_after>pub struct StrCursor<'a> {
    s: &'a str,
    at: *const u8,
}

impl<'a> StrCursor<'a> {
    pub fn new_at_start(s: &'a str) -> StrCursor<'a> {
        StrCursor {
            s: s,
            at: s.as_ptr(),
        }
    }

    pub fn new_at_end(s: &'a str) -> StrCursor<'a> {
        unsafe {
            StrCursor {
                s: s,
                at: s.as_ptr().offset(s.len() as isize),
            }
        }
    }

    pub fn new_left_of_byte_pos(s: &'a str, byte_pos: usize) -> StrCursor<'a> {
        unsafe {
            StrCursor {
                s: s,
                at: seek_utf8_cp_start_left(s, &s.as_bytes()[byte_pos]),
            }
        }
    }

    pub fn new_right_of_byte_pos(s: &'a str, byte_pos: usize) -> StrCursor<'a> {
        unsafe {
            StrCursor {
                s: s,
                at: seek_utf8_cp_start_right(s, &s.as_bytes()[byte_pos]),
            }
        }
    }

    pub fn at_prev_cp(mut self) -> Option<StrCursor<'a>> {
        match self.try_seek_left() {
            true => Some(self),
            false => None
        }
    }

    pub fn at_next_cp(mut self) -> Option<StrCursor<'a>> {
        match self.try_seek_right() {
            true => Some(self),
            false => None
        }
    }

    pub fn seek_prev_cp(&mut self) {
        if !self.try_seek_left() {
            panic!("cannot seek past the beginning of a string");
        }
    }

    pub fn seek_next_cp(&mut self) {
        if !self.try_seek_right() {
            panic!("cannot seek past the end of a string");
        }
    }

    pub fn slice_before(&self) -> &str {
        unsafe {
            self.s.slice_unchecked(0, self.byte_pos())
        }
    }

    pub fn slice_after(&self) -> &str {
        unsafe {
            self.s.slice_unchecked(self.byte_pos(), self.s.len())
        }
    }

    pub fn char_before(&self) -> Option<char> {
        self.at_prev_cp().and_then(|cur| cur.char_after())
    }

    pub fn char_after(&self) -> Option<char> {
        self.slice_after().chars().next()
    }

    pub fn byte_pos(&self) -> usize {
        self.at as usize - self.s.as_ptr() as usize
    }

    fn try_seek_left(&mut self) -> bool {
        unsafe {
            // We just have to ensure that offsetting the `at` pointer *at all* is safe.
            if self.byte_pos() == 0 {
                return false;
            }
            self.at = seek_utf8_cp_start_left(self.s, self.at.offset(-1));
            true
        }
    }

    fn try_seek_right(&mut self) -> bool {
        unsafe {
            // We just have to ensure that offsetting the `at` pointer *at all* is safe.
            if self.byte_pos() == self.s.len() {
                return false;
            }
            self.at = seek_utf8_cp_start_right(self.s, self.at.offset(1));
            true
        }
    }
}

impl<'a> Copy for StrCursor<'a> {}

impl<'a> Clone for StrCursor<'a> {
    fn clone(&self) -> StrCursor<'a> {
        *self
    }
}

impl<'a> std::fmt::Debug for StrCursor<'a> {
	fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after())
    }
}

#[cfg(test)]
#[test]
fn test_new_at_start() {
    let cur = StrCursor::new_at_start("abcdef");
    assert_eq!(cur.slice_before(), "");
    assert_eq!(cur.slice_after(), "abcdef");
}

#[cfg(test)]
#[test]
fn test_new_at_end() {
    let cur = StrCursor::new_at_end("abcdef");
    assert_eq!(cur.slice_before(), "abcdef");
    assert_eq!(cur.slice_after(), "");
}

#[cfg(test)]
#[test]
fn test_new_left_of_byte_pos() {
    let s = "This is a 本当 test.";
    let cur = StrCursor::new_left_of_byte_pos(s, 11);
    assert_eq!(cur.slice_before(), "This is a ");
    assert_eq!(cur.slice_after(), "本当 test.");
}

#[cfg(test)]
#[test]
fn test_new_right_of_byte_pos() {
    let s = "This is a 本当 test.";
    let cur = StrCursor::new_right_of_byte_pos(s, 11);
    assert_eq!(cur.slice_before(), "This is a 本");
    assert_eq!(cur.slice_after(), "当 test.");
}

#[cfg(test)]
#[test]
fn test_at_prev_cp() {
    let s = "大嫌い,💪❤";
    let cur = StrCursor::new_at_end(s);
    let bps = test_util::finite_iterate(cur, StrCursor::at_prev_cp)
        .map(|cur| cur.byte_pos())
        .collect::<Vec<_>>();
    assert_eq!(bps, vec![14, 10, 9, 6, 3, 0]);
}

#[cfg(test)]
#[test]
fn test_at_next_cp() {
    let s = "大嫌い,💪❤";
    let cur = StrCursor::new_at_start(s);
    let bps = test_util::finite_iterate(cur, StrCursor::at_next_cp)
        .map(|cur| cur.byte_pos())
        .collect::<Vec<_>>();
    assert_eq!(bps, vec![3, 6, 9, 10, 14, 17]);
}

#[cfg(test)]
#[test]
fn test_char_before_and_after() {
    let s = "大嫌い,💪❤";
    let cur = StrCursor::new_at_start(s);
    let r = test_util::finite_iterate_lead(cur, StrCursor::at_next_cp)
        .map(|cur| (cur.byte_pos(), cur.char_before(), cur.char_after()))
        .collect::<Vec<_>>();
    assert_eq!(r, vec![
        (0, None, Some('大')),
        (3, Some('大'), Some('嫌')),
        (6, Some('嫌'), Some('い')),
        (9, Some('い'), Some(',')),
        (10, Some(','), Some('💪')),
        (14, Some('💪'), Some('❤')),
        (17, Some('❤'), None)
    ]);
}

unsafe fn seek_utf8_cp_start_left(s: &str, mut from: *const u8) -> *const u8 {
    let beg = s.as_ptr();
    while from > beg && (*from & 0b11_00_0000 == 0b10_00_0000) {
        from = from.offset(-1);
    }
    from
}

#[cfg(test)]
#[test]
fn test_seek_utf8_cp_start_left() {
    let s = "カブム！";
    let b = s.as_bytes();
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[0]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[1]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[2]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[3]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[4]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_left(s, &b[5]) }, &b[3]);
}

unsafe fn seek_utf8_cp_start_right(s: &str, mut from: *const u8) -> *const u8 {
    let end = s.as_ptr().offset(s.len() as isize);
    while from < end && (*from & 0b11_00_0000 == 0b10_00_0000) {
        from = from.offset(1);
    }
    from
}

#[cfg(test)]
#[test]
fn test_seek_utf8_cp_start_right() {
    let s = "カブム！";
    let b = s.as_bytes();
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[0]) }, &b[0]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[1]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[2]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[3]) }, &b[3]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[4]) }, &b[6]);
    assert_eq!(unsafe { seek_utf8_cp_start_right(s, &b[5]) }, &b[6]);
}

#[cfg(test)]
mod test_util {
    pub struct FiniteIter<T, F>(Option<T>, F);

    impl<T, F> Iterator for FiniteIter<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        type Item = T;

        fn next(&mut self) -> Option<Self::Item> {
            self.0.take().and_then(|last| {
                match (self.1)(last) {
                    Some(e) => {
                        self.0 = Some(e);
                        self.0.clone()
                    },
                    None => None
                }
            })
        }
    }

    pub fn finite_iterate<T, F>(seed: T, f: F) -> FiniteIter<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        FiniteIter(Some(seed), f)
    }
    pub struct FiniteIterLead<T, F>(Option<T>, F, bool);

    impl<T, F> Iterator for FiniteIterLead<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        type Item = T;

        fn next(&mut self) -> Option<Self::Item> {
            if !self.2 {
                self.2 = true;
                return self.0.clone();
            }

            self.0.take().and_then(|last| {
                match (self.1)(last) {
                    Some(e) => {
                        self.0 = Some(e);
                        self.0.clone()
                    },
                    None => None
                }
            })
        }
    }

    pub fn finite_iterate_lead<T, F>(seed: T, f: F) -> FiniteIterLead<T, F>
    where
        F: FnMut(T) -> Option<T>,
        T: Clone,
    {
        FiniteIterLead(Some(seed), f, false)
    }
}
<|endoftext|>


<commit_before>/// Calculate the crc64 checksum of the given data, starting with the given crc.
///
/// Implements the CRC64 used by Redis, which is the variant with "Jones" coefficients and init value of 0.
///
/// Specification of this CRC64 variant follows:
///
/// ```text
/// Name: crc-64-jones
/// Width: 64 bites
/// Poly: 0xad93d23594c935a9
/// Reflected In: True
/// Xor_In: 0xffffffffffffffff
/// Reflected_Out: True
/// Xor_Out: 0x0
/// Check("123456789"): 0xe9c6d914c4b8d9ca
/// ```
///
/// Example:
///
/// ```rust
/// crc64::crc64(0, "123456789".as_bytes());
/// ```

use std::mem;
use crc_table::CRC64_TAB;
mod crc_table;

fn crc_reflect(data: u64, len: usize) -> u64 {
    let mut data = data;
    let mut ret = data & 0x01;

    let mut i = 1usize;
    while i < len {
        data >>= 1;
        ret = (ret << 1) | (data & 0x01);
        i+=1;
    }

    ret
}

fn crc64_trivial(crc: u64, in_data: &[u8]) -> u64 {
    let mut crc = crc;
    let len = in_data.len();

    let poly : u64 = 0xad93d23594c935a9;

    let mut bit : bool;

    let mut offset = 0usize;

    while offset < len {
        let c = in_data[offset];
        let mut i = 0x01;
        while i & 0xff != 0x0 {
            bit = crc & 0x8000000000000000 != 0x0;
            if c & i != 0x0 {
                bit = !bit;
            }
            crc <<= 1;
            if bit {
                crc ^= poly;
            }
            i <<= 1;
        }
        crc &= 0xffffffffffffffff;
        offset+=1;
    }
    crc = crc & 0xffffffffffffffff;

    return crc_reflect(crc, 64) ^ 0x0000000000000000;
}

pub fn crc64_init() -> Vec<Vec<u64>> {
    let mut crc : u64;

    let mut table : Vec<Vec<u64>> = Vec::with_capacity(8);

    for _ in (0..8) {
        table.push(Vec::with_capacity(256));
    };

    for n in (0usize..256) {
        table[0].push(crc64_trivial(0, &vec![n as u8]));
        table[1].push(0);
        table[2].push(0);
        table[3].push(0);
        table[4].push(0);
        table[5].push(0);
        table[6].push(0);
        table[7].push(0);
    }

    for n in (0usize..256) {
        crc = table[0][n];
        for k in (1usize..8) {
            let idx  = (crc as usize) & 0xff;
            crc = table[0][idx] ^ (crc >> 8);
            table[k][n] = crc;
        }
    };

    table
}

// transmute slice of 8 u8 values to one u64 (drop the length)
macro_rules! slice_to_long {
    ($curVec:expr) => {
        {
            unsafe {
                let (tmp, _) : (*const u64, usize) = mem::transmute(&$curVec);
                *tmp
            }
        }
    }
}

pub fn crc64(crc: u64, data: &[u8]) -> u64 {
    let mut crc = crc;
    let mut len = data.len();
    let mut offset = 0usize;

    while len >= 8 {
        crc ^= slice_to_long!(data[offset..(offset+8)]);
        crc = CRC64_TAB[7][(crc & 0xff) as usize] ^
              CRC64_TAB[6][((crc >> 8) & 0xff) as usize] ^
              CRC64_TAB[5][((crc >> 16) & 0xff) as usize] ^
              CRC64_TAB[4][((crc >> 24) & 0xff) as usize] ^
              CRC64_TAB[3][((crc >> 32) & 0xff) as usize] ^
              CRC64_TAB[2][((crc >> 40) & 0xff) as usize] ^
              CRC64_TAB[1][((crc >> 48) & 0xff) as usize] ^
              CRC64_TAB[0][(crc >> 56) as usize];

        offset += 8;
        len -= 8;
    }

    while len > 0 {
        crc = CRC64_TAB[0][((crc ^ data[offset] as u64) & 0xff) as usize] ^ (crc >> 8);
        offset += 1;
        len -= 1;
    }

    crc
}

#[test]
fn test_crc64_works() {
    assert_eq!(0xe9c6d914c4b8d9ca, crc64(0, "123456789".as_bytes()))
}
<commit_msg>Implement Crc64 as a struct with Write<commit_after>/// Calculate the crc64 checksum of the given data, starting with the given crc.
///
/// Implements the CRC64 used by Redis, which is the variant with "Jones" coefficients and init value of 0.
///
/// Specification of this CRC64 variant follows:
///
/// ```text
/// Name: crc-64-jones
/// Width: 64 bites
/// Poly: 0xad93d23594c935a9
/// Reflected In: True
/// Xor_In: 0xffffffffffffffff
/// Reflected_Out: True
/// Xor_Out: 0x0
/// Check("123456789"): 0xe9c6d914c4b8d9ca
/// ```
///
/// Example:
///
/// ```rust
/// crc64::crc64(0, "123456789".as_bytes());
/// ```

use std::io;
use std::io::Write;
use std::mem;
use crc_table::CRC64_TAB;
mod crc_table;

fn crc_reflect(data: u64, len: usize) -> u64 {
    let mut data = data;
    let mut ret = data & 0x01;

    let mut i = 1usize;
    while i < len {
        data >>= 1;
        ret = (ret << 1) | (data & 0x01);
        i+=1;
    }

    ret
}

fn crc64_trivial(crc: u64, in_data: &[u8]) -> u64 {
    let mut crc = crc;
    let len = in_data.len();

    let poly : u64 = 0xad93d23594c935a9;

    let mut bit : bool;

    let mut offset = 0usize;

    while offset < len {
        let c = in_data[offset];
        let mut i = 0x01;
        while i & 0xff != 0x0 {
            bit = crc & 0x8000000000000000 != 0x0;
            if c & i != 0x0 {
                bit = !bit;
            }
            crc <<= 1;
            if bit {
                crc ^= poly;
            }
            i <<= 1;
        }
        crc &= 0xffffffffffffffff;
        offset+=1;
    }
    crc = crc & 0xffffffffffffffff;

    return crc_reflect(crc, 64) ^ 0x0000000000000000;
}

pub fn crc64_init() -> Vec<Vec<u64>> {
    let mut crc : u64;

    let mut table : Vec<Vec<u64>> = Vec::with_capacity(8);

    for _ in (0..8) {
        table.push(Vec::with_capacity(256));
    };

    for n in (0usize..256) {
        table[0].push(crc64_trivial(0, &vec![n as u8]));
        table[1].push(0);
        table[2].push(0);
        table[3].push(0);
        table[4].push(0);
        table[5].push(0);
        table[6].push(0);
        table[7].push(0);
    }

    for n in (0usize..256) {
        crc = table[0][n];
        for k in (1usize..8) {
            let idx  = (crc as usize) & 0xff;
            crc = table[0][idx] ^ (crc >> 8);
            table[k][n] = crc;
        }
    };

    table
}

// transmute slice of 8 u8 values to one u64 (drop the length)
macro_rules! slice_to_long {
    ($curVec:expr) => {
        {
            unsafe {
                let (tmp, _) : (*const u64, usize) = mem::transmute(&$curVec);
                *tmp
            }
        }
    }
}

pub fn crc64(crc: u64, data: &[u8]) -> u64 {
    let mut crc = crc;
    let mut len = data.len();
    let mut offset = 0usize;

    while len >= 8 {
        crc ^= slice_to_long!(data[offset..(offset+8)]);
        crc = CRC64_TAB[7][(crc & 0xff) as usize] ^
              CRC64_TAB[6][((crc >> 8) & 0xff) as usize] ^
              CRC64_TAB[5][((crc >> 16) & 0xff) as usize] ^
              CRC64_TAB[4][((crc >> 24) & 0xff) as usize] ^
              CRC64_TAB[3][((crc >> 32) & 0xff) as usize] ^
              CRC64_TAB[2][((crc >> 40) & 0xff) as usize] ^
              CRC64_TAB[1][((crc >> 48) & 0xff) as usize] ^
              CRC64_TAB[0][(crc >> 56) as usize];

        offset += 8;
        len -= 8;
    }

    while len > 0 {
        crc = CRC64_TAB[0][((crc ^ data[offset] as u64) & 0xff) as usize] ^ (crc >> 8);
        offset += 1;
        len -= 1;
    }

    crc
}

pub struct Crc64 {
    crc64: u64,
}

impl Crc64 {
    pub fn new() -> Crc64 {
        Crc64 { crc64: 0 }
    }
    pub fn get(&self) -> u64 {
        self.crc64.clone()
    }
}

impl Write for Crc64 {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.crc64 = crc64(self.crc64, buf);
        Ok(buf.len())
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[test]
fn test_crc64_works() {
    assert_eq!(0xe9c6d914c4b8d9ca, crc64(0, "123456789".as_bytes()))
}

#[test]
fn test_crc64_write() {
    let step1 = "12345".as_bytes();
    let step2 = "6789".as_bytes();
    let value1 = 17326901458626182669;
    let value2 = 16845390139448941002;
    assert_eq!(value1, crc64(0, &step1));
    assert_eq!(value2, crc64(value1.clone(), &step2));

    let mut crc = Crc64::new();
    assert_eq!(crc.write(&step1).unwrap(), step1.len());
    assert_eq!(value1, crc.get());
    assert_eq!(crc.write(&step2).unwrap(), step2.len());
    assert_eq!(value2, crc.get());
}
<|endoftext|>


<commit_before>#![crate_name = "hashids"]

#[macro_use]
extern crate failure;
extern crate regex;

use regex::Regex;
use std::collections::HashMap;

const DEFAULT_ALPHABET: &'static str =
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
const DEFAULT_SEPARATORS: &'static str = "cfhistuCFHISTU";
const SEPARTOR_DIV: f32 = 3.5;
const GUARD_DIV: u32 = 12;
const MIN_ALPHABET_LENGTH: usize = 16;

#[derive(Debug, Fail)]
pub enum HashIdsError {
    #[fail(display = "invalid alphabet length")]
    InvalidAlphabetLength,
}

pub struct HashIds {
    salt: String,
    pub alphabet: String,
    separators: String,
    min_hash_length: usize,
    guards: String,
}

impl HashIds {
    pub fn new(
        salt: String,
        min_hash_length: usize,
        alphabet: String,
    ) -> Result<HashIds, HashIdsError> {
        let min_length = HashIds::get_min_hash_length(min_hash_length);
        let unique_alphabet = HashIds::get_unique_alphabet(alphabet);

        if unique_alphabet.len() < MIN_ALPHABET_LENGTH {
            return Err(HashIdsError::InvalidAlphabetLength);
        }

        let (t_separators, mut t_alphabet) = HashIds::get_separators(unique_alphabet);
        let mut shuffled_separators = HashIds::hashids_shuffle(t_separators.clone(), salt.clone());

        if HashIds::need_manipulate(shuffled_separators.len(), t_alphabet.len()) == true {
            let mut seps_len = ((t_alphabet.len() as f32) / SEPARTOR_DIV) as usize;
            if seps_len == 1 {
                seps_len += 1;
            }

            if seps_len > shuffled_separators.len() {
                let diff = seps_len - shuffled_separators.len();

                shuffled_separators.push_str(&t_alphabet[..diff]);
                t_alphabet = t_alphabet[diff..].to_string();
            } else {
                shuffled_separators = shuffled_separators[..seps_len].to_string();
            }
        }

        let mut shuffled_alphabet = HashIds::hashids_shuffle(t_alphabet.clone(), salt.clone());
        let guard_count = (shuffled_alphabet.len() as f32 / GUARD_DIV as f32).ceil() as usize;

        let t_guards;

        if shuffled_alphabet.len() < 3 {
            t_guards = shuffled_separators[..guard_count].to_string();
            shuffled_separators = shuffled_separators[guard_count..].to_string();
        } else {
            t_guards = shuffled_alphabet[..guard_count].to_string();
            shuffled_alphabet = shuffled_alphabet[guard_count..].to_string();
        }

        Ok(HashIds {
            salt: salt,
            min_hash_length: min_length,
            guards: t_guards,
            separators: shuffled_separators,
            alphabet: shuffled_alphabet,
        })
    }

    pub fn new_with_salt_and_min_length(
        salt: String,
        min_hash_length: usize,
    ) -> Result<HashIds, HashIdsError> {
        HashIds::new(salt, min_hash_length, DEFAULT_ALPHABET.to_string())
    }

    pub fn new_with_salt(salt: String) -> Result<HashIds, HashIdsError> {
        HashIds::new_with_salt_and_min_length(salt, 0)
    }

    fn need_manipulate(slen: usize, alen: usize) -> bool {
        if slen <= 0 || (((alen / slen) as f32) > SEPARTOR_DIV) {
            return true;
        }

        false
    }

    fn get_min_hash_length(length: usize) -> usize {
        if length > 0 {
            return length;
        } else {
            return 0;
        }
    }

    fn get_separators(alphabet: String) -> (String, String) {
        HashIds::get_non_duplicated_string(DEFAULT_SEPARATORS.to_string(), alphabet)
    }

    fn hashids_shuffle(alphabet: String, salt: String) -> String {
        if salt.len() <= 0 {
            return alphabet;
        }

        let salt_len = salt.len();
        let arr = salt.as_bytes();
        let len = alphabet.len();
        let mut bytes = alphabet.into_bytes();
        let shuffle = &mut bytes[..];

        let mut i: usize = len - 1;
        let mut v: usize = 0;
        let mut p: usize = 0;

        while i > 0 {
            v %= salt_len;
            let t = arr[v] as usize;
            p += t;
            let j = (t + v + p) % i;

            shuffle.swap(i, j);

            i = i - 1;
            v = v + 1;
        }

        let mut shuffled_alphabet = String::with_capacity(len);
        for i in 0..len {
            shuffled_alphabet.push(shuffle[i] as char);
        }

        shuffled_alphabet
    }

    fn get_non_duplicated_string(separators: String, alphabet: String) -> (String, String) {
        let mut check_separator_map = HashMap::new();
        let mut check_alphabet_map = HashMap::new();

        let mut modified_separators = String::new();
        let mut modified_alphabet = String::new();

        for c in separators.chars() {
            check_separator_map.insert(c, 1);
        }

        for c in alphabet.chars() {
            check_alphabet_map.insert(c, 1);
        }

        for c in separators.chars() {
            if check_alphabet_map.contains_key(&c) {
                modified_separators.push(c);
            }
        }

        for c in alphabet.chars() {
            if !check_separator_map.contains_key(&c) {
                modified_alphabet.push(c);
            }
        }

        (modified_separators, modified_alphabet)
    }

    fn get_unique_alphabet(alphabet: String) -> String {
        let mut unique_alphabet: String = String::new();
        let mut check_map = HashMap::new();

        for c in alphabet.chars() {
            if !check_map.contains_key(&c) {
                unique_alphabet.push(c);
                check_map.insert(c, 1);
            }
        }

        unique_alphabet
    }

    pub fn encode_hex(&self, hex: String) -> String {
        let regex1 = Regex::new(r"^[0-9a-fA-F]+$").unwrap();
        if regex1.is_match(&hex.to_string()) == false {
            return String::new();
        }

        let mut numbers: Vec<i64> = Vec::new();
        let regex2 = Regex::new(r"[\w\W]{1,12}").unwrap();
        for matcher in regex2.find_iter(&hex.to_string()) {
            let mut num = String::new();
            num.push('1');
            num.push_str(&hex[matcher.0..matcher.1]);
            let v: i64 = i64::from_str_radix(&num.to_string(), 16).unwrap();
            numbers.push(v);
        }

        self.encode(&numbers)
    }

    pub fn decode_hex(&self, hash: String) -> String {
        let mut ret = String::new();
        let numbers = self.decode(hash);
        for number in numbers.iter() {
            let r = format!("{:x}", number);
            ret.push_str(&r[1..]);
        }

        ret
    }

    pub fn encode(&self, numbers: &Vec<i64>) -> String {
        if numbers.len() == 0 {
            return "".to_string();
        }

        for number in numbers.iter() {
            if *number > 9007199254740992 {
                return "".to_string();
            }
        }

        self._encode(numbers)
    }

    pub fn decode(&self, hash: String) -> Vec<i64> {
        let ret: Vec<i64> = Vec::new();
        if hash.len() == 0 {
            return ret;
        }

        self._decode(hash)
    }

    fn _decode(&self, hash: String) -> Vec<i64> {
        use regex::Regex;

        let mut regexp = String::new();
        regexp.push('[');
        regexp.push_str(&self.guards[..]);
        regexp.push(']');

        let re = Regex::new(&regexp[..]).unwrap();
        let t_hash = re.replace_all(&hash[..], " ");

        let split1: Vec<&str> = t_hash[..].split_whitespace().collect();
        let mut i = 0;

        let len = split1.len();
        if len == 3 || len == 2 {
            i = 1;
        }
        let mut hash_breakdown = split1[i].to_string();

        let lottery = hash_breakdown[0..1].to_string();
        hash_breakdown = hash_breakdown[1..].to_string();

        let mut regexp2 = String::new();
        regexp2.push('[');
        regexp2.push_str(&self.separators[..]);
        regexp2.push(']');

        let re2 = Regex::new(&regexp2[..]).unwrap();
        hash_breakdown = re2.replace_all(&hash_breakdown[..], " ");

        let split2: Vec<&str> = hash_breakdown[..].split_whitespace().collect();

        let mut alphabet = self.alphabet.clone();

        let mut ret: Vec<i64> = Vec::new();

        for s in split2 {
            let sub_hash = s.to_string();
            let mut buffer = String::new();
            buffer.push_str(&lottery[..]);
            buffer.push_str(&self.salt[..]);
            buffer.push_str(&alphabet.clone()[..]);

            let alpha_len = alphabet.len();
            alphabet = HashIds::hashids_shuffle(alphabet, buffer[0..alpha_len].to_string());
            ret.push(HashIds::unhash(sub_hash, alphabet.clone()));
        }

        let check_hash = self._encode(&ret);
        if check_hash != hash {
            return Vec::new();
        }

        ret
    }

    fn index_of(input: &[u8], v: u8) -> i64 {
        let mut i = 0;
        for s in input.iter() {
            if *s == v {
                return i;
            }

            i += 1;
        }

        return -1;
    }

    fn unhash(input: String, alphabet: String) -> i64 {
        let mut number: i64 = 0;
        let input_slice = input.as_bytes();
        let alpha_slice = alphabet.as_bytes();
        let len = input.len();
        let alpha_len = alphabet.len() as i64;
        let mut i: usize = 0;
        loop {
            if i >= len {
                break;
            }

            let v = input_slice[i] as usize;
            let pos = HashIds::index_of(alpha_slice, v as u8);
            let pow_size = (len - i - 1) as u32;
            number += (pos * alpha_len.pow(pow_size)) as i64;
            i += 1;
        }

        number
    }

    fn hash(input: i64, alphabet: String) -> String {
        let mut t_in = input;
        let mut hash = "".to_string();
        let len = alphabet.len() as i64;

        loop {
            let idx = (t_in % len) as usize;
            let mut t = alphabet[idx..idx + 1].to_string();
            t.push_str(&hash[..]);
            hash = t;
            t_in /= len;

            if t_in <= 0 {
                break;
            }
        }

        hash
    }

    fn _encode(&self, numbers: &Vec<i64>) -> String {
        let mut number_hash_int = 0;
        let mut count = 100;
        for number in numbers.iter() {
            number_hash_int += *number % count;
            count += 1;
        }

        let idx = (number_hash_int % (self.alphabet.len() as i64)) as usize;
        let ret = self.alphabet[idx..idx + 1].to_string();
        let mut ret_str = ret.clone();

        let mut t_alphabet = self.alphabet.clone();
        let mut i = 0;
        let len = self.separators.len() as i64;
        let last_len = count - 100;
        for number in numbers.iter() {
            let mut buffer = ret.clone();
            buffer.push_str(&self.salt[..]);
            buffer.push_str(&t_alphabet[..]);
            t_alphabet = HashIds::hashids_shuffle(
                t_alphabet.clone(),
                buffer[0..t_alphabet.len()].to_string(),
            );
            let last = HashIds::hash(*number, t_alphabet.clone());

            ret_str.push_str(&last[..]);

            if (i + 1) < last_len {
                let mut v = *number % (last.as_bytes()[0] as i64 + i);
                v = v % len;
                ret_str.push(self.separators.as_bytes()[v as usize] as char);
            }
            i += 1;
        }

        if ret_str.len() < self.min_hash_length {
            let guard_idx = (number_hash_int + ret_str.clone().into_bytes()[0] as i64) as usize
                % self.guards.len();
            let guard = self.guards[guard_idx..guard_idx + 1].to_string();
            let mut t = guard.clone();
            t.push_str(&ret_str[..]);
            ret_str = t;

            if ret_str.len() < self.min_hash_length {
                let guard_idx = (number_hash_int + ret_str.clone().into_bytes()[2] as i64) as usize
                    % self.guards.len();
                ret_str.push_str(&self.guards[guard_idx..guard_idx + 1]);
            }
        }

        let half_len = t_alphabet.len() / 2;
        while ret_str.len() < self.min_hash_length {
            t_alphabet = HashIds::hashids_shuffle(t_alphabet.clone(), t_alphabet.clone());
            let mut t_ret = "".to_string();
            t_ret.push_str(&t_alphabet[half_len..]);
            t_ret.push_str(&ret_str[..]);
            t_ret.push_str(&t_alphabet[0..half_len]);
            ret_str = t_ret;

            let excess = ret_str.len() as i64 - self.min_hash_length as i64;
            if excess > 0 {
                let start_pos = (excess as i64 / 2) as usize;
                ret_str = ret_str[start_pos..start_pos + self.min_hash_length].to_string();
            }
        }

        ret_str
    }
}
<commit_msg>Impl debug for HashIds<commit_after>#![crate_name = "hashids"]

#[macro_use]
extern crate failure;
extern crate regex;

use regex::Regex;
use std::collections::HashMap;

const DEFAULT_ALPHABET: &'static str =
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
const DEFAULT_SEPARATORS: &'static str = "cfhistuCFHISTU";
const SEPARTOR_DIV: f32 = 3.5;
const GUARD_DIV: u32 = 12;
const MIN_ALPHABET_LENGTH: usize = 16;

#[derive(Debug, Fail)]
pub enum HashIdsError {
    #[fail(display = "invalid alphabet length")]
    InvalidAlphabetLength,
}

#[derive(Debug)]
pub struct HashIds {
    salt: String,
    pub alphabet: String,
    separators: String,
    min_hash_length: usize,
    guards: String,
}

impl HashIds {
    pub fn new(
        salt: String,
        min_hash_length: usize,
        alphabet: String,
    ) -> Result<HashIds, HashIdsError> {
        let min_length = HashIds::get_min_hash_length(min_hash_length);
        let unique_alphabet = HashIds::get_unique_alphabet(alphabet);

        if unique_alphabet.len() < MIN_ALPHABET_LENGTH {
            return Err(HashIdsError::InvalidAlphabetLength);
        }

        let (t_separators, mut t_alphabet) = HashIds::get_separators(unique_alphabet);
        let mut shuffled_separators = HashIds::hashids_shuffle(t_separators.clone(), salt.clone());

        if HashIds::need_manipulate(shuffled_separators.len(), t_alphabet.len()) == true {
            let mut seps_len = ((t_alphabet.len() as f32) / SEPARTOR_DIV) as usize;
            if seps_len == 1 {
                seps_len += 1;
            }

            if seps_len > shuffled_separators.len() {
                let diff = seps_len - shuffled_separators.len();

                shuffled_separators.push_str(&t_alphabet[..diff]);
                t_alphabet = t_alphabet[diff..].to_string();
            } else {
                shuffled_separators = shuffled_separators[..seps_len].to_string();
            }
        }

        let mut shuffled_alphabet = HashIds::hashids_shuffle(t_alphabet.clone(), salt.clone());
        let guard_count = (shuffled_alphabet.len() as f32 / GUARD_DIV as f32).ceil() as usize;

        let t_guards;

        if shuffled_alphabet.len() < 3 {
            t_guards = shuffled_separators[..guard_count].to_string();
            shuffled_separators = shuffled_separators[guard_count..].to_string();
        } else {
            t_guards = shuffled_alphabet[..guard_count].to_string();
            shuffled_alphabet = shuffled_alphabet[guard_count..].to_string();
        }

        Ok(HashIds {
            salt: salt,
            min_hash_length: min_length,
            guards: t_guards,
            separators: shuffled_separators,
            alphabet: shuffled_alphabet,
        })
    }

    pub fn new_with_salt_and_min_length(
        salt: String,
        min_hash_length: usize,
    ) -> Result<HashIds, HashIdsError> {
        HashIds::new(salt, min_hash_length, DEFAULT_ALPHABET.to_string())
    }

    pub fn new_with_salt(salt: String) -> Result<HashIds, HashIdsError> {
        HashIds::new_with_salt_and_min_length(salt, 0)
    }

    fn need_manipulate(slen: usize, alen: usize) -> bool {
        if slen <= 0 || (((alen / slen) as f32) > SEPARTOR_DIV) {
            return true;
        }

        false
    }

    fn get_min_hash_length(length: usize) -> usize {
        if length > 0 {
            return length;
        } else {
            return 0;
        }
    }

    fn get_separators(alphabet: String) -> (String, String) {
        HashIds::get_non_duplicated_string(DEFAULT_SEPARATORS.to_string(), alphabet)
    }

    fn hashids_shuffle(alphabet: String, salt: String) -> String {
        if salt.len() <= 0 {
            return alphabet;
        }

        let salt_len = salt.len();
        let arr = salt.as_bytes();
        let len = alphabet.len();
        let mut bytes = alphabet.into_bytes();
        let shuffle = &mut bytes[..];

        let mut i: usize = len - 1;
        let mut v: usize = 0;
        let mut p: usize = 0;

        while i > 0 {
            v %= salt_len;
            let t = arr[v] as usize;
            p += t;
            let j = (t + v + p) % i;

            shuffle.swap(i, j);

            i = i - 1;
            v = v + 1;
        }

        let mut shuffled_alphabet = String::with_capacity(len);
        for i in 0..len {
            shuffled_alphabet.push(shuffle[i] as char);
        }

        shuffled_alphabet
    }

    fn get_non_duplicated_string(separators: String, alphabet: String) -> (String, String) {
        let mut check_separator_map = HashMap::new();
        let mut check_alphabet_map = HashMap::new();

        let mut modified_separators = String::new();
        let mut modified_alphabet = String::new();

        for c in separators.chars() {
            check_separator_map.insert(c, 1);
        }

        for c in alphabet.chars() {
            check_alphabet_map.insert(c, 1);
        }

        for c in separators.chars() {
            if check_alphabet_map.contains_key(&c) {
                modified_separators.push(c);
            }
        }

        for c in alphabet.chars() {
            if !check_separator_map.contains_key(&c) {
                modified_alphabet.push(c);
            }
        }

        (modified_separators, modified_alphabet)
    }

    fn get_unique_alphabet(alphabet: String) -> String {
        let mut unique_alphabet: String = String::new();
        let mut check_map = HashMap::new();

        for c in alphabet.chars() {
            if !check_map.contains_key(&c) {
                unique_alphabet.push(c);
                check_map.insert(c, 1);
            }
        }

        unique_alphabet
    }

    pub fn encode_hex(&self, hex: String) -> String {
        let regex1 = Regex::new(r"^[0-9a-fA-F]+$").unwrap();
        if regex1.is_match(&hex.to_string()) == false {
            return String::new();
        }

        let mut numbers: Vec<i64> = Vec::new();
        let regex2 = Regex::new(r"[\w\W]{1,12}").unwrap();
        for matcher in regex2.find_iter(&hex.to_string()) {
            let mut num = String::new();
            num.push('1');
            num.push_str(&hex[matcher.0..matcher.1]);
            let v: i64 = i64::from_str_radix(&num.to_string(), 16).unwrap();
            numbers.push(v);
        }

        self.encode(&numbers)
    }

    pub fn decode_hex(&self, hash: String) -> String {
        let mut ret = String::new();
        let numbers = self.decode(hash);
        for number in numbers.iter() {
            let r = format!("{:x}", number);
            ret.push_str(&r[1..]);
        }

        ret
    }

    pub fn encode(&self, numbers: &Vec<i64>) -> String {
        if numbers.len() == 0 {
            return "".to_string();
        }

        for number in numbers.iter() {
            if *number > 9007199254740992 {
                return "".to_string();
            }
        }

        self._encode(numbers)
    }

    pub fn decode(&self, hash: String) -> Vec<i64> {
        let ret: Vec<i64> = Vec::new();
        if hash.len() == 0 {
            return ret;
        }

        self._decode(hash)
    }

    fn _decode(&self, hash: String) -> Vec<i64> {
        use regex::Regex;

        let mut regexp = String::new();
        regexp.push('[');
        regexp.push_str(&self.guards[..]);
        regexp.push(']');

        let re = Regex::new(&regexp[..]).unwrap();
        let t_hash = re.replace_all(&hash[..], " ");

        let split1: Vec<&str> = t_hash[..].split_whitespace().collect();
        let mut i = 0;

        let len = split1.len();
        if len == 3 || len == 2 {
            i = 1;
        }
        let mut hash_breakdown = split1[i].to_string();

        let lottery = hash_breakdown[0..1].to_string();
        hash_breakdown = hash_breakdown[1..].to_string();

        let mut regexp2 = String::new();
        regexp2.push('[');
        regexp2.push_str(&self.separators[..]);
        regexp2.push(']');

        let re2 = Regex::new(&regexp2[..]).unwrap();
        hash_breakdown = re2.replace_all(&hash_breakdown[..], " ");

        let split2: Vec<&str> = hash_breakdown[..].split_whitespace().collect();

        let mut alphabet = self.alphabet.clone();

        let mut ret: Vec<i64> = Vec::new();

        for s in split2 {
            let sub_hash = s.to_string();
            let mut buffer = String::new();
            buffer.push_str(&lottery[..]);
            buffer.push_str(&self.salt[..]);
            buffer.push_str(&alphabet.clone()[..]);

            let alpha_len = alphabet.len();
            alphabet = HashIds::hashids_shuffle(alphabet, buffer[0..alpha_len].to_string());
            ret.push(HashIds::unhash(sub_hash, alphabet.clone()));
        }

        let check_hash = self._encode(&ret);
        if check_hash != hash {
            return Vec::new();
        }

        ret
    }

    fn index_of(input: &[u8], v: u8) -> i64 {
        let mut i = 0;
        for s in input.iter() {
            if *s == v {
                return i;
            }

            i += 1;
        }

        return -1;
    }

    fn unhash(input: String, alphabet: String) -> i64 {
        let mut number: i64 = 0;
        let input_slice = input.as_bytes();
        let alpha_slice = alphabet.as_bytes();
        let len = input.len();
        let alpha_len = alphabet.len() as i64;
        let mut i: usize = 0;
        loop {
            if i >= len {
                break;
            }

            let v = input_slice[i] as usize;
            let pos = HashIds::index_of(alpha_slice, v as u8);
            let pow_size = (len - i - 1) as u32;
            number += (pos * alpha_len.pow(pow_size)) as i64;
            i += 1;
        }

        number
    }

    fn hash(input: i64, alphabet: String) -> String {
        let mut t_in = input;
        let mut hash = "".to_string();
        let len = alphabet.len() as i64;

        loop {
            let idx = (t_in % len) as usize;
            let mut t = alphabet[idx..idx + 1].to_string();
            t.push_str(&hash[..]);
            hash = t;
            t_in /= len;

            if t_in <= 0 {
                break;
            }
        }

        hash
    }

    fn _encode(&self, numbers: &Vec<i64>) -> String {
        let mut number_hash_int = 0;
        let mut count = 100;
        for number in numbers.iter() {
            number_hash_int += *number % count;
            count += 1;
        }

        let idx = (number_hash_int % (self.alphabet.len() as i64)) as usize;
        let ret = self.alphabet[idx..idx + 1].to_string();
        let mut ret_str = ret.clone();

        let mut t_alphabet = self.alphabet.clone();
        let mut i = 0;
        let len = self.separators.len() as i64;
        let last_len = count - 100;
        for number in numbers.iter() {
            let mut buffer = ret.clone();
            buffer.push_str(&self.salt[..]);
            buffer.push_str(&t_alphabet[..]);
            t_alphabet = HashIds::hashids_shuffle(
                t_alphabet.clone(),
                buffer[0..t_alphabet.len()].to_string(),
            );
            let last = HashIds::hash(*number, t_alphabet.clone());

            ret_str.push_str(&last[..]);

            if (i + 1) < last_len {
                let mut v = *number % (last.as_bytes()[0] as i64 + i);
                v = v % len;
                ret_str.push(self.separators.as_bytes()[v as usize] as char);
            }
            i += 1;
        }

        if ret_str.len() < self.min_hash_length {
            let guard_idx = (number_hash_int + ret_str.clone().into_bytes()[0] as i64) as usize
                % self.guards.len();
            let guard = self.guards[guard_idx..guard_idx + 1].to_string();
            let mut t = guard.clone();
            t.push_str(&ret_str[..]);
            ret_str = t;

            if ret_str.len() < self.min_hash_length {
                let guard_idx = (number_hash_int + ret_str.clone().into_bytes()[2] as i64) as usize
                    % self.guards.len();
                ret_str.push_str(&self.guards[guard_idx..guard_idx + 1]);
            }
        }

        let half_len = t_alphabet.len() / 2;
        while ret_str.len() < self.min_hash_length {
            t_alphabet = HashIds::hashids_shuffle(t_alphabet.clone(), t_alphabet.clone());
            let mut t_ret = "".to_string();
            t_ret.push_str(&t_alphabet[half_len..]);
            t_ret.push_str(&ret_str[..]);
            t_ret.push_str(&t_alphabet[0..half_len]);
            ret_str = t_ret;

            let excess = ret_str.len() as i64 - self.min_hash_length as i64;
            if excess > 0 {
                let start_pos = (excess as i64 / 2) as usize;
                ret_str = ret_str[start_pos..start_pos + self.min_hash_length].to_string();
            }
        }

        ret_str
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Jeremy Mason
//
// Licensed under the MIT license <LICENSE or
// http://opensource.org/licenses/MIT>. This file may not be copied, modified,
// or distributed except according to those terms.

//! This crate provides three types to compress integer arrays. The design
//! generally favors decompression speed and the ability to index the
//! compressed array over the compression ratio, on the principle that the
//! runtime penalty for using compressed arrays should be as small as possible.
//!
//! # Usage
//!
//! Add this to your `Cargo.toml`:
//! ```toml
//! [dependencies]
//! mayda = "0.1"
//! ```
//! and this to your crate root:
//! ```rust
//! extern crate mayda;
//! ```
//!
//! # Example: encoding and decoding
//!
//! The Uniform struct is recommended for general purpose integer compression.
//! Use the Encodable trait to encode and decode the array.
//!
//! ```rust
//! extern crate mayda;
//!
//! use std::mem;
//! use mayda::{Uniform, Encodable};
//!
//! // Integers in some interval of length 255, require one byte per integer
//! let input: Vec<u32> = (0..128).map(|x| (x * 73) % 181 + 307).collect();
//!
//! let mut uniform = Uniform::new();
//! uniform.encode(&input).unwrap();
//!
//! let i_bytes = mem::size_of_val(input.as_slice());
//! let u_bytes = mem::size_of_val(uniform.storage());
//!
//! // 128 bytes for encoded entries, 12 bytes of overhead
//! assert_eq!(i_bytes, 512);
//! assert_eq!(u_bytes, 140);
//!
//! let output: Vec<u32> = uniform.decode().unwrap();
//! assert_eq!(input, output);
//! ```
//!
//! # Example: indexing
//!
//! Use the Access trait to index the compressed array. This is similar to
//! `Index`, but returns a vector instead of a slice.
//!
//! ```rust
//! extern crate mayda;
//!
//! use mayda::{Uniform, Encodable, Access};
//!
//! // All primitive integer types supported
//! let input: Vec<isize> = (-64..64).collect();
//!
//! let mut uniform = Uniform::new();
//! uniform.encode(&input).unwrap();
//!
//! let val: isize = uniform.access(64);
//! assert_eq!(val, 0);
//!
//! // Vector is returned to give ownership to the caller
//! let range: Vec<isize> = uniform.access(..10);
//! assert_eq!(range, (-64..-54).collect::<Vec<_>>());
//! ```
//!
//! # Algorithm
//!
//! The compression algorithm relies on the observation that for many integer
//! arrays, the probability distribution of a block of 128 entries is not
//! uniform over all values that can be represented by the integer type. For
//! example, an array of indices into a second array with 256 entries has
//! entries that are bounded below by 0 and above by 255. This requires only
//! eight bits per entry, rather than the 32 or 64 generally set aside for a
//! usize index. The basic idea of the compression algorithm is to represent
//! all of the entries in a block with a single minimum necessary bit width.
//! This allows SIMD operations and manual loop unrolling to avoid branches to
//! be used to accelerate encoding and decoding.
//!
//! This approach does not perform well for probability distributions with
//! outliers though, or for situations where the median value is nonzero. This
//! crate provides three types that handle this situation by applying different
//! initial transformations to the input integer array.
//!
//! The `Uniform` type targets encoding and decoding speed. The only
//! transformation is to subtract the minimum value from the entries, with the
//! result that the compression depends only on the difference between the
//! largest and smallest entries.
//!
//! The `Monotone` type is specifically intended for arrays with monotone
//! increasing entries. A blocks of entries is transformed into an offset and
//! an array of differences of successive entries, and the array of differences
//! is encoded by the approach above. The compression depends only on the
//! largest entry in the difference array.
//!
//! The `Unimodal` type performs the most extensive transformations and offers
//! the most robust compression. The median value is subtracted from the
//! entries, the entries are mapped to the unsigned integers by the zig-zag
//! encoding, and the most significant bits of any outliers are removed and
//! stored separately. The result is that the compression effectively depends
//! only on the standard deviation of the probability distribution of the block
//! entries.
//!
/// # Indexing
///
/// Indexing an object of the `Uniform`, `Monotone` or `Unimodal` types is not
/// a simple pointer offset. Part of the header encodes the relative offsets to
/// every block in a compressed form, with the result that random access via
/// the `Access` trait is an `O(log(idx))` operation, where `idx` is the value
/// of the index (not the length of the array). The overhead of this part of
/// the header is around a tenth of a bit per encoded integer.
///
/// If you need to access several nearby entries, consider accessing the range
/// and indexing the returned vector for performance.
///
//! # Safety
//!
//! As a general rule, you **should not** decode or access objects of the
//! `Uniform`, `Monotone` or `Unimodal` types from untrusted sources.
//!
//! `mayda` performs wildly unsafe pointer operations during encoding and
//! decoding. Changing the header information with `mut_storage()` could cause
//! data to be written to or read from arbitrary addresses in memory.
//!
//! That said, the situation is the same for any of the data structures in the
//! standard library. For example, this is why the `set_len` method of a `Vec`
//! is unsafe.

#![feature(inclusive_range)]
#![feature(inclusive_range_syntax)]
#![feature(iter_arith)]
#![feature(specialization)]

extern crate mayda_codec;

pub mod error;
pub mod monotone;
pub mod uniform;
pub mod unimodal;
pub mod utility;

pub use self::error::Error;
pub use self::monotone::Monotone;
pub use self::uniform::Uniform;
pub use self::unimodal::Unimodal;
pub use self::utility::{Access, Encodable};
<commit_msg>Inline comments broke build.<commit_after>// Copyright 2016 Jeremy Mason
//
// Licensed under the MIT license <LICENSE or
// http://opensource.org/licenses/MIT>. This file may not be copied, modified,
// or distributed except according to those terms.

//! This crate provides three types to compress integer arrays. The design
//! generally favors decompression speed and the ability to index the
//! compressed array over the compression ratio, on the principle that the
//! runtime penalty for using compressed arrays should be as small as possible.
//!
//! # Usage
//!
//! Add this to your `Cargo.toml`:
//! ```toml
//! [dependencies]
//! mayda = "0.1"
//! ```
//! and this to your crate root:
//! ```rust
//! extern crate mayda;
//! ```
//!
//! # Example: encoding and decoding
//!
//! The Uniform struct is recommended for general purpose integer compression.
//! Use the Encodable trait to encode and decode the array.
//!
//! ```rust
//! extern crate mayda;
//!
//! use std::mem;
//! use mayda::{Uniform, Encodable};
//!
//! // Integers in some interval of length 255, require one byte per integer
//! let input: Vec<u32> = (0..128).map(|x| (x * 73) % 181 + 307).collect();
//!
//! let mut uniform = Uniform::new();
//! uniform.encode(&input).unwrap();
//!
//! let i_bytes = mem::size_of_val(input.as_slice());
//! let u_bytes = mem::size_of_val(uniform.storage());
//!
//! // 128 bytes for encoded entries, 12 bytes of overhead
//! assert_eq!(i_bytes, 512);
//! assert_eq!(u_bytes, 140);
//!
//! let output: Vec<u32> = uniform.decode().unwrap();
//! assert_eq!(input, output);
//! ```
//!
//! # Example: indexing
//!
//! Use the Access trait to index the compressed array. This is similar to
//! `Index`, but returns a vector instead of a slice.
//!
//! ```rust
//! extern crate mayda;
//!
//! use mayda::{Uniform, Encodable, Access};
//!
//! // All primitive integer types supported
//! let input: Vec<isize> = (-64..64).collect();
//!
//! let mut uniform = Uniform::new();
//! uniform.encode(&input).unwrap();
//!
//! let val: isize = uniform.access(64);
//! assert_eq!(val, 0);
//!
//! // Vector is returned to give ownership to the caller
//! let range: Vec<isize> = uniform.access(..10);
//! assert_eq!(range, (-64..-54).collect::<Vec<_>>());
//! ```
//!
//! # Algorithm
//!
//! The compression algorithm relies on the observation that for many integer
//! arrays, the probability distribution of a block of 128 entries is not
//! uniform over all values that can be represented by the integer type. For
//! example, an array of indices into a second array with 256 entries has
//! entries that are bounded below by 0 and above by 255. This requires only
//! eight bits per entry, rather than the 32 or 64 generally set aside for a
//! usize index. The basic idea of the compression algorithm is to represent
//! all of the entries in a block with a single minimum necessary bit width.
//! This allows SIMD operations and manual loop unrolling to avoid branches to
//! be used to accelerate encoding and decoding.
//!
//! This approach does not perform well for probability distributions with
//! outliers though, or for situations where the median value is nonzero. This
//! crate provides three types that handle this situation by applying different
//! initial transformations to the input integer array.
//!
//! The `Uniform` type targets encoding and decoding speed. The only
//! transformation is to subtract the minimum value from the entries, with the
//! result that the compression depends only on the difference between the
//! largest and smallest entries.
//!
//! The `Monotone` type is specifically intended for arrays with monotone
//! increasing entries. A blocks of entries is transformed into an offset and
//! an array of differences of successive entries, and the array of differences
//! is encoded by the approach above. The compression depends only on the
//! largest entry in the difference array.
//!
//! The `Unimodal` type performs the most extensive transformations and offers
//! the most robust compression. The median value is subtracted from the
//! entries, the entries are mapped to the unsigned integers by the zig-zag
//! encoding, and the most significant bits of any outliers are removed and
//! stored separately. The result is that the compression effectively depends
//! only on the standard deviation of the probability distribution of the block
//! entries.
//!
//! # Indexing
//!
//! Indexing an object of the `Uniform`, `Monotone` or `Unimodal` types is not
//! a simple pointer offset. Part of the header encodes the relative offsets to
//! every block in a compressed form, with the result that random access via
//! the `Access` trait is an `O(log(idx))` operation, where `idx` is the value
//! of the index (not the length of the array). The overhead of this part of
//! the header is around a tenth of a bit per encoded integer.
//!
//! If you need to access several nearby entries, consider accessing the range
//! and indexing the returned vector for performance.
//!
//! # Safety
//!
//! As a general rule, you **should not** decode or access objects of the
//! `Uniform`, `Monotone` or `Unimodal` types from untrusted sources.
//!
//! `mayda` performs wildly unsafe pointer operations during encoding and
//! decoding. Changing the header information with `mut_storage()` could cause
//! data to be written to or read from arbitrary addresses in memory.
//!
//! That said, the situation is the same for any of the data structures in the
//! standard library. For example, this is why the `set_len` method of a `Vec`
//! is unsafe.

#![feature(inclusive_range)]
#![feature(inclusive_range_syntax)]
#![feature(iter_arith)]
#![feature(specialization)]

extern crate mayda_codec;

pub mod error;
pub mod monotone;
pub mod uniform;
pub mod unimodal;
pub mod utility;

pub use self::error::Error;
pub use self::monotone::Monotone;
pub use self::uniform::Uniform;
pub use self::unimodal::Unimodal;
pub use self::utility::{Access, Encodable};
<|endoftext|>


<commit_before>#![no_std]

#[doc(hidden)]
pub extern crate core as _core;

/// Asserts at compile-time that the types have equal sizes.
///
/// This especially is useful for when coercing pointers between different types
/// and ensuring the underlying values are the same size.
///
/// # Example
///
/// ```
/// #[macro_use]
/// extern crate static_assertions;
///
/// struct Byte(u8);
///
/// fn main() {
///     assert_eq_size!(Byte, u8);
///     // assert_eq_size!(Byte, u16); // Fails to compile
///
///     // Supports unlimited arguments:
///     assert_eq_size!([Byte; 4], [u16; 2], u32);
/// }
/// ```
#[macro_export]
macro_rules! assert_eq_size {
    ($x:ty, $($xs:ty),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            use $crate::_core::mem::{forget, transmute, uninitialized};
            $(forget::<$xs>(transmute(uninitialized::<$x>()));)+
        }
    }
}

/// Asserts at compile-time that the values have equal sizes.
#[macro_export]
macro_rules! assert_eq_size_val {
    ($x:expr, $($xs:expr),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            use $crate::_core::{mem, ptr};
            let mut copy = ptr::read(&$x);
            $(ptr::write(&mut copy, mem::transmute(ptr::read(&$xs)));)+
            mem::forget(copy);
        }
    }
}

/// Asserts at compile-time that the constant expression evaluates to `true`.
#[macro_export]
macro_rules! const_assert {
    ($cond:expr) => {
        // Causes overflow if condition is false
        let _ = [(); 0 - (!($cond) as usize)];
    };
    ($($xs:expr),+) => {
        const_assert!($($xs)&&+);
    };
    ($($xs:expr);+ $(;)*) => {
        const_assert!($($xs),+);
    };
}
<commit_msg>Add to assert_eq_size_val doc<commit_after>#![no_std]

#[doc(hidden)]
pub extern crate core as _core;

/// Asserts at compile-time that the types have equal sizes.
///
/// This especially is useful for when coercing pointers between different types
/// and ensuring the underlying values are the same size.
///
/// # Example
///
/// ```
/// #[macro_use]
/// extern crate static_assertions;
///
/// struct Byte(u8);
///
/// fn main() {
///     assert_eq_size!(Byte, u8);
///     // assert_eq_size!(Byte, u16); // Fails to compile
///
///     // Supports unlimited arguments:
///     assert_eq_size!([Byte; 4], [u16; 2], u32);
/// }
/// ```
#[macro_export]
macro_rules! assert_eq_size {
    ($x:ty, $($xs:ty),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            use $crate::_core::mem::{forget, transmute, uninitialized};
            $(forget::<$xs>(transmute(uninitialized::<$x>()));)+
        }
    }
}

/// Asserts at compile-time that the values have equal sizes.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # fn main() {
/// struct Byte(u8);
///
/// let x = 10u8;
/// let y = Byte(42); // Works for non-cloneable types
///
/// assert_eq_size_val!(x, y);
/// assert_eq_size_val!(x, y, 0u8);
///
/// // Fails to compile:
/// // assert_eq_size_val!(x, 0u32);
/// # }
/// ```
#[macro_export]
macro_rules! assert_eq_size_val {
    ($x:expr, $($xs:expr),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            use $crate::_core::{mem, ptr};
            let mut copy = ptr::read(&$x);
            $(ptr::write(&mut copy, mem::transmute(ptr::read(&$xs)));)+
            mem::forget(copy);
        }
    }
}

/// Asserts at compile-time that the constant expression evaluates to `true`.
#[macro_export]
macro_rules! const_assert {
    ($cond:expr) => {
        // Causes overflow if condition is false
        let _ = [(); 0 - (!($cond) as usize)];
    };
    ($($xs:expr),+) => {
        const_assert!($($xs)&&+);
    };
    ($($xs:expr);+ $(;)*) => {
        const_assert!($($xs),+);
    };
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate rustc_serialize;
extern crate url;
extern crate regex;

use regex::{Captures, Regex};
use rustc_serialize::json;

use hyper::Client;
use hyper::server::{Handler, Request, Response as HyperResponse};
use std::collections::HashMap;
use std::io::Read;

fn params<R: Read>(read: &mut R) -> HashMap<String, String> {
    let mut buffer = String::new();
    read.read_to_string(&mut buffer).unwrap();
    let mut params = HashMap::new();
    for (k, v) in url::form_urlencoded::parse(buffer.as_bytes()) {
        params.insert(k, v);
    }
    params
}

pub enum Response {
    Channel(String),
    Ephemeral(String),
}

pub trait Responder {
    fn respond(&self, response: Response) -> ();
}

pub struct DefaultResponder {
    response_url: String,
}

/// A payload to reply to commands with
/// for formatting rules see [this doc](https://api.slack.com/docs/formatting)
/// for attachments see [this doc](https://api.slack.com/docs/attachments)
#[derive(Debug, RustcEncodable)]
pub struct ResponseBody {
    pub text: String,
    pub response_type: Option<String>,
}

impl Responder for DefaultResponder {
    fn respond(&self, response: Response) {
        let body = match response {
            Response::Channel(text) => {
                ResponseBody {
                    text: text,
                    response_type: Some("in_channel".to_owned()),
                }
            }
            Response::Ephemeral(text) => {
                ResponseBody {
                    text: text,
                    response_type: None,
                }
            }
        };
        let client = Client::new();
        let _ = client.post(&self.response_url[..])
                      .body(json::encode(&body).unwrap().as_bytes())
                      .send();
    }
}

pub struct DiscardResponder;

impl Responder for DiscardResponder {
    fn respond(&self, _: Response) {

    }
}

/// A Handle handles matched commands
pub trait Handle: Sync + Send {
    fn handle(&self,
              cmd: &Command,
              caps: &Option<Captures>,
              responder: Box<Responder>)
              -> Option<Response>;
}

impl<F> Handle for F
    where F: Fn(&Command, &Option<Captures>, Box<Responder>) -> Option<Response>,
          F: Send + Sync
{
    fn handle(&self,
              cmd: &Command,
              caps: &Option<Captures>,
              responder: Box<Responder>)
              -> Option<Response> {
        self(cmd, caps, responder)
    }
}

pub struct TokenValidator<H: Handle + 'static> {
    handler: H,
    token: String,
}

impl<H: Handle + 'static> Handle for TokenValidator<H> {
    fn handle(&self,
              cmd: &Command,
              caps: &Option<Captures>,
              responder: Box<Responder>)
              -> Option<Response> {
        if cmd.token == self.token {
            self.handler.handle(cmd, caps, responder)
        } else {
            None
        }
    }
}

/// A matcher matches commands
pub trait Matcher: Send + Sync {
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool);
}

impl<F> Matcher for F
    where F: Fn(&Command) -> (Option<Captures>, bool),
          F: Send + Sync
{
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool) {
        self(cmd)
    }
}

/// A direct command matcher
///
pub struct MatchCommand(String);

impl Matcher for MatchCommand {
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool) {
        (None, cmd.command == self.0)
    }
}

/// A regex pattern matcher
///
pub struct MatchRegex(Regex);

impl Matcher for MatchRegex {
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool) {
        if self.0.is_match(cmd.command.as_ref()) {
            (self.0.captures(cmd.command.as_ref()), true)
        } else {
            (None, false)
        }
    }
}

/// A binding between a command handler and which commands its handles
pub struct Route {
    handler: Box<Handle>,
    matcher: Box<Matcher>,
}

///
/// A command de-multiplexor
///
#[derive(Default)]
pub struct Mux {
    routes: Vec<Box<Route>>,
}

impl Mux {
    pub fn command<C, T, H>(&mut self, cmd: C, token: T, handler: H)
        where C: Into<String>,
              T: Into<String>,
              H: Handle + 'static
    {
        self.matching(MatchCommand(cmd.into()),
                      TokenValidator {
                          handler: handler,
                          token: token.into(),
                      })
    }

    pub fn matching<M, H>(&mut self, matcher: M, handler: H)
        where M: Matcher + 'static,
              H: Handle + 'static
    {
        let route = Route {
            handler: Box::new(handler),
            matcher: Box::new(matcher),
        };
        self.route(route)
    }

    ///
    pub fn route(&mut self, route: Route) {
        self.routes.push(Box::new(route));
    }

    pub fn handler<'a>(&self, cmd: &'a Command) -> Option<(Option<Captures<'a>>, &Box<Handle>)> {
        for r in self.routes.iter() {
            if let (captures, true) = r.matcher.matches(cmd) {
                return Some((captures, &r.handler));
            }
        }
        None
    }

    pub fn handle(&self, cmd: &Command) {
        // set up responder
        let responder = DefaultResponder { response_url: cmd.response_url.clone() };
        // handle cmd
        if let &Some((ref captures, handler)) = &self.handler(&cmd) {
            handler.handle(&cmd, &captures, Box::new(responder));
        }
    }
}

#[derive(Default)]
pub struct Command {
    pub token: String,
    pub team_id: String,
    pub team_domain: String,
    pub channel_id: String,
    pub channel_name: String,
    pub user_id: String,
    pub user_name: String,
    pub command: String,
    pub text: String,
    pub response_url: String,
}

impl Command {
    pub fn from_params(params: HashMap<String, String>) -> Option<Command> {
        if let (Some(token),
                Some(team_id),
                Some(team_domain),
                Some(channel_id),
                Some(channel_name),
                Some(user_id),
                Some(user_name),
                Some(command),
                Some(text),
                Some(response_url)) = (params.get("token"),
                                       params.get("team_id"),
                                       params.get("team_domain"),
                                       params.get("channel_id"),
                                       params.get("channel_name"),
                                       params.get("user_id"),
                                       params.get("user_name"),
                                       params.get("command"),
                                       params.get("text"),
                                       params.get("response_url")) {
            Some(Command {
                token: token.clone(),
                team_id: team_id.clone(),
                team_domain: team_domain.clone(),
                channel_id: channel_id.clone(),
                channel_name: channel_name.clone(),
                user_id: user_id.clone(),
                user_name: user_name.clone(),
                command: command.clone(),
                text: text.clone(),
                response_url: response_url.clone(),
            })
        } else {
            None
        }
    }
}

impl Handler for Mux {
    // https://api.slack.com/slash-commands
    fn handle(&self, req: Request, res: HyperResponse) {
        let (_, _, _, _, _, mut body) = req.deconstruct();
        // parse params
        let params = params(&mut body);
        // parse cmd
        if let Some(cmd) = Command::from_params(params) {
            self.handle(&cmd)
        }
        let _ = res.send(b"ok");
        ()
    }
}

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

    #[test]
    fn matches_commands() {
        let cmd = Command { command: "/test".to_owned(), ..Default::default() };
        let (_, matched) = MatchCommand("/test".to_owned()).matches(&cmd);
        assert!(matched)
    }

    #[test]
    fn matches_regexes() {
        let cmd = Command { command: "/test".to_owned(), ..Default::default() };
        let (_, matched) = MatchRegex(Regex::new("(test)").unwrap()).matches(&cmd);
        assert!(matched)
    }
}
<commit_msg>remove intermediate rep<commit_after>extern crate hyper;
extern crate rustc_serialize;
extern crate url;
extern crate regex;

use regex::{Captures, Regex};
use rustc_serialize::json;

use hyper::Client;
use hyper::server::{Handler, Request, Response as HyperResponse};
use std::collections::HashMap;
use std::io::Read;

fn params<R: Read>(read: &mut R) -> HashMap<String, String> {
    let mut buffer = String::new();
    read.read_to_string(&mut buffer).unwrap();
    let mut params = HashMap::new();
    for (k, v) in url::form_urlencoded::parse(buffer.as_bytes()) {
        params.insert(k, v);
    }
    params
}

pub trait Responder {
    fn respond(&self, response: Response) -> ();
}

pub struct DefaultResponder {
    response_url: String,
}

/// A payload to reply to commands with
/// for formatting rules see [this doc](https://api.slack.com/docs/formatting)
/// for attachments see [this doc](https://api.slack.com/docs/attachments)
#[derive(Debug, RustcEncodable)]
pub struct Response {
    pub text: String,
    pub response_type: String,
}

impl Response {
    pub fn ephemeral<T>(text: T) -> Response where T: Into<String> {
        Response {
            text: text.into(),
            response_type: "ephemeral".to_owned()
        }
    }
    pub fn in_channel<T>(text: T) -> Response where T: Into<String> {
        Response {
            text: text.into(),
            response_type: "in_channel".to_owned()
        }
    }
}

impl Responder for DefaultResponder {
    fn respond(&self, response: Response) {
        let client = Client::new();
        let _ = client.post(&self.response_url[..])
                      .body(json::encode(&response).unwrap().as_bytes())
                      .send();
    }
}

pub struct DiscardResponder;

impl Responder for DiscardResponder {
    fn respond(&self, _: Response) {

    }
}

/// A Handle handles matched commands
pub trait Handle: Sync + Send {
    fn handle(&self,
              cmd: &Command,
              caps: &Option<Captures>,
              responder: Box<Responder>)
              -> Option<Response>;
}

impl<F> Handle for F
    where F: Fn(&Command, &Option<Captures>, Box<Responder>) -> Option<Response>,
          F: Send + Sync
{
    fn handle(&self,
              cmd: &Command,
              caps: &Option<Captures>,
              responder: Box<Responder>)
              -> Option<Response> {
        self(cmd, caps, responder)
    }
}

pub struct TokenValidator<H: Handle + 'static> {
    handler: H,
    token: String,
}

impl<H: Handle + 'static> Handle for TokenValidator<H> {
    fn handle(&self,
              cmd: &Command,
              caps: &Option<Captures>,
              responder: Box<Responder>)
              -> Option<Response> {
        if cmd.token == self.token {
            self.handler.handle(cmd, caps, responder)
        } else {
            None
        }
    }
}

/// A matcher matches commands
pub trait Matcher: Send + Sync {
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool);
}

impl<F> Matcher for F
    where F: Fn(&Command) -> (Option<Captures>, bool),
          F: Send + Sync
{
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool) {
        self(cmd)
    }
}

/// A direct command matcher
///
pub struct MatchCommand(String);

impl Matcher for MatchCommand {
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool) {
        (None, cmd.command == self.0)
    }
}

/// A regex pattern matcher
///
pub struct MatchRegex(Regex);

impl Matcher for MatchRegex {
    fn matches<'a>(&self, cmd: &'a Command) -> (Option<Captures<'a>>, bool) {
        if self.0.is_match(cmd.command.as_ref()) {
            (self.0.captures(cmd.command.as_ref()), true)
        } else {
            (None, false)
        }
    }
}

/// A binding between a command handler and which commands its handles
pub struct Route {
    handler: Box<Handle>,
    matcher: Box<Matcher>,
}

///
/// A command de-multiplexor
///
#[derive(Default)]
pub struct Mux {
    routes: Vec<Box<Route>>,
}

impl Mux {
    pub fn command<C, T, H>(&mut self, cmd: C, token: T, handler: H)
        where C: Into<String>,
              T: Into<String>,
              H: Handle + 'static
    {
        self.matching(MatchCommand(cmd.into()),
                      TokenValidator {
                          handler: handler,
                          token: token.into(),
                      })
    }

    pub fn matching<M, H>(&mut self, matcher: M, handler: H)
        where M: Matcher + 'static,
              H: Handle + 'static
    {
        let route = Route {
            handler: Box::new(handler),
            matcher: Box::new(matcher),
        };
        self.route(route)
    }

    ///
    pub fn route(&mut self, route: Route) {
        self.routes.push(Box::new(route));
    }

    pub fn handler<'a>(&self, cmd: &'a Command) -> Option<(Option<Captures<'a>>, &Box<Handle>)> {
        for r in self.routes.iter() {
            if let (captures, true) = r.matcher.matches(cmd) {
                return Some((captures, &r.handler));
            }
        }
        None
    }

    pub fn handle(&self, cmd: &Command) {
        // set up responder
        let responder = DefaultResponder { response_url: cmd.response_url.clone() };
        // handle cmd
        if let &Some((ref captures, handler)) = &self.handler(&cmd) {
            handler.handle(&cmd, &captures, Box::new(responder));
        }
    }
}

#[derive(Default)]
pub struct Command {
    pub token: String,
    pub team_id: String,
    pub team_domain: String,
    pub channel_id: String,
    pub channel_name: String,
    pub user_id: String,
    pub user_name: String,
    pub command: String,
    pub text: String,
    pub response_url: String,
}

impl Command {
    pub fn from_params(params: HashMap<String, String>) -> Option<Command> {
        if let (Some(token),
                Some(team_id),
                Some(team_domain),
                Some(channel_id),
                Some(channel_name),
                Some(user_id),
                Some(user_name),
                Some(command),
                Some(text),
                Some(response_url)) = (params.get("token"),
                                       params.get("team_id"),
                                       params.get("team_domain"),
                                       params.get("channel_id"),
                                       params.get("channel_name"),
                                       params.get("user_id"),
                                       params.get("user_name"),
                                       params.get("command"),
                                       params.get("text"),
                                       params.get("response_url")) {
            Some(Command {
                token: token.clone(),
                team_id: team_id.clone(),
                team_domain: team_domain.clone(),
                channel_id: channel_id.clone(),
                channel_name: channel_name.clone(),
                user_id: user_id.clone(),
                user_name: user_name.clone(),
                command: command.clone(),
                text: text.clone(),
                response_url: response_url.clone(),
            })
        } else {
            None
        }
    }
}

impl Handler for Mux {
    // https://api.slack.com/slash-commands
    fn handle(&self, req: Request, res: HyperResponse) {
        let (_, _, _, _, _, mut body) = req.deconstruct();
        // parse params
        let params = params(&mut body);
        // parse cmd
        if let Some(cmd) = Command::from_params(params) {
            self.handle(&cmd)
        }
        let _ = res.send(b"ok");
        ()
    }
}

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

    #[test]
    fn matches_commands() {
        let cmd = Command { command: "/test".to_owned(), ..Default::default() };
        let (_, matched) = MatchCommand("/test".to_owned()).matches(&cmd);
        assert!(matched)
    }

    #[test]
    fn matches_regexes() {
        let cmd = Command { command: "/test".to_owned(), ..Default::default() };
        let (_, matched) = MatchRegex(Regex::new("(test)").unwrap()).matches(&cmd);
        assert!(matched)
    }
}
<|endoftext|>