<commit_before>
use std::env::current_exe;
use std::io::{BufWriter, BufReader, Write};
use std::fs::{File,PathExt};
use std::path::Path;
use rustc_serialize::{
    json,
    Encodable,
    Decodable,
};

static SETTING_FILENAME: &'static str = "settings.json";

pub struct Settings {
    pub asset_folder: String,
    pub window_size: [u32; 2],
    pub window_background_color: [f32; 3],
    pub comment1_offset_y: f64,
    pub comment2_offset_y: f64,
    pub board_padding: f64,
    pub board_size: [f64; 2],
    pub board_offset_y: f64,
    pub tile_width: i32,
    pub tile_height: i32,
    pub tile_size: f64,
    pub tile_padding: f64,
    pub tile_background_color: [f32; 3],
    pub tiles_colors: Vec<[f32; 3]>,
    pub tile_unknow_color: [f32; 3],
    pub tile_move_time: f64,
    pub tile_new_time: f64,
    pub tile_combine_time: f64,
    pub best_rect: [f64; 4],
    pub score_rect: [f64; 4],
    pub label_color: [f32; 3],
    pub button_color: [f32; 3],
    pub text_dark_color: [f32; 3],
    pub text_light_color: [f32; 3],
}

impl Settings {
    pub fn load() -> Settings {
        Settings::from_settings_in_json(&SettingsInJson::load())
    }

    fn from_settings_in_json<'a>(s: &'a SettingsInJson) -> Settings {
        let board_size = [
            s.tile_size * s.tile_width as f64 + s.tile_padding * (s.tile_width + 1) as f64,
            s.tile_size * s.tile_height as f64 + s.tile_padding * (s.tile_height + 1) as f64,

        ];

        let mut tiles_colors = Vec::<[f32; 3]>::new();
        for color in s.tiles_colors.iter() {
            tiles_colors.push([
                color[0] / 255.0,
                color[1] / 255.0,
                color[2] / 255.0,
            ]);
        }
        Settings {
            asset_folder: s.asset_folder.clone(),
            comment1_offset_y: s.comment1_offset_y,
            comment2_offset_y: s.comment2_offset_y,
            window_size: [
                (s.board_padding * 2.0 + board_size[0]) as u32,
                (s.board_padding * 2.0 + board_size[1] + s.board_offset_y) as u32,
            ],
            window_background_color: [
                s.window_background_color[0] / 255.0,
                s.window_background_color[1] / 255.0,
                s.window_background_color[2] / 255.0,
            ],
            board_padding: s.board_padding,
            board_size: board_size,
            board_offset_y: s.board_offset_y,
            tile_width: s.tile_width,
            tile_height: s.tile_height,
            tile_size: s.tile_size,
            tile_padding: s.tile_padding,
            tile_background_color: [
                s.tile_background_color[0] / 255.0,
                s.tile_background_color[1] / 255.0,
                s.tile_background_color[2] / 255.0,
            ],
            tiles_colors: tiles_colors,
            tile_unknow_color: [
                s.tile_unknow_color[0] / 255.0,
                s.tile_unknow_color[1] / 255.0,
                s.tile_unknow_color[2] / 255.0,
            ],
            tile_move_time: s.tile_move_time,
            tile_new_time: s.tile_new_time,
            tile_combine_time: s.tile_combine_time,
            best_rect: [
                s.best_rect[0],
                s.best_rect[1],
                s.best_rect[2],
                s.best_rect[3],
            ],
            score_rect: [
                s.score_rect[0],
                s.score_rect[1],
                s.score_rect[2],
                s.score_rect[3],
            ],
            label_color: [
                s.label_color[0] / 255.0,
                s.label_color[1] / 255.0,
                s.label_color[2] / 255.0,
            ],
            button_color: [
                s.button_color[0] / 255.0,
                s.button_color[1] / 255.0,
                s.button_color[2] / 255.0,
            ],
            text_dark_color: [
                s.text_dark_color[0] / 255.0,
                s.text_dark_color[1] / 255.0,
                s.text_dark_color[2] / 255.0,
            ],
            text_light_color: [
                s.text_light_color[0] / 255.0,
                s.text_light_color[1] / 255.0,
                s.text_light_color[2] / 255.0,
            ],
        }
    }
}

#[derive(RustcEncodable, RustcDecodable)]
struct SettingsInJson {
    asset_folder: String,

    // r g b (0 - 255)
    window_background_color: Vec<f32>,

    comment1_offset_y: f64,
    comment2_offset_y: f64,

    board_padding: f64,
    board_offset_y: f64,

    tile_width: i32,
    tile_height: i32,
    tile_size: f64,
    tile_padding: f64,
    tile_background_color: Vec<f32>,
    tiles_colors: Vec<Vec<f32>>,
    tile_unknow_color: Vec<f32>,

    tile_move_time: f64,
    tile_new_time: f64,
    tile_combine_time: f64,

    best_rect: Vec<f64>,
    score_rect: Vec<f64>,

    label_color: Vec<f32>,
    button_color: Vec<f32>,
    text_dark_color: Vec<f32>,
    text_light_color: Vec<f32>,
}

impl SettingsInJson {
    pub fn default_settings() -> SettingsInJson {
        let mut tiles_colors = Vec::<Vec<f32>>::new();
        // empty color
        tiles_colors.push(vec![204.0, 192.0, 179.0]);
        // 2 color
        tiles_colors.push(vec![238.0, 228.0, 218.0]);
        // 4 color
        tiles_colors.push(vec![237.0, 224.0, 200.0]);
        // 8 color
        tiles_colors.push(vec![242.0, 177.0, 121.0]);
        // 16 color
        tiles_colors.push(vec![245.0, 149.0, 99.0]);
        // 32 color
        tiles_colors.push(vec![246.0, 124.0, 95.0]);
        // 64 color
        tiles_colors.push(vec![246.0, 94.0, 59.0]);
        // 128 color
        tiles_colors.push(vec![237.0, 207.0, 114.0]);
        // 256 color
        tiles_colors.push(vec![237.0, 204.0, 97.0]);
        // 512 color
        tiles_colors.push(vec![237.0, 200.0, 80.0]);
        SettingsInJson {
            asset_folder: "bin/assets".to_string(),
            window_background_color: vec![255.0, 248.0, 239.0],
            comment1_offset_y: 72.0,
            comment2_offset_y: 100.0,
            board_padding: 12.0,
            board_offset_y: 128.0,
            tile_width: 4,
            tile_height: 4,
            tile_size: 72.0,
            tile_padding: 16.0,
            tile_background_color: vec![187.0, 173.0, 160.0],
            tiles_colors: tiles_colors,
            tile_unknow_color: vec![200.0, 0.0, 0.0],
            tile_move_time: 0.1,
            tile_new_time: 0.1,
            tile_combine_time: 0.1,
            best_rect: vec![284.0, 12.0, 96.0, 48.0,],
            score_rect: vec![176.0, 12.0, 96.0, 48.0],
            label_color: vec![187.0, 173.0, 160.0],
            button_color: vec![142.0, 122.0, 102.0],
            text_dark_color: vec![119.0, 110.0, 101.0],
            text_light_color: vec![249.0, 246.0, 242.0],
        }
    }

    pub fn load() -> SettingsInJson {
        let exe_path = current_exe();
        if exe_path.is_err() {
            return SettingsInJson::default_settings();
        }
        let mut exe_path = exe_path.unwrap();
        exe_path.pop();
        let path = exe_path.join(Path::new(SETTING_FILENAME));
        if !path.as_path().exists() || !path.is_file() {
            println!("Configuration file not found. Generating a default one.");
            let default = SettingsInJson::default_settings();
            default.save();
            return default;
        }
        let file = File::open(&path).unwrap();
        let mut reader = BufReader::new(file);
        let mut decoder = json::Decoder::new(json::Json::from_reader(&mut reader).unwrap());
        Decodable::decode(&mut decoder).unwrap()
    }

    pub fn save(&self) {
        let exe_path = current_exe();
        if exe_path.is_err() {
            println!("WARNING: Failed to save settings: can't find exe path.");
            return;
        }
        let path = exe_path.unwrap();
        let file = File::create(&path.with_file_name(SETTING_FILENAME)).unwrap();
        let mut writer = BufWriter::new(file);

        match json::encode(self) {
            Ok(encoded) => {
                if let Err(e) = writer.write(encoded.as_bytes()) {
                    println!("WARNING: Failed to save settings: {}", e);
                }
            }, Err(e) => {
                println!("WARNING: Failed to save settings: {}", e);
            }
        }

        // match self.encode(&mut encoder) {
        //     Ok(()) => (),
        //     Err(e) => { println!("WARNING: Failed to save settings: {}", e); },
        // }
    }
}
<commit_msg>don't use path.exists()<commit_after>
use std::env::current_exe;
use std::io::{BufWriter, BufReader, Write};
use std::fs::{File};
use std::path::Path;
use rustc_serialize::{
    json,
    Encodable,
    Decodable,
};

static SETTING_FILENAME: &'static str = "settings.json";

pub struct Settings {
    pub asset_folder: String,
    pub window_size: [u32; 2],
    pub window_background_color: [f32; 3],
    pub comment1_offset_y: f64,
    pub comment2_offset_y: f64,
    pub board_padding: f64,
    pub board_size: [f64; 2],
    pub board_offset_y: f64,
    pub tile_width: i32,
    pub tile_height: i32,
    pub tile_size: f64,
    pub tile_padding: f64,
    pub tile_background_color: [f32; 3],
    pub tiles_colors: Vec<[f32; 3]>,
    pub tile_unknow_color: [f32; 3],
    pub tile_move_time: f64,
    pub tile_new_time: f64,
    pub tile_combine_time: f64,
    pub best_rect: [f64; 4],
    pub score_rect: [f64; 4],
    pub label_color: [f32; 3],
    pub button_color: [f32; 3],
    pub text_dark_color: [f32; 3],
    pub text_light_color: [f32; 3],
}

impl Settings {
    pub fn load() -> Settings {
        Settings::from_settings_in_json(&SettingsInJson::load())
    }

