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

extern crate regex;

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

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;

pub enum HashIdsError { 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 mut 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>Fix separator calculation logic<commit_after>#![crate_name = "hashids"]

extern crate regex;

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

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;

pub enum HashIdsError { 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 mut 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>#![crate_name = "rust_hl_lua"]
#![crate_type = "lib"]
#![comment = "Lua bindings for Rust"]
#![license = "MIT"]
#![allow(visible_private_types)]
#![feature(macro_rules)]

extern crate libc;

use std::kinds::marker::ContravariantLifetime;

pub use lua_tables::LuaTable;

pub mod functions_read;
pub mod lua_tables;
pub mod userdata;

mod ffi;
mod functions_write;
mod rust_tables;
mod tuples;
mod values;

/**
 * Main object of the library
 * The lifetime parameter corresponds to the lifetime of the Lua object itself
 */
pub struct Lua<'lua> {
    lua: *mut ffi::lua_State,
    marker: ContravariantLifetime<'lua>,
    must_be_closed: bool,
    inside_callback: bool           // if true, we are inside a callback
}

/**
 * Object which allows access to a Lua variable
 */
pub struct LoadedVariable<'var, 'lua> {
    lua: &'var mut Lua<'lua>,
    size: uint       // number of elements at the top of the stack
}

/**
 * Should be implemented by whatever type is pushable on the Lua stack
 */
pub trait Pushable<'lua>: ::std::any::Any {
    /**
     * Pushes the value on the top of the stack
     * Must return the number of elements pushed
     */
    fn push_to_lua(self, lua: &mut Lua<'lua>) -> uint {
        self.push_as_userdata(lua)
    }

    /**
     * Pushes the value on the top of the stack as a user data
     * This means that the value will only be readable as itself and not convertible to anything
     * Also, objects pushed as userdata will not be cloned by Lua
     */
    fn push_as_userdata(self, lua: &mut Lua<'lua>) -> uint {
        userdata::push_userdata(self, lua)
    }

    /**
     * Pushes over another element
     */
    fn push_over<'var>(self, mut over: LoadedVariable<'var, 'lua>)
        -> (LoadedVariable<'var, 'lua>, uint)
    {
        let val = self.push_to_lua(over.lua);
        over.size += val;
        (over, val)
    }
}

/**
 * Should be implemented by types that can be read by consomming a LoadedVariable
 */
pub trait ConsumeReadable<'a, 'lua> {
    /**
     * Returns the LoadedVariable in case of failure
     */
    fn read_from_variable(var: LoadedVariable<'a, 'lua>) -> Result<Self, LoadedVariable<'a, 'lua>>;
}

/**
 * Should be implemented by whatever type can be read by copy from the Lua stack
 */
pub trait CopyReadable : Clone + ::std::any::Any {
    /**
     * # Arguments
     *  * `lua` - The Lua object to read from
     *  * `index` - The index on the stack to read from
     */
    fn read_from_lua<'lua>(lua: &mut Lua<'lua>, index: i32) -> Option<Self> {
        userdata::read_copy_userdata(lua, index)
    }
}

/**
 * Types that can be indices in Lua tables
 */
pub trait Index<'lua>: Pushable<'lua> + CopyReadable {
}

/**
 * Error that can happen when executing Lua code
 */
#[deriving(Show)]
pub enum LuaError {
    /**
     * There was a syntax error when parsing the Lua code
     */
    SyntaxError(String),

    /**
     * There was an error during execution of the Lua code (for example not enough parameters for a function call)
     */
    ExecutionError(String),

    /**
     * The call to `execute` has requested the wrong type of data
     */
    WrongType
}

// this alloc function is required to create a lua state
extern "C" fn alloc(_ud: *mut libc::c_void, ptr: *mut libc::c_void, _osize: libc::size_t, nsize: libc::size_t) -> *mut libc::c_void {
    unsafe {
        if nsize == 0 {
            libc::free(ptr as *mut libc::c_void);
            std::ptr::mut_null()
        } else {
            libc::realloc(ptr, nsize)
        }
    }
}

// called whenever lua encounters an unexpected error
extern "C" fn panic(lua: *mut ffi::lua_State) -> libc::c_int {
    let err = unsafe { ffi::lua_tostring(lua, -1) };
    fail!("PANIC: unprotected error in call to Lua API ({})\n", err);
}

impl<'lua> Lua<'lua> {
    /**
     * Builds a new Lua context
     * # Failure
     * The function fails if lua_newstate fails (which indicates lack of memory)
     */
    pub fn new() -> Lua {
        let lua = unsafe { ffi::lua_newstate(alloc, std::ptr::mut_null()) };
        if lua.is_null() {
            fail!("lua_newstate failed");
        }

        unsafe { ffi::lua_atpanic(lua, panic) };

        Lua {
            lua: lua,
            marker: ContravariantLifetime,
            must_be_closed: true,
            inside_callback: false
        }
    }

    /**
     * Takes an existing lua_State and build a Lua object from it
     * # Arguments
     *  * close_at_the_end: if true, lua_close will be called on the lua_State on the destructor
     */
    pub unsafe fn from_existing_state<T>(lua: *mut T, close_at_the_end: bool) -> Lua {
        Lua {
            lua: std::mem::transmute(lua),
            marker: ContravariantLifetime,
            must_be_closed: close_at_the_end,
            inside_callback: false
        }
    }

    /**
     * Opens all standard Lua libraries
     * This is done by calling `luaL_openlibs`
     */
    pub fn openlibs(&mut self) {
        unsafe { ffi::luaL_openlibs(self.lua) }
    }

    /**
     * Executes some Lua code on the context
     */
    pub fn execute<T: CopyReadable>(&mut self, code: &str) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load(self, code));
        f.call()
    }

    /**
     * Executes some Lua code on the context
     */
    pub fn execute_from_reader<T: CopyReadable, R: std::io::Reader + 'static>(&mut self, code: R) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load_from_reader(self, code));
        f.call()
    }

    /**
     * Reads the value of a global variable
     */
    pub fn get<'a, I: Str, V: ConsumeReadable<'a, 'lua>>(&'a mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        ConsumeReadable::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok()
    }

    /**
     * Modifies the value of a global variable
     */
    pub fn set<I: Str, V: Pushable<'lua>>(&mut self, index: I, value: V) {
        value.push_to_lua(self);
        unsafe { ffi::lua_setglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
    }

    /**
     *
     */
    pub fn load_new_table<'var>(&'var mut self) -> LuaTable<'var, 'lua> {
        unsafe { ffi::lua_newtable(self.lua) };
        ConsumeReadable::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok().unwrap()
    }
}

// TODO: these destructors crash the compiler
// https://github.com/mozilla/rust/issues/13853
// https://github.com/mozilla/rust/issues/14377
/*impl<'lua> Drop for Lua<'lua> {
    fn drop(&mut self) {
        if self.must_be_closed {
            unsafe { ffi::lua_close(self.lua) }
        }
    }
}

impl<'a> Drop for LoadedVariable<'a, 'lua> {
    fn drop(&mut self) {
        unsafe { ffi::lua_pop(self.lua.lua, self.size as libc::c_int) }
    }
}

impl<'a> LoadedVariable<'a, 'lua> {
    fn pop_nb(mut self, nb: uint) -> LoadedVariable<'a, 'lua> {
        assert!(nb <= self.size);
        unsafe { ffi::lua_pop(self.lua.lua, nb as libc::c_int); }
        self.size -= nb;
        self
    }
}*/

#[cfg(test)]
mod tests {
    #[test]
    fn globals_readwrite() {
        let mut lua = super::Lua::new();

        lua.set("a", 2i);
        let x: int = lua.get("a").unwrap();
        assert_eq!(x, 2)
    }

    #[test]
    fn execute() {
        let mut lua = super::Lua::new();

        let val: int = lua.execute("return 5").unwrap();
        assert_eq!(val, 5);
    }

    // TODO: doesn't compile, have absolutely NO IDEA why
    /*#[test]
    fn table_readwrite() {
        let mut lua = super::Lua::new();

        lua.execute("a = { foo = 5 }");

        assert_eq!(lua.access("a").get(&"foo").unwrap(), 2);

        {   let access = lua.access("a");
            access.set(5, 3);
            assert_eq!(access.get(5), 3);
        }
    }*/
}
<commit_msg>Destructors now running<commit_after>#![crate_name = "rust_hl_lua"]
#![crate_type = "lib"]
#![comment = "Lua bindings for Rust"]
#![license = "MIT"]
#![allow(visible_private_types)]
#![feature(macro_rules)]
#![feature(unsafe_destructor)]

extern crate libc;

use std::kinds::marker::ContravariantLifetime;

pub use lua_tables::LuaTable;

pub mod functions_read;
pub mod lua_tables;
pub mod userdata;

