<commit_before>use cgmath;
use cgmath::{Angle, Deg, Matrix4, Point2, Point3, Vector3};
use game::constants::{RESOLUTION_X, RESOLUTION_Y, TILE_WIDTH, VIEW_DISTANCE};
use gfx::{Factory, Resources, texture};
use gfx::format::Rgba8;
use gfx::handle::ShaderResourceView;
use gfx_app::mouse_controls::MouseInputState;
use graphics::orientation::Orientation;
use image;
use shaders::{Position, Projection};
use std::io::Cursor;

pub mod camera;
pub mod orientation;

#[derive(Debug)]
pub struct DeltaTime(pub f64);

#[derive(Debug, Clone)]
pub struct Dimensions {
  pub width: u32,
  pub height: u32,
}

impl Dimensions {
  pub fn new(_window_width: u32, _window_height: u32) -> Dimensions {
    Dimensions {
      width: RESOLUTION_X,
      height: RESOLUTION_Y,
    }
  }

  pub fn get_view_matrix() -> Matrix4<f32> {
    Matrix4::look_at(
      Point3::new(0.0, 0.0, VIEW_DISTANCE),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    )
  }

  pub fn world_to_projection(&self, input: &camera::CameraInputState) -> Projection {
    let view: Matrix4<f32> = Matrix4::look_at(
      Point3::new(0.0, 0.0, input.distance),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    );
    let aspect_ratio = self.width as f32 / self.height as f32;
    Projection {
      model: view.into(),
      view: view.into(),
      proj: cgmath::perspective(cgmath::Deg(75.0f32), aspect_ratio, 0.1, 4000.0).into(),
    }
  }
}

pub fn flip_y_axel(point: Point2<f32>) -> Point2<f32> {
  Point2::new(point.x, RESOLUTION_Y as f32 - point.y)
}

pub fn direction(start_point: Point2<f32>, end_point: Point2<f32>) -> u32 {
  let theta = cgmath::Angle::atan2(end_point.y - start_point.y, end_point.x - start_point.x);
  let angle = match theta {
    Deg(i) => i
  };
  let a = angle.floor() as i32;
  if a < 0 { (360 + a) as u32 } else { a as u32 }
}

pub fn direction_movement(direction: u32) -> Point2<f32> {
  let f_direction = direction as f32;
  Point2::new((Angle::cos(Deg(f_direction)) * 100.0).round() / 100.0,
              (Angle::sin(Deg(f_direction)) * 100.0).round() / 100.0)
}

pub fn get_orientation(start_point: Point2<f32>, end_point: Point2<f32>) -> Orientation {
  let angle_in_degrees = direction(start_point, end_point);

  match angle_in_degrees {
    345 ... 360 | 0 ... 22 => Orientation::Right,
    23 ... 68 => Orientation::UpRight,
    69 ... 114 => Orientation::Up,
    115 ... 160 => Orientation::UpLeft,
    161 ... 206 => Orientation::Left,
    207 ... 252 => Orientation::DownLeft,
    253 ... 298 => Orientation::Down,
    299 ... 344 => Orientation::DownRight,
    _ => unreachable!("Invalid orientation")
  }
}

pub fn get_orientation_from_center(mouse_input: &MouseInputState) -> Orientation {
  if let Some(end_point_gl) = mouse_input.left_click_point {
    let start_point = Point2::new((RESOLUTION_X / 2) as f32, (RESOLUTION_Y / 2) as f32);
    get_orientation(start_point, flip_y_axel(end_point_gl))
  } else {
    Orientation::Right
  }
}

pub fn overlaps(a: Position, b: Position, width: f32, height: f32) -> bool {
  a.position[0] < b.position[0] + width &&
    a.position[0] + width > b.position[0] &&
    a.position[1] < b.position[1] + height &&
    a.position[1] + a.position[1] > b.position[1]
}

fn is_within_map_borders(point: Point2<f64>) -> bool {
  point.x > 0.0 && point.x < 63.0 && point.y > 0.0 && point.y < 63.0
}

pub fn can_move(screen_pos: Position) -> bool {
  let x_coord = f64::from(screen_pos.position[0]);
  let y_coord = f64::from(screen_pos.position[1]);
  let point = Point2::new(
    (x_coord / TILE_WIDTH + y_coord / TILE_WIDTH).round() + 31.0,
    (y_coord / TILE_WIDTH - x_coord / TILE_WIDTH).round() + 32.0);
  is_within_map_borders(point)
}

pub fn load_texture<R, F>(factory: &mut F, data: &[u8]) -> Result<ShaderResourceView<R, [f32; 4]>, String> where R: Resources, F: Factory<R> {
  let img = image::load(Cursor::new(data), image::PNG).unwrap().to_rgba();
  let (width, height) = img.dimensions();
  let kind = texture::Kind::D2(width as texture::Size, height as texture::Size, texture::AaMode::Single);
  let (_, view) = match factory.create_texture_immutable_u8::<Rgba8>(kind, texture::Mipmap::Provided, &[&img]) {
    Ok(val) => val,
    Err(e) => panic!("Couldn't create texture {:?}", e)
  };
  Ok(view)
}
<commit_msg>Add "coords_to_tile" function<commit_after>use cgmath;
use cgmath::{Angle, Deg, Matrix4, Point2, Point3, Vector3};
use game::constants::{RESOLUTION_X, RESOLUTION_Y, TILE_WIDTH, TILES_PCS_H, TILES_PCS_W, VIEW_DISTANCE};
use gfx::{Factory, Resources, texture};
use gfx::format::Rgba8;
use gfx::handle::ShaderResourceView;
use gfx_app::mouse_controls::MouseInputState;
use graphics::orientation::Orientation;
use image;
use shaders::{Position, Projection};
use std::io::Cursor;

pub mod camera;
pub mod orientation;

#[derive(Debug)]
pub struct DeltaTime(pub f64);

#[derive(Debug, Clone)]
pub struct Dimensions {
  pub width: u32,
  pub height: u32,
}

impl Dimensions {
  pub fn new(_window_width: u32, _window_height: u32) -> Dimensions {
    Dimensions {
      width: RESOLUTION_X,
      height: RESOLUTION_Y,
    }
  }

  pub fn get_view_matrix() -> Matrix4<f32> {
    Matrix4::look_at(
      Point3::new(0.0, 0.0, VIEW_DISTANCE),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    )
  }

  pub fn world_to_projection(&self, input: &camera::CameraInputState) -> Projection {
    let view: Matrix4<f32> = Matrix4::look_at(
      Point3::new(0.0, 0.0, input.distance),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    );
    let aspect_ratio = self.width as f32 / self.height as f32;
    Projection {
      model: view.into(),
      view: view.into(),
      proj: cgmath::perspective(cgmath::Deg(75.0f32), aspect_ratio, 0.1, 4000.0).into(),
    }
  }
}

pub fn flip_y_axel(point: Point2<f32>) -> Point2<f32> {
  Point2::new(point.x, RESOLUTION_Y as f32 - point.y)
}

pub fn direction(start_point: Point2<f32>, end_point: Point2<f32>) -> u32 {
  let theta = cgmath::Angle::atan2(end_point.y - start_point.y, end_point.x - start_point.x);
  let angle = match theta {
    Deg(i) => i
  };
  let a = angle.floor() as i32;
  if a < 0 { (360 + a) as u32 } else { a as u32 }
}

pub fn direction_movement(direction: u32) -> Point2<f32> {
  let f_direction = direction as f32;
  Point2::new((Angle::cos(Deg(f_direction)) * 100.0).round() / 100.0,
              (Angle::sin(Deg(f_direction)) * 100.0).round() / 100.0)
}

pub fn get_orientation(start_point: Point2<f32>, end_point: Point2<f32>) -> Orientation {
  let angle_in_degrees = direction(start_point, end_point);

  match angle_in_degrees {
    345 ... 360 | 0 ... 22 => Orientation::Right,
    23 ... 68 => Orientation::UpRight,
    69 ... 114 => Orientation::Up,
    115 ... 160 => Orientation::UpLeft,
    161 ... 206 => Orientation::Left,
    207 ... 252 => Orientation::DownLeft,
    253 ... 298 => Orientation::Down,
    299 ... 344 => Orientation::DownRight,
    _ => unreachable!("Invalid orientation")
  }
}

pub fn get_orientation_from_center(mouse_input: &MouseInputState) -> Orientation {
  if let Some(end_point_gl) = mouse_input.left_click_point {
    let start_point = Point2::new((RESOLUTION_X / 2) as f32, (RESOLUTION_Y / 2) as f32);
    get_orientation(start_point, flip_y_axel(end_point_gl))
  } else {
    Orientation::Right
  }
}

pub fn overlaps(a: Position, b: Position, width: f32, height: f32) -> bool {
  a.position[0] < b.position[0] + width &&
    a.position[0] + width > b.position[0] &&
    a.position[1] < b.position[1] + height &&
    a.position[1] + a.position[1] > b.position[1]
}

fn is_within_map_borders(point: Point2<f64>) -> bool {
  point.x > 0.0 && point.x < 63.0 && point.y > 0.0 && point.y < 63.0
}

pub fn can_move(screen_pos: Position) -> bool {
  let x_coord = f64::from(screen_pos.position[0]);
  let y_coord = f64::from(screen_pos.position[1]);
  let point = Point2::new(
    (x_coord / TILE_WIDTH + y_coord / TILE_WIDTH).round() + 31.0,
    (y_coord / TILE_WIDTH - x_coord / TILE_WIDTH).round() + 32.0);
  is_within_map_borders(point)
}

pub fn coords_to_tile(position: Position) -> Point2<usize> {
  let pos = Point2 {
    x: -position.position[0],
    y: -position.position[1],
  };
  let tiles_w = TILES_PCS_W as f32 / 2.0;
  let tiles_h = TILES_PCS_H as f32 / 2.0;
  let tile_width = TILE_WIDTH as f32;
  let x = if pos.x > 0.0 { pos.x.abs() / tile_width + tiles_w } else { tiles_w - (pos.x.abs() / tile_width) };
  let y = if pos.y > 0.0 { pos.y.abs() / tile_width + tiles_h } else { tiles_h - (pos.y.abs() / tile_width) };
  Point2 {
    x: x.round() as usize,
    y: y.round() as usize,
  }
}

pub fn load_texture<R, F>(factory: &mut F, data: &[u8]) -> Result<ShaderResourceView<R, [f32; 4]>, String> where R: Resources, F: Factory<R> {
  let img = image::load(Cursor::new(data), image::PNG).unwrap().to_rgba();
  let (width, height) = img.dimensions();
  let kind = texture::Kind::D2(width as texture::Size, height as texture::Size, texture::AaMode::Single);
  let (_, view) = match factory.create_texture_immutable_u8::<Rgba8>(kind, texture::Mipmap::Provided, &[&img]) {
    Ok(val) => val,
    Err(e) => panic!("Couldn't create texture {:?}", e)
  };
  Ok(view)
}
<|endoftext|>


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

use super::super::results::{BearerResult, BearerError};