    fn from_settings_in_json<'a>(s: &'a SettingsInJson) -> Settings {
        let board_size = [
            s.tile_size * s.tile_width as f64 + s.tile_padding * (s.tile_width + 1) as f64,
            s.tile_size * s.tile_height as f64 + s.tile_padding * (s.tile_height + 1) as f64,

        ];

        let mut tiles_colors = Vec::<[f32; 3]>::new();
        for color in s.tiles_colors.iter() {
            tiles_colors.push([
                color[0] / 255.0,
                color[1] / 255.0,
                color[2] / 255.0,
            ]);
        }
        Settings {
            asset_folder: s.asset_folder.clone(),
            comment1_offset_y: s.comment1_offset_y,
            comment2_offset_y: s.comment2_offset_y,
            window_size: [
                (s.board_padding * 2.0 + board_size[0]) as u32,
                (s.board_padding * 2.0 + board_size[1] + s.board_offset_y) as u32,
            ],
            window_background_color: [
                s.window_background_color[0] / 255.0,
                s.window_background_color[1] / 255.0,
                s.window_background_color[2] / 255.0,
            ],
            board_padding: s.board_padding,
            board_size: board_size,
            board_offset_y: s.board_offset_y,
            tile_width: s.tile_width,
            tile_height: s.tile_height,
            tile_size: s.tile_size,
            tile_padding: s.tile_padding,
            tile_background_color: [
                s.tile_background_color[0] / 255.0,
                s.tile_background_color[1] / 255.0,
                s.tile_background_color[2] / 255.0,
            ],
            tiles_colors: tiles_colors,
            tile_unknow_color: [
                s.tile_unknow_color[0] / 255.0,
                s.tile_unknow_color[1] / 255.0,
                s.tile_unknow_color[2] / 255.0,
            ],
            tile_move_time: s.tile_move_time,
            tile_new_time: s.tile_new_time,
            tile_combine_time: s.tile_combine_time,
            best_rect: [
                s.best_rect[0],
                s.best_rect[1],
                s.best_rect[2],
                s.best_rect[3],
            ],
            score_rect: [
                s.score_rect[0],
                s.score_rect[1],
                s.score_rect[2],
                s.score_rect[3],
            ],
            label_color: [
                s.label_color[0] / 255.0,
                s.label_color[1] / 255.0,
                s.label_color[2] / 255.0,
            ],
            button_color: [
                s.button_color[0] / 255.0,
                s.button_color[1] / 255.0,
                s.button_color[2] / 255.0,
            ],
            text_dark_color: [
                s.text_dark_color[0] / 255.0,
                s.text_dark_color[1] / 255.0,
                s.text_dark_color[2] / 255.0,
            ],
            text_light_color: [
                s.text_light_color[0] / 255.0,
                s.text_light_color[1] / 255.0,
                s.text_light_color[2] / 255.0,
            ],
        }
    }
}

#[derive(RustcEncodable, RustcDecodable)]
struct SettingsInJson {
    asset_folder: String,

    // r g b (0 - 255)
    window_background_color: Vec<f32>,

    comment1_offset_y: f64,
    comment2_offset_y: f64,

    board_padding: f64,
    board_offset_y: f64,

    tile_width: i32,
    tile_height: i32,
    tile_size: f64,
    tile_padding: f64,
    tile_background_color: Vec<f32>,
    tiles_colors: Vec<Vec<f32>>,
    tile_unknow_color: Vec<f32>,

    tile_move_time: f64,
    tile_new_time: f64,
    tile_combine_time: f64,

    best_rect: Vec<f64>,
    score_rect: Vec<f64>,

    label_color: Vec<f32>,
    button_color: Vec<f32>,
    text_dark_color: Vec<f32>,
    text_light_color: Vec<f32>,
}

impl SettingsInJson {
    pub fn default_settings() -> SettingsInJson {
        let mut tiles_colors = Vec::<Vec<f32>>::new();
        // empty color
        tiles_colors.push(vec![204.0, 192.0, 179.0]);
        // 2 color
        tiles_colors.push(vec![238.0, 228.0, 218.0]);
        // 4 color
        tiles_colors.push(vec![237.0, 224.0, 200.0]);
        // 8 color
        tiles_colors.push(vec![242.0, 177.0, 121.0]);
        // 16 color
        tiles_colors.push(vec![245.0, 149.0, 99.0]);
        // 32 color
        tiles_colors.push(vec![246.0, 124.0, 95.0]);
        // 64 color
        tiles_colors.push(vec![246.0, 94.0, 59.0]);
        // 128 color
        tiles_colors.push(vec![237.0, 207.0, 114.0]);
        // 256 color
        tiles_colors.push(vec![237.0, 204.0, 97.0]);
        // 512 color
        tiles_colors.push(vec![237.0, 200.0, 80.0]);
        SettingsInJson {
            asset_folder: "bin/assets".to_string(),
            window_background_color: vec![255.0, 248.0, 239.0],
            comment1_offset_y: 72.0,
            comment2_offset_y: 100.0,
            board_padding: 12.0,
            board_offset_y: 128.0,
            tile_width: 4,
            tile_height: 4,
            tile_size: 72.0,
            tile_padding: 16.0,
            tile_background_color: vec![187.0, 173.0, 160.0],
            tiles_colors: tiles_colors,
            tile_unknow_color: vec![200.0, 0.0, 0.0],
            tile_move_time: 0.1,
            tile_new_time: 0.1,
            tile_combine_time: 0.1,
            best_rect: vec![284.0, 12.0, 96.0, 48.0,],
            score_rect: vec![176.0, 12.0, 96.0, 48.0],
            label_color: vec![187.0, 173.0, 160.0],
            button_color: vec![142.0, 122.0, 102.0],
            text_dark_color: vec![119.0, 110.0, 101.0],
            text_light_color: vec![249.0, 246.0, 242.0],
        }
    }

    pub fn load() -> SettingsInJson {
        let exe_path = current_exe();
        if exe_path.is_err() {
            return SettingsInJson::default_settings();
        }
        let mut exe_path = exe_path.unwrap();
        exe_path.pop();
        let path = exe_path.join(Path::new(SETTING_FILENAME));
// FIXME: use this if possible  (.exists() is unstable in Rust 1.0.0)
/*      if !path.as_path().exists() || !path.is_file() {
            println!("Configuration file not found. Generating a default one.");
            let default = SettingsInJson::default_settings();
            default.save();
            return default;
        }
        let file = File::open(&path).unwrap();
        let mut reader = BufReader::new(file);
*/
        let file = File::open(&path);
        match file {
            Err(e) => {
                println!("Configuration file can't be open ({}). Try to generate a default one.", e);
                let default = SettingsInJson::default_settings();
                default.save();
                return default;
            },
            _ => {}
        }
        let mut reader = BufReader::new(file.unwrap());
// End FIXME
        let mut decoder = json::Decoder::new(json::Json::from_reader(&mut reader).unwrap());
        Decodable::decode(&mut decoder).unwrap()
    }

    pub fn save(&self) {
        let exe_path = current_exe();
        if exe_path.is_err() {
            println!("WARNING: Failed to save settings: can't find exe path.");
            return;
        }
        let path = exe_path.unwrap();
        let file = File::create(&path.with_file_name(SETTING_FILENAME)).unwrap();
        let mut writer = BufWriter::new(file);

        match json::encode(self) {
            Ok(encoded) => {
                if let Err(e) = writer.write(encoded.as_bytes()) {
                    println!("WARNING: Failed to save settings: {}", e);
                }
            }, Err(e) => {
                println!("WARNING: Failed to save settings: {}", e);
            }
        }

        // match self.encode(&mut encoder) {
        //     Ok(()) => (),
        //     Err(e) => { println!("WARNING: Failed to save settings: {}", e); },
        // }
    }
}
<|endoftext|>


<commit_before>use core::cmp::{Eq, Ord};
use std::list;
use std::list::{List, Cons, Nil};

/**
 * A purely functional Pairing Heap [FSST86]
 *
 * Our implementation uses Linked List (cons cells) so may not be the
 * fastest way to implement this in Rust.
 *
 * This implementation is a port of the Standard ML found in Okasaki's
 * Purely Functional Data Structures.
 */
pub enum PairingHeap<E: Copy Eq Ord> {
  Empty_,
  PairingHeapCell(
    E,
    @List<PairingHeap<E>>
  )
}

pub trait Heap<E: Copy Eq Ord> {
  // returns true if the Heap is empty.
  pure fn is_empty(&self) -> bool;

  // returns a new Heap with the element inserted.
  pure fn insert(elem: E) -> self;

  // returns the minimum element without a modified heap
  pure fn find_min() -> Option<E>;

  // returns the minimum element and a new Heap without that element.
  pure fn delete_min() -> (Option<E>, self);
}

pure fn Empty<E: Copy Eq Ord>() -> PairingHeap<E> {
  Empty_
}

pure fn PairingHeap<E: Copy Eq Ord>(initial_value: E) -> PairingHeap<E> {
  PairingHeapCell(
    initial_value,
    @Nil
  )
}

impl<E: Copy Eq Ord> PairingHeap<E> : Eq {
  pure fn eq(other: &PairingHeap<E>) -> bool {
    match (self, *other) {
      (Empty_, Empty_) => {true}
      (PairingHeapCell(headA, restA), PairingHeapCell(headB, restB)) => {
        (headA == headB) && (restA == restB)
      }
      //(Empty_, PairingHeapCell(_)) => {false} // why are these unreachable?
      //(PairingHeapCell(_), Empty) => {false}
      (_, _) => {false}
    }
  }

  pure fn ne(other: &PairingHeap<E>) -> bool { !(self).eq(other) }
}

impl<E: Copy Eq Ord> PairingHeap<E> : Heap<E> {
  pure fn is_empty(&self) -> bool {
    *self == Empty_
  }

  pure fn insert(e: E) -> PairingHeap<E> {
    self.merge(PairingHeap(e))
  }

  pure fn find_min() -> Option<E> {
    match self {
      Empty_ => { None }
      PairingHeapCell(head, _) => { Some(head) }
    }
  }

  pure fn delete_min() -> (Option<E>, PairingHeap<E>) {
    match self {
      Empty_ => {(None, self)}
      PairingHeapCell(head, rest) => {(Some(head), self.merge_pairs(rest))}
    }
  }

  pure fn merge(other: PairingHeap<E>) -> PairingHeap<E> {
    match (self, other) {
      (Empty_, b) => { b }
      (a, Empty_) => { a }
      (x@PairingHeapCell(headA, restA), y@PairingHeapCell(headB, restB)) => {
        if (headA.le(&headB)) {
          PairingHeapCell(
            headA,
            @Cons(y, restA)
          )
        } else {
          PairingHeapCell(
            headB,
            @Cons(x, restB)
          )
        }
      }
    }
  }

  pure fn merge_pairs(heaps: @List<PairingHeap<E>>) -> PairingHeap<E> {
    match heaps {
      // Why are @-signs required for pattern matching here?
      @Cons(a, @Cons(b, xs)) => {a.merge(b).merge(self.merge_pairs(xs))}
      @Cons(elem, @Nil) => {elem}
      @Nil => {Empty()}
    }
  }
}

#[test]
fn test_heap_create() {
  let heap = PairingHeap(1);
  assert(!heap.is_empty());

  // inference fails on this without a type declaration.
  let heap : PairingHeap<()> = Empty();
  assert(heap.is_empty());
}

#[test]
fn test_heap_insert() {
  let v1 = PairingHeap(10);
  let v2 = v1.insert(1);
  let (one, v3) = v2.delete_min();
  let (ten, v4) = v3.delete_min();
  let (e, v5) = v4.delete_min();

  assert(one == Some(1));
  assert(ten == Some(10));
  assert(v4 == Empty_);
  assert(e == None);
  assert(v5 == Empty_);
}

#[test]
fn test_heap_insert_delete_interleved() {
  let v1 = PairingHeap(10);
  let (a, v2) = v1.delete_min();
  assert(a == Some(10));
  assert(v2 == Empty_);

  let v3 = v2.insert(9);
  let v4 = v3.insert(8);
  let v5 = v4.insert(11);

  let (b, v6) = v5.delete_min();
  assert(b == Some(8));

  let v7 = v6.insert(7);
  let v8 = v7.insert(12);

  let x = v8.find_min();
  assert(x == Some(7));

  let (c, v9) = v8.delete_min();
  assert(c == Some(7));

  let (d, v10) = v9.delete_min();
  assert(d == Some(9));

  let (e, v11) = v10.delete_min();
  assert(e == Some(11));

  let (f, v12) = v11.delete_min();
  assert(f == Some(12));

  let (g, v13) = v12.delete_min();
  assert(g == None);
  assert(v13 == Empty_);
}