mod ffi;
mod functions_write;
mod rust_tables;
mod tuples;
mod values;

/**
 * Main object of the library
 * The lifetime parameter corresponds to the lifetime of the Lua object itself
 */
pub struct Lua<'lua> {
    lua: *mut ffi::lua_State,
    marker: ContravariantLifetime<'lua>,
    must_be_closed: bool,
    inside_callback: bool           // if true, we are inside a callback
}

/**
 * Object which allows access to a Lua variable
 */
pub struct LoadedVariable<'var, 'lua> {
    lua: &'var mut Lua<'lua>,
    size: uint       // number of elements at the top of the stack
}

/**
 * Should be implemented by whatever type is pushable on the Lua stack
 */
pub trait Pushable<'lua>: ::std::any::Any {
    /**
     * Pushes the value on the top of the stack
     * Must return the number of elements pushed
     */
    fn push_to_lua(self, lua: &mut Lua<'lua>) -> uint {
        self.push_as_userdata(lua)
    }

    /**
     * Pushes the value on the top of the stack as a user data
     * This means that the value will only be readable as itself and not convertible to anything
     * Also, objects pushed as userdata will not be cloned by Lua
     */
    fn push_as_userdata(self, lua: &mut Lua<'lua>) -> uint {
        userdata::push_userdata(self, lua)
    }

    /**
     * Pushes over another element
     */
    fn push_over<'var>(self, mut over: LoadedVariable<'var, 'lua>)
        -> (LoadedVariable<'var, 'lua>, uint)
    {
        let val = self.push_to_lua(over.lua);
        over.size += val;
        (over, val)
    }
}

/**
 * Should be implemented by types that can be read by consomming a LoadedVariable
 */
pub trait ConsumeReadable<'a, 'lua> {
    /**
     * Returns the LoadedVariable in case of failure
     */
    fn read_from_variable(var: LoadedVariable<'a, 'lua>) -> Result<Self, LoadedVariable<'a, 'lua>>;
}

/**
 * Should be implemented by whatever type can be read by copy from the Lua stack
 */
pub trait CopyReadable : Clone + ::std::any::Any {
    /**
     * # Arguments
     *  * `lua` - The Lua object to read from
     *  * `index` - The index on the stack to read from
     */
    fn read_from_lua<'lua>(lua: &mut Lua<'lua>, index: i32) -> Option<Self> {
        userdata::read_copy_userdata(lua, index)
    }
}

/**
 * Types that can be indices in Lua tables
 */
pub trait Index<'lua>: Pushable<'lua> + CopyReadable {
}

/**
 * Error that can happen when executing Lua code
 */
#[deriving(Show)]
pub enum LuaError {
    /**
     * There was a syntax error when parsing the Lua code
     */
    SyntaxError(String),

    /**
     * There was an error during execution of the Lua code (for example not enough parameters for a function call)
     */
    ExecutionError(String),

    /**
     * The call to `execute` has requested the wrong type of data
     */
    WrongType
}

// this alloc function is required to create a lua state
extern "C" fn alloc(_ud: *mut libc::c_void, ptr: *mut libc::c_void, _osize: libc::size_t, nsize: libc::size_t) -> *mut libc::c_void {
    unsafe {
        if nsize == 0 {
            libc::free(ptr as *mut libc::c_void);
            std::ptr::mut_null()
        } else {
            libc::realloc(ptr, nsize)
        }
    }
}

// called whenever lua encounters an unexpected error
extern "C" fn panic(lua: *mut ffi::lua_State) -> libc::c_int {
    let err = unsafe { ffi::lua_tostring(lua, -1) };
    fail!("PANIC: unprotected error in call to Lua API ({})\n", err);
}

impl<'lua> Lua<'lua> {
    /**
     * Builds a new Lua context
     * # Failure
     * The function fails if lua_newstate fails (which indicates lack of memory)
     */
    pub fn new() -> Lua {
        let lua = unsafe { ffi::lua_newstate(alloc, std::ptr::mut_null()) };
        if lua.is_null() {
            fail!("lua_newstate failed");
        }

        unsafe { ffi::lua_atpanic(lua, panic) };

        Lua {
            lua: lua,
            marker: ContravariantLifetime,
            must_be_closed: true,
            inside_callback: false
        }
    }

    /**
     * Takes an existing lua_State and build a Lua object from it
     * # Arguments
     *  * close_at_the_end: if true, lua_close will be called on the lua_State on the destructor
     */
    pub unsafe fn from_existing_state<T>(lua: *mut T, close_at_the_end: bool) -> Lua {
        Lua {
            lua: std::mem::transmute(lua),
            marker: ContravariantLifetime,
            must_be_closed: close_at_the_end,
            inside_callback: false
        }
    }

    /**
     * Opens all standard Lua libraries
     * This is done by calling `luaL_openlibs`
     */
    pub fn openlibs(&mut self) {
        unsafe { ffi::luaL_openlibs(self.lua) }
    }

    /**
     * Executes some Lua code on the context
     */
    pub fn execute<T: CopyReadable>(&mut self, code: &str) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load(self, code));
        f.call()
    }

    /**
     * Executes some Lua code on the context
     */
    pub fn execute_from_reader<T: CopyReadable, R: std::io::Reader + 'static>(&mut self, code: R) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load_from_reader(self, code));
        f.call()
    }

    /**
     * Reads the value of a global variable
     */
    pub fn get<'a, I: Str, V: ConsumeReadable<'a, 'lua>>(&'a mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        ConsumeReadable::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok()
    }

    /**
     * Modifies the value of a global variable
     */
    pub fn set<I: Str, V: Pushable<'lua>>(&mut self, index: I, value: V) {
        value.push_to_lua(self);
        unsafe { ffi::lua_setglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
    }

    /**
     *
     */
    pub fn load_new_table<'var>(&'var mut self) -> LuaTable<'var, 'lua> {
        unsafe { ffi::lua_newtable(self.lua) };
        ConsumeReadable::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok().unwrap()
    }
}

#[unsafe_destructor]
impl<'lua> Drop for Lua<'lua> {
    fn drop(&mut self) {
        if self.must_be_closed {
            unsafe { ffi::lua_close(self.lua) }
        }
    }
}