pub fn build_path(config_dir: &str, client_name: &str) -> BearerResult<(String, bool)> {

    let config_dir_expanded = tilde_expand(config_dir.as_bytes());
    let config_dir_expanded = String::from_utf8(config_dir_expanded);
    if let Err(err) = config_dir_expanded {
        return Err(BearerError::UTF8EncodingError(
            format!("Cannot build path from config dir {}: {:?}",
                    config_dir,
                    err)));
    }
    let config_dir_expanded = config_dir_expanded.unwrap();
    let path = config_dir_expanded.clone();
    let path = Path::new(path.as_str());
    if !path.exists() {
        debug!("Creating the config dir {}, path not exists", config_dir);
        let res = fs::create_dir_all(&config_dir_expanded);
        if let Err(err) = res {
            return Err(BearerError::IOError(
                format!("Could not create directory {}: {}",
                        config_dir_expanded,
                        err)));
        }
    } else if !path.is_dir() {
        return Err(BearerError::ValueError(
            format!("Path {} is not a directory",
                    config_dir_expanded)));
    }

    let path = path.join(format!("{}.toml", client_name));

    match path.to_str() {
        Some(string) => Ok((string.to_string(), path.is_file())),
        None => {
            Err(BearerError::UTF8EncodingError(
                format!("Could not build path with config dir {} and client {}",
                        config_dir_expanded,
                        client_name)))
        }
    }
}

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

    use std::fs;
    use std::path::Path;
    use rand::{thread_rng, Rng};

    #[test]
    fn test_build_path_exists() {
        let (path, exists) = build_path(
            "src/tests/conf", "dummy_with_tokens").unwrap();
        assert_eq!(exists, true);
        assert!(path.ends_with("src/tests/conf/dummy_with_tokens.toml"));
    }

    #[test]
    fn test_build_path_not_exists() {
        let (path, exists) = build_path(
            "src/tests/conf", "not_exists").unwrap();
        assert_eq!(exists, false);
        assert!(path.ends_with("src/tests/conf/not_exists.toml"));
    }

    #[test]
    fn test_build_path_create_dir() {
        let rnd: String = thread_rng().gen_ascii_chars().take(10).collect();

        let tmpdir = format!("/tmp/test-bearer-{}", rnd);

        let dirpath = Path::new(tmpdir.as_str());
        assert_eq!(dirpath.exists(), false);

        let (path, exists) = build_path(
            tmpdir.as_str(), "not_exists").unwrap();
        assert_eq!(exists, false);

        let tmpdir = format!("/tmp/test-bearer-{}", rnd);
        let filepath = format!("{}/not_exists.toml", tmpdir);

        assert_eq!(path, filepath);

        let filepath = Path::new(filepath.as_str());

        assert_eq!(dirpath.exists(), true);
        assert_eq!(filepath.exists(), false);

        fs::remove_dir_all(tmpdir).unwrap();
    }

}
<commit_msg>Add the list clients helper<commit_after>use std::fs;
use std::path::Path;
use std::vec::Vec;
use tilde_expand::tilde_expand;

use super::super::results::{BearerResult, BearerError};

fn expand_path(config_dir: &str) -> BearerResult<String> {
    let config_dir_expanded = tilde_expand(config_dir.as_bytes());
    let config_dir_expanded = String::from_utf8(config_dir_expanded);
    if let Err(err) = config_dir_expanded {
        return Err(BearerError::UTF8EncodingError(
            format!("Cannot build path from config dir {}: {:?}",
                    config_dir,
                    err)));
    }
    Ok(config_dir_expanded.unwrap())
}

pub fn build_path(config_dir: &str, client_name: &str) -> BearerResult<(String, bool)> {

    let config_dir_expanded = expand_path(config_dir)?;
    let path = config_dir_expanded.clone();
    let path = Path::new(path.as_str());
    if !path.exists() {
        debug!("Creating the config dir {}, path not exists", config_dir);
        let res = fs::create_dir_all(&config_dir_expanded);
        if let Err(err) = res {
            return Err(BearerError::IOError(
                format!("Could not create directory {}: {}",
                        config_dir_expanded,
                        err)));
        }
    } else if !path.is_dir() {
        return Err(BearerError::ValueError(
            format!("Path {} is not a directory",
                    config_dir_expanded)));
    }

    let path = path.join(format!("{}.toml", client_name));

    match path.to_str() {
        Some(string) => Ok((string.to_string(), path.is_file())),
        None => {
            Err(BearerError::UTF8EncodingError(
                format!("Could not build path with config dir {} and client {}",
                        config_dir_expanded,
                        client_name)))
        }
    }
}

pub fn list_clients(config_dir: &str) -> BearerResult<Vec<String>> {
    let config_dir_expanded = expand_path(config_dir)?;
    let path = config_dir_expanded.clone();
    let path = Path::new(path.as_str());
    if !path.is_dir() {
        return Err(BearerError::ValueError(
            format!("Path {} is not a directory",
                    config_dir_expanded)));
    }
    let paths = fs::read_dir(path).unwrap();
    let mut ret = paths.map(
            |pth| pth.unwrap().path().file_name().unwrap().to_str().unwrap().to_string()
        ).filter(
            |pth| pth.ends_with(".toml")
        ).map(
            |pth| pth.as_str()[..pth.len() - 5].to_string()
        ).collect::<Vec<String>>();
    ret.sort();
    Ok(ret)
}

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

    use std::fs;
    use std::path::Path;
    use rand::{thread_rng, Rng};

    #[test]
    fn test_build_path_exists() {
        let (path, exists) = build_path(
            "src/tests/conf", "dummy_with_tokens").unwrap();
        assert_eq!(exists, true);
        assert!(path.ends_with("src/tests/conf/dummy_with_tokens.toml"));
    }

    #[test]
    fn test_build_path_not_exists() {
        let (path, exists) = build_path(
            "src/tests/conf", "not_exists").unwrap();
        assert_eq!(exists, false);
        assert!(path.ends_with("src/tests/conf/not_exists.toml"));
    }

    #[test]
    fn test_build_path_create_dir() {
        let rnd: String = thread_rng().gen_ascii_chars().take(10).collect();

        let tmpdir = format!("/tmp/test-bearer-{}", rnd);

        let dirpath = Path::new(tmpdir.as_str());
        assert_eq!(dirpath.exists(), false);

        let (path, exists) = build_path(
            tmpdir.as_str(), "not_exists").unwrap();
        assert_eq!(exists, false);

        let tmpdir = format!("/tmp/test-bearer-{}", rnd);
        let filepath = format!("{}/not_exists.toml", tmpdir);

        assert_eq!(path, filepath);

        let filepath = Path::new(filepath.as_str());

        assert_eq!(dirpath.exists(), true);
        assert_eq!(filepath.exists(), false);

        fs::remove_dir_all(tmpdir).unwrap();
    }

    #[test]
    fn test_list_clients_ok() {
        let clients = list_clients("src/tests/conf").unwrap();
        assert_eq!(
            clients.as_slice(),
            &["dummy", "dummy_with_tokens", "invalid"]
        )
    }

    #[test]
    fn test_list_clients_err() {
        let err = list_clients("not/an/existings/directory");
        assert_eq!(err.is_err(), true);
        let err = err.unwrap_err();
        assert_eq!(
            err,
            BearerError::ValueError("".to_string())
        )
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::path::{ Path, PathBuf };

use download;
use extract;
use verify;
use find_package::Package;

fn _install_package(package: Package, path: &Path) -> Result<bool, String> {
    let download_path = PathBuf::new();
        download_path.push(path);
        download_path.push(format!("download/{}", package.name));

    download::download_file(package.url, download_path);

    let tar_path = PathBuf::new();
        tar_path.push(path);
        tar_path.push(format!("download/{}.tar", package.name));

    extract::extract_gz(download_path, tar_path);

    let install_path = PathBuf::new();
        tar_path.push(path);
        tar_path.push(format!("install/{}", package.name));

    extract::extract_tar(tar_path, install_path);
}

pub fn install_package(name: &str, path: &Path) -> Result<bool, String> {
    let found_packages = try!(find_package::find_package(name, path));

    if(!found_packages.is_empty() && found_packages.count() > 1) {
        for (i, package) in found_packages.iter().enumerate() {
            let install_path = PathBuf::new();
                install_path.push(path);
                install_path.push(format!("installed/{}", package.name));

            if(!install_path.exists()) {
                println!("Package {}: {}", i, package);
            }
        }

        //TODO: Accept user input and install user-chosen package.
    } else {
        return _install_package(found_packages[0], path)
    }
}
<commit_msg>Error fixing<commit_after>use std::fs::File;
use std::path::{ Path, PathBuf };

use download;
use extract;
use verify;
use find_package;
use find_package::Package;

fn _install_package(package: &Package, path: &Path) -> Result<bool, String> {
    let mut download_path = PathBuf::new();
        download_path.push(path);
        download_path.push(format!("download/{}", package.name));

    if !download_path.exists() {
        try!(download::download_file(&package.url, download_path.as_path()));
    }

    let mut tar_path = PathBuf::new();
        tar_path.push(path);
        tar_path.push(format!("download/{}.tar", package.name));

    if !tar_path.exists() {
        try!(extract::extract_gz(download_path.as_path(), tar_path.as_path()));
    }

    let mut install_path = PathBuf::new();
        tar_path.push(path);
        tar_path.push(format!("install/{}", package.name));

    if !install_path.exists() {
        try!(extract::extract_tar(tar_path.as_path(), install_path.as_path()));
    }

    return Ok(true)
}

pub fn install_package(name: &str, path: &Path) -> Result<bool, String> {
    let found_packages = try!(find_package::find_package(name, path));

    if !found_packages.is_empty() && found_packages.len() > 1 {
        for (i, package) in found_packages.iter().enumerate() {
            let mut install_path = PathBuf::new();
                install_path.push(path);
                install_path.push(format!("installed/{}", package.name));

            if !install_path.exists() {
                println!("Package {}: {}", i, package.name);
            }
        }

        //TODO: Accept user input and install user-chosen package.
        return _install_package(&found_packages[0], path)
    } else {
        return _install_package(&found_packages[0], path)
    }
}
<|endoftext|>


<commit_before>//! Contains Lea's table type.
//!
//! # Weak tables
//!
//! A table can have weak keys and/or values. These will reference objects weakly and make no
//! difference for value types and strings. If an object is only reachable through weak references,
//! the GC will still collect the object and then modify all weak references that pointed to it to
//! make sure that they are still valid and don't point to freed memory.
//!
//! In case of weak tables, an entry will be removed if either the key or the value is collected
//! due to being only weakly reachable.
//!
//! A table with weak values will thus delete a value's mapping if the value isn't reachable from
//! outside the table and allows the table to be used like a cache.
//!
//! A table with weak keys will delete a key's mapping if the key is only weakly reachable. It is
//! acting as an "ephemeron" table and allows associating properties with objects that will be
//! automatically cleared when the object is collected.

#![macro_use]

use value::Value;
use mem::{TracedRef, Tracer, Traceable};

use std::collections::HashMap;
use std::ops::{Deref, DerefMut};

/// A table that maps Lea values to Lea values.
#[derive(Debug, Default)]
pub struct Table {
    data: HashMap<Value, Value>,
    metatable: Option<TracedRef<Table>>,
    weak_keys: bool,
    weak_vals: bool,
}

impl Table {
    /// Creates a new table, using the given `HashMap<Value, Value>` as the internal storage.
    pub fn new(data: HashMap<Value, Value>) -> Table {
        Table {
            data: data,
            metatable: None,
            weak_keys: false,
            weak_vals: false,
        }
    }

    pub fn get_weak_keys(&self) -> bool {
        self.weak_keys
    }

    pub fn set_weak_keys(&mut self, weak: bool) {
        self.weak_keys = weak;
    }

    pub fn get_weak_values(&self) -> bool {
        self.weak_vals
    }

    pub fn set_weak_values(&mut self, weak: bool) {
        self.weak_vals = weak;
    }

    /// Equivalent to assignment by Lea code. If the value is nil, the mapping is deleted. Returns
    /// the old value stored with the given key or `Err(())` if the key is nil (this is not
    /// supported).
    pub fn set(&mut self, k: Value, v: Value) -> Result<Option<Value>, ()> {
        if k == Value::TNil { return Err(()); }

        if v == Value::TNil {
            Ok(self.data.remove(&k))
        } else {
            Ok(self.data.insert(k, v))
        }
    }

    pub fn get(&self, k: &Value) -> Value {
        match self.data.get(k) {
            None => Value::TNil,
            Some(&v) => v,
        }
    }
}

impl Traceable for Table {
    fn trace<T: Tracer>(&self, t: &mut T) {
        for (ref k, ref v) in &self.data {
            k.trace(t);
            v.trace(t);
        }
    }
}

impl Deref for Table {
    type Target = HashMap<Value, Value>;

    fn deref(&self) -> &<Self as Deref>::Target {
        &self.data
    }
}

impl DerefMut for Table {
    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
        &mut self.data
    }
}