#[test]
fn test_immutable_heap() {
  let heap = PairingHeap(10);
  let x1 = heap.insert(1);

  assert(x1.find_min() == Some(1));
  assert(heap.find_min() == Some(10));

  let (a, v1) = heap.delete_min();
  assert(a == Some(10));
  assert(v1 == Empty_);

  let (b, x2) = x1.delete_min();
  assert(b == Some(1));
  assert(x2 != Empty_);
}

<commit_msg>spell interleave correctly. add check that deleting the last item results in an empty heap<commit_after>use core::cmp::{Eq, Ord};
use std::list;
use std::list::{List, Cons, Nil};

/**
 * A purely functional Pairing Heap [FSST86]
 *
 * Our implementation uses Linked List (cons cells) so may not be the
 * fastest way to implement this in Rust.
 *
 * This implementation is a port of the Standard ML found in Okasaki's
 * Purely Functional Data Structures.
 */
pub enum PairingHeap<E: Copy Eq Ord> {
  Empty_,
  PairingHeapCell(
    E,
    @List<PairingHeap<E>>
  )
}

pub trait Heap<E: Copy Eq Ord> {
  // returns true if the Heap is empty.
  pure fn is_empty(&self) -> bool;

  // returns a new Heap with the element inserted.
  pure fn insert(elem: E) -> self;

  // returns the minimum element without a modified heap
  pure fn find_min() -> Option<E>;

  // returns the minimum element and a new Heap without that element.
  pure fn delete_min() -> (Option<E>, self);
}

pure fn Empty<E: Copy Eq Ord>() -> PairingHeap<E> {
  Empty_
}

pure fn PairingHeap<E: Copy Eq Ord>(initial_value: E) -> PairingHeap<E> {
  PairingHeapCell(
    initial_value,
    @Nil
  )
}

impl<E: Copy Eq Ord> PairingHeap<E> : Eq {
  pure fn eq(other: &PairingHeap<E>) -> bool {
    match (self, *other) {
      (Empty_, Empty_) => {true}
      (PairingHeapCell(headA, restA), PairingHeapCell(headB, restB)) => {
        (headA == headB) && (restA == restB)
      }
      //(Empty_, PairingHeapCell(_)) => {false} // why are these unreachable?
      //(PairingHeapCell(_), Empty) => {false}
      (_, _) => {false}
    }
  }

  pure fn ne(other: &PairingHeap<E>) -> bool { !(self).eq(other) }
}

impl<E: Copy Eq Ord> PairingHeap<E> : Heap<E> {
  pure fn is_empty(&self) -> bool {
    *self == Empty_
  }

  pure fn insert(e: E) -> PairingHeap<E> {
    self.merge(PairingHeap(e))
  }

  pure fn find_min() -> Option<E> {
    match self {
      Empty_ => { None }
      PairingHeapCell(head, _) => { Some(head) }
    }
  }

  pure fn delete_min() -> (Option<E>, PairingHeap<E>) {
    match self {
      Empty_ => {(None, self)}
      PairingHeapCell(head, rest) => {(Some(head), self.merge_pairs(rest))}
    }
  }

  pure fn merge(other: PairingHeap<E>) -> PairingHeap<E> {
    match (self, other) {
      (Empty_, b) => { b }
      (a, Empty_) => { a }
      (x@PairingHeapCell(headA, restA), y@PairingHeapCell(headB, restB)) => {
        if (headA.le(&headB)) {
          PairingHeapCell(
            headA,
            @Cons(y, restA)
          )
        } else {
          PairingHeapCell(
            headB,
            @Cons(x, restB)
          )
        }
      }
    }
  }

  pure fn merge_pairs(heaps: @List<PairingHeap<E>>) -> PairingHeap<E> {
    match heaps {
      @Cons(a, @Cons(b, xs)) => {a.merge(b).merge(self.merge_pairs(xs))}
      @Cons(elem, @Nil) => {elem}
      @Nil => {Empty()}
    }
  }
}

#[test]
fn test_heap_create() {
  let heap = PairingHeap(1);
  assert(!heap.is_empty());

  // inference fails on this without a type declaration.
  let heap : PairingHeap<()> = Empty();
  assert(heap.is_empty());
}

#[test]
fn test_delete_last_item() {
  let v1 = PairingHeap(1);
  assert(!v1.is_empty());

  let (_, v2) = v1.delete_min();
  assert(v2.is_empty());
}

#[test]
fn test_heap_insert() {
  let v1 = PairingHeap(10);
  let v2 = v1.insert(1);
  let (one, v3) = v2.delete_min();
  let (ten, v4) = v3.delete_min();
  let (e, v5) = v4.delete_min();

  assert(one == Some(1));
  assert(ten == Some(10));
  assert(v4 == Empty_);
  assert(e == None);
  assert(v5 == Empty_);
}

#[test]
fn test_heap_insert_delete_interleaved() {
  let v1 = PairingHeap(10);
  let (a, v2) = v1.delete_min();
  assert(a == Some(10));
  assert(v2 == Empty_);

  let v3 = v2.insert(9);
  let v4 = v3.insert(8);
  let v5 = v4.insert(11);

  let (b, v6) = v5.delete_min();
  assert(b == Some(8));

  let v7 = v6.insert(7);
  let v8 = v7.insert(12);

  let x = v8.find_min();
  assert(x == Some(7));

  let (c, v9) = v8.delete_min();
  assert(c == Some(7));

  let (d, v10) = v9.delete_min();
  assert(d == Some(9));

  let (e, v11) = v10.delete_min();
  assert(e == Some(11));

  let (f, v12) = v11.delete_min();
  assert(f == Some(12));

  let (g, v13) = v12.delete_min();
  assert(g == None);
  assert(v13 == Empty_);
}

#[test]
fn test_immutable_heap() {
  let heap = PairingHeap(10);
  let x1 = heap.insert(1);

  assert(x1.find_min() == Some(1));
  assert(heap.find_min() == Some(10));

  let (a, v1) = heap.delete_min();
  assert(a == Some(10));
  assert(v1 == Empty_);

  let (b, x2) = x1.delete_min();
  assert(b == Some(1));
  assert(x2 != Empty_);
}

<|endoftext|>


<commit_before>// ignore-64bit
// build-fail

// FIXME https://github.com/rust-lang/rust/issues/59774
// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> ""
// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
#![allow(exceeding_bitshifts)]

fn main() {
    let _fat: [u8; (1<<31)+(1<<15)] = //~ ERROR too big for the current architecture
        [0; (1u32<<31) as usize +(1u32<<15) as usize];
}
<commit_msg>fix 32bit-only test<commit_after>// ignore-64bit
// build-fail

// FIXME https://github.com/rust-lang/rust/issues/59774
// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> ""
// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
#![allow(arithmetic_overflow)]

fn main() {
    let _fat: [u8; (1<<31)+(1<<15)] = //~ ERROR too big for the current architecture
        [0; (1u32<<31) as usize +(1u32<<15) as usize];
}
<|endoftext|>


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

use std::borrow::Cow;
use std::fs::File;
use std::io::{self, BufReader};
use std::path::Path;

use xml::reader::{XmlEvent, EventReader, Error as XmlError};

mod protocol;

pub use self::protocol::ProtocolParser as Parser;
pub use self::protocol::{Class, Constant, Domain, Field, Method, Protocol};

#[derive(Debug)]
pub enum VoidParser {
    Parsing(usize),
    Finished,
}

impl VoidParser {
    pub fn new() -> VoidParser {
        VoidParser::Parsing(0)
    }
    pub fn parse(self, event: &XmlEvent) -> Result<Self, ParseError> {
        Ok(match self {
            VoidParser::Parsing(depth) => {
                match *event {
                    XmlEvent::StartElement { .. } => VoidParser::Parsing(depth + 1),
                    XmlEvent::EndElement { .. } if depth == 0 => VoidParser::Finished,
                    XmlEvent::EndElement { .. } => VoidParser::Parsing(depth - 1),
                    _ => self,
                }
            }
            VoidParser::Finished => return Err(ParseError::ExpectedEnd),
        })
    }
}

impl Default for VoidParser {
    fn default() -> Self {
        VoidParser::new()
    }
}

pub fn parse<'a, P>(path: P) -> Result<Protocol<'a>, ParseError>
    where P: AsRef<Path>
{
    let path = path.as_ref();
    let file = try!(File::open(&path));
    let file = BufReader::new(file);

    let mut parser = Parser::new();

    for event in EventReader::new(file) {
        let event = try!(event);
        parser = try!(parser.parse(&event));
    }

    Ok(parser.into())
}

#[derive(Debug)]
pub enum ParseError {
    ExpectedAttribute(Cow<'static, str>, Cow<'static, str>),
    ExpectedElementStart(Cow<'static, str>),
    ExpectedAmqpRoot,
    // No more events are expected
    ExpectedEnd,
    Io(io::Error),
    Xml(XmlError),
}

impl<'a> From<io::Error> for ParseError {
    fn from(e: io::Error) -> Self {
        ParseError::Io(e)
    }
}

impl<'a> From<XmlError> for ParseError {
    fn from(e: XmlError) -> Self {
        ParseError::Xml(e)
    }
}
<commit_msg>[xmlparse] Remove the protocol parser from the public interface.<commit_after>// Copyright 2016 Alexander Reece
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::borrow::Cow;
use std::fs::File;
use std::io::{self, BufReader};
use std::path::Path;

use xml::reader::{XmlEvent, EventReader, Error as XmlError};

mod protocol;

use self::protocol::ProtocolParser as Parser;
pub use self::protocol::{Class, Constant, Domain, Field, Method, Protocol};

#[derive(Debug)]
pub enum VoidParser {
    Parsing(usize),
    Finished,
}

impl VoidParser {
    pub fn new() -> VoidParser {
        VoidParser::Parsing(0)
    }
    pub fn parse(self, event: &XmlEvent) -> Result<Self, ParseError> {
        Ok(match self {
            VoidParser::Parsing(depth) => {
                match *event {
                    XmlEvent::StartElement { .. } => VoidParser::Parsing(depth + 1),
                    XmlEvent::EndElement { .. } if depth == 0 => VoidParser::Finished,
                    XmlEvent::EndElement { .. } => VoidParser::Parsing(depth - 1),
                    _ => self,
                }
            }
            VoidParser::Finished => return Err(ParseError::ExpectedEnd),
        })
    }
}

impl Default for VoidParser {
    fn default() -> Self {
        VoidParser::new()
    }
}

pub fn parse<'a, P>(path: P) -> Result<Protocol<'a>, ParseError>
    where P: AsRef<Path>
{
    let path = path.as_ref();
    let file = try!(File::open(&path));
    let file = BufReader::new(file);

    let mut parser = Parser::new();

    for event in EventReader::new(file) {
        let event = try!(event);
        parser = try!(parser.parse(&event));
    }

    Ok(parser.into())
}

#[derive(Debug)]
pub enum ParseError {
    ExpectedAttribute(Cow<'static, str>, Cow<'static, str>),
    ExpectedElementStart(Cow<'static, str>),
    ExpectedAmqpRoot,
    // No more events are expected
    ExpectedEnd,
    Io(io::Error),
    Xml(XmlError),
}

impl<'a> From<io::Error> for ParseError {
    fn from(e: io::Error) -> Self {
        ParseError::Io(e)
    }
}