#[unsafe_destructor]
impl<'a, 'lua> Drop for LoadedVariable<'a, 'lua> {
    fn drop(&mut self) {
        unsafe { ffi::lua_pop(self.lua.lua, self.size as libc::c_int) }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn globals_readwrite() {
        let mut lua = super::Lua::new();

        lua.set("a", 2i);
        let x: int = lua.get("a").unwrap();
        assert_eq!(x, 2)
    }

    #[test]
    fn execute() {
        let mut lua = super::Lua::new();

        let val: int = lua.execute("return 5").unwrap();
        assert_eq!(val, 5);
    }

    // TODO: doesn't compile, have absolutely NO IDEA why
    /*#[test]
    fn table_readwrite() {
        let mut lua = super::Lua::new();

        lua.execute("a = { foo = 5 }");

        assert_eq!(lua.access("a").get(&"foo").unwrap(), 2);

        {   let access = lua.access("a");
            access.set(5, 3);
            assert_eq!(access.get(5), 3);
        }
    }*/
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate crypto;
extern crate merkle;
extern crate libc;
extern crate serde_json;

#[macro_use]
mod rescue;
pub mod vm;
mod utils;

pub use utils::bigint::{U256, M256, MI256};
pub use utils::gas::Gas;
pub use utils::address::Address;
pub use utils::opcode::Opcode;
pub use utils::read_hex;
<commit_msg>Problem: libc and serde_json not needed atm in sputnikvm<commit_after>#[macro_use]
extern crate log;
extern crate crypto;
extern crate merkle;

#[macro_use]
mod rescue;
pub mod vm;
mod utils;

pub use utils::bigint::{U256, M256, MI256};
pub use utils::gas::Gas;
pub use utils::address::Address;
pub use utils::opcode::Opcode;
pub use utils::read_hex;
<|endoftext|>


<commit_before>#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/7853871?s=128", html_favicon_url = "https://avatars0.githubusercontent.com/u/7853871?s=256", html_root_url = "http://ironframework.io/core/persistent")]
#![license = "MIT"]
//#![deny(missing_doc)]
#![deny(warnings)]
#![feature(default_type_params)]

//! A set of middleware for sharing data between requests in the Iron
//! framework.

extern crate iron;
extern crate typemap;
extern crate plugin;

use iron::{Request, Response, BeforeMiddleware, AfterMiddleware, IronResult};
use std::sync::{Arc, RWLock};
use typemap::Assoc;
use plugin::{PluginFor, Phantom};

pub struct Persistent<P, D> {
    data: Arc<RWLock<D>>
}

pub struct Config<P, C> {
    data: Arc<C>
}

impl<P, D> Assoc<Arc<RWLock<D>>> for Persistent<P, D> where P: Assoc<D> {}
impl<P, C> Assoc<Arc<C>> for Config<P, C> where P: Assoc<C> {}

impl<P, D> PluginFor<Request, Arc<RWLock<D>>> for Persistent<P, D>
    where D: Send + Sync,
          P: Assoc<D> {
    fn eval(req: &Request, _: Phantom<Persistent<P, D>>) -> Option<Arc<RWLock<D>>> {
        req.extensions.find::<Persistent<P, D>, Arc<RWLock<D>>>()
            .map(|x| x.clone())
    }
}

impl<P, C> PluginFor<Request, Arc<C>> for Config<P, C>
    where C: Send + Sync,
          P: Assoc<C> {
    fn eval(req: &Request, _: Phantom<Config<P, C>>) -> Option<Arc<C>> {
        req.extensions.find::<Config<P, C>, Arc<C>>()
            .map(|x| x.clone())
    }
}

impl<D: Send + Sync, P: Assoc<D>> BeforeMiddleware for Persistent<P, D> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<Persistent<P, D>, Arc<RWLock<D>>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> AfterMiddleware for Persistent<P, D> {
    fn after(&self, _: &mut Request, res: &mut Response) -> IronResult<()> {
        res.extensions.insert::<Persistent<P, D>, Arc<RWLock<D>>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> BeforeMiddleware for Config<P, D> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<Config<P, D>, Arc<D>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> AfterMiddleware for Config<P, D> {
    fn after(&self, _: &mut Request, res: &mut Response) -> IronResult<()> {
        res.extensions.insert::<Config<P, D>, Arc<D>>(self.data.clone());
        Ok(())
    }
}

<commit_msg>(feat) Constructors.<commit_after>#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/7853871?s=128", html_favicon_url = "https://avatars0.githubusercontent.com/u/7853871?s=256", html_root_url = "http://ironframework.io/core/persistent")]
#![license = "MIT"]
//#![deny(missing_doc)]
#![deny(warnings)]
#![feature(default_type_params)]

//! A set of middleware for sharing data between requests in the Iron
//! framework.

extern crate iron;
extern crate typemap;
extern crate plugin;

use iron::{Request, Response, BeforeMiddleware, AfterMiddleware, IronResult};
use std::sync::{Arc, RWLock};
use typemap::Assoc;
use plugin::{PluginFor, Phantom};

pub struct Persistent<P, D> {
    data: Arc<RWLock<D>>
}

impl<P, D: Send + Sync> Clone for Persistent<P, D> {
    fn clone(&self) -> Persistent<P, D> {
        Persistent { data: self.data.clone() }
    }
}

pub struct Config<P, C> {
    data: Arc<C>
}

impl<P, C: Send + Sync> Clone for Config<P, C> {
    fn clone(&self) -> Config<P, C> {
        Config { data: self.data.clone() }
    }
}

impl<P, D> Assoc<Arc<RWLock<D>>> for Persistent<P, D> where P: Assoc<D> {}
impl<P, C> Assoc<Arc<C>> for Config<P, C> where P: Assoc<C> {}

impl<P, D> PluginFor<Request, Arc<RWLock<D>>> for Persistent<P, D>
    where D: Send + Sync,
          P: Assoc<D> {
    fn eval(req: &Request, _: Phantom<Persistent<P, D>>) -> Option<Arc<RWLock<D>>> {
        req.extensions.find::<Persistent<P, D>, Arc<RWLock<D>>>()
            .map(|x| x.clone())
    }
}

impl<P, C> PluginFor<Request, Arc<C>> for Config<P, C>
    where C: Send + Sync,
          P: Assoc<C> {
    fn eval(req: &Request, _: Phantom<Config<P, C>>) -> Option<Arc<C>> {
        req.extensions.find::<Config<P, C>, Arc<C>>()
            .map(|x| x.clone())
    }
}

impl<D: Send + Sync, P: Assoc<D>> BeforeMiddleware for Persistent<P, D> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<Persistent<P, D>, Arc<RWLock<D>>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> AfterMiddleware for Persistent<P, D> {
    fn after(&self, _: &mut Request, res: &mut Response) -> IronResult<()> {
        res.extensions.insert::<Persistent<P, D>, Arc<RWLock<D>>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> BeforeMiddleware for Config<P, D> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<Config<P, D>, Arc<D>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> AfterMiddleware for Config<P, D> {
    fn after(&self, _: &mut Request, res: &mut Response) -> IronResult<()> {
        res.extensions.insert::<Config<P, D>, Arc<D>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> Persistent<P, D> {
    pub fn new(start: D) -> (Persistent<P, D>, Persistent<P, D>) {
        let x = Arc::new(RWLock::new(start));
        (Persistent { data: x.clone() }, Persistent { data: x })
    }
}

impl<C: Send + Sync, P: Assoc<C>> Config<P, C> {
    pub fn new(start: C) -> (Config<P, C>, Config<P, C>) {
        let x = Arc::new(start);
        (Config { data: x.clone() }, Config { data: x })
    }
}

<|endoftext|>


<commit_before>extern crate byteorder;

use std::io::Cursor;
use std::io::Read;
use byteorder::{LittleEndian, ReadBytesExt};

pub fn murmur3_32(source: &mut Read, seed: u32) -> u32 {
    const C1: u32 = 0xcc9e2d51;
    const C2: u32 = 0x1b873593;
    const R1: u32 = 15;
    const R2: u32 = 13;
    const M: u32 = 5;
    const N: u32 = 0xe6546b64;
    let mut hash = seed;
    let mut buf = [0; 4];
    let mut processed: u32 = 0;
    loop {
        match source.read(&mut buf[..]) {
            Ok(size) => {
                match size {
                    4 => {
                        let mut tmp = Cursor::new(buf);
                        let mut k = tmp.read_u32::<LittleEndian>().unwrap();
                        k = k.wrapping_mul(C1);
                        k = k.rotate_left(R1);
                        k = k.wrapping_mul(C2);
                        hash ^= k;
                        hash = hash.rotate_left(R2);
                        hash = (hash.wrapping_mul(M)).wrapping_add(N);
                        processed += 4;
                    }
                    3 => {
                        let mut k: u32 = 0;
                        k ^= (buf[2] as u32) << 16;
                        k ^= (buf[1] as u32) << 8;
                        k ^= buf[0] as u32;
                        k = k.wrapping_mul(C1);
                        k = k.rotate_left(15);
                        k = k.wrapping_mul(C2);
                        processed += 3;
                        hash ^= k;
                    }
                    2 => {
                        let mut k: u32 = 0;
                        k ^= (buf[1] as u32) << 8;
                        k ^= buf[0] as u32;
                        k = k.wrapping_mul(C1);
                        k = k.rotate_left(15);
                        k = k.wrapping_mul(C2);
                        processed += 2;
                        hash ^= k;
                    }
                    1 => {
                        let mut k: u32 = 0;
                        k ^= buf[0] as u32;
                        k = k.wrapping_mul(C1);
                        k = k.rotate_left(15);
                        k = k.wrapping_mul(C2);
                        processed += 1;
                        hash ^= k;
                    }
                    0 => {
                        hash ^= (processed) as u32;
                        hash ^= hash.wrapping_shr(16);
                        hash = hash.wrapping_mul(0x85ebca6b);
                        hash ^= hash.wrapping_shr(13);
                        hash = hash.wrapping_mul(0xc2b2ae35);
                        hash ^= hash.wrapping_shr(16);
                        return hash;
                    }
                    _ => panic!("Invalid read size!"),
                }
            }
            Err(e) => panic!(e),
        }
    }
}

<commit_msg>Some refactoring to include feedback from reddit<commit_after>extern crate byteorder;

use std::io::Cursor;
use std::io::Read;
use byteorder::{LittleEndian, ReadBytesExt};

pub fn murmur3_32(source: &mut Read, seed: u32) -> u32 {
    const C1: u32 = 0x85ebca6b;
    const C2: u32 = 0xc2b2ae35;
    const R1: u32 = 16;
    const R2: u32 = 13;
    const M: u32 = 5;
    const N: u32 = 0xe6546b64;
    let mut hash = seed;
    let mut buf = [0; 4];
    let mut processed: u32 = 0;
    loop {
        match source.read(&mut buf[..]) {
            Ok(size) => {
                match size {
                    4 => {
                        let mut tmp = Cursor::new(buf);
                        let k = tmp.read_u32::<LittleEndian>().unwrap();
                        hash ^= calc_k(k);
                        hash = hash.rotate_left(R2);
                        hash = (hash.wrapping_mul(M)).wrapping_add(N);
                    }
                    3 => {
                        let k: u32 = ((buf[2] as u32) << 16) | ((buf[1] as u32) << 8) |
                                     (buf[0] as u32);
                        hash ^= calc_k(k);
                    }
                    2 => {
                        let k: u32 = ((buf[1] as u32) << 8) | (buf[0] as u32);
                        hash ^= calc_k(k);
                    }
                    1 => {
                        let k: u32 = buf[0] as u32;
                        hash ^= calc_k(k);
                    }
                    0 => {
                        hash ^= (processed) as u32;
                        hash ^= hash.wrapping_shr(R1);
                        hash = hash.wrapping_mul(C1);
                        hash ^= hash.wrapping_shr(R2);
                        hash = hash.wrapping_mul(C2);
                        hash ^= hash.wrapping_shr(R1);
                        return hash;
                    }
                    _ => panic!("Invalid read size!"),
                };
                processed += size as u32;
            }
            Err(e) => panic!(e),
        }
    }
}

fn calc_k(k: u32) -> u32 {
    const C1: u32 = 0xcc9e2d51;
    const C2: u32 = 0x1b873593;
    const R1: u32 = 15;
    k.wrapping_mul(C1).rotate_left(R1).wrapping_mul(C2)
}
<|endoftext|>


<commit_before>// Copyright 2019 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interface to the random number generator of the operating system.
//!
//! # Platform sources
//!
//! | OS               | interface
//! |------------------|---------------------------------------------------------
//! | Linux, Android   | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random`
//! | Windows          | [`RtlGenRandom`][3]
//! | macOS            | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`)
//! | iOS              | [`SecRandomCopyBytes`][4]
//! | FreeBSD          | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5]
//! | OpenBSD          | [`getentropy`][6]
//! | NetBSD           | [`/dev/urandom`][7] after successfully polling `/dev/random`
//! | Dragonfly BSD    | [`/dev/random`][8]
//! | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10]
//! | Fuchsia OS       | [`cprng_draw`][11]
//! | Redox            | [`rand:`][12]
//! | CloudABI         | [`cloudabi_sys_random_get`][13]
//! | Haiku            | `/dev/random` (identical to `/dev/urandom`)
//! | L4RE, SGX, UEFI  | [RDRAND][18]
//! | Hermit           | [RDRAND][18] as [`sys_rand`][22] is currently broken.
//! | Web browsers     | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and ams.js][14])
//! | Node.js          | [`crypto.randomBytes`][15] (see [Support for WebAssembly and ams.js][16])
//! | WASI             | [`__wasi_random_get`][17]
//!
//! Getrandom doesn't have a blanket implementation for all Unix-like operating
//! systems that reads from `/dev/urandom`. This ensures all supported operating
//! systems are using the recommended interface and respect maximum buffer
//! sizes.
//!
//! ## Support for WebAssembly and ams.js
//!
//! The three Emscripten targets `asmjs-unknown-emscripten`,
//! `wasm32-unknown-emscripten` and `wasm32-experimental-emscripten` use
//! Emscripten's emulation of `/dev/random` on web browsers and Node.js.
//!
//! The bare WASM target `wasm32-unknown-unknown` tries to call the javascript
//! methods directly, using either `stdweb` or `wasm-bindgen` depending on what
//! features are activated for this crate. Note that if both features are
//! enabled `wasm-bindgen` will be used. If neither feature is enabled,
//! `getrandom` will always fail.
//!
//! The WASI target `wasm32-wasi` uses the `__wasi_random_get` function defined
//! by the WASI standard.
//!
//!
//! ## Early boot
//!
//! It is possible that early in the boot process the OS hasn't had enough time
//! yet to collect entropy to securely seed its RNG, especially on virtual
//! machines.
//!
//! Some operating systems always block the thread until the RNG is securely
//! seeded. This can take anywhere from a few seconds to more than a minute.
//! Others make a best effort to use a seed from before the shutdown and don't
//! document much.
//!
//! A few, Linux, NetBSD and Solaris, offer a choice between blocking and
//! getting an error; in these cases we always choose to block.
//!
//! On Linux (when the `genrandom` system call is not available) and on NetBSD
//! reading from `/dev/urandom` never blocks, even when the OS hasn't collected
//! enough entropy yet. To avoid returning low-entropy bytes, we first read from
//! `/dev/random` and only switch to `/dev/urandom` once this has succeeded.
//!
//! # Error handling
//!
//! We always choose failure over returning insecure "random" bytes. In general,
//! on supported platforms, failure is highly unlikely, though not impossible.
//! If an error does occur, then it is likely that it will occur on every call to
//! `getrandom`, hence after the first successful call one can be reasonably
//! confident that no errors will occur.
//!
//! On unsupported platforms, `getrandom` always fails. See the [`Error`] type
//! for more information on what data is returned on failure.
//!
//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html
//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html
//! [3]: https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/nf-ntsecapi-rtlgenrandom
//! [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
//! [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
//! [6]: https://man.openbsd.org/getentropy.2
//! [7]: http://netbsd.gw.com/cgi-bin/man-cgi?random+4+NetBSD-current
//! [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random&section=4
//! [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
//! [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html
//! [11]: https://fuchsia.googlesource.com/fuchsia/+/master/zircon/docs/syscalls/cprng_draw.md
//! [12]: https://github.com/redox-os/randd/blob/master/src/main.rs
//! [13]: https://github.com/nuxinl/cloudabi#random_get
//! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
//! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
//! [16]: #support-for-webassembly-and-amsjs
//! [17]: https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md#__wasi_random_get
//! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
//! [19]: https://www.unix.com/man-page/mojave/2/getentropy/
//! [20]: https://www.unix.com/man-page/mojave/4/random/
//! [21]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable
//! [22]: https://github.com/hermitcore/libhermit-rs/blob/09c38b0371cee6f56a541400ba453e319e43db53/src/syscalls/random.rs#L21

#![doc(
    html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
    html_favicon_url = "https://www.rust-lang.org/favicon.ico",
    html_root_url = "https://rust-random.github.io/rand/"
)]
#![no_std]
#![cfg_attr(feature = "stdweb", recursion_limit = "128")]

#[macro_use]
extern crate cfg_if;

cfg_if! {
    if #[cfg(feature = "log")] {
        #[allow(unused)]
        #[macro_use]
        extern crate log;
    } else {
        #[allow(unused)]
        macro_rules! error {
            ($($x:tt)*) => {};
        }
    }
}

mod error;
pub use crate::error::Error;

#[allow(dead_code)]
mod util;
// Unlike the other Unix, Fuchsia and iOS don't use the libc to make any calls.
#[cfg(any(
    target_os = "android",
    target_os = "dragonfly",
    target_os = "emscripten",
    target_os = "freebsd",
    target_os = "haiku",
    target_os = "illumos",
    target_os = "linux",
    target_os = "macos",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "redox",
    target_os = "solaris",
))]
#[allow(dead_code)]
mod util_libc;

// std-only trait definitions
#[cfg(feature = "std")]
mod error_impls;

// These targets read from a file as a fallback method.
#[cfg(any(
    target_os = "android",
    target_os = "linux",
    target_os = "macos",
    target_os = "solaris",
    target_os = "illumos",
))]
mod use_file;