macro_rules! hashmap {
    ( $($k:expr => $v:expr),* ) => {{
        let mut m = ::std::collections::HashMap::new();
        $( m.insert($k, $v); )*
        m
    }};
    ( $($k:expr => $v:expr,)* ) => {
        hashmap!($($k => $v),*)
    };
}

macro_rules! table {
    ( $($t:tt)* ) => {
        $crate::table::Table::new(hashmap!($($t)*))
    };
}

#[cfg(test)]
mod tests {
    use value::Value::*;

    #[test]
    fn test() {
        let mut t = table! {
            TNumber(0.5.into()) => TNumber(42.into()),
            TBool(true) => TNumber(24.into()),
        };

        assert_eq!(t.set(TBool(false), TNumber(123.0.into())), Ok(None));
        assert_eq!(t.data, hashmap! {
            TNumber(0.5.into()) => TNumber(42.into()),
            TBool(true) => TNumber(24.into()),
            TBool(false) => TNumber(123.0.into()),
        });

        assert_eq!(t.set(TBool(true), TNil), Ok(Some(TNumber(24.into()))));
        assert_eq!(t.data, hashmap! {
            TNumber(0.5.into()) => TNumber(42.into()),
            TBool(false) => TNumber(123.0.into()),
        });

        assert_eq!(t.set(TNil, TNil), Err(()));
    }
}
<commit_msg>Remove more value glob imports<commit_after>//! Contains Lea's table type.
//!
//! # Weak tables
//!
//! A table can have weak keys and/or values. These will reference objects weakly and make no
//! difference for value types and strings. If an object is only reachable through weak references,
//! the GC will still collect the object and then modify all weak references that pointed to it to
//! make sure that they are still valid and don't point to freed memory.
//!
//! In case of weak tables, an entry will be removed if either the key or the value is collected
//! due to being only weakly reachable.
//!
//! A table with weak values will thus delete a value's mapping if the value isn't reachable from
//! outside the table and allows the table to be used like a cache.
//!
//! A table with weak keys will delete a key's mapping if the key is only weakly reachable. It is
//! acting as an "ephemeron" table and allows associating properties with objects that will be
//! automatically cleared when the object is collected.

#![macro_use]

use value::Value;
use mem::{TracedRef, Tracer, Traceable};

use std::collections::HashMap;
use std::ops::{Deref, DerefMut};

/// A table that maps Lea values to Lea values.
#[derive(Debug, Default)]
pub struct Table {
    data: HashMap<Value, Value>,
    metatable: Option<TracedRef<Table>>,
    weak_keys: bool,
    weak_vals: bool,
}

impl Table {
    /// Creates a new table, using the given `HashMap<Value, Value>` as the internal storage.
    pub fn new(data: HashMap<Value, Value>) -> Table {
        Table {
            data: data,
            metatable: None,
            weak_keys: false,
            weak_vals: false,
        }
    }

    pub fn get_weak_keys(&self) -> bool {
        self.weak_keys
    }

    pub fn set_weak_keys(&mut self, weak: bool) {
        self.weak_keys = weak;
    }

    pub fn get_weak_values(&self) -> bool {
        self.weak_vals
    }

    pub fn set_weak_values(&mut self, weak: bool) {
        self.weak_vals = weak;
    }

    /// Equivalent to assignment by Lea code. If the value is nil, the mapping is deleted. Returns
    /// the old value stored with the given key or `Err(())` if the key is nil (this is not
    /// supported).
    pub fn set(&mut self, k: Value, v: Value) -> Result<Option<Value>, ()> {
        if k == Value::TNil { return Err(()); }

        if v == Value::TNil {
            Ok(self.data.remove(&k))
        } else {
            Ok(self.data.insert(k, v))
        }
    }

    pub fn get(&self, k: &Value) -> Value {
        match self.data.get(k) {
            None => Value::TNil,
            Some(&v) => v,
        }
    }
}

impl Traceable for Table {
    fn trace<T: Tracer>(&self, t: &mut T) {
        for (ref k, ref v) in &self.data {
            k.trace(t);
            v.trace(t);
        }
    }
}

impl Deref for Table {
    type Target = HashMap<Value, Value>;

    fn deref(&self) -> &<Self as Deref>::Target {
        &self.data
    }
}

impl DerefMut for Table {
    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
        &mut self.data
    }
}

macro_rules! hashmap {
    ( $($k:expr => $v:expr),* ) => {{
        let mut m = ::std::collections::HashMap::new();
        $( m.insert($k, $v); )*
        m
    }};
    ( $($k:expr => $v:expr,)* ) => {
        hashmap!($($k => $v),*)
    };
}

macro_rules! table {
    ( $($t:tt)* ) => {
        $crate::table::Table::new(hashmap!($($t)*))
    };
}

#[cfg(test)]
mod tests {
    use value::Value;

    #[test]
    fn test() {
        let mut t = table! {
            Value::TNumber(0.5.into()) => Value::TNumber(42.into()),
            Value::TBool(true) => Value::TNumber(24.into()),
        };

        assert_eq!(t.set(Value::TBool(false), Value::TNumber(123.0.into())), Ok(None));
        assert_eq!(t.data, hashmap! {
            Value::TNumber(0.5.into()) => Value::TNumber(42.into()),
            Value::TBool(true) => Value::TNumber(24.into()),
            Value::TBool(false) => Value::TNumber(123.0.into()),
        });

        assert_eq!(t.set(Value::TBool(true), Value::TNil), Ok(Some(Value::TNumber(24.into()))));
        assert_eq!(t.data, hashmap! {
            Value::TNumber(0.5.into()) => Value::TNumber(42.into()),
            Value::TBool(false) => Value::TNumber(123.0.into()),
        });

        assert_eq!(t.set(Value::TNil, Value::TNil), Err(()));
    }
}
<|endoftext|>


<commit_before>//! The "main crate" of the Rust compiler. This crate contains common
//! type definitions that are used by the other crates in the rustc
//! "family". Some prominent examples (note that each of these modules
//! has their own README with further details).
//!
//! - **HIR.** The "high-level (H) intermediate representation (IR)" is
//!   defined in the `hir` module.
//! - **MIR.** The "mid-level (M) intermediate representation (IR)" is
//!   defined in the `mir` module. This module contains only the
//!   *definition* of the MIR; the passes that transform and operate
//!   on MIR are found in `librustc_mir` crate.
//! - **Types.** The internal representation of types used in rustc is
//!   defined in the `ty` module. This includes the **type context**
//!   (or `tcx`), which is the central context during most of
//!   compilation, containing the interners and other things.
//! - **Traits.** Trait resolution is implemented in the `traits` module.
//! - **Type inference.** The type inference code can be found in the `infer` module;
//!   this code handles low-level equality and subtyping operations. The
//!   type check pass in the compiler is found in the `librustc_typeck` crate.
//!
//! For more information about how rustc works, see the [rustc guide].
//!
//! [rustc guide]: https://rust-lang.github.io/rustc-guide/
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]

#![deny(rust_2018_idioms)]
#![allow(explicit_outlives_requirements)]

#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(core_intrinsics)]
#![feature(drain_filter)]
#![cfg_attr(windows, feature(libc))]
#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(extern_types)]
#![feature(nll)]
#![feature(non_exhaustive)]
#![feature(proc_macro_internals)]
#![feature(optin_builtin_traits)]
#![feature(refcell_replace_swap)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_attrs)]
#![feature(slice_patterns)]
#![feature(specialization)]
#![feature(unboxed_closures)]
#![feature(thread_local)]
#![feature(trace_macros)]
#![feature(trusted_len)]
#![feature(vec_remove_item)]
#![feature(step_trait)]
#![feature(stmt_expr_attributes)]
#![feature(integer_atomics)]
#![feature(test)]
#![feature(in_band_lifetimes)]
#![feature(crate_visibility_modifier)]

#![recursion_limit="512"]

#![warn(elided_lifetimes_in_paths)]

#[macro_use] extern crate bitflags;
extern crate getopts;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate scoped_tls;
#[cfg(windows)]
extern crate libc;
#[macro_use] extern crate rustc_data_structures;

#[macro_use] extern crate log;
#[macro_use] extern crate syntax;

// FIXME: This import is used by deriving `RustcDecodable` and `RustcEncodable`. Removing this
// results in a bunch of "failed to resolve" errors. Hopefully, the compiler moves to serde or
// something, and we can get rid of this.
#[allow(rust_2018_idioms)]
extern crate serialize as rustc_serialize;

#[macro_use] extern crate smallvec;

// Note that librustc doesn't actually depend on these crates, see the note in
// `Cargo.toml` for this crate about why these are here.
#[allow(unused_extern_crates)]
extern crate flate2;
#[allow(unused_extern_crates)]
extern crate test;

#[macro_use]
mod macros;

// N.B., this module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;

pub mod cfg;
pub mod dep_graph;
pub mod hir;
pub mod ich;
pub mod infer;
pub mod lint;

pub mod middle {
    pub mod allocator;
    pub mod borrowck;
    pub mod expr_use_visitor;
    pub mod cstore;
    pub mod dead;
    pub mod dependency_format;
    pub mod entry;
    pub mod exported_symbols;
    pub mod free_region;
    pub mod intrinsicck;
    pub mod lib_features;
    pub mod lang_items;
    pub mod liveness;
    pub mod mem_categorization;
    pub mod privacy;
    pub mod reachable;
    pub mod region;
    pub mod recursion_limit;
    pub mod resolve_lifetime;
    pub mod stability;
    pub mod weak_lang_items;
}

pub mod mir;
pub mod session;
pub mod traits;
pub mod ty;

pub mod util {
    pub mod captures;
    pub mod common;
    pub mod ppaux;
    pub mod nodemap;
    pub mod time_graph;
    pub mod profiling;
    pub mod bug;
}

// A private module so that macro-expanded idents like
// `::rustc::lint::Lint` will also work in `rustc` itself.
//
// `libstd` uses the same trick.
#[doc(hidden)]
mod rustc {
    pub use crate::lint;
}

// FIXME(#27438): right now the unit tests of librustc don't refer to any actual
//                functions generated in librustc_data_structures (all
//                references are through generic functions), but statics are
//                referenced from time to time. Due to this bug we won't
//                actually correctly link in the statics unless we also
//                reference a function, so be sure to reference a dummy
//                function.
#[test]
fn noop() {
    rustc_data_structures::__noop_fix_for_27438();
}