impl<'a> From<XmlError> for ParseError {
    fn from(e: XmlError) -> Self {
        ParseError::Xml(e)
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("List", inherited=True) %>

${helpers.single_keyword("list-style-position", "outside inside", animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-lists/#propdef-list-style-position")}

// TODO(pcwalton): Implement the full set of counter styles per CSS-COUNTER-STYLES [1] 6.1:
//
//     decimal-leading-zero, armenian, upper-armenian, lower-armenian, georgian, lower-roman,
//     upper-roman
//
// TODO(bholley): Missing quite a few gecko properties here as well.
//
// In gecko, {upper,lower}-{roman,alpha} are implemented as @counter-styles in the
// UA, however they can also be set from pres attrs. When @counter-style is supported
// we may need to look into this and handle these differently.
//
// [1]: http://dev.w3.org/csswg/css-counter-styles/
% if product == "servo":
    ${helpers.single_keyword("list-style-type", """
        disc none circle square decimal disclosure-open disclosure-closed lower-alpha upper-alpha
        arabic-indic bengali cambodian cjk-decimal devanagari gujarati gurmukhi kannada khmer lao
        malayalam mongolian myanmar oriya persian telugu thai tibetan cjk-earthly-branch
        cjk-heavenly-stem lower-greek hiragana hiragana-iroha katakana katakana-iroha""",
        animation_value_type="discrete",
        spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type",
        servo_restyle_damage="rebuild_and_reflow")}
% else:
    ${helpers.predefined_type("list-style-type",
                              "ListStyleType",
                              "computed::ListStyleType::disc()",
                              initial_specified_value="specified::ListStyleType::disc()",
                              animation_value_type="discrete",
                              boxed=True,
                              spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type",
                              servo_restyle_damage="rebuild_and_reflow")}
% endif

${helpers.predefined_type("list-style-image",
                          "ListStyleImage",
                          initial_value="specified::ListStyleImage::none()",
                          initial_specified_value="specified::ListStyleImage::none()",
                          animation_value_type="discrete",
                          boxed=product == "gecko",
                          spec="https://drafts.csswg.org/css-lists/#propdef-list-style-image")}

${helpers.predefined_type("quotes",
                          "Quotes",
                          "computed::Quotes::get_initial_value()",
                          animation_value_type="discrete",
                          spec="https://drafts.csswg.org/css-content/#propdef-quotes",
                          servo_restyle_damage="rebuild_and_reflow")}

${helpers.predefined_type("-moz-image-region",
                          "ClipRectOrAuto",
                          "computed::ClipRectOrAuto::auto()",
                          animation_value_type="ComputedValue",
                          products="gecko",
                          boxed=True,
                          spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-image-region)")}
<commit_msg>Use restyle_damage=rebuild_and_reflow for list types<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("List", inherited=True) %>

${helpers.single_keyword("list-style-position", "outside inside", animation_value_type="discrete",
                         spec="https://drafts.csswg.org/css-lists/#propdef-list-style-position",
                         servo_restyle_damage="rebuild_and_reflow")}

// TODO(pcwalton): Implement the full set of counter styles per CSS-COUNTER-STYLES [1] 6.1:
//
//     decimal-leading-zero, armenian, upper-armenian, lower-armenian, georgian, lower-roman,
//     upper-roman
//
// TODO(bholley): Missing quite a few gecko properties here as well.
//
// In gecko, {upper,lower}-{roman,alpha} are implemented as @counter-styles in the
// UA, however they can also be set from pres attrs. When @counter-style is supported
// we may need to look into this and handle these differently.
//
// [1]: http://dev.w3.org/csswg/css-counter-styles/
% if product == "servo":
    ${helpers.single_keyword("list-style-type", """
        disc none circle square decimal disclosure-open disclosure-closed lower-alpha upper-alpha
        arabic-indic bengali cambodian cjk-decimal devanagari gujarati gurmukhi kannada khmer lao
        malayalam mongolian myanmar oriya persian telugu thai tibetan cjk-earthly-branch
        cjk-heavenly-stem lower-greek hiragana hiragana-iroha katakana katakana-iroha""",
        animation_value_type="discrete",
        spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type",
        servo_restyle_damage="rebuild_and_reflow")}
% else:
    ${helpers.predefined_type("list-style-type",
                              "ListStyleType",
                              "computed::ListStyleType::disc()",
                              initial_specified_value="specified::ListStyleType::disc()",
                              animation_value_type="discrete",
                              boxed=True,
                              spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type",
                              servo_restyle_damage="rebuild_and_reflow")}
% endif

${helpers.predefined_type("list-style-image",
                          "ListStyleImage",
                          initial_value="specified::ListStyleImage::none()",
                          initial_specified_value="specified::ListStyleImage::none()",
                          animation_value_type="discrete",
                          boxed=product == "gecko",
                          spec="https://drafts.csswg.org/css-lists/#propdef-list-style-image",
                          servo_restyle_damage="rebuild_and_reflow")}

${helpers.predefined_type("quotes",
                          "Quotes",
                          "computed::Quotes::get_initial_value()",
                          animation_value_type="discrete",
                          spec="https://drafts.csswg.org/css-content/#propdef-quotes",
                          servo_restyle_damage="rebuild_and_reflow")}

${helpers.predefined_type("-moz-image-region",
                          "ClipRectOrAuto",
                          "computed::ClipRectOrAuto::auto()",
                          animation_value_type="ComputedValue",
                          products="gecko",
                          boxed=True,
                          spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-image-region)")}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

struct Monster {
    damage: isize
}

fn main() {
    let _m = Monster(); //~ ERROR `Monster` is a struct variant name, but
    //~^ HELP did you mean to write: `Monster { /* fields */ }`?
}
<commit_msg>Update error comment<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

struct Monster {
    damage: isize
}

fn main() {
    let _m = Monster(); //~ ERROR `Monster` is the name of a struct or
    //~^ HELP did you mean to write: `Monster { /* fields */ }`?
}
<|endoftext|>


<commit_before>use wlroots_sys::{wlr_xcursor_manager, wlr_xcursor_manager_create, wlr_xcursor_manager_load,
                  wlr_xcursor_manager_set_cursor_image, wlr_xcursor_manager_destroy,
                  wlr_xcursor_manager_get_xcursor, wlr_xcursor_manager_theme};
use types::{Cursor, XCursor, XCursorTheme};
use std::ptr;
use utils::{safe_as_cstring, c_to_rust_string};
use std::marker::PhantomData;

#[derive(Debug)]
pub struct XCursorManagerTheme<'manager> {
    theme: *mut wlr_xcursor_manager_theme,
    phantom: PhantomData<&'manager XCursorManager>
}

#[derive(Debug)]
pub struct XCursorManager {
    manager: *mut wlr_xcursor_manager,
}

impl<'manager> XCursorManagerTheme<'manager> {
    fn new(theme: *mut wlr_xcursor_manager_theme) -> Self {
        XCursorManagerTheme {
            theme: theme,
            phantom: PhantomData
        }
    }

    pub fn scale(&self) -> f32 {
        unsafe {
            (*self.theme).scale
        }
    }

    pub fn theme(self) -> XCursorTheme {
        unsafe {
            XCursorTheme::new((*self.theme).theme)
        }
    }
}

impl XCursorManager {
    pub fn create<T: Into<Option<String>>>(name: T, size: u32) -> Option<Self> {
        unsafe {
            let name_str = name.into().map(safe_as_cstring);
            let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
            let manager = wlr_xcursor_manager_create(name_ptr, size);
            if manager.is_null() {
                None
            } else {
                Some(XCursorManager { manager: manager })
            }
        }
    }

    pub fn name(&self) -> String {
        unsafe {
            c_to_rust_string((*self.manager).name).expect("Could not parse make as UTF-8")
        }
    }

    pub fn size(&self) -> u32 {
        unsafe { (*self.manager).size }
    }

    pub fn get_xcursor<'manager, T: Into<Option<String>>>(&'manager self, name: T, scale: f32) -> Option<XCursor<'manager>> {
        let name_str = name.into().map(safe_as_cstring);
        let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
        unsafe {
            let xcursor = wlr_xcursor_manager_get_xcursor(self.manager, name_ptr, scale);
            if xcursor.is_null() {
                None
            } else {
                Some(XCursor::from_ptr(xcursor))
            }
        }
    }

    pub fn scaled_themes<'manager>(&'manager self) -> Vec<XCursorManagerTheme<'manager>> {
        unsafe {
            let mut result = vec![];

            wl_list_for_each!((*self.manager).scaled_themes, link, (theme: wlr_xcursor_manager_theme) => {
                result.push(XCursorManagerTheme::new(theme))
            });

            result
        }
    }

    /// returns false if the scaled theme was successfully loaded and true otherwise
    pub fn load(&self, scale: f32) -> bool {
        unsafe {
            match wlr_xcursor_manager_load(self.manager, scale) {
                0 => false,
                _ => true
            }
        }
    }

    pub fn set_cursor_image(&mut self, name: String, cursor: &Cursor) {
        let name_str = safe_as_cstring(name);
        unsafe {
            wlr_xcursor_manager_set_cursor_image(self.manager, name_str.as_ptr(), cursor.as_ptr());
        }
    }
}

impl Drop for XCursorManager {
    fn drop(&mut self) {
        unsafe { wlr_xcursor_manager_destroy(self.manager) }
    }
}
<commit_msg>xcursormanager docs<commit_after>use wlroots_sys::{wlr_xcursor_manager, wlr_xcursor_manager_create, wlr_xcursor_manager_load,
                  wlr_xcursor_manager_set_cursor_image, wlr_xcursor_manager_destroy,
                  wlr_xcursor_manager_get_xcursor, wlr_xcursor_manager_theme};
use types::{Cursor, XCursor, XCursorTheme};
use std::ptr;
use utils::{safe_as_cstring, c_to_rust_string};
use std::marker::PhantomData;

/// An `XCursorTheme` at a particular scale factor of the base size.
#[derive(Debug)]
pub struct XCursorManagerTheme<'manager> {
    theme: *mut wlr_xcursor_manager_theme,
    phantom: PhantomData<&'manager XCursorManager>
}

/// XCursorManager dynamically loads xcursor themes at sizes necessary for use on outputs at
/// arbitrary scale factors. You should call `load` for each output you will show your cursor on,
/// with the scale factor parameter set to that output's scale factor.
#[derive(Debug)]
pub struct XCursorManager {
    manager: *mut wlr_xcursor_manager,
}

impl<'manager> XCursorManagerTheme<'manager> {
    fn new(theme: *mut wlr_xcursor_manager_theme) -> Self {
        XCursorManagerTheme {
            theme: theme,
            phantom: PhantomData
        }
    }

    /// Get the scale factor of the theme.
    pub fn scale(&self) -> f32 {
        unsafe {
            (*self.theme).scale
        }
    }

    /// Get the underlying `XCursorTheme` for this managed theme.
    pub fn theme(self) -> XCursorTheme {
        unsafe {
            XCursorTheme::new((*self.theme).theme)
        }
    }
}

impl XCursorManager {
    /// Create a new `XCursorManager`.
    pub fn create<T: Into<Option<String>>>(name: T, size: u32) -> Option<Self> {
        unsafe {
            let name_str = name.into().map(safe_as_cstring);
            let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
            let manager = wlr_xcursor_manager_create(name_ptr, size);
            if manager.is_null() {
                None
            } else {
                Some(XCursorManager { manager: manager })
            }
        }
    }

    /// Get the name of the theme this `XCursorManager` manages.
    pub fn name(&self) -> String {
        unsafe {
            c_to_rust_string((*self.manager).name).expect("Could not parse make as UTF-8")
        }
    }