// System-specific implementations.
//
// These should all provide getrandom_inner with the same signature as getrandom.
cfg_if! {
    if #[cfg(target_os = "android")] {
        #[path = "linux_android.rs"] mod imp;
    } else if #[cfg(target_os = "cloudabi")] {
        #[path = "cloudabi.rs"] mod imp;
    } else if #[cfg(target_os = "dragonfly")] {
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(target_os = "emscripten")] {
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(target_os = "freebsd")] {
        #[path = "freebsd.rs"] mod imp;
    } else if #[cfg(target_os = "fuchsia")] {
        #[path = "fuchsia.rs"] mod imp;
    } else if #[cfg(target_os = "haiku")] {
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(target_os = "illumos")] {
        #[path = "solaris_illumos.rs"] mod imp;
    } else if #[cfg(target_os = "ios")] {
        #[path = "ios.rs"] mod imp;
    } else if #[cfg(target_os = "linux")] {
        #[path = "linux_android.rs"] mod imp;
    } else if #[cfg(target_os = "macos")] {
        #[path = "macos.rs"] mod imp;
    } else if #[cfg(target_os = "netbsd")] {
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(target_os = "openbsd")] {
        #[path = "openbsd.rs"] mod imp;
    } else if #[cfg(target_os = "redox")] {
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(target_os = "solaris")] {
        #[path = "solaris_illumos.rs"] mod imp;
    } else if #[cfg(target_os = "wasi")] {
        #[path = "wasi.rs"] mod imp;
    } else if #[cfg(windows)] {
        #[path = "windows.rs"] mod imp;
    } else if #[cfg(all(target_arch = "x86_64", any(
                  target_os = "hermit",
                  target_os = "l4re",
                  target_os = "uefi",
                  target_env = "sgx",
              )))] {
        #[path = "rdrand.rs"] mod imp;
    } else if #[cfg(target_arch = "wasm32")] {
        cfg_if! {
            if #[cfg(feature = "wasm-bindgen")] {
                #[path = "wasm32_bindgen.rs"] mod imp;
            } else if #[cfg(feature = "stdweb")] {
                #[path = "wasm32_stdweb.rs"] mod imp;
            } else {
                #[path = "dummy.rs"] mod imp;
            }
        }
    } else {
        #[path = "dummy.rs"] mod imp;
    }
}