// Build the diagnostics array at the end so that the metadata includes error use sites.
__build_diagnostic_array! { librustc, DIAGNOSTICS }
<commit_msg>Rollup merge of #58723 - Centril:deny-elided_lifetimes_in_paths-librustc, r=oli-obk<commit_after>//! The "main crate" of the Rust compiler. This crate contains common
//! type definitions that are used by the other crates in the rustc
//! "family". Some prominent examples (note that each of these modules
//! has their own README with further details).
//!
//! - **HIR.** The "high-level (H) intermediate representation (IR)" is
//!   defined in the `hir` module.
//! - **MIR.** The "mid-level (M) intermediate representation (IR)" is
//!   defined in the `mir` module. This module contains only the
//!   *definition* of the MIR; the passes that transform and operate
//!   on MIR are found in `librustc_mir` crate.
//! - **Types.** The internal representation of types used in rustc is
//!   defined in the `ty` module. This includes the **type context**
//!   (or `tcx`), which is the central context during most of
//!   compilation, containing the interners and other things.
//! - **Traits.** Trait resolution is implemented in the `traits` module.
//! - **Type inference.** The type inference code can be found in the `infer` module;
//!   this code handles low-level equality and subtyping operations. The
//!   type check pass in the compiler is found in the `librustc_typeck` crate.
//!
//! For more information about how rustc works, see the [rustc guide].
//!
//! [rustc guide]: https://rust-lang.github.io/rustc-guide/
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]

#![deny(rust_2018_idioms)]
#![allow(explicit_outlives_requirements)]

#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(core_intrinsics)]
#![feature(drain_filter)]
#![cfg_attr(windows, feature(libc))]
#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(extern_types)]
#![feature(nll)]
#![feature(non_exhaustive)]
#![feature(proc_macro_internals)]
#![feature(optin_builtin_traits)]
#![feature(refcell_replace_swap)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_attrs)]
#![feature(slice_patterns)]
#![feature(specialization)]
#![feature(unboxed_closures)]
#![feature(thread_local)]
#![feature(trace_macros)]
#![feature(trusted_len)]
#![feature(vec_remove_item)]
#![feature(step_trait)]
#![feature(stmt_expr_attributes)]
#![feature(integer_atomics)]
#![feature(test)]
#![feature(in_band_lifetimes)]
#![feature(crate_visibility_modifier)]

#![recursion_limit="512"]

#[macro_use] extern crate bitflags;
extern crate getopts;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate scoped_tls;
#[cfg(windows)]
extern crate libc;
#[macro_use] extern crate rustc_data_structures;

#[macro_use] extern crate log;
#[macro_use] extern crate syntax;

// FIXME: This import is used by deriving `RustcDecodable` and `RustcEncodable`. Removing this
// results in a bunch of "failed to resolve" errors. Hopefully, the compiler moves to serde or
// something, and we can get rid of this.
#[allow(rust_2018_idioms)]
extern crate serialize as rustc_serialize;

#[macro_use] extern crate smallvec;

// Note that librustc doesn't actually depend on these crates, see the note in
// `Cargo.toml` for this crate about why these are here.
#[allow(unused_extern_crates)]
extern crate flate2;
#[allow(unused_extern_crates)]
extern crate test;

#[macro_use]
mod macros;

// N.B., this module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;

pub mod cfg;
pub mod dep_graph;
pub mod hir;
pub mod ich;
pub mod infer;
pub mod lint;

pub mod middle {
    pub mod allocator;
    pub mod borrowck;
    pub mod expr_use_visitor;
    pub mod cstore;
    pub mod dead;
    pub mod dependency_format;
    pub mod entry;
    pub mod exported_symbols;
    pub mod free_region;
    pub mod intrinsicck;
    pub mod lib_features;
    pub mod lang_items;
    pub mod liveness;
    pub mod mem_categorization;
    pub mod privacy;
    pub mod reachable;
    pub mod region;
    pub mod recursion_limit;
    pub mod resolve_lifetime;
    pub mod stability;
    pub mod weak_lang_items;
}

pub mod mir;
pub mod session;
pub mod traits;
pub mod ty;

pub mod util {
    pub mod captures;
    pub mod common;
    pub mod ppaux;
    pub mod nodemap;
    pub mod time_graph;
    pub mod profiling;
    pub mod bug;
}

// A private module so that macro-expanded idents like
// `::rustc::lint::Lint` will also work in `rustc` itself.
//
// `libstd` uses the same trick.
#[doc(hidden)]
mod rustc {
    pub use crate::lint;
}

// FIXME(#27438): right now the unit tests of librustc don't refer to any actual
//                functions generated in librustc_data_structures (all
//                references are through generic functions), but statics are
//                referenced from time to time. Due to this bug we won't
//                actually correctly link in the statics unless we also
//                reference a function, so be sure to reference a dummy
//                function.
#[test]
fn noop() {
    rustc_data_structures::__noop_fix_for_27438();
}

// Build the diagnostics array at the end so that the metadata includes error use sites.
__build_diagnostic_array! { librustc, DIAGNOSTICS }
<|endoftext|>


<commit_before>use nom::is_alphanumeric;

use data::Asn1Type;
use parse::asn1_type;
use parse::space::skip_other;

named!(pub asn1_seq_of <Asn1Type>, do_parse!(
  tag!("SEQUENCE OF") >>
  opt!(skip_other) >>
  t: alt!(
    do_parse!(
      s: take_while1!(is_alphanumeric) >>
      skip_other >>
      t: asn1_type >>
      (Some(s), t)
    ) |
    do_parse!(
      t: asn1_type >>
      (None, t)
    )
  ) >>
  (Asn1Type::SeqOf(
    t.0.and_then(|s| Some(String::from_utf8(Vec::from(s)).unwrap())),
    Box::new(t.1)
  ))
));

#[test]
fn test_seq_of() {
  assert_eq!(
    Asn1Type::SeqOf(None, Box::new(Asn1Type::Integer)),
    asn1_seq_of("SEQUENCE OF INTEGER,".as_bytes()).unwrap().1
  );
  assert_eq!(
    Asn1Type::SeqOf(Some("value".into()), Box::new(Asn1Type::Type("OCTET STRING".into()))),
    asn1_seq_of("SEQUENCE OF value OCTET STRING,".as_bytes()).unwrap().1
  );
  assert!(asn1_seq_of("SEQUENCE O ".as_bytes()).is_err());
}
<commit_msg>Work around issue with alt! in seq_of<commit_after>use nom::is_alphanumeric;
use nom::space;

use data::Asn1Type;
use parse::asn1_type;
use parse::space::skip_other;

named!(pub asn1_seq_of <Asn1Type>, do_parse!(
  tag!("SEQUENCE OF") >>
  opt!(skip_other) >>
  t: alt!(
    do_parse!(
      s: take_while1!(is_alphanumeric) >>
      // FIXME: We should use skip_other here, but the alt!
      // macro call requires a more strict termination point.
      // (The second option fails otherwise).
      space >>
      t: asn1_type >>
      (Some(s), t)
    ) |
    do_parse!(
      t: asn1_type >>
      (None, t)
    )
  ) >>
  (Asn1Type::SeqOf(
    t.0.and_then(|s| Some(String::from_utf8(Vec::from(s)).unwrap())),
    Box::new(t.1)
  ))
));

#[test]
fn test_seq_of() {
  assert_eq!(
    Asn1Type::SeqOf(None, Box::new(Asn1Type::Integer)),
    asn1_seq_of("SEQUENCE OF INTEGER,".as_bytes()).unwrap().1
  );
  assert_eq!(
    Asn1Type::SeqOf(Some("value".into()), Box::new(Asn1Type::Type("OCTET STRING".into()))),
    asn1_seq_of("SEQUENCE OF value OCTET STRING,".as_bytes()).unwrap().1
  );
  assert!(asn1_seq_of("SEQUENCE O ".as_bytes()).is_err());
}
<|endoftext|>


<commit_before>/// Postings module
///
/// Postings, also called inverted lists, is the key datastructure
/// to full-text search.

mod postings;
mod recorder;
mod serializer;
mod postings_writer;
mod term_info;
mod chained_postings;
mod vec_postings;
mod segment_postings;
mod intersection;
mod offset_postings;
mod freq_handler;
mod docset;
mod segment_postings_option;

pub use self::docset::{SkipResult, DocSet};
pub use self::offset_postings::OffsetPostings;
pub use self::recorder::{Recorder, NothingRecorder, TermFrequencyRecorder, TFAndPositionRecorder};
pub use self::serializer::PostingsSerializer;
pub use self::postings_writer::PostingsWriter;
pub use self::postings_writer::SpecializedPostingsWriter;
pub use self::term_info::TermInfo;
pub use self::postings::Postings;

#[cfg(test)]
pub use self::vec_postings::VecPostings;
pub use self::chained_postings::ChainedPostings;
pub use self::segment_postings::SegmentPostings;
pub use self::intersection::IntersectionDocSet;
pub use self::freq_handler::FreqHandler;

pub use self::segment_postings_option::SegmentPostingsOption;
pub use common::HasLen;

#[cfg(test)]
mod tests {

    use super::*;
    use schema::{Document, TEXT, SchemaBuilder, Term};
    use core::SegmentComponent;
    use indexer::SegmentWriter;
    use core::SegmentReader;
    use core::Index;
    use std::iter;
    use datastruct::stacker::Heap;
    use query::TermQuery;

    #[test]
    pub fn test_position_write() {
        let mut schema_builder = SchemaBuilder::default();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        let mut segment = index.new_segment();
        let mut posting_serializer = PostingsSerializer::open(&mut segment).unwrap();
        let term = Term::from_field_text(text_field, "abc");
        posting_serializer.new_term(&term, 3).unwrap();
        for doc_id in 0u32..3u32 {
            let positions = vec!(1,2,3,2);
            posting_serializer.write_doc(doc_id, 2, &positions).unwrap();
        }
        posting_serializer.close_term().unwrap();
        posting_serializer.close().unwrap();
        let read = segment.open_read(SegmentComponent::POSITIONS).unwrap();
        assert_eq!(read.len(), 13);
    }