    /// Get the base size (when scale = 1) in pixels for the theme.
    pub fn size(&self) -> u32 {
        unsafe { (*self.manager).size }
    }

    /// Retrieves a `XCursor` for the given cursor name at the given scale factor, or None if this
    /// `XCursorManager` has not loaded a cursor theme at the requested scale.
    pub fn get_xcursor<'manager, T: Into<Option<String>>>(&'manager self, name: T, scale: f32) -> Option<XCursor<'manager>> {
        let name_str = name.into().map(safe_as_cstring);
        let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
        unsafe {
            let xcursor = wlr_xcursor_manager_get_xcursor(self.manager, name_ptr, scale);
            if xcursor.is_null() {
                None
            } else {
                Some(XCursor::from_ptr(xcursor))
            }
        }
    }

    /// Get a list of all the scaled `XCursorManagerTheme`s managed by this manager.
    pub fn scaled_themes<'manager>(&'manager self) -> Vec<XCursorManagerTheme<'manager>> {
        unsafe {
            let mut result = vec![];

            wl_list_for_each!((*self.manager).scaled_themes, link, (theme: wlr_xcursor_manager_theme) => {
                result.push(XCursorManagerTheme::new(theme))
            });

            result
        }
    }

    /// Ensures an xcursor theme at the given scale factor is loaded in the manager.
    ///
    /// Returns false if the scaled theme was successfully loaded and true otherwise
    pub fn load(&self, scale: f32) -> bool {
        unsafe {
            match wlr_xcursor_manager_load(self.manager, scale) {
                0 => false,
                _ => true
            }
        }
    }

    /// Set a `Cursor`'s cursor image to the specified cursor name for all scale
    /// factors. The `Cursor` will take over from this point and ensure the correct
    /// cursor is used on each output, assuming an `OutputLayout` is attached to
    /// it.
    pub fn set_cursor_image(&mut self, name: String, cursor: &Cursor) {
        let name_str = safe_as_cstring(name);
        unsafe {
            wlr_xcursor_manager_set_cursor_image(self.manager, name_str.as_ptr(), cursor.as_ptr());
        }
    }
}

impl Drop for XCursorManager {
    fn drop(&mut self) {
        unsafe { wlr_xcursor_manager_destroy(self.manager) }
    }
}
<|endoftext|>


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

extern crate tokio_jsonrpc;
extern crate tokio_core;
extern crate futures;
#[macro_use]
extern crate serde_json;

use std::time::Duration;
use std::io::{Error as IoError, ErrorKind};

use tokio_jsonrpc::{Endpoint, LineCodec, Server, ServerCtl, ServerError};
use tokio_jsonrpc::message::RPCError;

use futures::{Future, Stream};
use futures::future::BoxFuture;
use tokio_core::reactor::{Core, Timeout, Handle};
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::io::{Io, Framed};
use serde_json::{Value, to_value, from_value};

struct AnswerServer;

/// A test server
///
/// It expects no parameters and the method to be `"test"` and returns 42 on RPC. It expects
/// `"notif"` as a notification. Both `rpc` and `notification` terminate the server.
impl Server for AnswerServer {
    type Success = u32;
    type RPCCallResult = Result<u32, ServerError>;
    type NotificationResult = Result<(), ()>;
    fn rpc(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>) -> Option<Self::RPCCallResult> {
        ctl.terminate();
        assert_eq!(method, "test");
        assert!(params.is_none());
        Some(Ok(42))
    }
    fn notification(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>) -> Option<Self::NotificationResult> {
        ctl.terminate();
        assert_eq!(method, "notif");
        assert!(params.is_none());
        Some(Ok(()))
    }
}

/// Set up a client and a server
///
/// Create a reactor, set a safety timeout (if the test doesn't finish in 15 seconds, panic) and
/// provide two connected TCP streams. We could use unix socket pair, but that wouldn't work on
/// windows, so we just connect on 127.0.0.1.
fn prepare() -> (Core, Framed<TcpStream, LineCodec>, Framed<TcpStream, LineCodec>) {
    let mut reactor = Core::new().unwrap();
    let handle = reactor.handle();
    // Kill the test if it gets stuck
    let timeout = Timeout::new(Duration::new(15, 0), &handle)
        .unwrap()
        .then(|_| -> Result<(), ()> { panic!("Timeout happened") });
    handle.spawn(timeout);
    // Build two connected TCP streams
    let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &handle).unwrap();
    let address = listener.local_addr().unwrap();
    let server_finished = listener.incoming()
        .into_future()
        .then(|result| match result {
            Ok((result, _incoming)) => Ok(result.unwrap().0),
            Err((err, _incoming)) => Err(err),
        });
    let client_finished = TcpStream::connect(&address, &handle);
    // Wait for both of them to be connected
    let (s1, s2) = reactor.run(server_finished.join(client_finished))
        .unwrap();
    // And return everything
    (reactor, s1.framed(LineCodec::new()), s2.framed(LineCodec::new()))
}

/// Single RPC call
///
/// Run both the server and client, send a request and wait for the answer. The server terminates
/// after the first request, so we can wait for both to terminate.
#[test]
fn rpc_answer() {
    let (mut reactor, s1, s2) = prepare();
    let both = {
        // Run in a sub-block, so we drop all the clients, etc.
        let handle = reactor.handle();
        let (_client, _ctl, server_finished) = Endpoint::new(s1, AnswerServer).start(&handle);
        let (client, _ctl, _finished) = Endpoint::client_only(s2).start(&handle);
        let client_finished = client.call("test".to_owned(), None, None)
            .and_then(|(_client, answered)| answered)
            .map(|response| assert_eq!(json!(42), response.unwrap().result.unwrap()));
        server_finished.map_err(|_| IoError::new(ErrorKind::Other, "Canceled"))
            .join(client_finished)
            .map(|_| ())
            .map_err(|e| panic!("{:?}", e))
    };
    reactor.run(both).unwrap();
}

/// Send a notification to the server.
#[test]
fn notification() {
    let (mut reactor, s1, s2) = prepare();
    let both = {
        // Run in a sub-block, so we drop all the clients, etc.
        let handle = reactor.handle();
        let (_client, _ctl, server_finished) = Endpoint::new(s1, AnswerServer).start(&handle);
        let (client, _ctl, _finished) = Endpoint::client_only(s2).start(&handle);
        let client_finished = client.notify("notif".to_owned(), None)
            .and_then(|_client| Ok(()));
        server_finished.map_err(|_| IoError::new(ErrorKind::Other, "Canceled"))
            .join(client_finished)
            .map(|_| ())
            .map_err(|e| panic!("{:?}", e))
    };
    reactor.run(both).unwrap();
}

struct AnotherServer(Handle);

/// Another testing server
///
/// It answers the RPC "timeout" with waiting that as long as is provided in the first and second
/// argument (seconds and microseconds) and then sending true back. It rejects all other methods.
/// It terminates on receiving any method.
impl Server for AnotherServer {
    type Success = bool;
    type RPCCallResult = BoxFuture<bool, ServerError>;
    type NotificationResult = Result<(), ()>;
    fn rpc(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>) -> Option<Self::RPCCallResult> {
        ctl.terminate();
        if method == "timeout" {
            let params: Vec<u64> = from_value(params.as_ref().unwrap().clone()).unwrap();
            let timeout = Timeout::new(Duration::new(params[0], params[1] as u32), &self.0)
                .unwrap()
                .map(|_| true)
                .map_err(|e| (-32000, "Server error".to_owned(), Some(to_value(format!("{}", e)).unwrap())))
                .boxed();
            Some(timeout)
        } else {
            None
        }
    }
}

/// Test where we call a non-existant method
///
/// And we get a proper error.
#[test]
fn wrong_method() {
    let (mut reactor, s1, s2) = prepare();
    let both = {
        // Run in a sub-block, so we drop all the clients, etc.
        let handle = reactor.handle();
        let (_client, _ctl, server_finished) = Endpoint::new(s1, AnotherServer(handle.clone())).start(&handle);
        let (client, _ctl, _finished) = Endpoint::client_only(s2).start(&handle);
        let client_finished = client.call("wrong".to_owned(), None, None)
            .and_then(|(_client, answered)| answered)
            .map(|response| {
                assert_eq!(RPCError {
                               code: -32601,
                               message: "Method not found".to_owned(),
                               data: Some(json!("wrong")),
                           },
                           response.unwrap().result.unwrap_err());
            });
        server_finished.map_err(|_| IoError::new(ErrorKind::Other, "Canceled"))
            .join(client_finished)
            .map(|_| ())
            .map_err(|e| panic!("{:?}", e))
    };
    reactor.run(both).unwrap();
}
<commit_msg>Some tests with methods taking longer time<commit_after>// Copyright 2017 tokio-jsonrpc Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate tokio_jsonrpc;
extern crate tokio_core;
extern crate futures;
#[macro_use]
extern crate serde_json;

use std::time::Duration;
use std::io::{Error as IoError, ErrorKind};

use tokio_jsonrpc::{Endpoint, LineCodec, Server, ServerCtl, ServerError};
use tokio_jsonrpc::message::RPCError;

use futures::{Future, Stream};
use futures::future::BoxFuture;
use tokio_core::reactor::{Core, Timeout, Handle};
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::io::{Io, Framed};
use serde_json::{Value, to_value, from_value};

struct AnswerServer;

/// A test server
///
/// It expects no parameters and the method to be `"test"` and returns 42 on RPC. It expects
/// `"notif"` as a notification. Both `rpc` and `notification` terminate the server.
impl Server for AnswerServer {
    type Success = u32;
    type RPCCallResult = Result<u32, ServerError>;
    type NotificationResult = Result<(), ()>;
    fn rpc(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>) -> Option<Self::RPCCallResult> {
        ctl.terminate();
        assert_eq!(method, "test");
        assert!(params.is_none());
        Some(Ok(42))
    }
    fn notification(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>) -> Option<Self::NotificationResult> {
        ctl.terminate();
        assert_eq!(method, "notif");
        assert!(params.is_none());
        Some(Ok(()))
    }
}

/// Set up a client and a server
///
/// Create a reactor, set a safety timeout (if the test doesn't finish in 15 seconds, panic) and
/// provide two connected TCP streams. We could use unix socket pair, but that wouldn't work on
/// windows, so we just connect on 127.0.0.1.
fn prepare() -> (Core, Framed<TcpStream, LineCodec>, Framed<TcpStream, LineCodec>) {
    let mut reactor = Core::new().unwrap();
    let handle = reactor.handle();
    // Kill the test if it gets stuck
    let timeout = Timeout::new(Duration::new(15, 0), &handle)
        .unwrap()
        .then(|_| -> Result<(), ()> { panic!("Timeout happened") });
    handle.spawn(timeout);
    // Build two connected TCP streams
    let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &handle).unwrap();
    let address = listener.local_addr().unwrap();
    let server_finished = listener.incoming()
        .into_future()
        .then(|result| match result {
            Ok((result, _incoming)) => Ok(result.unwrap().0),
            Err((err, _incoming)) => Err(err),
        });
    let client_finished = TcpStream::connect(&address, &handle);
    // Wait for both of them to be connected
    let (s1, s2) = reactor.run(server_finished.join(client_finished))
        .unwrap();
    // And return everything
    (reactor, s1.framed(LineCodec::new()), s2.framed(LineCodec::new()))
}