/// Fill `dest` with random bytes from the system's preferred random number
/// source.
///
/// This function returns an error on any failure, including partial reads. We
/// make no guarantees regarding the contents of `dest` on error.
///
/// Blocking is possible, at least during early boot; see module documentation.
///
/// In general, `getrandom` will be fast enough for interactive usage, though
/// significantly slower than a user-space CSPRNG; for the latter consider
/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html).
pub fn getrandom(dest: &mut [u8]) -> Result<(), error::Error> {
    imp::getrandom_inner(dest)
}
<commit_msg>Updating link to Fuchsia documentation (#81)<commit_after>// Copyright 2019 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interface to the random number generator of the operating system.
//!
//! # Platform sources
//!
//! | OS               | interface
//! |------------------|---------------------------------------------------------
//! | Linux, Android   | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random`
//! | Windows          | [`RtlGenRandom`][3]
//! | macOS            | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`)
//! | iOS              | [`SecRandomCopyBytes`][4]
//! | FreeBSD          | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5]
//! | OpenBSD          | [`getentropy`][6]
//! | NetBSD           | [`/dev/urandom`][7] after successfully polling `/dev/random`
//! | Dragonfly BSD    | [`/dev/random`][8]
//! | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10]
//! | Fuchsia OS       | [`cprng_draw`][11]
//! | Redox            | [`rand:`][12]
//! | CloudABI         | [`cloudabi_sys_random_get`][13]
//! | Haiku            | `/dev/random` (identical to `/dev/urandom`)
//! | L4RE, SGX, UEFI  | [RDRAND][18]
//! | Hermit           | [RDRAND][18] as [`sys_rand`][22] is currently broken.
//! | Web browsers     | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and ams.js][14])
//! | Node.js          | [`crypto.randomBytes`][15] (see [Support for WebAssembly and ams.js][16])
//! | WASI             | [`__wasi_random_get`][17]
//!
//! Getrandom doesn't have a blanket implementation for all Unix-like operating
//! systems that reads from `/dev/urandom`. This ensures all supported operating
//! systems are using the recommended interface and respect maximum buffer
//! sizes.
//!
//! ## Support for WebAssembly and ams.js
//!
//! The three Emscripten targets `asmjs-unknown-emscripten`,
//! `wasm32-unknown-emscripten` and `wasm32-experimental-emscripten` use
//! Emscripten's emulation of `/dev/random` on web browsers and Node.js.
//!
//! The bare WASM target `wasm32-unknown-unknown` tries to call the javascript
//! methods directly, using either `stdweb` or `wasm-bindgen` depending on what
//! features are activated for this crate. Note that if both features are
//! enabled `wasm-bindgen` will be used. If neither feature is enabled,
//! `getrandom` will always fail.
//!
//! The WASI target `wasm32-wasi` uses the `__wasi_random_get` function defined
//! by the WASI standard.
//!
//!
//! ## Early boot
//!
//! It is possible that early in the boot process the OS hasn't had enough time
//! yet to collect entropy to securely seed its RNG, especially on virtual
//! machines.
//!
//! Some operating systems always block the thread until the RNG is securely
//! seeded. This can take anywhere from a few seconds to more than a minute.
//! Others make a best effort to use a seed from before the shutdown and don't
//! document much.
//!
//! A few, Linux, NetBSD and Solaris, offer a choice between blocking and
//! getting an error; in these cases we always choose to block.
//!
//! On Linux (when the `genrandom` system call is not available) and on NetBSD
//! reading from `/dev/urandom` never blocks, even when the OS hasn't collected
//! enough entropy yet. To avoid returning low-entropy bytes, we first read from
//! `/dev/random` and only switch to `/dev/urandom` once this has succeeded.
//!
//! # Error handling
//!
//! We always choose failure over returning insecure "random" bytes. In general,
//! on supported platforms, failure is highly unlikely, though not impossible.
//! If an error does occur, then it is likely that it will occur on every call to
//! `getrandom`, hence after the first successful call one can be reasonably
//! confident that no errors will occur.
//!
//! On unsupported platforms, `getrandom` always fails. See the [`Error`] type
//! for more information on what data is returned on failure.
//!
//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html
//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html
//! [3]: https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/nf-ntsecapi-rtlgenrandom
//! [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
//! [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
//! [6]: https://man.openbsd.org/getentropy.2
//! [7]: http://netbsd.gw.com/cgi-bin/man-cgi?random+4+NetBSD-current
//! [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random&section=4
//! [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
//! [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html
//! [11]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw
//! [12]: https://github.com/redox-os/randd/blob/master/src/main.rs
//! [13]: https://github.com/nuxinl/cloudabi#random_get
//! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
//! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
//! [16]: #support-for-webassembly-and-amsjs
//! [17]: https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md#__wasi_random_get
//! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
//! [19]: https://www.unix.com/man-page/mojave/2/getentropy/
//! [20]: https://www.unix.com/man-page/mojave/4/random/
//! [21]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable
//! [22]: https://github.com/hermitcore/libhermit-rs/blob/09c38b0371cee6f56a541400ba453e319e43db53/src/syscalls/random.rs#L21

#![doc(
    html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
    html_favicon_url = "https://www.rust-lang.org/favicon.ico",
    html_root_url = "https://rust-random.github.io/rand/"
)]
#![no_std]
#![cfg_attr(feature = "stdweb", recursion_limit = "128")]

#[macro_use]
extern crate cfg_if;

cfg_if! {
    if #[cfg(feature = "log")] {
        #[allow(unused)]
        #[macro_use]
        extern crate log;
    } else {
        #[allow(unused)]
        macro_rules! error {
            ($($x:tt)*) => {};
        }
    }
}

mod error;
pub use crate::error::Error;

#[allow(dead_code)]
mod util;
// Unlike the other Unix, Fuchsia and iOS don't use the libc to make any calls.
#[cfg(any(
    target_os = "android",
    target_os = "dragonfly",
    target_os = "emscripten",
    target_os = "freebsd",
    target_os = "haiku",
    target_os = "illumos",
    target_os = "linux",
    target_os = "macos",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "redox",
    target_os = "solaris",
))]
#[allow(dead_code)]
mod util_libc;

// std-only trait definitions
#[cfg(feature = "std")]
mod error_impls;

// These targets read from a file as a fallback method.
#[cfg(any(
    target_os = "android",
    target_os = "linux",
    target_os = "macos",
    target_os = "solaris",
    target_os = "illumos",
))]
mod use_file;

// System-specific implementations.
//
// These should all provide getrandom_inner with the same signature as getrandom.
cfg_if! {
    if #[cfg(target_os = "android")] {
        #[path = "linux_android.rs"] mod imp;
    } else if #[cfg(target_os = "cloudabi")] {
        #[path = "cloudabi.rs"] mod imp;
    } else if #[cfg(target_os = "dragonfly")] {
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(target_os = "emscripten")] {
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(target_os = "freebsd")] {
        #[path = "freebsd.rs"] mod imp;
    } else if #[cfg(target_os = "fuchsia")] {
        #[path = "fuchsia.rs"] mod imp;
    } else if #[cfg(target_os = "haiku")] {
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(target_os = "illumos")] {
        #[path = "solaris_illumos.rs"] mod imp;
    } else if #[cfg(target_os = "ios")] {
        #[path = "ios.rs"] mod imp;
    } else if #[cfg(target_os = "linux")] {
        #[path = "linux_android.rs"] mod imp;
    } else if #[cfg(target_os = "macos")] {
        #[path = "macos.rs"] mod imp;
    } else if #[cfg(target_os = "netbsd")] {
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(target_os = "openbsd")] {
        #[path = "openbsd.rs"] mod imp;
    } else if #[cfg(target_os = "redox")] {
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(target_os = "solaris")] {
        #[path = "solaris_illumos.rs"] mod imp;
    } else if #[cfg(target_os = "wasi")] {
        #[path = "wasi.rs"] mod imp;
    } else if #[cfg(windows)] {
        #[path = "windows.rs"] mod imp;
    } else if #[cfg(all(target_arch = "x86_64", any(
                  target_os = "hermit",
                  target_os = "l4re",
                  target_os = "uefi",
                  target_env = "sgx",
              )))] {
        #[path = "rdrand.rs"] mod imp;
    } else if #[cfg(target_arch = "wasm32")] {
        cfg_if! {
            if #[cfg(feature = "wasm-bindgen")] {
                #[path = "wasm32_bindgen.rs"] mod imp;
            } else if #[cfg(feature = "stdweb")] {
                #[path = "wasm32_stdweb.rs"] mod imp;
            } else {
                #[path = "dummy.rs"] mod imp;
            }
        }
    } else {
        #[path = "dummy.rs"] mod imp;
    }
}