    #[test]
    pub fn test_position_and_fieldnorm() {
        let mut schema_builder = SchemaBuilder::default();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema.clone());
        let segment = index.new_segment();
        let heap = Heap::with_capacity(10_000_000);
        {
            let mut segment_writer = SegmentWriter::for_segment(&heap, segment.clone(), &schema).unwrap();
            {
                let mut doc = Document::default();
                doc.add_text(text_field, "a b a c a d a a.");
                doc.add_text(text_field, "d d d d a"); // checking that position works if the field has two values.
                segment_writer.add_document(&doc, &schema).unwrap();
            }
            {
                let mut doc = Document::default();
                doc.add_text(text_field, "b a");
                segment_writer.add_document(&doc, &schema).unwrap();
            }
            for i in 2..1000 {
                let mut doc = Document::default();
                let mut text = iter::repeat("e ").take(i).collect::<String>();
                text.push_str(" a");
                doc.add_text(text_field, &text);
                segment_writer.add_document(&doc, &schema).unwrap();
            }
            segment_writer.finalize().unwrap();
        }
        {
            let segment_reader = SegmentReader::open(segment).unwrap();
            {
                let fieldnorm_reader = segment_reader.get_fieldnorms_reader(text_field).unwrap();
                assert_eq!(fieldnorm_reader.get(0), 8 + 5);
                assert_eq!(fieldnorm_reader.get(1), 2);
                for i in 2 .. 1000 {
                    assert_eq!(fieldnorm_reader.get(i), i + 1);
                }
            }
            {
                let term_a = Term::from_field_text(text_field, "abcdef");
                assert!(segment_reader.read_postings_all_info(&term_a).is_none());
            }
            {
                let term_a = Term::from_field_text(text_field, "a");
                let mut postings_a = segment_reader.read_postings_all_info(&term_a).unwrap();
                assert_eq!(postings_a.len(), 1000);
                assert!(postings_a.advance());
                assert_eq!(postings_a.doc(), 0);
                assert_eq!(postings_a.term_freq(), 6);
                assert_eq!(postings_a.positions(), [0, 2, 4, 6, 7, 13]);
                assert!(postings_a.advance());
                assert_eq!(postings_a.doc(), 1u32);
                assert_eq!(postings_a.term_freq(), 1);
                for i in 2u32 .. 1000u32 {
                    assert!(postings_a.advance());
                    assert_eq!(postings_a.term_freq(), 1);
                    assert_eq!(postings_a.positions(), [i]);
                    assert_eq!(postings_a.doc(), i);
                }
                assert!(!postings_a.advance());
            }
            {
                let term_e = Term::from_field_text(text_field, "e");
                let mut postings_e = segment_reader.read_postings_all_info(&term_e).unwrap();
                assert_eq!(postings_e.len(), 1000 - 2);
                for i in 2u32 .. 1000u32 {
                    assert!(postings_e.advance());
                    assert_eq!(postings_e.term_freq(), i);
                    let positions = postings_e.positions();
                    assert_eq!(positions.len(), i as usize);
                    for j in 0..positions.len() {
                        assert_eq!(positions[j], (j as u32));
                    }
                    assert_eq!(postings_e.doc(), i);
                }
                assert!(!postings_e.advance());
            }
        }
    }

    #[test]
    pub fn test_position_and_fieldnorm2() {
        let mut schema_builder = SchemaBuilder::default();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        {
            let mut index_writer = index.writer_with_num_threads(1, 40_000_000).unwrap();
            {
                let mut doc = Document::default();
                doc.add_text(text_field, "g b b d c g c");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::default();
                doc.add_text(text_field, "g a b b a d c g c");
                index_writer.add_document(doc).unwrap();
            }
            assert!(index_writer.commit().is_ok());
        }
        let term_query = TermQuery::from(Term::from_field_text(text_field, "a"));
        let searcher = index.searcher();
        let mut term_weight = term_query.specialized_weight(&*searcher);
        term_weight.segment_postings_options = SegmentPostingsOption::FreqAndPositions;
        let segment_reader = &searcher.segment_readers()[0];
        let mut term_scorer = term_weight.specialized_scorer(segment_reader).unwrap();
        assert!(term_scorer.advance());
        assert_eq!(term_scorer.doc(), 1u32);
        assert_eq!(term_scorer.postings().positions(), &[1u32, 4]);
    }

    #[test]
    fn test_intersection() {
        {
            let left = VecPostings::from(vec!(1, 3, 9));
            let right = VecPostings::from(vec!(3, 4, 9, 18));
            let mut intersection = IntersectionDocSet::from(vec!(left, right));
            assert!(intersection.advance());
            assert_eq!(intersection.doc(), 3);
            assert!(intersection.advance());
            assert_eq!(intersection.doc(), 9);
            assert!(!intersection.advance());
        }
        {
            let a = VecPostings::from(vec!(1, 3, 9));
            let b = VecPostings::from(vec!(3, 4, 9, 18));
            let c = VecPostings::from(vec!(1, 5, 9, 111));
            let mut intersection = IntersectionDocSet::from(vec!(a, b, c));
            assert!(intersection.advance());
            assert_eq!(intersection.doc(), 9);
            assert!(!intersection.advance());
        }
    }

}
<commit_msg>NOBUG Added Bench for segment postings.<commit_after>/// Postings module
///
/// Postings, also called inverted lists, is the key datastructure
/// to full-text search.

mod postings;
mod recorder;
mod serializer;
mod postings_writer;
mod term_info;
mod chained_postings;
mod vec_postings;
mod segment_postings;
mod intersection;
mod offset_postings;
mod freq_handler;
mod docset;
mod segment_postings_option;

pub use self::docset::{SkipResult, DocSet};
pub use self::offset_postings::OffsetPostings;
pub use self::recorder::{Recorder, NothingRecorder, TermFrequencyRecorder, TFAndPositionRecorder};
pub use self::serializer::PostingsSerializer;
pub use self::postings_writer::PostingsWriter;
pub use self::postings_writer::SpecializedPostingsWriter;
pub use self::term_info::TermInfo;
pub use self::postings::Postings;

#[cfg(test)]
pub use self::vec_postings::VecPostings;
pub use self::chained_postings::ChainedPostings;
pub use self::segment_postings::SegmentPostings;
pub use self::intersection::IntersectionDocSet;
pub use self::freq_handler::FreqHandler;

pub use self::segment_postings_option::SegmentPostingsOption;
pub use common::HasLen;

#[cfg(test)]
mod tests {

    use super::*;
    use schema::{Document, TEXT, STRING, SchemaBuilder, Term};
    use core::SegmentComponent;
    use indexer::SegmentWriter;
    use core::SegmentReader;
    use core::Index;
    use std::iter;
    use datastruct::stacker::Heap;
    use query::TermQuery;
    use schema::Field;
    use test::Bencher;
    use rand::{XorShiftRng, Rng, SeedableRng};

    #[test]
    pub fn test_position_write() {
        let mut schema_builder = SchemaBuilder::default();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        let mut segment = index.new_segment();
        let mut posting_serializer = PostingsSerializer::open(&mut segment).unwrap();
        let term = Term::from_field_text(text_field, "abc");
        posting_serializer.new_term(&term, 3).unwrap();
        for doc_id in 0u32..3u32 {
            let positions = vec!(1,2,3,2);
            posting_serializer.write_doc(doc_id, 2, &positions).unwrap();
        }
        posting_serializer.close_term().unwrap();
        posting_serializer.close().unwrap();
        let read = segment.open_read(SegmentComponent::POSITIONS).unwrap();
        assert_eq!(read.len(), 13);
    }

    #[test]
    pub fn test_position_and_fieldnorm() {
        let mut schema_builder = SchemaBuilder::default();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema.clone());
        let segment = index.new_segment();
        let heap = Heap::with_capacity(10_000_000);
        {
            let mut segment_writer = SegmentWriter::for_segment(&heap, segment.clone(), &schema).unwrap();
            {
                let mut doc = Document::default();
                doc.add_text(text_field, "a b a c a d a a.");
                doc.add_text(text_field, "d d d d a"); // checking that position works if the field has two values.
                segment_writer.add_document(&doc, &schema).unwrap();
            }
            {
                let mut doc = Document::default();
                doc.add_text(text_field, "b a");
                segment_writer.add_document(&doc, &schema).unwrap();
            }
            for i in 2..1000 {
                let mut doc = Document::default();
                let mut text = iter::repeat("e ").take(i).collect::<String>();
                text.push_str(" a");
                doc.add_text(text_field, &text);
                segment_writer.add_document(&doc, &schema).unwrap();
            }
            segment_writer.finalize().unwrap();
        }
        {
            let segment_reader = SegmentReader::open(segment).unwrap();
            {
                let fieldnorm_reader = segment_reader.get_fieldnorms_reader(text_field).unwrap();
                assert_eq!(fieldnorm_reader.get(0), 8 + 5);
                assert_eq!(fieldnorm_reader.get(1), 2);
                for i in 2 .. 1000 {
                    assert_eq!(fieldnorm_reader.get(i), i + 1);
                }
            }
            {
                let term_a = Term::from_field_text(text_field, "abcdef");
                assert!(segment_reader.read_postings_all_info(&term_a).is_none());
            }
            {
                let term_a = Term::from_field_text(text_field, "a");
                let mut postings_a = segment_reader.read_postings_all_info(&term_a).unwrap();
                assert_eq!(postings_a.len(), 1000);
                assert!(postings_a.advance());
                assert_eq!(postings_a.doc(), 0);
                assert_eq!(postings_a.term_freq(), 6);
                assert_eq!(postings_a.positions(), [0, 2, 4, 6, 7, 13]);
                assert!(postings_a.advance());
                assert_eq!(postings_a.doc(), 1u32);
                assert_eq!(postings_a.term_freq(), 1);
                for i in 2u32 .. 1000u32 {
                    assert!(postings_a.advance());
                    assert_eq!(postings_a.term_freq(), 1);
                    assert_eq!(postings_a.positions(), [i]);
                    assert_eq!(postings_a.doc(), i);
                }
                assert!(!postings_a.advance());
            }
            {
                let term_e = Term::from_field_text(text_field, "e");
                let mut postings_e = segment_reader.read_postings_all_info(&term_e).unwrap();
                assert_eq!(postings_e.len(), 1000 - 2);
                for i in 2u32 .. 1000u32 {
                    assert!(postings_e.advance());
                    assert_eq!(postings_e.term_freq(), i);
                    let positions = postings_e.positions();
                    assert_eq!(positions.len(), i as usize);
                    for j in 0..positions.len() {
                        assert_eq!(positions[j], (j as u32));
                    }
                    assert_eq!(postings_e.doc(), i);
                }
                assert!(!postings_e.advance());
            }
        }
    }

    #[test]
    pub fn test_position_and_fieldnorm2() {
        let mut schema_builder = SchemaBuilder::default();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        {
            let mut index_writer = index.writer_with_num_threads(1, 40_000_000).unwrap();
            {
                let mut doc = Document::default();
                doc.add_text(text_field, "g b b d c g c");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::default();
                doc.add_text(text_field, "g a b b a d c g c");
                index_writer.add_document(doc).unwrap();
            }
            assert!(index_writer.commit().is_ok());
        }
        let term_query = TermQuery::from(Term::from_field_text(text_field, "a"));
        let searcher = index.searcher();
        let mut term_weight = term_query.specialized_weight(&*searcher);
        term_weight.segment_postings_options = SegmentPostingsOption::FreqAndPositions;
        let segment_reader = &searcher.segment_readers()[0];
        let mut term_scorer = term_weight.specialized_scorer(segment_reader).unwrap();
        assert!(term_scorer.advance());
        assert_eq!(term_scorer.doc(), 1u32);
        assert_eq!(term_scorer.postings().positions(), &[1u32, 4]);
    }

    #[test]
    fn test_intersection() {
        {
            let left = VecPostings::from(vec!(1, 3, 9));
            let right = VecPostings::from(vec!(3, 4, 9, 18));
            let mut intersection = IntersectionDocSet::from(vec!(left, right));
            assert!(intersection.advance());
            assert_eq!(intersection.doc(), 3);
            assert!(intersection.advance());
            assert_eq!(intersection.doc(), 9);
            assert!(!intersection.advance());
        }
        {
            let a = VecPostings::from(vec!(1, 3, 9));
            let b = VecPostings::from(vec!(3, 4, 9, 18));
            let c = VecPostings::from(vec!(1, 5, 9, 111));
            let mut intersection = IntersectionDocSet::from(vec!(a, b, c));
            assert!(intersection.advance());
            assert_eq!(intersection.doc(), 9);
            assert!(!intersection.advance());
        }
    }

    lazy_static! {
        static ref TERM_A: Term = {
            let field = Field(0);
            Term::from_field_text(field, "a")
        };
        static ref TERM_B: Term = {
            let field = Field(0);
            Term::from_field_text(field, "b")
        };
        static ref INDEX: Index = {
            let mut schema_builder = SchemaBuilder::default();
            let text_field = schema_builder.add_text_field("text", STRING);
            let schema = schema_builder.build();

            let seed: &[u32; 4] = &[1, 2, 3, 4];
            let mut rng: XorShiftRng = XorShiftRng::from_seed(*seed);

            let index = Index::create_in_ram(schema);
            {
                let mut index_writer = index.writer_with_num_threads(1, 40_000_000).unwrap();
                for _ in 0 .. 15_000_000 {
                    let mut doc = Document::default();
                    if rng.gen_weighted_bool(15) {
                        doc.add_text(text_field, "a");
                    }
                    if rng.gen_weighted_bool(10) {
                        doc.add_text(text_field, "b");
                    }
                    index_writer.add_document(doc).unwrap();
                }
                assert!(index_writer.commit().is_ok());
            }
            index
        };
    }

    #[bench]
    fn bench_segment_postings(b: &mut Bencher) {
        let searcher = INDEX.searcher();
        let segment_reader = searcher.segment_reader(0);

        b.iter(|| {
            let mut segment_postings = segment_reader.read_postings(&*TERM_A, SegmentPostingsOption::NoFreq).unwrap();
            while segment_postings.advance() {}
        });
    }

    #[bench]
    fn bench_segment_intersection(b: &mut Bencher) {
        let searcher = INDEX.searcher();
        let segment_reader = searcher.segment_reader(0);

        b.iter(|| {
            let segment_postings_a = segment_reader.read_postings(&*TERM_A, SegmentPostingsOption::NoFreq).unwrap();
            let segment_postings_b = segment_reader.read_postings(&*TERM_B, SegmentPostingsOption::NoFreq).unwrap();
            let mut intersection = IntersectionDocSet::from(vec!(segment_postings_a, segment_postings_b));
            while intersection.advance() {}
        });
    }
}
<|endoftext|>