/// Single RPC call
///
/// Run both the server and client, send a request and wait for the answer. The server terminates
/// after the first request, so we can wait for both to terminate.
#[test]
fn rpc_answer() {
    let (mut reactor, s1, s2) = prepare();
    let both = {
        // Run in a sub-block, so we drop all the clients, etc.
        let handle = reactor.handle();
        let (_client, _ctl, server_finished) = Endpoint::new(s1, AnswerServer).start(&handle);
        let (client, _ctl, _finished) = Endpoint::client_only(s2).start(&handle);
        let client_finished = client.call("test".to_owned(), None, None)
            .and_then(|(_client, answered)| answered)
            .map(|response| assert_eq!(json!(42), response.unwrap().result.unwrap()));
        server_finished.map_err(|_| IoError::new(ErrorKind::Other, "Canceled"))
            .join(client_finished)
            .map(|_| ())
            .map_err(|e| panic!("{:?}", e))
    };
    reactor.run(both).unwrap();
}

/// Send a notification to the server.
#[test]
fn notification() {
    let (mut reactor, s1, s2) = prepare();
    let both = {
        // Run in a sub-block, so we drop all the clients, etc.
        let handle = reactor.handle();
        let (_client, _ctl, server_finished) = Endpoint::new(s1, AnswerServer).start(&handle);
        let (client, _ctl, _finished) = Endpoint::client_only(s2).start(&handle);
        let client_finished = client.notify("notif".to_owned(), None)
            .and_then(|_client| Ok(()));
        server_finished.map_err(|_| IoError::new(ErrorKind::Other, "Canceled"))
            .join(client_finished)
            .map(|_| ())
            .map_err(|e| panic!("{:?}", e))
    };
    reactor.run(both).unwrap();
}

struct AnotherServer(Handle);

/// Another testing server
///
/// It answers the RPC "timeout" with waiting that as long as is provided in the first and second
/// argument (seconds and microseconds) and then sending true back. It rejects all other methods.
/// It terminates on receiving any method.
impl Server for AnotherServer {
    type Success = bool;
    type RPCCallResult = BoxFuture<bool, ServerError>;
    type NotificationResult = Result<(), ()>;
    fn rpc(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>) -> Option<Self::RPCCallResult> {
        ctl.terminate();
        if method == "timeout" {
            let params: Vec<u64> = from_value(params.as_ref().unwrap().clone()).unwrap();
            let timeout = Timeout::new(Duration::new(params[0], params[1] as u32), &self.0)
                .unwrap()
                .map(|_| true)
                .map_err(|e| (-32000, "Server error".to_owned(), Some(to_value(format!("{}", e)).unwrap())))
                .boxed();
            Some(timeout)
        } else {
            None
        }
    }
}

/// Test where we call a non-existant method
///
/// And we get a proper error.
#[test]
fn wrong_method() {
    let (mut reactor, s1, s2) = prepare();
    let both = {
        // Run in a sub-block, so we drop all the clients, etc.
        let handle = reactor.handle();
        let (_client, _ctl, server_finished) = Endpoint::new(s1, AnotherServer(handle.clone())).start(&handle);
        let (client, _ctl, _finished) = Endpoint::client_only(s2).start(&handle);
        let client_finished = client.call("wrong".to_owned(), None, None)
            .and_then(|(_client, answered)| answered)
            .map(|response| {
                assert_eq!(RPCError {
                               code: -32601,
                               message: "Method not found".to_owned(),
                               data: Some(json!("wrong")),
                           },
                           response.unwrap().result.unwrap_err());
            });
        server_finished.map_err(|_| IoError::new(ErrorKind::Other, "Canceled"))
            .join(client_finished)
            .map(|_| ())
            .map_err(|e| panic!("{:?}", e))
    };
    reactor.run(both).unwrap();
}

/// Test we can get a timeout if the method takes a long time.
#[test]
fn timeout() {
    let (mut reactor, s1, s2) = prepare();
    let both = {
        // Run in a sub-block, so we drop all the clients, etc.
        let handle = reactor.handle();
        let (_client, _ctl, server_finished) = Endpoint::new(s1, AnotherServer(handle.clone())).start(&handle);
        let (client, _ctl, _finished) = Endpoint::client_only(s2).start(&handle);
        let client_finished = client.call("timeout".to_owned(), Some(json!([3, 0])), Some(Duration::new(1, 0)))
            .and_then(|(_client, answered)| answered)
            .map(|response| assert!(response.is_none()));
        server_finished.map_err(|_| IoError::new(ErrorKind::Other, "Canceled"))
            .join(client_finished)
            .map(|_| ())
            .map_err(|e| panic!("{:?}", e))
    };
    reactor.run(both).unwrap();
}

/// Test the server works even when there are some methods taking some time
#[test]
fn delayed() {
    let (mut reactor, s1, s2) = prepare();
    let both = {
        // Run in a sub-block, so we drop all the clients, etc.
        let handle = reactor.handle();
        let (_client, _ctl, server_finished) = Endpoint::new(s1, AnotherServer(handle.clone())).start(&handle);
        let (client, _ctl, _finished) = Endpoint::client_only(s2).start(&handle);
        let client_finished = client.call("timeout".to_owned(), Some(json!([0, 500000])), Some(Duration::new(1, 0)))
            .and_then(|(_client, answered)| answered)
            .map(|response| assert!(response.unwrap().result.unwrap().as_bool().unwrap()));
        server_finished.map_err(|_| IoError::new(ErrorKind::Other, "Canceled"))
            .join(client_finished)
            .map(|_| ())
            .map_err(|e| panic!("{:?}", e))
    };
    reactor.run(both).unwrap();
}

// TODO: Check running in parallel
<|endoftext|>


<commit_before>mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "792c645ca7d11a8d254df307d019c5bf01445c37";

#[rustfmt::skip]
static EXCLUDE: &[&str] = &[
    // Compile-fail expr parameter in const generic position: f::<1 + 2>()
    "test/ui/const-generics/const-expression-parameter.rs",

    // Deprecated anonymous parameter syntax in traits
    "test/ui/issues/issue-13105.rs",
    "test/ui/issues/issue-13775.rs",
    "test/ui/issues/issue-34074.rs",
    "test/ui/proc-macro/trait-fn-args-2015.rs",

    // Not actually test cases
    "test/rustdoc-ui/test-compile-fail2.rs",
    "test/rustdoc-ui/test-compile-fail3.rs",
    "test/ui/include-single-expr-helper.rs",
    "test/ui/include-single-expr-helper-1.rs",
    "test/ui/issues/auxiliary/issue-21146-inc.rs",
    "test/ui/json-bom-plus-crlf-multifile-aux.rs",
    "test/ui/lint/expansion-time-include.rs",
    "test/ui/macros/auxiliary/macro-comma-support.rs",
    "test/ui/macros/auxiliary/macro-include-items-expr.rs",
];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    let path = if let Some(path) = path_string.strip_prefix("tests/rust/src/") {
        path
    } else if let Some(path) = path_string.strip_prefix("tests/rust/library/") {
        path
    } else {
        panic!("unexpected path in Rust dist: {}", path_string);
    };

    // TODO assert that parsing fails on the parse-fail cases
    if path.starts_with("test/parse-fail")
        || path.starts_with("test/compile-fail")
        || path.starts_with("test/rustfix")
    {
        return false;
    }

    if path.starts_with("test/ui") {
        let stderr_path = entry.path().with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    !EXCLUDE.contains(&path)
}