/// Fill `dest` with random bytes from the system's preferred random number
/// source.
///
/// This function returns an error on any failure, including partial reads. We
/// make no guarantees regarding the contents of `dest` on error.
///
/// Blocking is possible, at least during early boot; see module documentation.
///
/// In general, `getrandom` will be fast enough for interactive usage, though
/// significantly slower than a user-space CSPRNG; for the latter consider
/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html).
pub fn getrandom(dest: &mut [u8]) -> Result<(), error::Error> {
    imp::getrandom_inner(dest)
}
<|endoftext|>


<commit_before>
#![feature(phase)]

pub fn xor(source: &[u8], key: &[u8]) -> Vec<u8> {
    match key.len() {
        0 => source.to_vec(),
        1 => xor_with_byte(source, key[0]),
        _ => {
            let key_iter = InfiniteByteIterator::new(key);
            source.iter().zip(key_iter).map(|(&a, b)| a ^ b).collect()
        },
    }
}

pub fn xor_with_byte(source: &[u8], byte: u8) -> Vec<u8> {
    source.iter().map(|&a| a ^ byte).collect()
}

struct InfiniteByteIterator<'a> {
    bytes: &'a [u8],
    index: uint
}

impl<'a> InfiniteByteIterator<'a> {
    pub fn new(bytes: &'a [u8]) -> InfiniteByteIterator<'a> {
        InfiniteByteIterator {
            bytes: bytes,
            index: 0
        }
    }
}

impl<'a> Iterator<u8> for InfiniteByteIterator<'a> {
    fn next(&mut self) -> Option<u8> {
        let byte = self.bytes[self.index];
        self.index = next_index(self.index, self.bytes.len());
        Some(byte)
    }
}

fn next_index(index: uint, count: uint) -> uint {
    if index + 1 < count { index + 1 } else { 0 }
}

#[cfg(test)]
mod test {
    #[phase(plugin)] extern crate stainless;

    pub use super::{
        xor,
        xor_with_byte,
    };

    describe! xor {
        it "should return right result" {
            let source = &[0, 1, 2, 3];
            let key = &[34, 52];
            assert!(xor(source, key).as_slice() == &[34, 53, 32, 55]);
        }

        it "should return right result with one byte xor" {
            let source = &[0, 1, 2, 3];
            let key = &[47];
            assert!(xor(source, key).as_slice() == &[47, 46, 45, 44]);
        }

        it "should return source if key is empty" {
            let source = &[0, 1, 2, 3];
            let key = &[];
            assert!(xor(source, key).as_slice() == &[0, 1, 2, 3]);
        }

        it "should return empty result if source is empty" {
            let source = &[];
            let key = &[45, 32, 56];
            assert!(xor(source, key).as_slice() == &[]);
        }
    }

    describe! xor_with_byte {
        it "should return right result" {
            let source = &[0, 1, 2, 3];
            assert!(xor_with_byte(source, 23).as_slice() == &[23, 22, 21, 20]);
        }
    }
}
<commit_msg>Upgraded tests to current rust.<commit_after>
#![feature(phase)]

pub fn xor(source: &[u8], key: &[u8]) -> Vec<u8> {
    match key.len() {
        0 => source.to_vec(),
        1 => xor_with_byte(source, key[0]),
        _ => {
            let key_iter = InfiniteByteIterator::new(key);
            source.iter().zip(key_iter).map(|(&a, b)| a ^ b).collect()
        },
    }
}

pub fn xor_with_byte(source: &[u8], byte: u8) -> Vec<u8> {
    source.iter().map(|&a| a ^ byte).collect()
}

struct InfiniteByteIterator<'a> {
    bytes: &'a [u8],
    index: uint
}

impl<'a> InfiniteByteIterator<'a> {
    pub fn new(bytes: &'a [u8]) -> InfiniteByteIterator<'a> {
        InfiniteByteIterator {
            bytes: bytes,
            index: 0
        }
    }
}

impl<'a> Iterator<u8> for InfiniteByteIterator<'a> {
    fn next(&mut self) -> Option<u8> {
        let byte = self.bytes[self.index];
        self.index = next_index(self.index, self.bytes.len());
        Some(byte)
    }
}

fn next_index(index: uint, count: uint) -> uint {
    if index + 1 < count { index + 1 } else { 0 }
}

#[cfg(test)]
mod test {
    #[phase(plugin)] extern crate stainless;

    pub use super::{
        xor,
        xor_with_byte,
    };

    describe! xor {
        it "should return valid result" {
            let source = &[0, 1, 2, 3];
            let key = &[34, 52];
            assert!(xor(source, key) == [34, 53, 32, 55]);
        }

        it "should return valid result with one byte xor" {
            let source = &[0, 1, 2, 3];
            let key = &[47];
            assert!(xor(source, key) == [47, 46, 45, 44]);
        }

        it "should return source if key is empty" {
            let source = &[0, 1, 2, 3];
            let key = &[];
            assert!(xor(source, key) == [0, 1, 2, 3]);
        }

        it "should return empty result if source is empty" {
            let source = &[];
            let key = &[45, 32, 56];
            assert!(xor(source, key) == []);
        }
    }

    describe! xor_with_byte {
        it "should return valid result" {
            let source = &[0, 1, 2, 3];
            assert!(xor_with_byte(source, 23) == [23, 22, 21, 20]);
        }
    }
}
<|endoftext|>


<commit_before>//!
//! ### Namespaces
//!
//! The XPath specification assumes that the XML being processed has a
//! prefix defined for every namespace present in the document. If you
//! are processing XML that was parsed from text, this will be true by
//! construction.
//!
//! If you have programmatically created XML with namespaces but not
//! defined prefixes, some XPath behavior may be confusing:
//!
//! 1. The `name` method will not include a prefix, even if the
//! element or attribute has a namespace.
//! 2. The `namespace` axis will not include namespaces without
//! prefixes.
//!

#![crate_name = "xpath"]

#![feature(box_syntax)]
#![feature(collections)]
#![feature(core)]
#![feature(std_misc)]

#[macro_use]
extern crate peresil;
extern crate document;

use std::borrow::ToOwned;
use std::collections::HashMap;
use std::num::Float;
use std::{iter,string};

use self::Value::{Boolean,Number,String};

use nodeset::{Nodeset,Node,ToNode};
use parser::Parser;
use tokenizer::{Tokenizer,TokenDeabbreviator};

pub use function::Function;
pub use expression::Expression;

#[macro_use]
pub mod macros;
pub mod nodeset;
pub mod axis;
mod expression;
pub mod function;
mod node_test;
pub mod parser;
mod token;
pub mod tokenizer;

// TODO - this doesn't need to be public, figure out how to make it so
#[derive(PartialEq,Debug,Clone)]
pub enum LiteralValue {
    Boolean(bool),
    Number(f64),
    String(string::String),
}

impl LiteralValue {
    fn into_value<'d>(self) -> Value<'d> {
        match self {
            LiteralValue::Boolean(v) => Boolean(v),
            LiteralValue::Number(v)  => Number(v),
            LiteralValue::String(v)  => String(v),
        }
    }
}

#[derive(PartialEq,Debug,Clone)]
pub enum Value<'d> {
    Boolean(bool),
    Number(f64),
    String(string::String),
    Nodeset(Nodeset<'d>),
}

fn str_to_num(s: &str) -> f64 {
    s.trim().parse().unwrap_or(Float::nan())
}

impl<'d> Value<'d> {
    pub fn boolean(&self) -> bool {
        use Value::*;
        match *self {
            Boolean(val) => val,
            Number(n) => n != 0.0 && ! n.is_nan(),
            String(ref s) => ! s.is_empty(),
            Nodeset(ref nodeset) => nodeset.size() > 0,
        }
    }

    pub fn number(&self) -> f64 {
        use Value::*;
        match *self {
            Boolean(val) => if val { 1.0 } else { 0.0 },
            Number(val) => val,
            String(ref s) => str_to_num(s),
            Nodeset(..) => str_to_num(&self.string()),
        }
    }