<commit_before>#![feature(core)]

extern crate "bootstrap-rs" as bootstrap;
extern crate gl;

use bootstrap::window::Window;

mod render;
mod gl_render;

struct MainWindow
{
    close: bool
}

fn main() {
    let mut main_window = MainWindow {
        close: false
    };

    println!("initializing bootstrap");
    let instance = bootstrap::init();

    println!("creating window");
    let mut window = Window::new("Rust Window", instance);

    gl_render::init(&window);
    gl_render::gl_test();

    loop {
        window.handle_messages();

        // handle messages
        loop {
            match window.next_message() {
                Some(message) => println!("message: {:?}", message),
                None => break
            }
        }

        if main_window.close {
            break;
        }
    };
}
<commit_msg>Close Window - Close messages are now handled, so the application stops when you try to close the window.<commit_after>#![feature(core)]

extern crate "bootstrap-rs" as bootstrap;
extern crate gl;

use bootstrap::window::{Window, Message};
use bootstrap::window::Message::*;

mod render;
mod gl_render;

struct MainWindow
{
    close: bool
}

fn main() {
    let mut main_window = MainWindow {
        close: false
    };

    println!("initializing bootstrap");
    let instance = bootstrap::init();

    println!("creating window");
    let mut window = Window::new("Rust Window", instance);

    gl_render::init(&window);
    gl_render::gl_test();

    loop {
        window.handle_messages();

        // handle messages
        loop {
            match window.next_message() {
                Some(message) => {
                    println!("message: {:?}", message);
                    match message {
                        Activate => (),
                        Close => main_window.close = true,
                        Destroy => (),
                        Paint => ()
                    }
                },
                None => break
            }
        }

        if main_window.close {
            break;
        }
    };
}
<|endoftext|>


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

extern crate cgmath;
#[macro_use]
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate time;
extern crate rand;
extern crate genmesh;
extern crate noise;

use rand::Rng;
use cgmath::FixedArray;
use cgmath::{Matrix4, Point3, Vector3};
use cgmath::{Transform, AffineMatrix3};
use gfx::traits::{Device, Stream, ToIndexSlice, ToSlice, FactoryExt};
use genmesh::{Vertices, Triangulate};
use genmesh::generators::{Plane, SharedVertex, IndexedPolygon};
use time::precise_time_s;

use noise::{Seed, perlin2};

gfx_vertex!( Vertex {
    a_Pos@ pos: [f32; 3],
    a_Color@ color: [f32; 3],
});

gfx_parameters!( Params {
    u_Model@ model: [[f32; 4]; 4],
    u_View@ view: [[f32; 4]; 4],
    u_Proj@ proj: [[f32; 4]; 4],
});

fn calculate_color(height: f32) -> [f32; 3] {
    if height > 8.0 {
        [0.9, 0.9, 0.9] // white
    } else if height > 0.0 {
        [0.7, 0.7, 0.7] // greay
    } else if height > -5.0 {
        [0.2, 0.7, 0.2] // green
    } else {
        [0.2, 0.2, 0.7] // blue
    }
}

pub fn main() {
    let (mut stream, mut device, mut factory) = gfx_window_glutin::init(
        glutin::Window::new().unwrap());
    stream.out.window.set_title("Terrain example");

    let rand_seed = rand::thread_rng().gen();
    let seed = Seed::new(rand_seed);
    let plane = Plane::subdivide(256, 256);
    let vertex_data: Vec<Vertex> = plane.shared_vertex_iter()
        .map(|(x, y)| {
            let h = perlin2(&seed, &[x, y]) * 32.0;
            Vertex {
                pos: [25.0 * x, 25.0 * y, h],
                color: calculate_color(h),
            }
        })
        .collect();

    let index_data: Vec<u32> = plane.indexed_polygon_iter()
        .triangulate()
        .vertices()
        .map(|i| i as u32)
        .collect();
    let slice = index_data.to_slice(&mut factory, gfx::PrimitiveType::TriangleList);

    let mesh = factory.create_mesh(&vertex_data);
    let program = {
        let vs = gfx::ShaderSource {
            glsl_120: Some(include_bytes!("terrain_120.glslv")),
            glsl_150: Some(include_bytes!("terrain_150.glslv")),
            .. gfx::ShaderSource::empty()
        };
        let fs = gfx::ShaderSource {
            glsl_120: Some(include_bytes!("terrain_120.glslf")),
            glsl_150: Some(include_bytes!("terrain_150.glslf")),
            .. gfx::ShaderSource::empty()
        };
        factory.link_program_source(vs, fs).unwrap()
    };

    let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

    let data = Params {
        model: Matrix4::identity().into_fixed(),
        view: Matrix4::identity().into_fixed(),
        proj: cgmath::perspective(cgmath::deg(60.0f32),
                                  stream.get_aspect_ratio(),
                                  0.1, 1000.0
                                  ).into_fixed(),
        _r: std::marker::PhantomData,
    };
    let mut context = gfx::batch::Context::new();
    let mut batch = context.make_batch(&program, data, &mesh, slice, &state)
                           .unwrap();

    'main: loop {
        // quit when Esc is pressed.
        for event in stream.out.window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) => break 'main,
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        let time = precise_time_s() as f32;
        let x = time.sin();
        let y = time.cos();
        let view: AffineMatrix3<f32> = Transform::look_at(
            &Point3::new(x * 32.0, y * 32.0, 16.0),
            &Point3::new(0.0, 0.0, 0.0),
            &Vector3::unit_z(),
        );
        batch.params.view = view.mat.into_fixed();

        stream.clear(gfx::ClearData {
            color: [0.3, 0.3, 0.3, 1.0],
            depth: 1.0,
            stencil: 0,
        });
        stream.draw(&(&batch, &context)).unwrap();
        stream.present(&mut device);
    }
}
<commit_msg>Fixed the terrain<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate cgmath;
#[macro_use]
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate time;
extern crate rand;
extern crate genmesh;
extern crate noise;

use rand::Rng;
use cgmath::FixedArray;
use cgmath::{Matrix4, Point3, Vector3};
use cgmath::{Transform, AffineMatrix3};
use gfx::traits::{Stream, ToIndexSlice, ToSlice, FactoryExt};
use genmesh::{Vertices, Triangulate};
use genmesh::generators::{Plane, SharedVertex, IndexedPolygon};
use time::precise_time_s;

use noise::{Seed, perlin2};

gfx_vertex!( Vertex {
    a_Pos@ pos: [f32; 3],
    a_Color@ color: [f32; 3],
});

gfx_parameters!( Params {
    u_Model@ model: [[f32; 4]; 4],
    u_View@ view: [[f32; 4]; 4],
    u_Proj@ proj: [[f32; 4]; 4],
});

fn calculate_color(height: f32) -> [f32; 3] {
    if height > 8.0 {
        [0.9, 0.9, 0.9] // white
    } else if height > 0.0 {
        [0.7, 0.7, 0.7] // greay
    } else if height > -5.0 {
        [0.2, 0.7, 0.2] // green
    } else {
        [0.2, 0.2, 0.7] // blue
    }
}

pub fn main() {
    let (mut stream, mut device, mut factory) = gfx_window_glutin::init(
        glutin::Window::new().unwrap());
    stream.out.window.set_title("Terrain example");

    let rand_seed = rand::thread_rng().gen();
    let seed = Seed::new(rand_seed);
    let plane = Plane::subdivide(256, 256);
    let vertex_data: Vec<Vertex> = plane.shared_vertex_iter()
        .map(|(x, y)| {
            let h = perlin2(&seed, &[x, y]) * 32.0;
            Vertex {
                pos: [25.0 * x, 25.0 * y, h],
                color: calculate_color(h),
            }
        })
        .collect();

    let index_data: Vec<u32> = plane.indexed_polygon_iter()
        .triangulate()
        .vertices()
        .map(|i| i as u32)
        .collect();
    let slice = index_data.to_slice(&mut factory, gfx::PrimitiveType::TriangleList);

    let mesh = factory.create_mesh(&vertex_data);
    let program = {
        let vs = gfx::ShaderSource {
            glsl_120: Some(include_bytes!("terrain_120.glslv")),
            glsl_150: Some(include_bytes!("terrain_150.glslv")),
            .. gfx::ShaderSource::empty()
        };
        let fs = gfx::ShaderSource {
            glsl_120: Some(include_bytes!("terrain_120.glslf")),
            glsl_150: Some(include_bytes!("terrain_150.glslf")),
            .. gfx::ShaderSource::empty()
        };
        factory.link_program_source(vs, fs).unwrap()
    };

    let data = Params {
        model: Matrix4::identity().into_fixed(),
        view: Matrix4::identity().into_fixed(),
        proj: cgmath::perspective(cgmath::deg(60.0f32),
                                  stream.get_aspect_ratio(),
                                  0.1, 1000.0
                                  ).into_fixed(),
        _r: std::marker::PhantomData,
    };
    let mut batch = gfx::batch::Full::new(mesh, program, data)
                                     .unwrap();
    batch.slice = slice;
    batch.state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

    'main: loop {
        // quit when Esc is pressed.
        for event in stream.out.window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) => break 'main,
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        let time = precise_time_s() as f32;
        let x = time.sin();
        let y = time.cos();
        let view: AffineMatrix3<f32> = Transform::look_at(
            &Point3::new(x * 32.0, y * 32.0, 16.0),
            &Point3::new(0.0, 0.0, 0.0),
            &Vector3::unit_z(),
        );
        batch.param.view = view.mat.into_fixed();

        stream.clear(gfx::ClearData {
            color: [0.3, 0.3, 0.3, 1.0],
            depth: 1.0,
            stencil: 0,
        });
        stream.draw(&batch).unwrap();
        stream.present(&mut device);
    }
}
<|endoftext|>


<commit_before>use kernel32;
use Lib;
use winapi::DWORD;
use Symbol;

#[test]
fn works_getlasterror() {
    let lib = Lib::new("kernel32.dll").unwrap();
    let gle = unsafe {
        lib.find_func::<extern "system" fn() -> DWORD>(b"GetLastError").unwrap()
    };
    unsafe {
        kernel32::SetLastError(42);
        assert_eq!(kernel32::GetLastError(), gle.get()())
    }
}