#[allow(dead_code)]
pub fn edition(path: &Path) -> &'static str {
    if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
        "2015"
    } else {
        "2018"
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
    let mut missing = String::new();
    let test_src = Path::new("tests/rust/src");
    for exclude in EXCLUDE {
        if !test_src.join(exclude).exists() {
            missing += "\ntests/rust/src/";
            missing += exclude;
        }
    }
    if !missing.is_empty() {
        panic!("excluded test file does not exist:{}\n", missing);
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<commit_msg>Interpret test path exclusions as relative to Rust repo root<commit_after>mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "792c645ca7d11a8d254df307d019c5bf01445c37";

#[rustfmt::skip]
static EXCLUDE: &[&str] = &[
    // Compile-fail expr parameter in const generic position: f::<1 + 2>()
    "src/test/ui/const-generics/const-expression-parameter.rs",

    // Deprecated anonymous parameter syntax in traits
    "src/test/ui/issues/issue-13105.rs",
    "src/test/ui/issues/issue-13775.rs",
    "src/test/ui/issues/issue-34074.rs",
    "src/test/ui/proc-macro/trait-fn-args-2015.rs",

    // Not actually test cases
    "src/test/rustdoc-ui/test-compile-fail2.rs",
    "src/test/rustdoc-ui/test-compile-fail3.rs",
    "src/test/ui/include-single-expr-helper.rs",
    "src/test/ui/include-single-expr-helper-1.rs",
    "src/test/ui/issues/auxiliary/issue-21146-inc.rs",
    "src/test/ui/json-bom-plus-crlf-multifile-aux.rs",
    "src/test/ui/lint/expansion-time-include.rs",
    "src/test/ui/macros/auxiliary/macro-comma-support.rs",
    "src/test/ui/macros/auxiliary/macro-include-items-expr.rs",
];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    let path = if let Some(path) = path_string.strip_prefix("tests/rust/") {
        path
    } else {
        panic!("unexpected path in Rust dist: {}", path_string);
    };

    // TODO assert that parsing fails on the parse-fail cases
    if path.starts_with("src/test/parse-fail")
        || path.starts_with("src/test/compile-fail")
        || path.starts_with("src/test/rustfix")
    {
        return false;
    }

    if path.starts_with("src/test/ui") {
        let stderr_path = entry.path().with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    !EXCLUDE.contains(&path)
}

#[allow(dead_code)]
pub fn edition(path: &Path) -> &'static str {
    if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
        "2015"
    } else {
        "2018"
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
    let mut missing = String::new();
    let test_src = Path::new("tests/rust");
    for exclude in EXCLUDE {
        if !test_src.join(exclude).exists() {
            missing += "\ntests/rust/";
            missing += exclude;
        }
    }
    if !missing.is_empty() {
        panic!("excluded test file does not exist:{}\n", missing);
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<|endoftext|>


<commit_before>use cgmath::prelude::*;
use cgmath::{Matrix4, Point2, Point3, Vector3};

use rand;

use crate::aabb::{self, AABB};
use crate::color::Color;
use crate::index_ptr::IndexPtr;
use crate::material::Material;
use crate::pt_renderer::{Intersect, Ray};
use crate::util::ConvArr;
use crate::vertex::Vertex;
use crate::Float;

#[derive(Default)]
pub struct TriangleBuilder {
    vertices: Vec<IndexPtr<Vertex>>,
}

impl TriangleBuilder {
    pub fn new() -> Self {
        Self {
            vertices: Vec::new(),
        }
    }

    pub fn add_vertex(&mut self, vertex: IndexPtr<Vertex>) {
        self.vertices.push(vertex);
    }

    pub fn build(self, ng: [f32; 3], material: IndexPtr<Material>) -> Result<Triangle, String> {
        if self.vertices.len() != 3 {
            Err("Triangle doesn't have 3 vertices!".to_string())
        } else {
            Ok(Triangle::new(
                self.vertices[0].clone(),
                self.vertices[1].clone(),
                self.vertices[2].clone(),
                Vector3::from_arr(ng),
                material,
            ))
        }
    }
}

/// Tracable triangle
#[derive(Clone, Debug)]
pub struct Triangle {
    v1: IndexPtr<Vertex>,
    v2: IndexPtr<Vertex>,
    v3: IndexPtr<Vertex>,
    /// Geometric normal
    ng: Vector3<Float>,
    to_barycentric: Matrix4<Float>,
    pub material: IndexPtr<Material>,
}

impl Triangle {
    fn new(
        v1: IndexPtr<Vertex>,
        v2: IndexPtr<Vertex>,
        v3: IndexPtr<Vertex>,
        ng: Vector3<Float>,
        material: IndexPtr<Material>,
    ) -> Self {
        let p1 = v1.p;
        let p2 = v2.p;
        let p3 = v3.p;
        let z = (p2 - p1).cross(p3 - p1).normalize();
        let from_barycentric = Matrix4::from_cols(
            (p2 - p1).extend(0.0),
            (p3 - p1).extend(0.0),
            z.extend(0.0),
            p1.to_homogeneous(),
        );
        let to_barycentric = from_barycentric
            .invert()
            .expect("Non invertible barycentric tranform");
        Self {
            v1,
            v2,
            v3,
            ng,
            to_barycentric,
            material,
        }
    }

    fn normal(&self, u: Float, v: Float) -> Vector3<Float> {
        let n1 = self.v1.n;
        let n2 = self.v2.n;
        let n3 = self.v3.n;
        (1.0 - u - v) * n1 + u * n2 + v * n3
    }

    fn tex_coords(&self, u: Float, v: Float) -> Point2<Float> {
        let t1 = self.v1.t;
        let t2 = self.v2.t;
        let t3 = self.v3.t;
        (1.0 - u - v) * t1 + (u * t2 - (-v) * t3)
    }

    pub fn aabb(&self) -> AABB {
        let mut min = self.v1.p;
        min = aabb::min_point(&min, &self.v2.p);
        min = aabb::min_point(&min, &self.v3.p);
        let mut max = self.v1.p;
        max = aabb::max_point(&max, &self.v2.p);
        max = aabb::max_point(&max, &self.v3.p);
        AABB { min, max }
    }

    pub fn le(&self, dir: Vector3<Float>) -> Color {
        if let Some(le) = self.material.emissive {
            if self.ng.dot(dir) > 0.0 {
                return le;
            }
        }
        Color::black()
    }

    pub fn center(&self) -> Point3<Float> {
        Point3::centroid(&[self.v1.p, self.v2.p, self.v3.p])
    }

    pub fn area(&self) -> Float {
        0.5 / self.to_barycentric.determinant().abs()
    }

    pub fn random_point(&self) -> (Point3<Float>, Vector3<Float>) {
        let r1: Float = rand::random();
        let r2: Float = rand::random();
        let sr1 = r1.sqrt();
        let u = 1.0 - sr1;
        let v = r2 * sr1;
        (self.pos(u, v), self.normal(u, v))
    }

    fn pos(&self, u: Float, v: Float) -> Point3<Float> {
        // Have to substract one component since cgmath points cannot by summed
        // and there is not a cleaner method to convert to Vector3
        (1.0 - u - v) * self.v1.p + (u * self.v2.p - (-v) * self.v3.p)
    }
}

#[derive(Debug)]
pub struct Hit<'a> {
    pub tri: &'a Triangle,
    pub t: Float,
    pub u: Float,
    pub v: Float,
}

impl<'a> Intersect<'a, Hit<'a>> for Triangle {
    fn intersect(&self, ray: &Ray) -> Option<Hit> {
        let bary_o = self.to_barycentric * ray.orig.to_homogeneous();
        let bary_d = self.to_barycentric * ray.dir.extend(0.0);
        let t = -bary_o.z / bary_d.z;
        let u = bary_o.x + t * bary_d.x;
        let v = bary_o.y + t * bary_d.y;
        if u >= 0.0 && v >= 0.0 && u + v <= 1.0 && t > 0.0 && t < ray.length {
            Some(Hit { tri: self, t, u, v })
        } else {
            None
        }
    }
}

impl Hit<'_> {
    pub fn pos(&self) -> Point3<Float> {
        self.tri.pos(self.u, self.v)
    }

    pub fn normal(&self) -> Vector3<Float> {
        self.tri.normal(self.u, self.v)
    }

    pub fn tex_coords(&self) -> Point2<Float> {
        self.tri.tex_coords(self.u, self.v)
    }
}
<commit_msg>Clean up triangle barycentric interpolation<commit_after>use cgmath::prelude::*;
use cgmath::{Matrix4, Point2, Point3, Vector3};

use rand;

use crate::aabb::{self, AABB};
use crate::color::Color;
use crate::index_ptr::IndexPtr;
use crate::material::Material;
use crate::pt_renderer::{Intersect, Ray};
use crate::util::ConvArr;
use crate::vertex::Vertex;
use crate::Float;

#[derive(Default)]
pub struct TriangleBuilder {
    vertices: Vec<IndexPtr<Vertex>>,
}

impl TriangleBuilder {
    pub fn new() -> Self {
        Self {
            vertices: Vec::new(),
        }
    }

    pub fn add_vertex(&mut self, vertex: IndexPtr<Vertex>) {
        self.vertices.push(vertex);
    }

    pub fn build(self, ng: [f32; 3], material: IndexPtr<Material>) -> Result<Triangle, String> {
        if self.vertices.len() != 3 {
            Err("Triangle doesn't have 3 vertices!".to_string())
        } else {
            Ok(Triangle::new(
                self.vertices[0].clone(),
                self.vertices[1].clone(),
                self.vertices[2].clone(),
                Vector3::from_arr(ng),
                material,
            ))
        }
    }
}

/// Tracable triangle
#[derive(Clone, Debug)]
pub struct Triangle {
    v1: IndexPtr<Vertex>,
    v2: IndexPtr<Vertex>,
    v3: IndexPtr<Vertex>,
    /// Geometric normal
    ng: Vector3<Float>,
    to_barycentric: Matrix4<Float>,
    pub material: IndexPtr<Material>,
}

impl Triangle {
    fn new(
        v1: IndexPtr<Vertex>,
        v2: IndexPtr<Vertex>,
        v3: IndexPtr<Vertex>,
        ng: Vector3<Float>,
        material: IndexPtr<Material>,
    ) -> Self {
        let p1 = v1.p;
        let p2 = v2.p;
        let p3 = v3.p;
        let z = (p2 - p1).cross(p3 - p1).normalize();
        let from_barycentric = Matrix4::from_cols(
            (p2 - p1).extend(0.0),
            (p3 - p1).extend(0.0),
            z.extend(0.0),
            p1.to_homogeneous(),
        );
        let to_barycentric = from_barycentric
            .invert()
            .expect("Non invertible barycentric tranform");
        Self {
            v1,
            v2,
            v3,
            ng,
            to_barycentric,
            material,
        }
    }

    fn pos(&self, u: Float, v: Float) -> Point3<Float> {
        let p1 = self.v1.p;
        let p2 = self.v2.p;
        let p3 = self.v3.p;
        (1.0 - u - v) * p1 + u * p2.to_vec() + v * p3.to_vec()
    }

    fn normal(&self, u: Float, v: Float) -> Vector3<Float> {
        let n1 = self.v1.n;
        let n2 = self.v2.n;
        let n3 = self.v3.n;
        (1.0 - u - v) * n1 + u * n2 + v * n3
    }

    fn tex_coords(&self, u: Float, v: Float) -> Point2<Float> {
        let t1 = self.v1.t;
        let t2 = self.v2.t;
        let t3 = self.v3.t;
        (1.0 - u - v) * t1 + u * t2.to_vec() + v * t3.to_vec()
    }

    pub fn aabb(&self) -> AABB {
        let mut min = self.v1.p;
        min = aabb::min_point(&min, &self.v2.p);
        min = aabb::min_point(&min, &self.v3.p);
        let mut max = self.v1.p;
        max = aabb::max_point(&max, &self.v2.p);
        max = aabb::max_point(&max, &self.v3.p);
        AABB { min, max }
    }

    pub fn le(&self, dir: Vector3<Float>) -> Color {
        if let Some(le) = self.material.emissive {
            if self.ng.dot(dir) > 0.0 {
                return le;
            }
        }
        Color::black()
    }

    pub fn center(&self) -> Point3<Float> {
        Point3::centroid(&[self.v1.p, self.v2.p, self.v3.p])
    }

    pub fn area(&self) -> Float {
        0.5 / self.to_barycentric.determinant().abs()
    }

    pub fn random_point(&self) -> (Point3<Float>, Vector3<Float>) {
        let r1: Float = rand::random();
        let r2: Float = rand::random();
        let sr1 = r1.sqrt();
        let u = 1.0 - sr1;
        let v = r2 * sr1;
        (self.pos(u, v), self.normal(u, v))
    }
}

#[derive(Debug)]
pub struct Hit<'a> {
    pub tri: &'a Triangle,
    pub t: Float,
    pub u: Float,
    pub v: Float,
}

impl<'a> Intersect<'a, Hit<'a>> for Triangle {
    fn intersect(&self, ray: &Ray) -> Option<Hit> {
        let bary_o = self.to_barycentric * ray.orig.to_homogeneous();
        let bary_d = self.to_barycentric * ray.dir.extend(0.0);
        let t = -bary_o.z / bary_d.z;
        let u = bary_o.x + t * bary_d.x;
        let v = bary_o.y + t * bary_d.y;
        if u >= 0.0 && v >= 0.0 && u + v <= 1.0 && t > 0.0 && t < ray.length {
            Some(Hit { tri: self, t, u, v })
        } else {
            None
        }
    }
}

impl Hit<'_> {
    pub fn pos(&self) -> Point3<Float> {
        self.tri.pos(self.u, self.v)
    }

    pub fn normal(&self) -> Vector3<Float> {
        self.tri.normal(self.u, self.v)
    }

    pub fn tex_coords(&self) -> Point2<Float> {
        self.tri.tex_coords(self.u, self.v)
    }
}
<|endoftext|>


<commit_before>extern crate bincode;
extern crate rustc_serialize;

use bincode::SizeLimit;
use bincode::rustc_serialize::{encode, decode};
use rustc_serialize::{Encodable, Decodable};

use ::{KeyType, ValueType};

use std::collections::{BTreeMap, BTreeSet};
use std::collections::btree_map::Iter as MIter;
use std::collections::btree_set::Iter as SIter;
use std::error::Error;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write, ErrorKind};
use std::io::Error as IOError;
use std::iter::Peekable;
use std::marker::PhantomData;

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
pub struct KeyValuePair<K: KeyType, V: ValueType> {
    pub key: K,
    pub value: V,
}

pub struct WALFile<K: KeyType, V: ValueType> {
    fd: File,  // the WAL file
    key_size: usize,
    value_size: usize,
    _k_marker: PhantomData<K>,
    _v_marker: PhantomData<V>
}

pub struct WALIterator<K: KeyType, V: ValueType> {
    wal_file: WALFile<K,V>,  // the WAL file
    _k_marker: PhantomData<K>,
    _v_marker: PhantomData<V>
}

impl <K: KeyType, V: ValueType> WALFile<K,V> {
    pub fn new(wal_file_path: String, key_size: usize, value_size: usize) -> Result<WALFile<K,V>, Box<Error>> {
        let mut wal_file = try!(OpenOptions::new().read(true).create(false).open(wal_file_path));

        return Ok(WALFile{fd: wal_file,
                          key_size: key_size,
                          value_size: value_size,
                          _k_marker: PhantomData,
                          _v_marker: PhantomData});
    }