    pub fn string(&self) -> string::String {
        use Value::*;
        match *self {
            Boolean(v) => v.to_string(),
            Number(n) => {
                if n.is_infinite() {
                    if n.signum() < 0.0 {
                        "-Infinity".to_owned()
                    } else {
                        "Infinity".to_owned()
                    }
                } else {
                    n.to_string()
                }
            },
            String(ref val) => val.clone(),
            Nodeset(ref ns) => match ns.document_order_first() {
                Some(n) => n.string_value(),
                None => "".to_owned(),
            },
        }
    }

    #[allow(dead_code)]
    fn into_literal_value(self) -> LiteralValue {
        use Value::*;
        match self {
            Boolean(v) => LiteralValue::Boolean(v),
            Number(v)  => LiteralValue::Number(v),
            String(v)  => LiteralValue::String(v),
            Nodeset(_) => panic!("Cannot convert a nodeset to a literal"),
        }
    }
}

type BoxFunc = Box<Function + 'static>;
pub type Functions = HashMap<string::String, BoxFunc>;
pub type Variables<'d> = HashMap<string::String, Value<'d>>;
pub type Namespaces = HashMap<string::String, string::String>;

#[derive(Copy,Clone)]
pub struct EvaluationContext<'a, 'd : 'a> {
    node: Node<'d>,
    functions: &'a Functions,
    variables: &'a Variables<'d>,
    namespaces: &'a Namespaces,
    position: usize,
    size: usize,
}

impl<'a, 'd> EvaluationContext<'a, 'd> {
    pub fn new<N>(node: N,
                  functions: &'a Functions,
                  variables: &'a Variables<'d>,
                  namespaces: &'a Namespaces)
                  -> EvaluationContext<'a, 'd>
        where N: ToNode<'d>
    {
        EvaluationContext {
            node: node.into_node(),
            functions: functions,
            variables: variables,
            namespaces: namespaces,
            position: 1,
            size: 1,
        }
    }

    fn new_context_for<N>(&self, node: N) -> EvaluationContext<'a, 'd>
        where N: ToNode<'d>
    {
        EvaluationContext {
            node: node.into_node(),
            .. *self
        }
    }

    fn position(&self) -> usize {
        self.position
    }

    fn size(&self) -> usize {
        self.size
    }

    fn function_for_name(&self, name: &str) -> Option<&'a BoxFunc> {
        self.functions.get(&name.to_owned())
    }

    fn value_of(&self, name: &str) -> Option<&Value<'d>> {
        self.variables.get(&name.to_owned())
    }

    fn namespace_for(&self, prefix: &str) -> Option<&str> {
        self.namespaces.get(prefix).map(|ns| &ns[..])
    }

    fn predicate_iter<'p>(&'p self, nodes: Nodeset<'d>)
                          -> EvaluationContextPredicateIter<'a, 'd, 'p>
    {
        let sz = nodes.size();
        EvaluationContextPredicateIter {
            parent: self,
            nodes: nodes.into_iter().enumerate(),
            size: sz,
        }
    }
}

struct EvaluationContextPredicateIter<'a : 'p, 'd : 'a + 'p, 'p> {
    parent: &'p EvaluationContext<'a, 'd>,
    nodes: iter::Enumerate<nodeset::IntoIter<'d>>,
    size: usize,
}

impl<'a, 'd, 'p> Iterator for EvaluationContextPredicateIter<'a, 'd, 'p> {
    type Item = EvaluationContext<'a, 'd>;

    fn next(&mut self) -> Option<EvaluationContext<'a, 'd>> {
        self.nodes.next().map(|(idx, node)| {
            EvaluationContext {
                node: node,
                position: idx + 1,
                size: self.size,
                .. *self.parent
            }
        })
    }
}

pub struct Factory {
    parser: Parser,
}

impl Factory {
    pub fn new() -> Factory {
        Factory { parser: Parser::new() }
    }

    pub fn build(&self, xpath: &str) -> parser::ParseResult {
        let tokenizer = Tokenizer::new(xpath);
        let deabbreviator = TokenDeabbreviator::new(tokenizer);

        self.parser.parse(deabbreviator)
    }
}

#[cfg(test)]
mod test {
    use std::borrow::ToOwned;
    use std::num::Float;

    use document::Package;

    use super::Value;

    #[test]
    fn number_of_string_is_ieee_754_number() {
        let v = Value::String("1.5".to_owned());
        assert_eq!(1.5, v.number());
    }

    #[test]
    fn number_of_string_with_negative_is_negative_number() {
        let v = Value::String("-1.5".to_owned());
        assert_eq!(-1.5, v.number());
    }

    #[test]
    fn number_of_string_with_surrounding_whitespace_is_number_without_whitespace() {
        let v = Value::String("\r\n1.5 \t".to_owned());
        assert_eq!(1.5, v.number());
    }

    #[test]
    fn number_of_garbage_string_is_nan() {
        let v = Value::String("I am not an IEEE 754 number".to_owned());
        assert!(v.number().is_nan());
    }

    #[test]
    fn number_of_boolean_true_is_1() {
        let v = Value::Boolean(true);
        assert_eq!(1.0, v.number());
    }

    #[test]
    fn number_of_boolean_false_is_0() {
        let v = Value::Boolean(false);
        assert_eq!(0.0, v.number());
    }

    #[test]
    fn number_of_nodeset_is_number_value_of_first_node_in_document_order() {
        let package = Package::new();
        let doc = package.as_document();

        let c1 = doc.create_comment("42.42");
        let c2 = doc.create_comment("1234");
        doc.root().append_child(c1);
        doc.root().append_child(c2);

        let v = Value::Nodeset(nodeset![c2, c1]);
        assert_eq!(42.42, v.number());
    }

    #[test]
    fn string_of_true_is_true() {
        let v = Value::Boolean(true);
        assert_eq!("true", v.string());
    }

    #[test]
    fn string_of_false_is_false() {
        let v = Value::Boolean(false);
        assert_eq!("false", v.string());
    }

    #[test]
    fn string_of_nan_is_nan() {
        let v = Value::Number(Float::nan());
        assert_eq!("NaN", v.string());
    }

    #[test]
    fn string_of_positive_zero_is_zero() {
        let v = Value::Number(Float::zero());
        assert_eq!("0", v.string());
    }

    #[test]
    fn string_of_negative_zero_is_zero() {
        let v = Value::Number(Float::neg_zero());
        assert_eq!("0", v.string());
    }

    #[test]
    fn string_of_positive_infinity_is_infinity() {
        let v = Value::Number(Float::infinity());
        assert_eq!("Infinity", v.string());
    }

    #[test]
    fn string_of_negative_infinity_is_minus_infinity() {
        let v = Value::Number(Float::neg_infinity());
        assert_eq!("-Infinity", v.string());
    }

    #[test]
    fn string_of_integer_has_no_decimal() {
        let v = Value::Number(-42.0);
        assert_eq!("-42", v.string());
    }

    #[test]
    fn string_of_decimal_has_fractional_part() {
        let v = Value::Number(1.2);
        assert_eq!("1.2", v.string());
    }

    #[test]
    fn string_of_nodeset_is_string_value_of_first_node_in_document_order() {
        let package = Package::new();
        let doc = package.as_document();

        let c1 = doc.create_comment("comment 1");
        let c2 = doc.create_comment("comment 2");
        doc.root().append_child(c1);
        doc.root().append_child(c2);

        let v = Value::Nodeset(nodeset![c2, c1]);
        assert_eq!("comment 1", v.string());
    }
}
<commit_msg>Unicode support is feature-gated<commit_after>//!
//! ### Namespaces
//!
//! The XPath specification assumes that the XML being processed has a
//! prefix defined for every namespace present in the document. If you
//! are processing XML that was parsed from text, this will be true by
//! construction.
//!
//! If you have programmatically created XML with namespaces but not
//! defined prefixes, some XPath behavior may be confusing:
//!
//! 1. The `name` method will not include a prefix, even if the
//! element or attribute has a namespace.
//! 2. The `namespace` axis will not include namespaces without
//! prefixes.
//!

#![crate_name = "xpath"]

#![feature(box_syntax)]
#![feature(collections)]
#![feature(core)]
#![feature(std_misc)]
#![feature(unicode)]

#[macro_use]
extern crate peresil;
extern crate document;

use std::borrow::ToOwned;
use std::collections::HashMap;
use std::num::Float;
use std::{iter,string};

use self::Value::{Boolean,Number,String};

use nodeset::{Nodeset,Node,ToNode};
use parser::Parser;
use tokenizer::{Tokenizer,TokenDeabbreviator};

pub use function::Function;
pub use expression::Expression;

#[macro_use]
pub mod macros;
pub mod nodeset;
pub mod axis;
mod expression;
pub mod function;
mod node_test;
pub mod parser;
mod token;
pub mod tokenizer;

// TODO - this doesn't need to be public, figure out how to make it so
#[derive(PartialEq,Debug,Clone)]
pub enum LiteralValue {
    Boolean(bool),
    Number(f64),
    String(string::String),
}