#[test]
fn works_getlasterror0() {
    let lib = Lib::new("kernel32.dll").unwrap();
    let gle = unsafe {
        lib.find_func::<extern "system" fn() -> DWORD>(b"GetLastError").unwrap()
    };
    unsafe {
        kernel32::SetLastError(42);
        assert_eq!(kernel32::GetLastError(), gle.get()())
    }
}

#[test]
fn fails_new_kernel23() {
    Lib::new("kernel23").err().unwrap();
}
<commit_msg>Clean up windows tests.<commit_after>use Func;
use kernel32;
use Lib;
use winapi::DWORD;
use Symbol;

#[test]
fn works_getlasterror() {
    let lib = Lib::new("kernel32.dll").unwrap();
    let gle: Func<extern "system" fn() -> DWORD> = unsafe {
        lib.find_func("GetLastError\0").unwrap()
    };
    unsafe {
        kernel32::SetLastError(42);
        assert_eq!(kernel32::GetLastError(), gle.get()())
    }
}

#[test]
fn works_getlasterror0() {
    let lib = Lib::new("kernel32.dll").unwrap();
    let gle: Func<extern "system" fn() -> DWORD> = unsafe {
        lib.find_func("GetLastError\0").unwrap()
    };
    unsafe {
        kernel32::SetLastError(42);
        assert_eq!(kernel32::GetLastError(), gle.get()())
    }
}

#[test]
fn fails_new_kernel23() {
    Lib::new("kernel23").err().unwrap();
}
<|endoftext|>


<commit_before>use bencode::BEncode;
use std::path::PathBuf;
use std::collections::{HashMap, BTreeMap};
use std::{fmt, cmp};
use url::Url;
use ring::digest;
use util::hash_to_id;
use disk;

#[derive(Serialize, Deserialize, Clone)]
pub struct Info {
    pub name: String,
    pub announce: String,
    pub piece_len: u32,
    pub total_len: u64,
    pub hashes: Vec<Vec<u8>>,
    pub hash: [u8; 20],
    pub files: Vec<File>,
    pub file_idx: HashMap<PathBuf, usize>,
    pub private: bool,
    pub be_name: Option<Vec<u8>>,
}

impl fmt::Debug for Info {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Torrent Info {{
                name: {:?},
                announce: {:?},
                piece_len: {:?},
                total_len: {:?},
                hash: {:?},
                files: {:?}
            }}",
            self.name,
            self.announce,
            self.piece_len,
            self.total_len,
            hash_to_id(&self.hash),
            self.files
        )
    }
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct File {
    pub path: PathBuf,
    pub length: u64,
}

impl File {
    fn from_bencode(data: BEncode) -> Result<File, &'static str> {
        let mut d = data.into_dict().ok_or("File must be a dictionary type!")?;
        match (d.remove("name"), d.remove("path"), d.remove("length")) {
            (Some(v), None, Some(l)) => {
                let f = File {
                    path: PathBuf::from(v.into_string().ok_or("Path must be a valid string.")?),
                    length: l.into_int().ok_or("File length must be a valid int")? as u64,
                };
                Ok(f)
            }
            (None, Some(path), Some(l)) => {
                let mut p = PathBuf::new();
                for dir in path.into_list().ok_or("File path should be a list")? {
                    p.push(
                        dir.into_string().ok_or("File path parts should be strings")?,
                    );
                }
                let f = File {
                    path: p,
                    length: l.into_int().ok_or("File length must be a valid int")? as u64,
                };
                Ok(f)
            }
            _ => Err("File dict must contain length and name or path"),
        }
    }
}

impl Info {
    pub fn from_magnet(data: &str) -> Result<Info, &'static str> {
        let url = match Url::parse(data) {
            Ok(u) => u,
            Err(_) => return Err("Failed to parse magnet URL!"),
        };

        if url.scheme() != "magnet" {
            return Err("magnet URL must use magnet scheme");
        };
        // TODO: Actually implmeent this
        unimplemented!();
    }

    pub fn to_bencode(&self) -> BEncode {
        let mut torrent = BTreeMap::new();
        let mut info = BTreeMap::new();
        torrent.insert(
            "announce".to_owned(),
            BEncode::String(self.announce.clone().into_bytes()),
        );
        if let Some(ref n) = self.be_name {
            info.insert("name".to_owned(), BEncode::String(n.clone()));
        }
        info.insert(
            "piece length".to_owned(),
            BEncode::Int(self.piece_len as i64),
        );
        let mut pieces = Vec::with_capacity(self.hashes.len() * 20);
        for h in &self.hashes {
            pieces.extend_from_slice(h);
        }
        info.insert("piece".to_owned(), BEncode::String(pieces));
        if self.files.len() == 1 {
            info.insert(
                "length".to_owned(),
                BEncode::Int(self.files[0].length as i64),
            );
            // This is pretty awful, but we guarantee utf8 on creation, so should be fine.
            info.insert(
                "path".to_owned(),
                BEncode::String(
                    self.files[0]
                        .path
                        .clone()
                        .into_os_string()
                        .into_string()
                        .unwrap()
                        .into_bytes(),
                ),
            );
        } else {
            let files = self.files
                .iter()
                .map(|f| {
                    let mut fb = BTreeMap::new();
                    fb.insert("length".to_owned(), BEncode::Int(f.length as i64));
                    fb.insert(
                        "path".to_owned(),
                        BEncode::String(
                            f.path
                                .clone()
                                .into_os_string()
                                .into_string()
                                .unwrap()
                                .into_bytes(),
                        ),
                    );
                    BEncode::Dict(fb)
                })
                .collect();
            info.insert("files".to_owned(), BEncode::List(files));
        }
        torrent.insert("info".to_owned(), BEncode::Dict(info));
        BEncode::Dict(torrent)
    }

    pub fn from_bencode(data: BEncode) -> Result<Info, &'static str> {
        data.into_dict()
            .and_then(|mut d| {
                d.remove("info").and_then(|i| i.into_dict()).map(|i| (d, i))
            })
            .ok_or("invalid info field")
            .and_then(|(mut d, mut i)| {
                let mut info_bytes = Vec::new();
                BEncode::Dict(i.clone()).encode(&mut info_bytes).unwrap();
                let mut ctx = digest::Context::new(&digest::SHA1);
                ctx.update(&info_bytes[..]);
                let digest = ctx.finish();
                let mut hash = [0u8; 20];
                hash.copy_from_slice(digest.as_ref());

                let a = d.remove("announce").and_then(|a| a.into_string()).ok_or(
                    "Info must have announce url",
                )?;
                let pl = i.remove("piece length").and_then(|i| i.into_int()).ok_or(
                    "Info must specify piece length",
                )?;
                let hashes = i.remove("pieces")
                    .and_then(|p| p.into_bytes())
                    .map(|mut p| {
                        let mut v = Vec::new();
                        while !p.is_empty() {
                            let remaining = p.split_off(20);
                            v.push(p);
                            p = remaining;
                        }
                        v
                    })
                    .ok_or("Info must provide valid hashes")?;

                let private = if let Some(v) = i.remove("private") {
                    v.into_int()
                        .and_then(|p| if p == 1 { Some(true) } else { None })
                        .ok_or("private key must be an integer equal to 1 if present!")?
                } else {
                    false
                };

                let be_name = if let Some(v) = i.remove("name") {
                    Some(v.into_bytes().ok_or("name field must be a bitstring!")?)
                } else {
                    None
                };

                let files = parse_bencode_files(i)?;
                let name = if files.is_empty() {
                    files[0]
                        .path
                        .clone()
                        .into_os_string()
                        .into_string()
                        .map_err(|_| "Only UTF8 paths are accepted")?
                } else if !files[0].path.has_root() {
                    let mut piter = files[0].path.components();
                    piter
                        .next()
                        .unwrap()
                        .as_os_str()
                        .to_os_string()
                        .into_string()
                        .map_err(|_| "Only UTF8 paths are accepted")?
                } else {
                    unreachable!();
                };

                let mut file_idx = HashMap::new();
                for (i, file) in files.iter().enumerate() {
                    file_idx.insert(file.path.clone(), i);
                }
                let total_len = files.iter().map(|f| f.length).sum();
                Ok(Info {
                    name,
                    announce: a,
                    piece_len: pl as u32,
                    hashes,
                    hash,
                    files,
                    file_idx,
                    total_len,
                    private,
                    be_name,
                })
            })
    }

    #[cfg(test)]
    pub fn with_pieces(pieces: usize) -> Info {
        Info {
            name: String::from(""),
            announce: String::from(""),
            piece_len: 16_384,
            total_len: 16_384 * pieces as u64,
            hashes: vec![vec![0u8]; pieces],
            hash: [0u8; 20],
            files: vec![],
            file_idx: HashMap::new(),
            private: false,
            be_name: None,
        }
    }

    pub fn block_len(&self, idx: u32, offset: u32) -> u32 {
        if idx != self.pieces() - 1 {
            16_384
        } else {
            let last_piece_len =
                (self.total_len - self.piece_len as u64 * (self.pieces() as u64 - 1)) as u32;
            // Note this is not the real last block len, just what it will be IF the offset really
            // is for the last block
            let last_block_len = last_piece_len - offset;
            if offset < last_piece_len && last_block_len <= 16_384 {
                last_block_len
            } else {
                16_384
            }
        }
    }

    pub fn piece_len(&self, idx: u32) -> u32 {
        if idx != self.pieces() - 1 {
            self.piece_len
        } else {
            (self.total_len - self.piece_len as u64 * (self.pieces() as u64 - 1)) as u32
        }
    }

    pub fn pieces(&self) -> u32 {
        self.hashes.len() as u32
    }

    /// Calculates the file offsets for a given block at index/begin
    pub fn block_disk_locs(&self, index: u32, begin: u32) -> Vec<disk::Location> {
        let len = self.block_len(index, begin);
        self.calc_disk_locs(index, begin, len)
    }

    /// Calculates the file offsets for a given piece at index
    pub fn piece_disk_locs(&self, index: u32) -> Vec<disk::Location> {
        let len = self.piece_len(index);
        self.calc_disk_locs(index, 0, len)
    }

    /// Calculates the file offsets for a given index, begin, and block length.
    fn calc_disk_locs(&self, index: u32, begin: u32, len: u32) -> Vec<disk::Location> {
        let mut len = len as u64;
        // The absolute byte offset where we start processing data.
        let mut cur_start = index as u64 * self.piece_len as u64 + begin as u64;
        // Current index of the data block we're writing
        let mut data_start = 0;
        // The current file end length.
        let mut fidx = 0;
        // Iterate over all file lengths, if we find any which end a bigger
        // idx than cur_start, write from cur_start..cur_start + file_write_len for that file
        // and continue if we're now at the end of the file.
        let mut locs = Vec::new();
        for f in &self.files {
            fidx += f.length;
            if cur_start < fidx {
                let file_write_len = cmp::min(fidx - cur_start, len);
                let offset = cur_start - (fidx - f.length);
                if file_write_len == len {
                    // The file is longer than our len, just write to it,
                    // exit loop
                    locs.push(disk::Location::new(
                        f.path.clone(),
                        offset,
                        data_start,
                        data_start + file_write_len,
                    ));
                    break;
                } else {
                    // Write to the end of file, continue
                    locs.push(disk::Location::new(
                        f.path.clone(),
                        offset,
                        data_start,
                        data_start + file_write_len,
                    ));
                    len -= file_write_len;
                    cur_start += file_write_len;
                    data_start += file_write_len;
                }
            }
        }
        locs
    }
}