    pub fn iter(&self) -> WALIterator<K,V> {
        WALIterator{wal_file: *self, _k_marker: self._k_marker, _v_marker: self._v_marker}
    }

    pub fn is_new(&self) -> Result<bool, Box<Error>> {
        return Ok(try!(self.fd.metadata()).len() == 0);
    }

    pub fn write_record(&mut self, kv: &KeyValuePair<K,V>) -> Result<(), Box<Error>> {
        // encode the record
        let record_size = self.key_size + self.value_size;
        let mut buff = try!(encode(&kv, SizeLimit::Bounded(record_size as u64)));

        // padd it out to the max size
        if buff.len() > self.key_size + self.value_size {
            return Err(From::from(IOError::new(ErrorKind::InvalidData, "Key and value size are too large")));
        } else {
            let diff = (self.key_size + self.value_size) - buff.len();
            buff.extend(vec![0; diff]);
        }

        match self.fd.write_all(&buff) {
            Ok(_) => Ok( () ),
            Err(e) => Err(From::from(e))
        }
    }
}

impl <'a, K: KeyType, V: ValueType> Iterator for WALIterator<K,V> {
    type Item = KeyValuePair<K,V>;

    fn next(&mut self) -> Option<Self::Item> {
        let total_size = self.wal_file.key_size + self.wal_file.value_size;
        let mut buff = vec![0; total_size];

        // attempt to read a buffer's worth and decode
        match self.wal_file.fd.read_exact(&mut buff) {
            Ok(_) => {
                match decode(&buff) {
                    Ok(record) => Some(record),
                    Err(_) => None
                }
            },
            Err(_) => None
        }
    }
}

/*

struct MemoryRecordIterator<'a, 'b, K: KeyType, V: ValueType> {
    key_size: usize,
    value_size: usize,
    key_iter: Peekable<MIter<'a, K, BTreeSet<V>>>,
    value_iter: Option<Peekable<SIter<'b, V>>>
}

impl <'a, 'b, K: KeyType, V: ValueType> MemoryRecordIterator<'a, 'b, K, V> {
    fn new(key_size: usize, value_size: usize, mem_tree: BTreeMap<K, BTreeSet<V>>) -> MemoryRecordIterator<'a, 'b, K,V> {
        let key_it = mem_tree.iter().peekable();

        MemoryRecordIterator {key_size: key_size,
                              value_size: value_size,
                              key_iter: key_it,
                              value_iter: key_it.peek().iter().peekable()}
    }
}

impl <'a, 'b, K: KeyType, V: ValueType> Iterator for MemoryRecordIterator<'a, 'b, K,V> {
    type Item = Vec<u8>;

    fn next(&mut self) -> Option<Self::Item> {

    }
}

*/

#[cfg(test)]
mod tests {
    use tests::gen_temp_name;
    use std::fs;
    use std::fs::OpenOptions;
    use wal_file::{WALFile, KeyValuePair};

    #[test]
    fn test_iterator() {
        let file_path = gen_temp_name();
        let wal_file = WALFile::new(file_path.to_owned() + ".wal", 20, 20).unwrap();

        let kv1 = KeyValuePair{key: "hello".to_owned(), value: "world".to_owned()};
        let kv2 = KeyValuePair{key: "foo".to_owned(), value: "bar".to_owned()};

        wal_file.write_record(kv1);
        wal_file.write_record(kv2);

        let wal_it = wal_file.iter();

        let it_kv1 = wal_it.next().unwrap();

        assert!(kv1.key == it_kv1.key);
        assert!(kv1.value == it_kv1.value);

        let it_kv2 = wal_it.next().unwrap();

        assert!(kv2.key == it_kv2.key);
        assert!(kv2.value == it_kv2.value);
    }
}
<commit_msg>Added IntoIterator trait for WALFile<commit_after>extern crate bincode;
extern crate rustc_serialize;

use bincode::SizeLimit;
use bincode::rustc_serialize::{encode, decode};
use rustc_serialize::{Encodable, Decodable};

use ::{KeyType, ValueType};

use std::collections::{BTreeMap, BTreeSet};
use std::collections::btree_map::Iter as MIter;
use std::collections::btree_set::Iter as SIter;
use std::error::Error;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write, ErrorKind};
use std::io::Error as IOError;
use std::iter::Peekable;
use std::marker::PhantomData;

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
pub struct KeyValuePair<K: KeyType, V: ValueType> {
    pub key: K,
    pub value: V,
}

pub struct WALFile<K: KeyType, V: ValueType> {
    fd: File,  // the WAL file
    key_size: usize,
    value_size: usize,
    _k_marker: PhantomData<K>,
    _v_marker: PhantomData<V>
}

pub struct WALIterator<K: KeyType, V: ValueType> {
    wal_file: WALFile<K,V>,  // the WAL file
    _k_marker: PhantomData<K>,
    _v_marker: PhantomData<V>
}

impl <K: KeyType, V: ValueType> WALFile<K,V> {
    pub fn new(wal_file_path: String, key_size: usize, value_size: usize) -> Result<WALFile<K,V>, Box<Error>> {
        let mut wal_file = try!(OpenOptions::new().read(true).create(false).open(wal_file_path));

        return Ok(WALFile{fd: wal_file,
                          key_size: key_size,
                          value_size: value_size,
                          _k_marker: PhantomData,
                          _v_marker: PhantomData});
    }

    pub fn is_new(&self) -> Result<bool, Box<Error>> {
        return Ok(try!(self.fd.metadata()).len() == 0);
    }

    pub fn write_record(&mut self, kv: &KeyValuePair<K,V>) -> Result<(), Box<Error>> {
        // encode the record
        let record_size = self.key_size + self.value_size;
        let mut buff = try!(encode(&kv, SizeLimit::Bounded(record_size as u64)));

        // padd it out to the max size
        if buff.len() > self.key_size + self.value_size {
            return Err(From::from(IOError::new(ErrorKind::InvalidData, "Key and value size are too large")));
        } else {
            let diff = (self.key_size + self.value_size) - buff.len();
            buff.extend(vec![0; diff]);
        }

        match self.fd.write_all(&buff) {
            Ok(_) => Ok( () ),
            Err(e) => Err(From::from(e))
        }
    }
}

impl <K: KeyType, V: ValueType> IntoIterator for WALFile<K,V> {
    type Item = KeyValuePair<K,V>;
    type IntoIter = WALIterator<K,V>;

    fn into_iter(self) -> Self::IntoIter {
        let k_marker = self._k_marker;
        let v_marker = self._v_marker;

        WALIterator{wal_file: self, _k_marker: k_marker, _v_marker: v_marker}
    }
}

impl <'a, K: KeyType, V: ValueType> Iterator for WALIterator<K,V> {
    type Item = KeyValuePair<K,V>;

    fn next(&mut self) -> Option<Self::Item> {
        let total_size = self.wal_file.key_size + self.wal_file.value_size;
        let mut buff = vec![0; total_size];

        // attempt to read a buffer's worth and decode
        match self.wal_file.fd.read_exact(&mut buff) {
            Ok(_) => {
                match decode(&buff) {
                    Ok(record) => Some(record),
                    Err(_) => None
                }
            },
            Err(_) => None
        }
    }
}

/*

struct MemoryRecordIterator<'a, 'b, K: KeyType, V: ValueType> {
    key_size: usize,
    value_size: usize,
    key_iter: Peekable<MIter<'a, K, BTreeSet<V>>>,
    value_iter: Option<Peekable<SIter<'b, V>>>
}

impl <'a, 'b, K: KeyType, V: ValueType> MemoryRecordIterator<'a, 'b, K, V> {
    fn new(key_size: usize, value_size: usize, mem_tree: BTreeMap<K, BTreeSet<V>>) -> MemoryRecordIterator<'a, 'b, K,V> {
        let key_it = mem_tree.iter().peekable();

        MemoryRecordIterator {key_size: key_size,
                              value_size: value_size,
                              key_iter: key_it,
                              value_iter: key_it.peek().iter().peekable()}
    }
}

impl <'a, 'b, K: KeyType, V: ValueType> Iterator for MemoryRecordIterator<'a, 'b, K,V> {
    type Item = Vec<u8>;

    fn next(&mut self) -> Option<Self::Item> {

    }
}

*/

#[cfg(test)]
mod tests {
    use tests::gen_temp_name;
    use std::fs;
    use std::fs::OpenOptions;
    use wal_file::{WALFile, KeyValuePair};

    #[test]
    fn test_iterator() {
        let file_path = gen_temp_name();
        let wal_file = WALFile::new(file_path.to_owned() + ".wal", 20, 20).unwrap();

        let kv1 = KeyValuePair{key: "hello".to_owned(), value: "world".to_owned()};
        let kv2 = KeyValuePair{key: "foo".to_owned(), value: "bar".to_owned()};

        wal_file.write_record(kv1);
        wal_file.write_record(kv2);

        let wal_it = wal_file.iter();

        let it_kv1 = wal_it.next().unwrap();

        assert!(kv1.key == it_kv1.key);
        assert!(kv1.value == it_kv1.value);

        let it_kv2 = wal_it.next().unwrap();

        assert!(kv2.key == it_kv2.key);
        assert!(kv2.value == it_kv2.value);
    }
}
<|endoftext|>


<commit_before>// A unit struct
struct Nil;

// A tuple struct
struct Pair(i32, f64);

// A struct with two fields
struct Point {
    x: f64,
    y: f64,
}

// Structs can be reused as fields of another struct
#[allow(dead_code)]
struct Rectangle {
    p1: Point,
    p2: Point,
}

fn main() {
    // Instantiate a `Point`
    let point: Point = Point { x: 0.3, y: 0.4 };

    // Access the fields of the point
    println!("point coordinates: ({}, {})", point.x, point.y);

    // Destructure the point using a `let` binding
    let Point { x: my_x, y: my_y } = point;

    let _rectangle = Rectangle {
        // struct instantiation is an expression too
        p1: Point { x: my_y, y: my_x },
        p2: point,
    };

    // Instantiate a unit struct
    let _nil = Nil;

    // Instantiate a tuple struct
    let pair = Pair(1, 0.1);

    // Destructure a tuple struct
    let Pair(integer, decimal) = pair;

    println!("pair contains {:?} and {:?}", integer, decimal);
}
<commit_msg>Switch from f64 to f32<commit_after>// A unit struct
struct Nil;

// A tuple struct
struct Pair(i32, f32);

// A struct with two fields
struct Point {
    x: f32,
    y: f32,
}

// Structs can be reused as fields of another struct
#[allow(dead_code)]
struct Rectangle {
    p1: Point,
    p2: Point,
}

fn main() {
    // Instantiate a `Point`
    let point: Point = Point { x: 0.3, y: 0.4 };

    // Access the fields of the point
    println!("point coordinates: ({}, {})", point.x, point.y);

    // Destructure the point using a `let` binding
    let Point { x: my_x, y: my_y } = point;

    let _rectangle = Rectangle {
        // struct instantiation is an expression too
        p1: Point { x: my_y, y: my_x },
        p2: point,
    };

    // Instantiate a unit struct
    let _nil = Nil;

    // Instantiate a tuple struct
    let pair = Pair(1, 0.1);

    // Destructure a tuple struct
    let Pair(integer, decimal) = pair;

    println!("pair contains {:?} and {:?}", integer, decimal);
}
<|endoftext|>