impl LiteralValue {
    fn into_value<'d>(self) -> Value<'d> {
        match self {
            LiteralValue::Boolean(v) => Boolean(v),
            LiteralValue::Number(v)  => Number(v),
            LiteralValue::String(v)  => String(v),
        }
    }
}

#[derive(PartialEq,Debug,Clone)]
pub enum Value<'d> {
    Boolean(bool),
    Number(f64),
    String(string::String),
    Nodeset(Nodeset<'d>),
}

fn str_to_num(s: &str) -> f64 {
    s.trim().parse().unwrap_or(Float::nan())
}

impl<'d> Value<'d> {
    pub fn boolean(&self) -> bool {
        use Value::*;
        match *self {
            Boolean(val) => val,
            Number(n) => n != 0.0 && ! n.is_nan(),
            String(ref s) => ! s.is_empty(),
            Nodeset(ref nodeset) => nodeset.size() > 0,
        }
    }

    pub fn number(&self) -> f64 {
        use Value::*;
        match *self {
            Boolean(val) => if val { 1.0 } else { 0.0 },
            Number(val) => val,
            String(ref s) => str_to_num(s),
            Nodeset(..) => str_to_num(&self.string()),
        }
    }

    pub fn string(&self) -> string::String {
        use Value::*;
        match *self {
            Boolean(v) => v.to_string(),
            Number(n) => {
                if n.is_infinite() {
                    if n.signum() < 0.0 {
                        "-Infinity".to_owned()
                    } else {
                        "Infinity".to_owned()
                    }
                } else {
                    n.to_string()
                }
            },
            String(ref val) => val.clone(),
            Nodeset(ref ns) => match ns.document_order_first() {
                Some(n) => n.string_value(),
                None => "".to_owned(),
            },
        }
    }

    #[allow(dead_code)]
    fn into_literal_value(self) -> LiteralValue {
        use Value::*;
        match self {
            Boolean(v) => LiteralValue::Boolean(v),
            Number(v)  => LiteralValue::Number(v),
            String(v)  => LiteralValue::String(v),
            Nodeset(_) => panic!("Cannot convert a nodeset to a literal"),
        }
    }
}

type BoxFunc = Box<Function + 'static>;
pub type Functions = HashMap<string::String, BoxFunc>;
pub type Variables<'d> = HashMap<string::String, Value<'d>>;
pub type Namespaces = HashMap<string::String, string::String>;

#[derive(Copy,Clone)]
pub struct EvaluationContext<'a, 'd : 'a> {
    node: Node<'d>,
    functions: &'a Functions,
    variables: &'a Variables<'d>,
    namespaces: &'a Namespaces,
    position: usize,
    size: usize,
}

impl<'a, 'd> EvaluationContext<'a, 'd> {
    pub fn new<N>(node: N,
                  functions: &'a Functions,
                  variables: &'a Variables<'d>,
                  namespaces: &'a Namespaces)
                  -> EvaluationContext<'a, 'd>
        where N: ToNode<'d>
    {
        EvaluationContext {
            node: node.into_node(),
            functions: functions,
            variables: variables,
            namespaces: namespaces,
            position: 1,
            size: 1,
        }
    }

    fn new_context_for<N>(&self, node: N) -> EvaluationContext<'a, 'd>
        where N: ToNode<'d>
    {
        EvaluationContext {
            node: node.into_node(),
            .. *self
        }
    }

    fn position(&self) -> usize {
        self.position
    }

    fn size(&self) -> usize {
        self.size
    }

    fn function_for_name(&self, name: &str) -> Option<&'a BoxFunc> {
        self.functions.get(&name.to_owned())
    }

    fn value_of(&self, name: &str) -> Option<&Value<'d>> {
        self.variables.get(&name.to_owned())
    }

    fn namespace_for(&self, prefix: &str) -> Option<&str> {
        self.namespaces.get(prefix).map(|ns| &ns[..])
    }

    fn predicate_iter<'p>(&'p self, nodes: Nodeset<'d>)
                          -> EvaluationContextPredicateIter<'a, 'd, 'p>
    {
        let sz = nodes.size();
        EvaluationContextPredicateIter {
            parent: self,
            nodes: nodes.into_iter().enumerate(),
            size: sz,
        }
    }
}

struct EvaluationContextPredicateIter<'a : 'p, 'd : 'a + 'p, 'p> {
    parent: &'p EvaluationContext<'a, 'd>,
    nodes: iter::Enumerate<nodeset::IntoIter<'d>>,
    size: usize,
}

impl<'a, 'd, 'p> Iterator for EvaluationContextPredicateIter<'a, 'd, 'p> {
    type Item = EvaluationContext<'a, 'd>;

    fn next(&mut self) -> Option<EvaluationContext<'a, 'd>> {
        self.nodes.next().map(|(idx, node)| {
            EvaluationContext {
                node: node,
                position: idx + 1,
                size: self.size,
                .. *self.parent
            }
        })
    }
}

pub struct Factory {
    parser: Parser,
}

impl Factory {
    pub fn new() -> Factory {
        Factory { parser: Parser::new() }
    }

    pub fn build(&self, xpath: &str) -> parser::ParseResult {
        let tokenizer = Tokenizer::new(xpath);
        let deabbreviator = TokenDeabbreviator::new(tokenizer);

        self.parser.parse(deabbreviator)
    }
}

#[cfg(test)]
mod test {
    use std::borrow::ToOwned;
    use std::num::Float;

    use document::Package;

    use super::Value;

    #[test]
    fn number_of_string_is_ieee_754_number() {
        let v = Value::String("1.5".to_owned());
        assert_eq!(1.5, v.number());
    }

    #[test]
    fn number_of_string_with_negative_is_negative_number() {
        let v = Value::String("-1.5".to_owned());
        assert_eq!(-1.5, v.number());
    }

    #[test]
    fn number_of_string_with_surrounding_whitespace_is_number_without_whitespace() {
        let v = Value::String("\r\n1.5 \t".to_owned());
        assert_eq!(1.5, v.number());
    }

    #[test]
    fn number_of_garbage_string_is_nan() {
        let v = Value::String("I am not an IEEE 754 number".to_owned());
        assert!(v.number().is_nan());
    }

    #[test]
    fn number_of_boolean_true_is_1() {
        let v = Value::Boolean(true);
        assert_eq!(1.0, v.number());
    }

    #[test]
    fn number_of_boolean_false_is_0() {
        let v = Value::Boolean(false);
        assert_eq!(0.0, v.number());
    }

    #[test]
    fn number_of_nodeset_is_number_value_of_first_node_in_document_order() {
        let package = Package::new();
        let doc = package.as_document();

        let c1 = doc.create_comment("42.42");
        let c2 = doc.create_comment("1234");
        doc.root().append_child(c1);
        doc.root().append_child(c2);

        let v = Value::Nodeset(nodeset![c2, c1]);
        assert_eq!(42.42, v.number());
    }

    #[test]
    fn string_of_true_is_true() {
        let v = Value::Boolean(true);
        assert_eq!("true", v.string());
    }

    #[test]
    fn string_of_false_is_false() {
        let v = Value::Boolean(false);
        assert_eq!("false", v.string());
    }

    #[test]
    fn string_of_nan_is_nan() {
        let v = Value::Number(Float::nan());
        assert_eq!("NaN", v.string());
    }

    #[test]
    fn string_of_positive_zero_is_zero() {
        let v = Value::Number(Float::zero());
        assert_eq!("0", v.string());
    }

    #[test]
    fn string_of_negative_zero_is_zero() {
        let v = Value::Number(Float::neg_zero());
        assert_eq!("0", v.string());
    }

    #[test]
    fn string_of_positive_infinity_is_infinity() {
        let v = Value::Number(Float::infinity());
        assert_eq!("Infinity", v.string());
    }

    #[test]
    fn string_of_negative_infinity_is_minus_infinity() {
        let v = Value::Number(Float::neg_infinity());
        assert_eq!("-Infinity", v.string());
    }

    #[test]
    fn string_of_integer_has_no_decimal() {
        let v = Value::Number(-42.0);
        assert_eq!("-42", v.string());
    }

    #[test]
    fn string_of_decimal_has_fractional_part() {
        let v = Value::Number(1.2);
        assert_eq!("1.2", v.string());
    }

    #[test]
    fn string_of_nodeset_is_string_value_of_first_node_in_document_order() {
        let package = Package::new();
        let doc = package.as_document();

        let c1 = doc.create_comment("comment 1");
        let c2 = doc.create_comment("comment 2");
        doc.root().append_child(c1);
        doc.root().append_child(c2);

        let v = Value::Nodeset(nodeset![c2, c1]);
        assert_eq!("comment 1", v.string());
    }
}
<|endoftext|>