fn parse_bencode_files(mut data: BTreeMap<String, BEncode>) -> Result<Vec<File>, &'static str> {
    match data.remove("files").and_then(|l| l.into_list()) {
        Some(fs) => {
            let mut path = PathBuf::new();
            path.push(data.remove("name").and_then(|v| v.into_string()).ok_or(
                "Multifile mode must have a name field",
            )?);
            let mut files = Vec::new();
            for f in fs {
                let mut file = File::from_bencode(f)?;
                file.path = path.join(file.path);
                files.push(file);
            }
            Ok(files)
        }
        None => File::from_bencode(BEncode::Dict(data)).map(|f| vec![f]),
    }
}
<commit_msg>Dont double remove name field<commit_after>use bencode::BEncode;
use std::path::PathBuf;
use std::collections::{HashMap, BTreeMap};
use std::{fmt, cmp};
use url::Url;
use ring::digest;
use util::hash_to_id;
use disk;

#[derive(Serialize, Deserialize, Clone)]
pub struct Info {
    pub name: String,
    pub announce: String,
    pub piece_len: u32,
    pub total_len: u64,
    pub hashes: Vec<Vec<u8>>,
    pub hash: [u8; 20],
    pub files: Vec<File>,
    pub file_idx: HashMap<PathBuf, usize>,
    pub private: bool,
    pub be_name: Option<Vec<u8>>,
}

impl fmt::Debug for Info {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Torrent Info {{
                name: {:?},
                announce: {:?},
                piece_len: {:?},
                total_len: {:?},
                hash: {:?},
                files: {:?}
            }}",
            self.name,
            self.announce,
            self.piece_len,
            self.total_len,
            hash_to_id(&self.hash),
            self.files
        )
    }
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct File {
    pub path: PathBuf,
    pub length: u64,
}

impl File {
    fn from_bencode(data: BEncode) -> Result<File, &'static str> {
        let mut d = data.into_dict().ok_or("File must be a dictionary type!")?;
        match (d.remove("name"), d.remove("path"), d.remove("length")) {
            (Some(v), None, Some(l)) => {
                let f = File {
                    path: PathBuf::from(v.into_string().ok_or("Path must be a valid string.")?),
                    length: l.into_int().ok_or("File length must be a valid int")? as u64,
                };
                Ok(f)
            }
            (None, Some(path), Some(l)) => {
                let mut p = PathBuf::new();
                for dir in path.into_list().ok_or("File path should be a list")? {
                    p.push(
                        dir.into_string().ok_or("File path parts should be strings")?,
                    );
                }
                let f = File {
                    path: p,
                    length: l.into_int().ok_or("File length must be a valid int")? as u64,
                };
                Ok(f)
            }
            _ => Err("File dict must contain length and name or path"),
        }
    }
}

impl Info {
    pub fn from_magnet(data: &str) -> Result<Info, &'static str> {
        let url = match Url::parse(data) {
            Ok(u) => u,
            Err(_) => return Err("Failed to parse magnet URL!"),
        };

        if url.scheme() != "magnet" {
            return Err("magnet URL must use magnet scheme");
        };
        // TODO: Actually implmeent this
        unimplemented!();
    }

    pub fn to_bencode(&self) -> BEncode {
        let mut torrent = BTreeMap::new();
        let mut info = BTreeMap::new();
        torrent.insert(
            "announce".to_owned(),
            BEncode::String(self.announce.clone().into_bytes()),
        );
        if let Some(ref n) = self.be_name {
            info.insert("name".to_owned(), BEncode::String(n.clone()));
        }
        info.insert(
            "piece length".to_owned(),
            BEncode::Int(self.piece_len as i64),
        );
        let mut pieces = Vec::with_capacity(self.hashes.len() * 20);
        for h in &self.hashes {
            pieces.extend_from_slice(h);
        }
        info.insert("piece".to_owned(), BEncode::String(pieces));
        if self.files.len() == 1 {
            info.insert(
                "length".to_owned(),
                BEncode::Int(self.files[0].length as i64),
            );
            // This is pretty awful, but we guarantee utf8 on creation, so should be fine.
            info.insert(
                "path".to_owned(),
                BEncode::String(
                    self.files[0]
                        .path
                        .clone()
                        .into_os_string()
                        .into_string()
                        .unwrap()
                        .into_bytes(),
                ),
            );
        } else {
            let files = self.files
                .iter()
                .map(|f| {
                    let mut fb = BTreeMap::new();
                    fb.insert("length".to_owned(), BEncode::Int(f.length as i64));
                    fb.insert(
                        "path".to_owned(),
                        BEncode::String(
                            f.path
                                .clone()
                                .into_os_string()
                                .into_string()
                                .unwrap()
                                .into_bytes(),
                        ),
                    );
                    BEncode::Dict(fb)
                })
                .collect();
            info.insert("files".to_owned(), BEncode::List(files));
        }
        torrent.insert("info".to_owned(), BEncode::Dict(info));
        BEncode::Dict(torrent)
    }

    pub fn from_bencode(data: BEncode) -> Result<Info, &'static str> {
        data.into_dict()
            .and_then(|mut d| {
                d.remove("info").and_then(|i| i.into_dict()).map(|i| (d, i))
            })
            .ok_or("invalid info field")
            .and_then(|(mut d, mut i)| {
                let mut info_bytes = Vec::new();
                BEncode::Dict(i.clone()).encode(&mut info_bytes).unwrap();
                let mut ctx = digest::Context::new(&digest::SHA1);
                ctx.update(&info_bytes[..]);
                let digest = ctx.finish();
                let mut hash = [0u8; 20];
                hash.copy_from_slice(digest.as_ref());

                let a = d.remove("announce").and_then(|a| a.into_string()).ok_or(
                    "Info must have announce url",
                )?;
                let pl = i.remove("piece length").and_then(|i| i.into_int()).ok_or(
                    "Info must specify piece length",
                )?;
                let hashes = i.remove("pieces")
                    .and_then(|p| p.into_bytes())
                    .map(|mut p| {
                        let mut v = Vec::new();
                        while !p.is_empty() {
                            let remaining = p.split_off(20);
                            v.push(p);
                            p = remaining;
                        }
                        v
                    })
                    .ok_or("Info must provide valid hashes")?;

                let private = if let Some(v) = i.remove("private") {
                    v.into_int()
                        .and_then(|p| if p == 1 { Some(true) } else { None })
                        .ok_or("private key must be an integer equal to 1 if present!")?
                } else {
                    false
                };

                let be_name = if let Some(v) = i.get("name").cloned() {
                    Some(v.into_bytes().ok_or("name field must be a bitstring!")?)
                } else {
                    None
                };

                let files = parse_bencode_files(i)?;
                let name = if files.is_empty() {
                    files[0]
                        .path
                        .clone()
                        .into_os_string()
                        .into_string()
                        .map_err(|_| "Only UTF8 paths are accepted")?
                } else if !files[0].path.has_root() {
                    let mut piter = files[0].path.components();
                    piter
                        .next()
                        .unwrap()
                        .as_os_str()
                        .to_os_string()
                        .into_string()
                        .map_err(|_| "Only UTF8 paths are accepted")?
                } else {
                    unreachable!();
                };

                let mut file_idx = HashMap::new();
                for (i, file) in files.iter().enumerate() {
                    file_idx.insert(file.path.clone(), i);
                }
                let total_len = files.iter().map(|f| f.length).sum();
                Ok(Info {
                    name,
                    announce: a,
                    piece_len: pl as u32,
                    hashes,
                    hash,
                    files,
                    file_idx,
                    total_len,
                    private,
                    be_name,
                })
            })
    }

    #[cfg(test)]
    pub fn with_pieces(pieces: usize) -> Info {
        Info {
            name: String::from(""),
            announce: String::from(""),
            piece_len: 16_384,
            total_len: 16_384 * pieces as u64,
            hashes: vec![vec![0u8]; pieces],
            hash: [0u8; 20],
            files: vec![],
            file_idx: HashMap::new(),
            private: false,
            be_name: None,
        }
    }

    pub fn block_len(&self, idx: u32, offset: u32) -> u32 {
        if idx != self.pieces() - 1 {
            16_384
        } else {
            let last_piece_len =
                (self.total_len - self.piece_len as u64 * (self.pieces() as u64 - 1)) as u32;
            // Note this is not the real last block len, just what it will be IF the offset really
            // is for the last block
            let last_block_len = last_piece_len - offset;
            if offset < last_piece_len && last_block_len <= 16_384 {
                last_block_len
            } else {
                16_384
            }
        }
    }

    pub fn piece_len(&self, idx: u32) -> u32 {
        if idx != self.pieces() - 1 {
            self.piece_len
        } else {
            (self.total_len - self.piece_len as u64 * (self.pieces() as u64 - 1)) as u32
        }
    }

    pub fn pieces(&self) -> u32 {
        self.hashes.len() as u32
    }

    /// Calculates the file offsets for a given block at index/begin
    pub fn block_disk_locs(&self, index: u32, begin: u32) -> Vec<disk::Location> {
        let len = self.block_len(index, begin);
        self.calc_disk_locs(index, begin, len)
    }

    /// Calculates the file offsets for a given piece at index
    pub fn piece_disk_locs(&self, index: u32) -> Vec<disk::Location> {
        let len = self.piece_len(index);
        self.calc_disk_locs(index, 0, len)
    }

    /// Calculates the file offsets for a given index, begin, and block length.
    fn calc_disk_locs(&self, index: u32, begin: u32, len: u32) -> Vec<disk::Location> {
        let mut len = len as u64;
        // The absolute byte offset where we start processing data.
        let mut cur_start = index as u64 * self.piece_len as u64 + begin as u64;
        // Current index of the data block we're writing
        let mut data_start = 0;
        // The current file end length.
        let mut fidx = 0;
        // Iterate over all file lengths, if we find any which end a bigger
        // idx than cur_start, write from cur_start..cur_start + file_write_len for that file
        // and continue if we're now at the end of the file.
        let mut locs = Vec::new();
        for f in &self.files {
            fidx += f.length;
            if cur_start < fidx {
                let file_write_len = cmp::min(fidx - cur_start, len);
                let offset = cur_start - (fidx - f.length);
                if file_write_len == len {
                    // The file is longer than our len, just write to it,
                    // exit loop
                    locs.push(disk::Location::new(
                        f.path.clone(),
                        offset,
                        data_start,
                        data_start + file_write_len,
                    ));
                    break;
                } else {
                    // Write to the end of file, continue
                    locs.push(disk::Location::new(
                        f.path.clone(),
                        offset,
                        data_start,
                        data_start + file_write_len,
                    ));
                    len -= file_write_len;
                    cur_start += file_write_len;
                    data_start += file_write_len;
                }
            }
        }
        locs
    }
}

fn parse_bencode_files(mut data: BTreeMap<String, BEncode>) -> Result<Vec<File>, &'static str> {
    match data.remove("files").and_then(|l| l.into_list()) {
        Some(fs) => {
            let mut path = PathBuf::new();
            path.push(data.remove("name").and_then(|v| v.into_string()).ok_or(
                "Multifile mode must have a name field",
            )?);
            let mut files = Vec::new();
            for f in fs {
                let mut file = File::from_bencode(f)?;
                file.path = path.join(file.path);
                files.push(file);
            }
            Ok(files)
        }
        None => File::from_bencode(BEncode::Dict(data)).map(|f| vec![f]),
    }
}
<|endoftext|>