<commit_before>use cube_shell::cube_shell;
use id_allocator::IdAllocator;
use terrain_block::BlockPosition;
use terrain_game_loader::{TerrainGameLoader, OwnerId};
use physics::Physics;
use state::EntityId;
use std::cmp::max;
use std::collections::RingBuf;
use std::num::Float;
use std::num::SignedInt;
use stopwatch::TimerSet;
use yaglw::gl_context::GLContext;

// values are approximately in microseconds, but they don't have to be.
pub const BLOCK_UPDATE_BUDGET: int = 20000;
pub const BLOCK_LOAD_COST: int = 800;
pub const BLOCK_UNLOAD_COST: int = 200;

pub const LOD_THRESHOLDS: [i32, ..3] = [1, 8, 16];

fn radius_between(p1: &BlockPosition, p2: &BlockPosition) -> i32 {
  let dx = (p1.as_pnt().x - p2.as_pnt().x).abs();
  let dy = (p1.as_pnt().y - p2.as_pnt().y).abs();
  let dz = (p1.as_pnt().z - p2.as_pnt().z).abs();
  max(max(dx, dy), dz)
}

/// Keep surroundings loaded around a given world position.
pub struct SurroundingsLoader {
  pub id: OwnerId,
  pub last_position: Option<BlockPosition>,

  pub max_load_distance: i32,
  pub next_load_distance: i32,
  pub load_queue: RingBuf<BlockPosition>,

  pub loaded_vec: Vec<BlockPosition>,
  pub next_unload_index: uint,

  pub solid_boundary: Vec<BlockPosition>,
}

impl SurroundingsLoader {
  pub fn new(id: OwnerId, max_load_distance: i32) -> SurroundingsLoader {
    assert!(max_load_distance >= 0);

    SurroundingsLoader {
      id: id,
      last_position: None,

      max_load_distance: max_load_distance,
      next_load_distance: 0,
      load_queue: RingBuf::new(),

      loaded_vec: Vec::new(),
      next_unload_index: 0,

      solid_boundary: {
        let mut b = Vec::new();
        b.push_all(cube_shell(&BlockPosition::new(0, 0, 0), 0).as_slice());
        b.push_all(cube_shell(&BlockPosition::new(0, 0, 0), 1).as_slice());
        b.push_all(cube_shell(&BlockPosition::new(0, 0, 0), 2).as_slice());
        b
      },
    }
  }

  pub fn update(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    terrain_game_loader: &mut TerrainGameLoader,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics,
    position: BlockPosition,
  ) {
    if Some(position) != self.last_position {
      self.last_position.map(
        |last_position|
          for solid_block in
            self.solid_boundary.iter().map(|&dp| last_position + dp.as_pnt().to_vec()) {
              terrain_game_loader.remove_placeholder(physics, &solid_block, self.id);
            }
        );

      // There will make some of the remove_placeholders redundant. Fix?
      for solid_block in self.solid_boundary.iter().map(|&dp| position + dp.as_pnt().to_vec()) {
        terrain_game_loader.insert_placeholder(id_allocator, physics, &solid_block, self.id);
      }

      self.load_queue.clear();
      self.load_queue.push_back(position);

      self.next_unload_index = 0;
      self.next_load_distance = 0;
      self.last_position = Some(position);
    }

    let mut budget = BLOCK_UPDATE_BUDGET;
    while budget > 0 {
      if self.next_unload_index < self.loaded_vec.len() {
        let block_position = self.loaded_vec[self.next_unload_index];
        if radius_between(&position, &block_position) > self.max_load_distance {
          if terrain_game_loader.unload(timers, gl, physics, &block_position, self.id) {
            budget -= BLOCK_UNLOAD_COST;
          }

          self.loaded_vec.swap_remove(self.next_unload_index);
        } else {
          self.next_unload_index += 1;
        }
      } else {
        let block_position =
          match self.load_queue.pop_front() {
            None => break,
            Some(block_position) => block_position,
          };

        let lod = {
          let mut lod = 0;
          for &threshold in LOD_THRESHOLDS.iter() {
            if self.next_load_distance <= threshold {
              break;
            }
            lod += 1;
          }
          lod
        };

        if terrain_game_loader.load(
          timers,
          gl,
          id_allocator,
          physics,
          &block_position,
          lod,
          self.id,
        ) {
          budget -= BLOCK_LOAD_COST;
        }

        self.loaded_vec.push(block_position);

        if self.load_queue.is_empty() {
          debug!("Done loading surroundings at distance {}", self.next_load_distance);
          self.next_load_distance += 1;
          if self.next_load_distance <= self.max_load_distance {
            self.load_queue.extend(cube_shell(&position, self.next_load_distance).into_iter());
          } else {
            debug!("Done loading surroundings");
          }
        }
      }
    }
  }
}
<commit_msg>Charge block loading budget based on actual time elapsed.<commit_after>use cube_shell::cube_shell;
use id_allocator::IdAllocator;
use terrain_block::BlockPosition;
use terrain_game_loader::{TerrainGameLoader, OwnerId};
use physics::Physics;
use state::EntityId;
use std::cmp::max;
use std::collections::RingBuf;
use std::num::Float;
use std::num::SignedInt;
use time;
use stopwatch::TimerSet;
use yaglw::gl_context::GLContext;

// Rough budget (in microseconds) for how long block updating can take PER SurroundingsLoader.
pub const BLOCK_UPDATE_BUDGET: u64 = 20000;

pub const LOD_THRESHOLDS: [i32, ..3] = [1, 8, 16];

fn radius_between(p1: &BlockPosition, p2: &BlockPosition) -> i32 {
  let dx = (p1.as_pnt().x - p2.as_pnt().x).abs();
  let dy = (p1.as_pnt().y - p2.as_pnt().y).abs();
  let dz = (p1.as_pnt().z - p2.as_pnt().z).abs();
  max(max(dx, dy), dz)
}

/// Keep surroundings loaded around a given world position.
pub struct SurroundingsLoader {
  pub id: OwnerId,
  pub last_position: Option<BlockPosition>,

  pub max_load_distance: i32,
  pub next_load_distance: i32,
  pub load_queue: RingBuf<BlockPosition>,

  pub loaded_vec: Vec<BlockPosition>,
  pub next_unload_index: uint,

  pub solid_boundary: Vec<BlockPosition>,
}

impl SurroundingsLoader {
  pub fn new(id: OwnerId, max_load_distance: i32) -> SurroundingsLoader {
    assert!(max_load_distance >= 0);

    SurroundingsLoader {
      id: id,
      last_position: None,

      max_load_distance: max_load_distance,
      next_load_distance: 0,
      load_queue: RingBuf::new(),

      loaded_vec: Vec::new(),
      next_unload_index: 0,

      solid_boundary: {
        let mut b = Vec::new();
        b.push_all(cube_shell(&BlockPosition::new(0, 0, 0), 0).as_slice());
        b.push_all(cube_shell(&BlockPosition::new(0, 0, 0), 1).as_slice());
        b.push_all(cube_shell(&BlockPosition::new(0, 0, 0), 2).as_slice());
        b
      },
    }
  }

  pub fn update(
    &mut self,
    timers: &TimerSet,
    gl: &mut GLContext,
    terrain_game_loader: &mut TerrainGameLoader,
    id_allocator: &mut IdAllocator<EntityId>,
    physics: &mut Physics,
    position: BlockPosition,
  ) {
    if Some(position) != self.last_position {
      self.last_position.map(
        |last_position|
          for solid_block in
            self.solid_boundary.iter().map(|&dp| last_position + dp.as_pnt().to_vec()) {
              terrain_game_loader.remove_placeholder(physics, &solid_block, self.id);
            }
        );

      // There will make some of the remove_placeholders redundant. Fix?
      for solid_block in self.solid_boundary.iter().map(|&dp| position + dp.as_pnt().to_vec()) {
        terrain_game_loader.insert_placeholder(id_allocator, physics, &solid_block, self.id);
      }

      self.load_queue.clear();
      self.load_queue.push_back(position);

      self.next_unload_index = 0;
      self.next_load_distance = 0;
      self.last_position = Some(position);
    }

    let target_time = time::precise_time_ns() + BLOCK_UPDATE_BUDGET * 1000;
    while time::precise_time_ns() < target_time {
      if self.next_unload_index < self.loaded_vec.len() {
        let block_position = self.loaded_vec[self.next_unload_index];
        if radius_between(&position, &block_position) > self.max_load_distance {
          terrain_game_loader.unload(timers, gl, physics, &block_position, self.id);
          self.loaded_vec.swap_remove(self.next_unload_index);
        } else {
          self.next_unload_index += 1;
        }
      } else {
        let block_position =
          match self.load_queue.pop_front() {
            None => break,
            Some(block_position) => block_position,
          };

        let lod = {
          let mut lod = 0;
          for &threshold in LOD_THRESHOLDS.iter() {
            if self.next_load_distance <= threshold {
              break;
            }
            lod += 1;
          }
          lod
        };

        terrain_game_loader.load(
          timers,
          gl,
          id_allocator,
          physics,
          &block_position,
          lod,
          self.id,
        );

        self.loaded_vec.push(block_position);

        if self.load_queue.is_empty() {
          debug!("Done loading surroundings at distance {}", self.next_load_distance);
          self.next_load_distance += 1;
          if self.next_load_distance <= self.max_load_distance {
            self.load_queue.extend(cube_shell(&position, self.next_load_distance).into_iter());
          } else {
            debug!("Done loading surroundings");
          }
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>// compile-flags: --document-private-items

#![crate_type = "lib"]

// @has static/static.FOO.html '//pre[@class="static"]' 'static FOO: usize'
static FOO: usize = 1;

// @has static/static.BAR.html '//pre[@class="static"]' 'pub static BAR: usize'
pub static BAR: usize = 1;

// @has static/static.BAZ.html '//pre[@class="static"]' 'pub static mut BAZ: usize'
pub static mut BAZ: usize = 1;
<commit_msg>fixup! Avoid extraneous space between visibility kw and ident for statics<commit_after>// compile-flags: --document-private-items

#![crate_type = "lib"]

// @has static/static.FOO.html '//pre' 'static FOO: usize'
static FOO: usize = 1;

// @has static/static.BAR.html '//pre' 'pub static BAR: usize'
pub static BAR: usize = 1;

// @has static/static.BAZ.html '//pre' 'pub static mut BAZ: usize'
pub static mut BAZ: usize = 1;
<|endoftext|>


<commit_before>use std::iter::Peekable;
use std::str::FromStr;
use std::time::Duration;

use game::{Position, FromTo, White, Black, NumPlies, NumMoves};
use search::NumNodes;
use types::{Cmd, RegisterParam, GoParam};
use types::options;

pub fn parse(s: &str) -> Option<Cmd> {
    let mut words = s.split(' ').peekable();

    let mut cmd_val: Option<Cmd> = None;

    while cmd_val.is_none() {
        let next_word_opt = words.next();
        let next_word = match next_word_opt {
            Some(val) => val,
            None => break,
        };

        cmd_val = match next_word {
            "uci" => Some(Cmd::Uci),
            "debug" => parse_on_off(&mut words).map(|val| Cmd::Debug(val)),
            "isready" => Some(Cmd::IsReady),
            "setoption" => parse_option_val(&mut words)
                               .map(|(name, val)| Cmd::SetOption(name, Some(val))),
            "register" => parse_register_vec(&mut words).map(|val| Cmd::Register(val)),
            "ucinewgame" => Some(Cmd::UciNewGame),
            "position" => parse_setup_position(&mut words)
                              .map(|(pos, moves)| Cmd::SetupPosition(pos, moves)),
            "go" => parse_go_param_vec(&mut words).map(|val| Cmd::Go(val)),
            "stop" => Some(Cmd::Stop),
            "ponderhit" => Some(Cmd::PonderHit),
            "quit" => Some(Cmd::Quit),
            _ => None,
        }
    }

    if let Some(Cmd::Debug(val)) = cmd_val {
        // TODO set debug
        debug!("debug is now {:?}", val);
    }

    debug!("parse() returning {:?}", cmd_val);

    cmd_val
}

fn parse_on_off(words: &mut Iterator<Item = &str>) -> Option<bool> {
    let mut ans = None;
    while ans.is_none() {
        let next_word_opt = words.next();
        let next_word = match next_word_opt {
            Some(val) => val,
            None => break,
        };
        ans = match next_word {
            "on" => Some(true),
            "off" => Some(false),
            _ => None,
        }
    }

    debug!("parse_on_off() returning {:?}", ans);

    ans
}

fn parse_option_val<'a, T>(_words: &mut Peekable<T>) -> Option<options::NameAndVal>
where T: Iterator<Item = &'a str> {
    debug!("dummy option parsing");
    // TODO parse options.
    Some((options::Name::Dummy, options::Val::Spin(1)))
}

fn parse_register_vec<'a, T>(words: &mut Peekable<T>) -> Option<Vec<RegisterParam>>
where T: Iterator<Item = &'a str> {
    let mut res = Vec::<RegisterParam>::new();
    while let Some(next_word) = words.next() {
        let register_val = match next_word {
            "later" => Some(RegisterParam::Later),
            "name" => {
                let mut name_vec = Vec::<&str>::new();
                loop {
                    let curr_name = words.peek().and_then( |s| {
                        if ["later", "name", "code"].contains(s) { None }
                        else { Some(*s) }
                    });
                    match curr_name {
                        Some(val) => {
                            name_vec.push(val);
                            words.next();
                        },
                        None => break,
                    }
                }
                Some(RegisterParam::Name(name_vec.connect(" ")))
            },
            "code" => words.next().map( |x| RegisterParam::Code(x.to_string())),
            _ => None,
        };
        if let Some(val) = register_val {
            res.push(val);
        }
    }
    let ans = if res.is_empty() { None } else { Some(res) };

    debug!("parse_register_vec() returning {:?}", ans);

    ans
}

fn parse_setup_position<'a, T>(words: &mut Peekable<T>) -> Option<(Position, Vec<FromTo>)>
where T: Iterator<Item = &'a str> {
    let temp = parse_position(words);
    temp.map(|pos| {
        // consume everything up to and including "moves"
        let mut curr_word = words.next();
        while let Some(val) = curr_word {
            if val == "moves" { break; }
            curr_word = words.next();
        }

        // Attempt to parse the moves
        let moves = match parse_move_vec(words) {
            Some(val) => val,
            None => Vec::new(),
        };

        (pos, moves)
    })
}

fn parse_position<'a, T>(words: &mut Peekable<T>) -> Option<Position>
where T: Iterator<Item = &'a str> {
    let ans = if words.peek() == Some(&"startpos") {
        debug!("parse_position() consumed \"startpos\"");
        words.next();
        Some(Position::start())
    } else if words.peek() == Some(&"fen") {
        words.next();
        let six_words: Vec<_> = words.by_ref().take(6).collect();
        debug!("parse_position(): six_words = {:?}", six_words);
        six_words.connect(" ").parse::<Position>().ok()
    } else {
        None
    };

    debug!("parse_position() returning {:?}", ans);

    ans
}

fn parse_move_vec<'a, T>(words: &mut Peekable<T>) -> Option<Vec<FromTo>>
where T: Iterator<Item = &'a str> {
    let mut res = Vec::<FromTo>::new();
    debug!("parse_move_vec() peeked at {:?}", words.peek());
    while let Some(val) = words.peek().and_then(|val| FromStr::from_str(*val).ok()) {
        debug!("parse_move_vec(): val = {:?}", val);
        res.push(val);
        words.next();
        debug!("parse_move_vec() peeked at {:?}", words.peek());
    }
    let ans = if res.is_empty() { None } else { Some(res) };

    debug!("parse_move_vec() returning {:?}", ans);

    ans
}

fn parse_go_param_vec<'a, T>(words: &mut Peekable<T>) -> Option<Vec<GoParam>>
where T: Iterator<Item = &'a str> {
    let mut res = Vec::<GoParam>::new();
    while let Some(next_word) = words.next() {
        match next_word {
            "search moves" => parse_move_vec(words).map(|x| GoParam::SearchMoves(x)),
            "ponder" => Some(GoParam::Ponder),
            "wtime"     => words.next().and_then(|s| s.parse::<i64>().ok())
                                       .map(|x| GoParam::Time(White,
                                                              Duration::milliseconds(x))),
            "btime"     => words.next().and_then(|s| s.parse::<i64>().ok())
                                       .map(|x| GoParam::Time(Black,
                                                              Duration::milliseconds(x))),
            "winc"      => words.next().and_then(|s| s.parse::<i64>().ok())
                                       .map(|x| GoParam::IncTime(White,
                                                                 Duration::milliseconds(x))),
            "binc"      => words.next().and_then(|s| s.parse::<i64>().ok())
                                       .map(|x| GoParam::IncTime(Black,
                                                                 Duration::milliseconds(x))),
            "movestogo" => words.next().and_then(|s| s.parse::<u32>().ok())
                                       .map(|x| GoParam::MovesToGo(NumMoves(x))),
            "depth"     => words.next().and_then(|s| s.parse::<u32>().ok())
                                       .map(|x| GoParam::Depth(NumPlies(x))),
            "nodes"     => words.next().and_then(|s| s.parse::<u64>().ok())
                                       .map(|x| GoParam::Nodes(NumNodes(x))),
            "mate"      => words.next().and_then(|s| s.parse::<u32>().ok())
                                       .map(|x| GoParam::Mate(NumMoves(x))),
            "movetime"  => words.next().and_then(|s| s.parse::<i64>().ok())
                                       .map(|x| GoParam::MoveTime(Duration::milliseconds(x))),
            "infinite" => Some(GoParam::Infinite),
            _ => None,
        }.map(|val| res.push(val));
    }
    let ans = if res.is_empty() { None } else { Some(res) };

    debug!("parse_go_param_vec() returning {:?}", ans);

    ans
}
<commit_msg>Fix searchmoves parsing bug<commit_after>use std::iter::Peekable;
use std::str::FromStr;
use std::time::Duration;

use game::{Position, FromTo, White, Black, NumPlies, NumMoves};
use search::NumNodes;
use types::{Cmd, RegisterParam, GoParam};
use types::options;

pub fn parse(s: &str) -> Option<Cmd> {
    let mut words = s.split(' ').peekable();

    let mut cmd_val: Option<Cmd> = None;

    while cmd_val.is_none() {
        let next_word_opt = words.next();
        let next_word = match next_word_opt {
            Some(val) => val,
            None => break,
        };

        cmd_val = match next_word {
            "uci" => Some(Cmd::Uci),
            "debug" => parse_on_off(&mut words).map(|val| Cmd::Debug(val)),
            "isready" => Some(Cmd::IsReady),
            "setoption" => parse_option_val(&mut words)
                               .map(|(name, val)| Cmd::SetOption(name, Some(val))),
            "register" => parse_register_vec(&mut words).map(|val| Cmd::Register(val)),
            "ucinewgame" => Some(Cmd::UciNewGame),
            "position" => parse_setup_position(&mut words)
                              .map(|(pos, moves)| Cmd::SetupPosition(pos, moves)),
            "go" => parse_go_param_vec(&mut words).map(|val| Cmd::Go(val)),
            "stop" => Some(Cmd::Stop),
            "ponderhit" => Some(Cmd::PonderHit),
            "quit" => Some(Cmd::Quit),
            _ => None,
        }
    }

    if let Some(Cmd::Debug(val)) = cmd_val {
        // TODO set debug
        debug!("debug is now {:?}", val);
    }

    debug!("parse() returning {:?}", cmd_val);

    cmd_val
}

fn parse_on_off(words: &mut Iterator<Item = &str>) -> Option<bool> {
    let mut ans = None;
    while ans.is_none() {
        let next_word_opt = words.next();
        let next_word = match next_word_opt {
            Some(val) => val,
            None => break,
        };
        ans = match next_word {
            "on" => Some(true),
            "off" => Some(false),
            _ => None,
        }
    }

    debug!("parse_on_off() returning {:?}", ans);

    ans
}

fn parse_option_val<'a, T>(_words: &mut Peekable<T>) -> Option<options::NameAndVal>
where T: Iterator<Item = &'a str> {
    debug!("dummy option parsing");
    // TODO parse options.
    Some((options::Name::Dummy, options::Val::Spin(1)))
}

fn parse_register_vec<'a, T>(words: &mut Peekable<T>) -> Option<Vec<RegisterParam>>
where T: Iterator<Item = &'a str> {
    let mut res = Vec::<RegisterParam>::new();
    while let Some(next_word) = words.next() {
        let register_val = match next_word {
            "later" => Some(RegisterParam::Later),
            "name" => {
                let mut name_vec = Vec::<&str>::new();
                loop {
                    let curr_name = words.peek().and_then( |s| {
                        if ["later", "name", "code"].contains(s) { None }
                        else { Some(*s) }
                    });
                    match curr_name {
                        Some(val) => {
                            name_vec.push(val);
                            words.next();
                        },
                        None => break,
                    }
                }
                Some(RegisterParam::Name(name_vec.connect(" ")))
            },
            "code" => words.next().map( |x| RegisterParam::Code(x.to_string())),
            _ => None,
        };
        if let Some(val) = register_val {
            res.push(val);
        }
    }
    let ans = if res.is_empty() { None } else { Some(res) };

    debug!("parse_register_vec() returning {:?}", ans);

    ans
}

fn parse_setup_position<'a, T>(words: &mut Peekable<T>) -> Option<(Position, Vec<FromTo>)>
where T: Iterator<Item = &'a str> {
    let temp = parse_position(words);
    temp.map(|pos| {
        // consume everything up to and including "moves"
        let mut curr_word = words.next();
        while let Some(val) = curr_word {
            if val == "moves" { break; }
            curr_word = words.next();
        }

        // Attempt to parse the moves
        let moves = match parse_move_vec(words) {
            Some(val) => val,
            None => Vec::new(),
        };

        (pos, moves)
    })
}

fn parse_position<'a, T>(words: &mut Peekable<T>) -> Option<Position>
where T: Iterator<Item = &'a str> {
    let ans = if words.peek() == Some(&"startpos") {
        debug!("parse_position() consumed \"startpos\"");
        words.next();
        Some(Position::start())
    } else if words.peek() == Some(&"fen") {
        words.next();
        let six_words: Vec<_> = words.by_ref().take(6).collect();
        debug!("parse_position(): six_words = {:?}", six_words);
        six_words.connect(" ").parse::<Position>().ok()
    } else {
        None
    };

    debug!("parse_position() returning {:?}", ans);

    ans
}

fn parse_move_vec<'a, T>(words: &mut Peekable<T>) -> Option<Vec<FromTo>>
where T: Iterator<Item = &'a str> {
    let mut res = Vec::<FromTo>::new();
    debug!("parse_move_vec() peeked at {:?}", words.peek());
    while let Some(val) = words.peek().and_then(|val| FromStr::from_str(*val).ok()) {
        debug!("parse_move_vec(): val = {:?}", val);
        res.push(val);
        words.next();
        debug!("parse_move_vec() peeked at {:?}", words.peek());
    }
    let ans = if res.is_empty() { None } else { Some(res) };

    debug!("parse_move_vec() returning {:?}", ans);

    ans
}

fn parse_go_param_vec<'a, T>(words: &mut Peekable<T>) -> Option<Vec<GoParam>>
where T: Iterator<Item = &'a str> {
    let mut res = Vec::<GoParam>::new();
    while let Some(next_word) = words.next() {
        match next_word {
            "searchmoves" => parse_move_vec(words).map(|x| GoParam::SearchMoves(x)),
            "ponder" => Some(GoParam::Ponder),
            "wtime"     => words.next().and_then(|s| s.parse::<i64>().ok())
                                       .map(|x| GoParam::Time(White,
                                                              Duration::milliseconds(x))),
            "btime"     => words.next().and_then(|s| s.parse::<i64>().ok())
                                       .map(|x| GoParam::Time(Black,
                                                              Duration::milliseconds(x))),
            "winc"      => words.next().and_then(|s| s.parse::<i64>().ok())
                                       .map(|x| GoParam::IncTime(White,
                                                                 Duration::milliseconds(x))),
            "binc"      => words.next().and_then(|s| s.parse::<i64>().ok())
                                       .map(|x| GoParam::IncTime(Black,
                                                                 Duration::milliseconds(x))),
            "movestogo" => words.next().and_then(|s| s.parse::<u32>().ok())
                                       .map(|x| GoParam::MovesToGo(NumMoves(x))),
            "depth"     => words.next().and_then(|s| s.parse::<u32>().ok())
                                       .map(|x| GoParam::Depth(NumPlies(x))),
            "nodes"     => words.next().and_then(|s| s.parse::<u64>().ok())
                                       .map(|x| GoParam::Nodes(NumNodes(x))),
            "mate"      => words.next().and_then(|s| s.parse::<u32>().ok())
                                       .map(|x| GoParam::Mate(NumMoves(x))),
            "movetime"  => words.next().and_then(|s| s.parse::<i64>().ok())
                                       .map(|x| GoParam::MoveTime(Duration::milliseconds(x))),
            "infinite" => Some(GoParam::Infinite),
            _ => None,
        }.map(|val| res.push(val));
    }
    let ans = if res.is_empty() { None } else { Some(res) };

    debug!("parse_go_param_vec() returning {:?}", ans);

    ans
}
<|endoftext|>


<commit_before>use std::borrow::Cow;

use serde::ser::Serialize;

use crate::crypto;
use crate::errors::Result;
use crate::header::Header;
use crate::pem::decoder::PemEncodedKey;
use crate::serialization::b64_encode_part;

/// A key to encode a JWT with. Can be a secret, a PEM-encoded key or a DER-encoded key.
/// This key can be re-used so make sure you only initialize it once if you can for better performance
#[derive(Debug, Clone, PartialEq)]
pub struct EncodingKey<'a> {
    content: Cow<'a, [u8]>,
}

impl<'a> EncodingKey<'a> {
    /// If you're using HMAC, use that.
    pub fn from_secret(secret: &'a [u8]) -> Self {
        EncodingKey { content: Cow::Borrowed(secret) }
    }

    /// If you are loading a RSA key from a .pem file.
    /// This errors if the key is not a valid RSA key.
    pub fn from_rsa_pem(key: &'a [u8]) -> Result<Self> {
        let pem_key = PemEncodedKey::new(key)?;
        let content = pem_key.as_rsa_key()?;
        Ok(EncodingKey { content: Cow::Owned(content.to_vec()) })
    }

    /// If you are loading a ECDSA key from a .pem file
    /// This errors if the key is not a valid private EC key
    pub fn from_ec_pem(key: &'a [u8]) -> Result<Self> {
        let pem_key = PemEncodedKey::new(key)?;
        let content = pem_key.as_ec_private_key()?;
        Ok(EncodingKey { content: Cow::Owned(content.to_vec()) })
    }

    /// If you know what you're doing and have the DER-encoded key, for RSA or ECDSA
    pub fn from_der(der: &'a [u8]) -> Self {
        EncodingKey { content: Cow::Borrowed(der) }
    }

    /// Access the key, normal users do not need to use that.
    pub(crate) fn inner(&'a self) -> &'a [u8] {
        &self.content
    }
}

/// Encode the header and claims given and sign the payload using the algorithm from the header and the key.
/// If the algorithm given is RSA or EC, the key needs to be in the PEM format.
///
/// ```rust
/// use serde::{Deserialize, Serialize};
/// use jsonwebtoken::{encode, Algorithm, Header, EncodingKey};
///
/// #[derive(Debug, Serialize, Deserialize)]
/// struct Claims {
///    sub: String,
///    company: String
/// }
///
/// let my_claims = Claims {
///     sub: "b@b.com".to_owned(),
///     company: "ACME".to_owned()
/// };
///
/// // my_claims is a struct that implements Serialize
/// // This will create a JWT using HS256 as algorithm
/// let token = encode(&Header::default(), &my_claims, &EncodingKey::from_secret("secret".as_ref())).unwrap();
/// ```
pub fn encode<T: Serialize>(header: &Header, claims: &T, key: &EncodingKey) -> Result<String> {
    let encoded_header = b64_encode_part(&header)?;
    let encoded_claims = b64_encode_part(&claims)?;
    let message = [encoded_header.as_ref(), encoded_claims.as_ref()].join(".");
    let signature = crypto::sign(&*message, key, header.alg)?;

    Ok([message, signature].join("."))
}
<commit_msg>Remove EncodingKey lifetime<commit_after>use serde::ser::Serialize;

use crate::crypto;
use crate::errors::Result;
use crate::header::Header;
use crate::pem::decoder::PemEncodedKey;
use crate::serialization::b64_encode_part;

/// A key to encode a JWT with. Can be a secret, a PEM-encoded key or a DER-encoded key.
/// This key can be re-used so make sure you only initialize it once if you can for better performance
#[derive(Debug, Clone, PartialEq)]
pub struct EncodingKey {
    content: Vec<u8>,
}

impl EncodingKey {
    /// If you're using HMAC, use that.
    pub fn from_secret(secret: &[u8]) -> Self {
        EncodingKey { content: secret.to_vec() }
    }

    /// If you are loading a RSA key from a .pem file.
    /// This errors if the key is not a valid RSA key.
    pub fn from_rsa_pem(key: &[u8]) -> Result<Self> {
        let pem_key = PemEncodedKey::new(key)?;
        let content = pem_key.as_rsa_key()?;
        Ok(EncodingKey { content: content.to_vec() })
    }

    /// If you are loading a ECDSA key from a .pem file
    /// This errors if the key is not a valid private EC key
    pub fn from_ec_pem(key: &[u8]) -> Result<Self> {
        let pem_key = PemEncodedKey::new(key)?;
        let content = pem_key.as_ec_private_key()?;
        Ok(EncodingKey { content: content.to_vec() })
    }

    /// If you know what you're doing and have the DER-encoded key, for RSA or ECDSA
    pub fn from_der(der: &[u8]) -> Self {
        EncodingKey { content: der.to_vec() }
    }

    pub(crate) fn inner(&self) -> &[u8] {
        &self.content
    }
}

/// Encode the header and claims given and sign the payload using the algorithm from the header and the key.
/// If the algorithm given is RSA or EC, the key needs to be in the PEM format.
///
/// ```rust
/// use serde::{Deserialize, Serialize};
/// use jsonwebtoken::{encode, Algorithm, Header, EncodingKey};
///
/// #[derive(Debug, Serialize, Deserialize)]
/// struct Claims {
///    sub: String,
///    company: String
/// }
///
/// let my_claims = Claims {
///     sub: "b@b.com".to_owned(),
///     company: "ACME".to_owned()
/// };
///
/// // my_claims is a struct that implements Serialize
/// // This will create a JWT using HS256 as algorithm
/// let token = encode(&Header::default(), &my_claims, &EncodingKey::from_secret("secret".as_ref())).unwrap();
/// ```
pub fn encode<T: Serialize>(header: &Header, claims: &T, key: &EncodingKey) -> Result<String> {
    let encoded_header = b64_encode_part(&header)?;
    let encoded_claims = b64_encode_part(&claims)?;
    let message = [encoded_header.as_ref(), encoded_claims.as_ref()].join(".");
    let signature = crypto::sign(&*message, key, header.alg)?;

    Ok([message, signature].join("."))
}
<|endoftext|>


<commit_before>//! Checks the licenses of third-party dependencies by inspecting vendors.

use std::collections::{BTreeSet, HashSet, HashMap};
use std::fs;
use std::path::Path;
use std::process::Command;

use serde::Deserialize;
use serde_json;

const LICENSES: &[&str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "Apache-2.0 OR MIT",
    "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license
    "MIT",
    "Unlicense/MIT",
    "Unlicense OR MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std/test).
const EXCEPTIONS: &[&str] = &[
    "mdbook",             // MPL2, mdbook
    "openssl",            // BSD+advertising clause, cargo, mdbook
    "pest",               // MPL2, mdbook via handlebars
    "arrayref",           // BSD-2-Clause, mdbook via handlebars via pest
    "thread-id",          // Apache-2.0, mdbook
    "toml-query",         // MPL-2.0, mdbook
    "is-match",           // MPL-2.0, mdbook
    "cssparser",          // MPL-2.0, rustdoc
    "smallvec",           // MPL-2.0, rustdoc
    "rdrand",             // ISC, mdbook, rustfmt
    "fuchsia-cprng",      // BSD-3-Clause, mdbook, rustfmt
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros",   // MPL-2.0, rustdoc
    "selectors",          // MPL-2.0, rustdoc
    "clippy_lints",       // MPL-2.0, rls
    "colored",            // MPL-2.0, rustfmt
    "ordslice",           // Apache-2.0, rls
    "cloudabi",           // BSD-2-Clause, (rls -> crossbeam-channel 0.2 -> rand 0.5)
    "ryu",                // Apache-2.0, rls/cargo/... (because of serde)
    "bytesize",           // Apache-2.0, cargo
    "im-rc",              // MPL-2.0+, cargo
    "adler32",            // BSD-3-Clause AND Zlib, cargo dep that isn't used
    "constant_time_eq",   // CC0-1.0, rustfmt
    "utf8parse",          // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
    "vte",                // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
    "sized-chunks",       // MPL-2.0+, cargo via im-rc
    // FIXME: this dependency violates the documentation comment above:
    "fortanix-sgx-abi",   // MPL-2.0+, libstd but only for `sgx` target
];

/// Which crates to check against the whitelist?
const WHITELIST_CRATES: &[CrateVersion<'_>] = &[
    CrateVersion("rustc", "0.0.0"),
    CrateVersion("rustc_codegen_llvm", "0.0.0"),
];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
const WHITELIST: &[Crate<'_>] = &[
    Crate("adler32"),
    Crate("aho-corasick"),
    Crate("annotate-snippets"),
    Crate("ansi_term"),
    Crate("arrayvec"),
    Crate("atty"),
    Crate("autocfg"),
    Crate("backtrace"),
    Crate("backtrace-sys"),
    Crate("bitflags"),
    Crate("build_const"),
    Crate("byteorder"),
    Crate("c2-chacha"),
    Crate("cc"),
    Crate("cfg-if"),
    Crate("chalk-engine"),
    Crate("chalk-macros"),
    Crate("cloudabi"),
    Crate("cmake"),
    Crate("compiler_builtins"),
    Crate("crc"),
    Crate("crc32fast"),
    Crate("crossbeam-deque"),
    Crate("crossbeam-epoch"),
    Crate("crossbeam-queue"),
    Crate("crossbeam-utils"),
    Crate("datafrog"),
    Crate("dlmalloc"),
    Crate("either"),
    Crate("ena"),
    Crate("env_logger"),
    Crate("filetime"),
    Crate("flate2"),
    Crate("fortanix-sgx-abi"),
    Crate("fuchsia-zircon"),
    Crate("fuchsia-zircon-sys"),
    Crate("getopts"),
    Crate("getrandom"),
    Crate("hashbrown"),
    Crate("humantime"),
    Crate("indexmap"),
    Crate("itertools"),
    Crate("jobserver"),
    Crate("kernel32-sys"),
    Crate("lazy_static"),
    Crate("libc"),
    Crate("libz-sys"),
    Crate("lock_api"),
    Crate("log"),
    Crate("log_settings"),
    Crate("measureme"),
    Crate("memchr"),
    Crate("memmap"),
    Crate("memoffset"),
    Crate("miniz-sys"),
    Crate("miniz_oxide"),
    Crate("miniz_oxide_c_api"),
    Crate("nodrop"),
    Crate("num_cpus"),
    Crate("owning_ref"),
    Crate("parking_lot"),
    Crate("parking_lot_core"),
    Crate("pkg-config"),
    Crate("polonius-engine"),
    Crate("ppv-lite86"),
    Crate("proc-macro2"),
    Crate("quick-error"),
    Crate("quote"),
    Crate("rand"),
    Crate("rand_chacha"),
    Crate("rand_core"),
    Crate("rand_hc"),
    Crate("rand_isaac"),
    Crate("rand_pcg"),
    Crate("rand_xorshift"),
    Crate("redox_syscall"),
    Crate("redox_termios"),
    Crate("regex"),
    Crate("regex-syntax"),
    Crate("remove_dir_all"),
    Crate("rustc-demangle"),
    Crate("rustc-hash"),
    Crate("rustc-rayon"),
    Crate("rustc-rayon-core"),
    Crate("rustc_version"),
    Crate("scoped-tls"),
    Crate("scopeguard"),
    Crate("semver"),
    Crate("semver-parser"),
    Crate("serde"),
    Crate("serde_derive"),
    Crate("smallvec"),
    Crate("stable_deref_trait"),
    Crate("syn"),
    Crate("synstructure"),
    Crate("tempfile"),
    Crate("termcolor"),
    Crate("terminon"),
    Crate("termion"),
    Crate("term_size"),
    Crate("thread_local"),
    Crate("ucd-util"),
    Crate("unicode-width"),
    Crate("unicode-xid"),
    Crate("unreachable"),
    Crate("utf8-ranges"),
    Crate("vcpkg"),
    Crate("version_check"),
    Crate("void"),
    Crate("wasi"),
    Crate("winapi"),
    Crate("winapi-build"),
    Crate("winapi-i686-pc-windows-gnu"),
    Crate("winapi-util"),
    Crate("winapi-x86_64-pc-windows-gnu"),
    Crate("wincolor"),
];

// Some types for Serde to deserialize the output of `cargo metadata` to.

#[derive(Deserialize)]
struct Output {
    resolve: Resolve,
}

#[derive(Deserialize)]
struct Resolve {
    nodes: Vec<ResolveNode>,
}

#[derive(Deserialize)]
struct ResolveNode {
    id: String,
    dependencies: Vec<String>,
}

/// A unique identifier for a crate.
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct Crate<'a>(&'a str); // (name)

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct CrateVersion<'a>(&'a str, &'a str); // (name, version)

impl Crate<'_> {
    pub fn id_str(&self) -> String {
        format!("{} ", self.0)
    }
}

impl<'a> CrateVersion<'a> {
    /// Returns the struct and whether or not the dependency is in-tree.
    pub fn from_str(s: &'a str) -> (Self, bool) {
        let mut parts = s.split(' ');
        let name = parts.next().unwrap();
        let version = parts.next().unwrap();
        let path = parts.next().unwrap();

        let is_path_dep = path.starts_with("(path+");

        (CrateVersion(name, version), is_path_dep)
    }

    pub fn id_str(&self) -> String {
        format!("{} {}", self.0, self.1)
    }
}

impl<'a> From<CrateVersion<'a>> for Crate<'a> {
    fn from(cv: CrateVersion<'a>) -> Crate<'a> {
        Crate(cv.0)
    }
}

/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
///
/// Specifically, this checks that the license is correct.
pub fn check(path: &Path, bad: &mut bool) {
    // Check licences.
    let path = path.join("../vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // Skip our exceptions.
        let is_exception = EXCEPTIONS.iter().any(|exception| {
            dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("vendor/{}", exception))
        });
        if is_exception {
            continue;
        }

        let toml = dir.path().join("Cargo.toml");
        *bad = !check_license(&toml) || *bad;
    }
    assert!(saw_dir, "no vendored source");
}

/// Checks the dependency of `WHITELIST_CRATES` at the given path. Changes `bad` to `true` if a
/// check failed.
///
/// Specifically, this checks that the dependencies are on the `WHITELIST`.
pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
    // Get dependencies from Cargo metadata.
    let resolve = get_deps(path, cargo);

    // Get the whitelist in a convenient form.
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies.
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false);
        unapproved.append(&mut bad);
    }

    if !unapproved.is_empty() {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep.id_str());
        }
        *bad = true;
    }

    check_crate_duplicate(&resolve, bad);
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let contents = t!(fs::read_to_string(&path));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1..l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}

/// Gets the dependencies of the crate at the given path using `cargo metadata`.
fn get_deps(path: &Path, cargo: &Path) -> Resolve {
    // Run `cargo metadata` to get the set of dependencies.
    let output = Command::new(cargo)
        .arg("metadata")
        .arg("--format-version")
        .arg("1")
        .arg("--manifest-path")
        .arg(path.join("../Cargo.toml"))
        .output()
        .expect("Unable to run `cargo metadata`")
        .stdout;
    let output = String::from_utf8_lossy(&output);
    let output: Output = serde_json::from_str(&output).unwrap();

    output.resolve
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a>(
    whitelist: &'a HashSet<Crate<'_>>,
    resolve: &'a Resolve,
    visited: &mut BTreeSet<CrateVersion<'a>>,
    krate: CrateVersion<'a>,
    must_be_on_whitelist: bool,
) -> BTreeSet<Crate<'a>> {
    // This will contain bad deps.
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate.
    if visited.contains(&krate) {
        return unapproved;
    }

    visited.insert(krate);

    // If this path is in-tree, we don't require it to be on the whitelist.
    if must_be_on_whitelist {
        // If this dependency is not on `WHITELIST`, add to bad set.
        if !whitelist.contains(&krate.into()) {
            unapproved.insert(krate.into());
        }
    }

    // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!).
    let to_check = resolve
        .nodes
        .iter()
        .find(|n| n.id.starts_with(&krate.id_str()))
        .expect("crate does not exist");

    for dep in to_check.dependencies.iter() {
        let (krate, is_path_dep) = CrateVersion::from_str(dep);

        let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep);
        unapproved.append(&mut bad);
    }

    unapproved
}

fn check_crate_duplicate(resolve: &Resolve, bad: &mut bool) {
    const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
        // These two crates take quite a long time to build, so don't allow two versions of them
        // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
        // under control.

        "cargo",
        "rustc-ap-syntax",
    ];
    let mut name_to_id: HashMap<_, Vec<_>> = HashMap::new();
    for node in resolve.nodes.iter() {
        name_to_id.entry(node.id.split_whitespace().next().unwrap())
            .or_default()
            .push(&node.id);
    }

    for name in FORBIDDEN_TO_HAVE_DUPLICATES {
        if name_to_id[name].len() <= 1 {
            continue
        }
        println!("crate `{}` is duplicated in `Cargo.lock`", name);
        for id in name_to_id[name].iter() {
            println!("  * {}", id);
        }
        *bad = true;
    }
}
<commit_msg>add hermit-abi to the whitelist<commit_after>//! Checks the licenses of third-party dependencies by inspecting vendors.

use std::collections::{BTreeSet, HashSet, HashMap};
use std::fs;
use std::path::Path;
use std::process::Command;

use serde::Deserialize;
use serde_json;

const LICENSES: &[&str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "Apache-2.0 OR MIT",
    "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license
    "MIT",
    "Unlicense/MIT",
    "Unlicense OR MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std/test).
const EXCEPTIONS: &[&str] = &[
    "mdbook",             // MPL2, mdbook
    "openssl",            // BSD+advertising clause, cargo, mdbook
    "pest",               // MPL2, mdbook via handlebars
    "arrayref",           // BSD-2-Clause, mdbook via handlebars via pest
    "thread-id",          // Apache-2.0, mdbook
    "toml-query",         // MPL-2.0, mdbook
    "is-match",           // MPL-2.0, mdbook
    "cssparser",          // MPL-2.0, rustdoc
    "smallvec",           // MPL-2.0, rustdoc
    "rdrand",             // ISC, mdbook, rustfmt
    "fuchsia-cprng",      // BSD-3-Clause, mdbook, rustfmt
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros",   // MPL-2.0, rustdoc
    "selectors",          // MPL-2.0, rustdoc
    "clippy_lints",       // MPL-2.0, rls
    "colored",            // MPL-2.0, rustfmt
    "ordslice",           // Apache-2.0, rls
    "cloudabi",           // BSD-2-Clause, (rls -> crossbeam-channel 0.2 -> rand 0.5)
    "ryu",                // Apache-2.0, rls/cargo/... (because of serde)
    "bytesize",           // Apache-2.0, cargo
    "im-rc",              // MPL-2.0+, cargo
    "adler32",            // BSD-3-Clause AND Zlib, cargo dep that isn't used
    "constant_time_eq",   // CC0-1.0, rustfmt
    "utf8parse",          // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
    "vte",                // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
    "hermit-abi",         // Apache-2.0 OR MIT
    "sized-chunks",       // MPL-2.0+, cargo via im-rc
    // FIXME: this dependency violates the documentation comment above:
    "fortanix-sgx-abi",   // MPL-2.0+, libstd but only for `sgx` target
];

/// Which crates to check against the whitelist?
const WHITELIST_CRATES: &[CrateVersion<'_>] = &[
    CrateVersion("rustc", "0.0.0"),
    CrateVersion("rustc_codegen_llvm", "0.0.0"),
];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
const WHITELIST: &[Crate<'_>] = &[
    Crate("adler32"),
    Crate("aho-corasick"),
    Crate("annotate-snippets"),
    Crate("ansi_term"),
    Crate("arrayvec"),
    Crate("atty"),
    Crate("autocfg"),
    Crate("backtrace"),
    Crate("backtrace-sys"),
    Crate("bitflags"),
    Crate("build_const"),
    Crate("byteorder"),
    Crate("c2-chacha"),
    Crate("cc"),
    Crate("cfg-if"),
    Crate("chalk-engine"),
    Crate("chalk-macros"),
    Crate("cloudabi"),
    Crate("cmake"),
    Crate("compiler_builtins"),
    Crate("crc"),
    Crate("crc32fast"),
    Crate("crossbeam-deque"),
    Crate("crossbeam-epoch"),
    Crate("crossbeam-queue"),
    Crate("crossbeam-utils"),
    Crate("datafrog"),
    Crate("dlmalloc"),
    Crate("either"),
    Crate("ena"),
    Crate("env_logger"),
    Crate("filetime"),
    Crate("flate2"),
    Crate("fortanix-sgx-abi"),
    Crate("fuchsia-zircon"),
    Crate("fuchsia-zircon-sys"),
    Crate("getopts"),
    Crate("getrandom"),
    Crate("hashbrown"),
    Crate("humantime"),
    Crate("indexmap"),
    Crate("itertools"),
    Crate("jobserver"),
    Crate("kernel32-sys"),
    Crate("lazy_static"),
    Crate("libc"),
    Crate("libz-sys"),
    Crate("lock_api"),
    Crate("log"),
    Crate("log_settings"),
    Crate("measureme"),
    Crate("memchr"),
    Crate("memmap"),
    Crate("memoffset"),
    Crate("miniz-sys"),
    Crate("miniz_oxide"),
    Crate("miniz_oxide_c_api"),
    Crate("nodrop"),
    Crate("num_cpus"),
    Crate("owning_ref"),
    Crate("parking_lot"),
    Crate("parking_lot_core"),
    Crate("pkg-config"),
    Crate("polonius-engine"),
    Crate("ppv-lite86"),
    Crate("proc-macro2"),
    Crate("quick-error"),
    Crate("quote"),
    Crate("rand"),
    Crate("rand_chacha"),
    Crate("rand_core"),
    Crate("rand_hc"),
    Crate("rand_isaac"),
    Crate("rand_pcg"),
    Crate("rand_xorshift"),
    Crate("redox_syscall"),
    Crate("redox_termios"),
    Crate("regex"),
    Crate("regex-syntax"),
    Crate("remove_dir_all"),
    Crate("rustc-demangle"),
    Crate("rustc-hash"),
    Crate("rustc-rayon"),
    Crate("rustc-rayon-core"),
    Crate("rustc_version"),
    Crate("scoped-tls"),
    Crate("scopeguard"),
    Crate("semver"),
    Crate("semver-parser"),
    Crate("serde"),
    Crate("serde_derive"),
    Crate("smallvec"),
    Crate("stable_deref_trait"),
    Crate("syn"),
    Crate("synstructure"),
    Crate("tempfile"),
    Crate("termcolor"),
    Crate("terminon"),
    Crate("termion"),
    Crate("term_size"),
    Crate("thread_local"),
    Crate("ucd-util"),
    Crate("unicode-width"),
    Crate("unicode-xid"),
    Crate("unreachable"),
    Crate("utf8-ranges"),
    Crate("vcpkg"),
    Crate("version_check"),
    Crate("void"),
    Crate("wasi"),
    Crate("winapi"),
    Crate("winapi-build"),
    Crate("winapi-i686-pc-windows-gnu"),
    Crate("winapi-util"),
    Crate("winapi-x86_64-pc-windows-gnu"),
    Crate("wincolor"),
];

// Some types for Serde to deserialize the output of `cargo metadata` to.

#[derive(Deserialize)]
struct Output {
    resolve: Resolve,
}

#[derive(Deserialize)]
struct Resolve {
    nodes: Vec<ResolveNode>,
}

#[derive(Deserialize)]
struct ResolveNode {
    id: String,
    dependencies: Vec<String>,
}

/// A unique identifier for a crate.
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct Crate<'a>(&'a str); // (name)

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct CrateVersion<'a>(&'a str, &'a str); // (name, version)

impl Crate<'_> {
    pub fn id_str(&self) -> String {
        format!("{} ", self.0)
    }
}

impl<'a> CrateVersion<'a> {
    /// Returns the struct and whether or not the dependency is in-tree.
    pub fn from_str(s: &'a str) -> (Self, bool) {
        let mut parts = s.split(' ');
        let name = parts.next().unwrap();
        let version = parts.next().unwrap();
        let path = parts.next().unwrap();

        let is_path_dep = path.starts_with("(path+");

        (CrateVersion(name, version), is_path_dep)
    }

    pub fn id_str(&self) -> String {
        format!("{} {}", self.0, self.1)
    }
}

impl<'a> From<CrateVersion<'a>> for Crate<'a> {
    fn from(cv: CrateVersion<'a>) -> Crate<'a> {
        Crate(cv.0)
    }
}

/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
///
/// Specifically, this checks that the license is correct.
pub fn check(path: &Path, bad: &mut bool) {
    // Check licences.
    let path = path.join("../vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // Skip our exceptions.
        let is_exception = EXCEPTIONS.iter().any(|exception| {
            dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("vendor/{}", exception))
        });
        if is_exception {
            continue;
        }

        let toml = dir.path().join("Cargo.toml");
        *bad = !check_license(&toml) || *bad;
    }
    assert!(saw_dir, "no vendored source");
}

/// Checks the dependency of `WHITELIST_CRATES` at the given path. Changes `bad` to `true` if a
/// check failed.
///
/// Specifically, this checks that the dependencies are on the `WHITELIST`.
pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
    // Get dependencies from Cargo metadata.
    let resolve = get_deps(path, cargo);

    // Get the whitelist in a convenient form.
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies.
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false);
        unapproved.append(&mut bad);
    }

    if !unapproved.is_empty() {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep.id_str());
        }
        *bad = true;
    }

    check_crate_duplicate(&resolve, bad);
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let contents = t!(fs::read_to_string(&path));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1..l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}

/// Gets the dependencies of the crate at the given path using `cargo metadata`.
fn get_deps(path: &Path, cargo: &Path) -> Resolve {
    // Run `cargo metadata` to get the set of dependencies.
    let output = Command::new(cargo)
        .arg("metadata")
        .arg("--format-version")
        .arg("1")
        .arg("--manifest-path")
        .arg(path.join("../Cargo.toml"))
        .output()
        .expect("Unable to run `cargo metadata`")
        .stdout;
    let output = String::from_utf8_lossy(&output);
    let output: Output = serde_json::from_str(&output).unwrap();

    output.resolve
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a>(
    whitelist: &'a HashSet<Crate<'_>>,
    resolve: &'a Resolve,
    visited: &mut BTreeSet<CrateVersion<'a>>,
    krate: CrateVersion<'a>,
    must_be_on_whitelist: bool,
) -> BTreeSet<Crate<'a>> {
    // This will contain bad deps.
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate.
    if visited.contains(&krate) {
        return unapproved;
    }

    visited.insert(krate);

    // If this path is in-tree, we don't require it to be on the whitelist.
    if must_be_on_whitelist {
        // If this dependency is not on `WHITELIST`, add to bad set.
        if !whitelist.contains(&krate.into()) {
            unapproved.insert(krate.into());
        }
    }

    // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!).
    let to_check = resolve
        .nodes
        .iter()
        .find(|n| n.id.starts_with(&krate.id_str()))
        .expect("crate does not exist");

    for dep in to_check.dependencies.iter() {
        let (krate, is_path_dep) = CrateVersion::from_str(dep);

        let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep);
        unapproved.append(&mut bad);
    }

    unapproved
}

fn check_crate_duplicate(resolve: &Resolve, bad: &mut bool) {
    const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
        // These two crates take quite a long time to build, so don't allow two versions of them
        // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
        // under control.

        "cargo",
        "rustc-ap-syntax",
    ];
    let mut name_to_id: HashMap<_, Vec<_>> = HashMap::new();
    for node in resolve.nodes.iter() {
        name_to_id.entry(node.id.split_whitespace().next().unwrap())
            .or_default()
            .push(&node.id);
    }

    for name in FORBIDDEN_TO_HAVE_DUPLICATES {
        if name_to_id[name].len() <= 1 {
            continue
        }
        println!("crate `{}` is duplicated in `Cargo.lock`", name);
        for id in name_to_id[name].iter() {
            println!("  * {}", id);
        }
        *bad = true;
    }
}
<|endoftext|>


<commit_before>//! Tidy checks source code in this repository.
//!
//! This program runs all of the various tidy checks for style, cleanliness,
//! etc. This is run by default on `./x.py test` and as part of the auto
//! builders. The tidy checks can be executed with `./x.py test src/tools/tidy`.

#![deny(warnings)]

use tidy::*;

use std::env;
use std::path::PathBuf;
use std::process;

fn main() {
    let path: PathBuf = env::args_os().nth(1).expect("need path to src").into();
    let cargo: PathBuf = env::args_os().nth(2).expect("need path to cargo").into();

    let args: Vec<String> = env::args().skip(1).collect();

    let mut bad = false;
    let verbose = args.iter().any(|s| *s == "--verbose");
    bins::check(&path, &mut bad);
    style::check(&path, &mut bad);
    debug_artifacts::check(&path, &mut bad);
    errors::check(&path, &mut bad);
    cargo::check(&path, &mut bad);
    edition::check(&path, &mut bad);
    let collected = features::check(&path, &mut bad, verbose);
    pal::check(&path, &mut bad);
    unstable_book::check(&path, collected, &mut bad);
    unit_tests::check(&path, &mut bad);
    if !args.iter().any(|s| *s == "--no-vendor") {
        deps::check(&path, &mut bad);
    }
    deps::check_whitelist(&path, &cargo, &mut bad);
    extdeps::check(&path, &mut bad);
    ui_tests::check(&path, &mut bad);
    error_codes_check::check(&path, &mut bad);

    if bad {
        eprintln!("some tidy checks failed");
        process::exit(1);
    }
}
<commit_msg>update tidy documentation to recommend ./x.py test tidy<commit_after>//! Tidy checks source code in this repository.
//!
//! This program runs all of the various tidy checks for style, cleanliness,
//! etc. This is run by default on `./x.py test` and as part of the auto
//! builders. The tidy checks can be executed with `./x.py test tidy`.

#![deny(warnings)]

use tidy::*;

use std::env;
use std::path::PathBuf;
use std::process;

fn main() {
    let path: PathBuf = env::args_os().nth(1).expect("need path to src").into();
    let cargo: PathBuf = env::args_os().nth(2).expect("need path to cargo").into();

    let args: Vec<String> = env::args().skip(1).collect();

    let mut bad = false;
    let verbose = args.iter().any(|s| *s == "--verbose");
    bins::check(&path, &mut bad);
    style::check(&path, &mut bad);
    debug_artifacts::check(&path, &mut bad);
    errors::check(&path, &mut bad);
    cargo::check(&path, &mut bad);
    edition::check(&path, &mut bad);
    let collected = features::check(&path, &mut bad, verbose);
    pal::check(&path, &mut bad);
    unstable_book::check(&path, collected, &mut bad);
    unit_tests::check(&path, &mut bad);
    if !args.iter().any(|s| *s == "--no-vendor") {
        deps::check(&path, &mut bad);
    }
    deps::check_whitelist(&path, &cargo, &mut bad);
    extdeps::check(&path, &mut bad);
    ui_tests::check(&path, &mut bad);
    error_codes_check::check(&path, &mut bad);

    if bad {
        eprintln!("some tidy checks failed");
        process::exit(1);
    }
}
<|endoftext|>


<commit_before>extern crate gtk;
use gtk::prelude::*;

extern crate cairo;

extern crate gstreamer as gst;
use gstreamer::*;

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

use ::media::Context;

use super::{MediaController, MediaHandler};

pub struct AudioController {
    media_ctl: MediaController,
}

impl AudioController {
    pub fn new(builder: &gtk::Builder) -> Self {
        AudioController {
            media_ctl: MediaController::new(
                builder.get_object("audio-container").unwrap(),
                builder.get_object("audio-drawingarea").unwrap()
            ),
        }
    }
}

impl Deref for AudioController {
	type Target = MediaController;

	fn deref(&self) -> &Self::Target {
		&self.media_ctl
	}
}

impl DerefMut for AudioController {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.media_ctl
	}
}

impl MediaHandler for AudioController {
    fn new_media(&mut self, context: &Context) {
        self.media_ctl.hide();
        // TODO: set an Option to indicate that no stream is initialized
    }
}
<commit_msg>Show audio container when an audio sink is defined (#7)<commit_after>extern crate gtk;
use gtk::prelude::*;

extern crate cairo;

extern crate gstreamer as gst;
use gstreamer::*;
use gstreamer::BinExt;

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

use ::media::Context;

use super::{MediaController, MediaHandler};

pub struct AudioController {
    media_ctl: MediaController,
}

impl AudioController {
    pub fn new(builder: &gtk::Builder) -> Self {
        AudioController {
            media_ctl: MediaController::new(
                builder.get_object("audio-container").unwrap(),
                builder.get_object("audio-drawingarea").unwrap()
            ),
        }
    }
}

impl Deref for AudioController {
	type Target = MediaController;

	fn deref(&self) -> &Self::Target {
		&self.media_ctl
	}
}

impl DerefMut for AudioController {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.media_ctl
	}
}

impl MediaHandler for AudioController {
    fn new_media(&mut self, context: &Context) {
        if let Some(audio_sink) = context.pipeline.get_by_name("audio_sink") {
            self.media_ctl.show();
        }
        else {
            self.media_ctl.hide();
        }
    }
}
<|endoftext|>


<commit_before>// 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 cfg::ControlFlowGraph;
use instruction::Instruction;
use symbol::Symbol;

/// A function within a program.
pub struct Function<'f, I: 'f + Instruction> {
    /// The [symbol] for this function. This provides the name and [`Address`].
    ///
    /// [`Address`]: struct.Symbol.html
    /// [symbol]: struct.Symbol.html
    pub symbol: Symbol,
    /// The [instructions] that comprise this function.
    ///
    /// [instructions]: trait.Instruction.html
    pub instructions: &'f [I],
    /// The [control flow graph] for this function. This is built from the
    /// `instructions`. It is made up of [basic blocks].
    ///
    /// [basic blocks]: struct.BasicBlock.html
    /// [control flow graph]: struct.ControlFlowGraph.html
    pub control_flow_graph: ControlFlowGraph<'f, I>,
}

impl<'f, I: Instruction> Function<'f, I> {
    /// Construct a new function
    pub fn new(symbol: Symbol, instructions: &'f [I]) -> Self {
        let cfg = ControlFlowGraph::new(instructions);
        Function {
            symbol: symbol,
            instructions: instructions,
            control_flow_graph: cfg,
        }
    }
}
<commit_msg>Function::calls gets addresses called by this function.<commit_after>// 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 address::Address;
use cfg::ControlFlowGraph;
use instruction::Instruction;
use symbol::Symbol;

/// A function within a program.
pub struct Function<'f, I: 'f + Instruction> {
    /// The [symbol] for this function. This provides the name and [`Address`].
    ///
    /// [`Address`]: struct.Symbol.html
    /// [symbol]: struct.Symbol.html
    pub symbol: Symbol,
    /// The [instructions] that comprise this function.
    ///
    /// [instructions]: trait.Instruction.html
    pub instructions: &'f [I],
    /// The [control flow graph] for this function. This is built from the
    /// `instructions`. It is made up of [basic blocks].
    ///
    /// [basic blocks]: struct.BasicBlock.html
    /// [control flow graph]: struct.ControlFlowGraph.html
    pub control_flow_graph: ControlFlowGraph<'f, I>,
}

impl<'f, I: Instruction> Function<'f, I> {
    /// Construct a new function
    pub fn new(symbol: Symbol, instructions: &'f [I]) -> Self {
        let cfg = ControlFlowGraph::new(instructions);
        Function {
            symbol: symbol,
            instructions: instructions,
            control_flow_graph: cfg,
        }
    }

    /// Get the addresses that are called by this function.
    ///
    /// This vector may contain duplicates.
    pub fn calls(&self) -> Vec<Address> {
        self.instructions
            .iter()
            .filter(|i| i.is_call())
            .filter_map(|i| i.target_address())
            .collect()
    }
}

#[cfg(test)]
mod tests {
    use address::Address;
    use function::Function;
    use symbol::Symbol;
    use tests::*;

    #[test]
    fn calls_none() {
        let insts = [TestInstruction::new(0, Opcode::Add),
                     TestInstruction::new(1, Opcode::Add),
                     TestInstruction::new(2, Opcode::Ret)];
        let f = Function::new(Symbol::new(Address::new(100), None), &insts);
        let calls = f.calls();
        assert!(calls.is_empty());
    }

    #[test]
    fn calls_some() {
        let insts = [TestInstruction::new(0, Opcode::Add),
                     TestInstruction::new(1, Opcode::Call(Address::new(500))),
                     TestInstruction::new(2, Opcode::Add),
                     TestInstruction::new(3, Opcode::Call(Address::new(400))),
                     TestInstruction::new(4, Opcode::Call(Address::new(500))),
                     TestInstruction::new(5, Opcode::Ret)];
        let f = Function::new(Symbol::new(Address::new(100), None), &insts);
        let calls = f.calls();
        assert_eq!(calls,
                   vec![Address::new(500), Address::new(400), Address::new(500)]);
    }
}
<|endoftext|>


<commit_before>use enum_primitive::FromPrimitive;

use map;
use room::Room;
use platform::random_i32;
use direction::Direction::*;

use self::RoomId::*;
use self::RoomContents::*;

const DEBUG: bool = false;
const NUM_ROOMS: usize = 19;
const NUM_MONSTERS: usize = 4;
const NUM_ROOMS_WITH_TREASURE: usize = 4;
const NUM_ROOMS_WITH_TERROR: usize = 4;
const MIN_TREASURE_AMOUNT: u8 = 10;
const MAX_TREASURE_AMOUNT: u8 = 110;

// There doesn't seem to be a convenient way to get the "size" or
// "range" of an enum's possible values, so we'll make a trait for
// that here.
//
// Ideally we could populate it automatically through a macro, but
// for now we'll just implement it manually for all our enums.
trait SizedEnum {
  fn size() -> usize;
}

enum_from_primitive! {
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum RoomId {
  Hallway = 0,
  AudienceChamber = 1,
  GreatHall = 2,
  PrivateMeeting = 3,
  InnerHallway = 4,
  Entrance = 5,
  Kitchen = 6,
  StoreRoom = 7,
  Lift = 8,
  RearVestibule = 9,
  Exit = 10,
  Dungeon = 11,
  Guardroom = 12,
  MasterBedroom = 13,
  UpperHallway = 14,
  Treasury = 15,
  ChambermaidsBedroom = 16,
  DressingChamber = 17,
  SmallRoom = 18,
}
}

impl SizedEnum for RoomId {
  fn size() -> usize { NUM_ROOMS }
}

enum_from_primitive! {
#[derive(Debug, Copy, Clone)]
pub enum MonsterId {
  Werewolf = 0,
  Fleshgorger = 1,
  Maldemer = 2,
  Dragon = 3,
}
}

impl SizedEnum for MonsterId {
  fn size() -> usize { NUM_MONSTERS }
}

#[derive(Debug, Copy, Clone)]
pub enum RoomContents {
  Treasure(u8),
  Terror(MonsterId),
}

pub type GameMap<'a> = map::Map<'a, RoomId, RoomContents>;

impl<'a> GameMap<'a> {
  pub fn create_rooms() -> [Room<RoomId, RoomContents>; NUM_ROOMS] {
    [Room::new(); NUM_ROOMS]
  }

  pub fn populate(&mut self) {
    self.describe_and_connect();
    self.allot_treasure();
    self.allot_terror();
    self.ensure_treasure();
  }

  fn allot<F>(&mut self, num_rooms: usize, allotter: F)
    where F: Fn() -> RoomContents
  {
    for _ in 0..num_rooms {
      loop {
        let room_id = random_enum::<RoomId>();
        if room_id != Entrance && room_id != Exit {
          let room = self.room(room_id);
          if room.contents.is_none() {
            let contents = allotter();
            if DEBUG {
              println!("DEBUG: Placing {:?} in {:?}.", contents, room_id);
            }
            room.contents = Some(contents);
            break;
          }
        }
      }
    }
  }

  fn allot_terror(&mut self) {
    self.allot(NUM_ROOMS_WITH_TERROR, || Terror(random_enum::<MonsterId>()))
  }

  fn allot_treasure(&mut self) {
    self.allot(NUM_ROOMS_WITH_TREASURE,
               || Treasure(random_treasure_amount()))
  }

  fn ensure_treasure(&mut self) {
    for &room_id in [Treasury, PrivateMeeting].iter() {
      let amount = random_treasure_amount();
      if DEBUG {
        println!("DEBUG: Placing ${} in {:?}.", amount, room_id);
      }
      self.room(room_id).contents = Some(Treasure(amount));
    }
  }

  fn describe_and_connect(&mut self) {
    self.room(Entrance).describe(
      "Entrance",
      "You are at the entrance to a forbidding-looking \
       stone castle. You are facing east."
    );

    self.room(Hallway).describe(
      "Hallway",
      "You are in the hallway. \
       There is a door to the south. \
       Through the windows to the north you can see a secret herb garden."
    );

    self.room(AudienceChamber).describe(
      "Audience Chamber",
      "This is the audience chamber. \
       There is a window to the west. By looking to the right \
       through it you can see the entrance to the castle. \
       Doors leave this room to the north, east, and south."
    );

    self.connect(Entrance, East, Hallway);
    self.connect(Hallway, South, AudienceChamber);
  }
}

fn random_enum<T: FromPrimitive + SizedEnum>() -> T {
  loop {
    let r = random_i32(0, T::size() as i32);
    match T::from_i32(r) {
      Some(t) => { return t; },
      None => {}
    }
  }
}

fn random_treasure_amount() -> u8 {
  random_i32(MIN_TREASURE_AMOUNT as i32, MAX_TREASURE_AMOUNT as i32) as u8
}

// Ideally we'd actually just get rid of MapRoomId and add a constraint
// to Map<T> requiring that T be type-castable as usize, but I don't
// know how to do that, so...
impl map::MapRoomId for RoomId {
  fn room_id(self) -> usize { self as usize }
}
<commit_msg>Add great hall.<commit_after>use enum_primitive::FromPrimitive;

use map;
use room::Room;
use platform::random_i32;
use direction::Direction::*;

use self::RoomId::*;
use self::RoomContents::*;

const DEBUG: bool = false;
const NUM_ROOMS: usize = 19;
const NUM_MONSTERS: usize = 4;
const NUM_ROOMS_WITH_TREASURE: usize = 4;
const NUM_ROOMS_WITH_TERROR: usize = 4;
const MIN_TREASURE_AMOUNT: u8 = 10;
const MAX_TREASURE_AMOUNT: u8 = 110;

// There doesn't seem to be a convenient way to get the "size" or
// "range" of an enum's possible values, so we'll make a trait for
// that here.
//
// Ideally we could populate it automatically through a macro, but
// for now we'll just implement it manually for all our enums.
trait SizedEnum {
  fn size() -> usize;
}

enum_from_primitive! {
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum RoomId {
  Hallway = 0,
  AudienceChamber = 1,
  GreatHall = 2,
  PrivateMeeting = 3,
  InnerHallway = 4,
  Entrance = 5,
  Kitchen = 6,
  StoreRoom = 7,
  Lift = 8,
  RearVestibule = 9,
  Exit = 10,
  Dungeon = 11,
  Guardroom = 12,
  MasterBedroom = 13,
  UpperHallway = 14,
  Treasury = 15,
  ChambermaidsBedroom = 16,
  DressingChamber = 17,
  SmallRoom = 18,
}
}

impl SizedEnum for RoomId {
  fn size() -> usize { NUM_ROOMS }
}

enum_from_primitive! {
#[derive(Debug, Copy, Clone)]
pub enum MonsterId {
  Werewolf = 0,
  Fleshgorger = 1,
  Maldemer = 2,
  Dragon = 3,
}
}

impl SizedEnum for MonsterId {
  fn size() -> usize { NUM_MONSTERS }
}

#[derive(Debug, Copy, Clone)]
pub enum RoomContents {
  Treasure(u8),
  Terror(MonsterId),
}

pub type GameMap<'a> = map::Map<'a, RoomId, RoomContents>;

impl<'a> GameMap<'a> {
  pub fn create_rooms() -> [Room<RoomId, RoomContents>; NUM_ROOMS] {
    [Room::new(); NUM_ROOMS]
  }

  pub fn populate(&mut self) {
    self.describe_and_connect();
    self.allot_treasure();
    self.allot_terror();
    self.ensure_treasure();
  }

  fn allot<F>(&mut self, num_rooms: usize, allotter: F)
    where F: Fn() -> RoomContents
  {
    for _ in 0..num_rooms {
      loop {
        let room_id = random_enum::<RoomId>();
        if room_id != Entrance && room_id != Exit {
          let room = self.room(room_id);
          if room.contents.is_none() {
            let contents = allotter();
            if DEBUG {
              println!("DEBUG: Placing {:?} in {:?}.", contents, room_id);
            }
            room.contents = Some(contents);
            break;
          }
        }
      }
    }
  }

  fn allot_terror(&mut self) {
    self.allot(NUM_ROOMS_WITH_TERROR, || Terror(random_enum::<MonsterId>()))
  }

  fn allot_treasure(&mut self) {
    self.allot(NUM_ROOMS_WITH_TREASURE,
               || Treasure(random_treasure_amount()))
  }

  fn ensure_treasure(&mut self) {
    for &room_id in [Treasury, PrivateMeeting].iter() {
      let amount = random_treasure_amount();
      if DEBUG {
        println!("DEBUG: Placing ${} in {:?}.", amount, room_id);
      }
      self.room(room_id).contents = Some(Treasure(amount));
    }
  }

  fn describe_and_connect(&mut self) {
    self.room(Entrance).describe(
      "Entrance",
      "You are at the entrance to a forbidding-looking \
       stone castle. You are facing east."
    );

    self.room(Hallway).describe(
      "Hallway",
      "You are in the hallway. \
       There is a door to the south. \
       Through the windows to the north you can see a secret herb garden."
    );

    self.room(AudienceChamber).describe(
      "Audience Chamber",
      "This is the audience chamber. \
       There is a window to the west. By looking to the right \
       through it you can see the entrance to the castle. \
       Doors leave this room to the north, east, and south."
    );

    self.room(GreatHall).describe(
      "Great Hall",
      "You are in the great hall, an L-shaped room. \
       There are doors to the east and to the north. \
       In the alcove is a door to the west."
    );

    self.connect(Entrance, East, Hallway);
    self.connect(Hallway, South, AudienceChamber);
    self.connect(GreatHall, North, AudienceChamber);
    self.connect(GreatHall, West, AudienceChamber);
  }
}

fn random_enum<T: FromPrimitive + SizedEnum>() -> T {
  loop {
    let r = random_i32(0, T::size() as i32);
    match T::from_i32(r) {
      Some(t) => { return t; },
      None => {}
    }
  }
}

fn random_treasure_amount() -> u8 {
  random_i32(MIN_TREASURE_AMOUNT as i32, MAX_TREASURE_AMOUNT as i32) as u8
}

// Ideally we'd actually just get rid of MapRoomId and add a constraint
// to Map<T> requiring that T be type-castable as usize, but I don't
// know how to do that, so...
impl map::MapRoomId for RoomId {
  fn room_id(self) -> usize { self as usize }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::time::Duration;
use quire::De;
use quire::validate::{Structure, Sequence, Scalar, Numeric};

use super::listen::{self, ListenSocket};
use super::http;

#[derive(RustcDecodable, Debug, PartialEq, Eq)]
pub struct SessionPool {
    pub listen: Vec<ListenSocket>,
    pub max_payload_size: usize,
    pub inactivity_handlers: Vec<http::Destination>,
    pub inactivity: Arc<InactivityTimeouts>,
}

#[derive(RustcDecodable, Debug, PartialEq, Eq)]
pub struct InactivityTimeouts {
    pub new_connection: De<Duration>,
    pub client_min: De<Duration>,
    pub client_max: De<Duration>,
    pub client_default: De<Duration>,
}

pub fn validator<'x>() -> Structure<'x> {
    Structure::new()
    .member("listen", listen::validator())
    .member("max_connections",
        Numeric::new().min(1).max(1 << 31).default(1000))
    .member("max_payload_size",
        Numeric::new().min(1).max(1 << 31).default(10_485_760))
    .member("inactivity_handlers",
        Sequence::new(http::destination_validator()))
    .member("inactivity", Structure::new()
        .member("new_connection", Scalar::new().min_length(1).default("60s"))
        .member("client_min", Scalar::new().min_length(1).default("1s"))
        .member("client_max", Scalar::new().min_length(1).default("2h"))
        .member("client_default", Scalar::new().min_length(1).default("1s"))
    )
}
<commit_msg>Fix validator for session pool config<commit_after>use std::sync::Arc;
use std::time::Duration;
use quire::De;
use quire::validate::{Structure, Sequence, Scalar, Numeric};

use super::listen::{self, ListenSocket};
use super::http;

#[derive(RustcDecodable, Debug, PartialEq, Eq)]
pub struct SessionPool {
    pub listen: Vec<ListenSocket>,
    pub max_payload_size: usize,
    pub inactivity_handlers: Vec<http::Destination>,
    pub inactivity: Arc<InactivityTimeouts>,
}

#[derive(RustcDecodable, Debug, PartialEq, Eq)]
pub struct InactivityTimeouts {
    pub new_connection: De<Duration>,
    pub client_min: De<Duration>,
    pub client_max: De<Duration>,
    pub client_default: De<Duration>,
}

pub fn validator<'x>() -> Structure<'x> {
    Structure::new()
    .member("listen", Sequence::new(listen::validator()))
    .member("max_connections",
        Numeric::new().min(1).max(1 << 31).default(1000))
    .member("max_payload_size",
        Numeric::new().min(1).max(1 << 31).default(10_485_760))
    .member("inactivity_handlers",
        Sequence::new(http::destination_validator()))
    .member("inactivity", Structure::new()
        .member("new_connection", Scalar::new().min_length(1).default("60s"))
        .member("client_min", Scalar::new().min_length(1).default("1s"))
        .member("client_max", Scalar::new().min_length(1).default("2h"))
        .member("client_default", Scalar::new().min_length(1).default("1s"))
    )
}
<|endoftext|>


<commit_before>#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Visibility {
    Visible,
    Invisible,
    Gone,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WindowStartSize {
    Exact(u16, u16),
    Fullscreen,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Progress {
    Value(u32, u32),
    Undefined,
}

pub type Menu = Option<Vec<MenuItem>>;

#[derive(Debug, PartialEq)]
pub enum MenuItem {
    Action(String, crate::callbacks::Action, MenuItemRole),
    Delimiter,
    Sub(String, Vec<MenuItem>, MenuItemRole),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MenuItemRole {
    None,
    Options,
    Help,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MessageSeverity {
    Info,
    Warning,
    Alert,
}

#[derive(Debug, Clone, PartialEq)]
pub enum TextContent {
    Plain(String),
    LabelDescription(String, String),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ImageScalePolicy {
    CropCenter, // TODO variants
    FitCenter,  // TODO variants
                // TODO Tile
}
#[derive(Debug, Clone, PartialEq)]
pub enum FindBy {
    Id(crate::ids::Id),
    Tag(String)
}

pub enum ApplicationResult {
    New(Box<dyn crate::controls::Application>),
    Existing(Box<dyn crate::controls::Application>),
    ErrorNonUiThread,
    ErrorUnspecified
}
impl ApplicationResult {
    pub fn unwrap(self) -> Box<dyn crate::controls::Application> {
        match self {
            ApplicationResult::New(app) | ApplicationResult::Existing(app) => app,
            ApplicationResult::ErrorNonUiThread => panic!("Application requested from non-UI thread"),
            ApplicationResult::ErrorUnspecified => panic!("Error getting Application"),
        }
    }
}
<commit_msg>More progress types<commit_after>#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Visibility {
    Visible,
    Invisible,
    Gone,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WindowStartSize {
    Exact(u16, u16),
    Fullscreen,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Progress {
    Value(u32, u32),
    Undefined,
    Error,
    None
}

pub type Menu = Option<Vec<MenuItem>>;

#[derive(Debug, PartialEq)]
pub enum MenuItem {
    Action(String, crate::callbacks::Action, MenuItemRole),
    Delimiter,
    Sub(String, Vec<MenuItem>, MenuItemRole),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MenuItemRole {
    None,
    Options,
    Help,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MessageSeverity {
    Info,
    Warning,
    Alert,
}

#[derive(Debug, Clone, PartialEq)]
pub enum TextContent {
    Plain(String),
    LabelDescription(String, String),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ImageScalePolicy {
    CropCenter, // TODO variants
    FitCenter,  // TODO variants
                // TODO Tile
}
#[derive(Debug, Clone, PartialEq)]
pub enum FindBy {
    Id(crate::ids::Id),
    Tag(String)
}

pub enum ApplicationResult {
    New(Box<dyn crate::controls::Application>),
    Existing(Box<dyn crate::controls::Application>),
    ErrorNonUiThread,
    ErrorUnspecified
}
impl ApplicationResult {
    pub fn unwrap(self) -> Box<dyn crate::controls::Application> {
        match self {
            ApplicationResult::New(app) | ApplicationResult::Existing(app) => app,
            ApplicationResult::ErrorNonUiThread => panic!("Application requested from non-UI thread"),
            ApplicationResult::ErrorUnspecified => panic!("Error getting Application"),
        }
    }
}
<|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.

#[macro_use]
extern crate nom;
extern crate amqp0_primitives as primitives;

#[cfg(not(feature = "lifeguard"))]
extern crate lifeguard;

mod common;
mod pool;

use nom::IResult;
use pool::ParserPool;

pub trait NomBytes<'a>: Sized {
    fn nom_bytes<'b, P>(&'a [u8], &'b mut P) -> IResult<&'a [u8], Self>
        where P: ParserPool,
              Self: 'a;
}<commit_msg>[parser-nom] Make pool module public.<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.

#[macro_use]
extern crate nom;
extern crate amqp0_primitives as primitives;

#[cfg(not(feature = "lifeguard"))]
extern crate lifeguard;

mod common;

pub mod pool;

use nom::IResult;
use pool::ParserPool;

pub trait NomBytes<'a>: Sized {
    fn nom_bytes<'b, P>(&'a [u8], &'b mut P) -> IResult<&'a [u8], Self>
        where P: ParserPool,
              Self: 'a;
}<|endoftext|>


<commit_before>use nom::*;
use std::str::FromStr;
use std::fmt::Debug;

#[derive(Debug, PartialEq)]
enum Rhs<N> {
    Binary(N, N),
    Chain(N)
}
type Yield = Vec<Vec<bool>>;

#[derive(Debug)]
struct RparseClauses<N, W>(Vec<(W, N, Rhs<N>, Yield)>);

fn is_token(c: char) -> bool { !c.is_whitespace() }

named!(parse_rparse_yield<&str, Yield>,
    delimited!(
        tag!("[["),
        separated_list_complete!(
            tag!(", "),
            delimited!(
                tag!("["),
                separated_list_complete!(
                    tag!(", "),
                    map!(
                        alt!(tag!("true") | tag!("false")),
                        |s| if s == "true" { true } else { false }
                    )
                ),
                tag!("]")
            )
        ),
        tag!("]]")
    )
);

fn parse_rparse_clauses<N, W>(s: &str) -> IResult<&str, RparseClauses<N, W>>
where
    N: FromStr,
    W: FromStr,
    <N as FromStr>::Err: Debug,
    <W as FromStr>::Err: Debug,
{
    map!(
        s,
        separated_nonempty_list_complete!(
            tag!("\n"),
            do_parse!(
                terminated!(digit, space)                                                   >>
                weight: take_while1!(|c| is_token(c) && c != ':')                           >>
                tag!(":")                                                                   >>
                lhs: take_while1!(is_token)                                                 >>
                delimited!(space, tag!("-->"), space)                                       >>
                rhs1: take_while1!(is_token)                                                >>
                space                                                                       >>
                o_rhs2: opt!(delimited!(not!(tag!("[[[")), take_while1!(is_token), space))  >>
                y: complete!(parse_rparse_yield)                                            >>
                (weight.parse().unwrap(), lhs.parse().unwrap(), if let Some(rhs2) = o_rhs2 { Rhs::Binary(rhs1.parse().unwrap(), rhs2.parse().unwrap()) } else { Rhs::Chain(rhs1.parse().unwrap()) }, y)
            )
        ),
        |v| RparseClauses(v)
    )
}

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

    #[test]
    fn rparse_yield () {
        let ys = vec![
            ("[[[false]]]", vec![vec![false]]),
            ("[[[false], [true]]]", vec![vec![false], vec![true]]),
            ("[[[false, true, false], [false], [true, false, false]]]", vec![vec![false, true, false], vec![false], vec![true, false, false]]),
        ];
        for (s, y) in ys {
            eprintln!("{:?}", parse_rparse_yield(s));
            assert_eq!(
                y,
                parse_rparse_yield(s).unwrap().1
            );
        }
    }

    #[test]
    fn rparse_clauses () {
        let ds = vec![
            ("10925 0.66:VROOT1 --> S1 $.1 [[[false, true]]]", (0.66, "VROOT1".to_owned(), Rhs::Binary("S1".to_owned(), "$.1".to_owned()), vec![vec![false, true]])),
            ("1 6.047046018020197E-5:VROOT1 --> ADV1 $(1 [[[false, true]]]", (6.047046018020197E-5, "VROOT1".to_owned(), Rhs::Binary("ADV1".to_owned(), "$(1".to_owned()), vec![vec![false, true]])),
            ("2 0.006557377049180328:PP2 --> @^PP2^VP3-APPRART1X2  [[[false], [false]]]", (0.006557377049180328, "PP2".to_owned(), Rhs::Chain("@^PP2^VP3-APPRART1X2".to_owned()), vec![vec![false], vec![false]]))
        ];
        for (s, deriv) in ds {
            eprintln!("{:?}", parse_rparse_clauses::<String, f64>(s));
            assert_eq!( (parse_rparse_clauses(s).unwrap().1).0, vec![deriv] );
        }
    }
}<commit_msg>conversion form rparse clauses to Lcfrs<commit_after>use nom::*;
use std::str::FromStr;
use std::fmt::Debug;
use super::*;

#[derive(Debug, PartialEq)]
enum Rhs<N> {
    Binary(N, N),
    Chain(N)
}
type Yield = Vec<Vec<bool>>;

#[derive(Debug)]
struct RparseClauses<N, W>(Vec<(W, N, Rhs<N>, Yield)>);

fn is_token(c: char) -> bool { !c.is_whitespace() }

named!(parse_rparse_yield<&str, Yield>,
    delimited!(
        tag!("[["),
        separated_list_complete!(
            tag!(", "),
            delimited!(
                tag!("["),
                separated_list_complete!(
                    tag!(", "),
                    map!(
                        alt!(tag!("true") | tag!("false")),
                        |s| if s == "true" { true } else { false }
                    )
                ),
                tag!("]")
            )
        ),
        tag!("]]")
    )
);

fn parse_rparse_clauses<N, W>(s: &str) -> IResult<&str, RparseClauses<N, W>>
where
    N: FromStr,
    W: FromStr,
    <N as FromStr>::Err: Debug,
    <W as FromStr>::Err: Debug,
{
    map!(
        s,
        separated_nonempty_list_complete!(
            tag!("\n"),
            do_parse!(
                terminated!(digit, space)                                                   >>
                weight: take_while1!(|c| is_token(c) && c != ':')                           >>
                tag!(":")                                                                   >>
                lhs: take_while1!(is_token)                                                 >>
                delimited!(space, tag!("-->"), space)                                       >>
                rhs1: take_while1!(is_token)                                                >>
                space                                                                       >>
                o_rhs2: opt!(delimited!(not!(tag!("[[[")), take_while1!(is_token), space))  >>
                y: complete!(parse_rparse_yield)                                            >>
                (weight.parse().unwrap(), lhs.parse().unwrap(), if let Some(rhs2) = o_rhs2 { Rhs::Binary(rhs1.parse().unwrap(), rhs2.parse().unwrap()) } else { Rhs::Chain(rhs1.parse().unwrap()) }, y)
            )
        ),
        |v| RparseClauses(v)
    )
}

impl<N, W> FromStr for RparseClauses<N, W>
where
    N: FromStr,
    W: FromStr,
    <N as FromStr>::Err: Debug,
    <W as FromStr>::Err: Debug,
{
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match parse_rparse_clauses(s) {
            IResult::Done(_, clauses) => Ok(clauses),
            _ => Err(())
        }
    }
}

impl<N, W> Into<Lcfrs<N, (), W>> for RparseClauses<N, W>
where
    N: FromStr,
    <N as FromStr>::Err: Debug
{
    fn into(self) -> Lcfrs<N, (), W> {
        let mut rules = Vec::with_capacity(self.0.len());
        for (weight, lhs, rhs, y) in self.0 {
            let tail = match rhs {
                Rhs::Chain(a) => vec![a],
                Rhs::Binary(a, b) => vec![a, b]
            };

            let mut composition = Vec::with_capacity(y.len());
            let mut ind1 = 0;
            let mut ind2 = 0;
            for ycomp in y {
                let mut component = Vec::with_capacity(ycomp.len());
                for snd_or_fst in ycomp {
                    if snd_or_fst { component.push(VarT::Var(1, ind2)); ind2 += 1; }
                    else { component.push(VarT::Var(0, ind1)); ind1 += 1; }
                }
                composition.push(component);
            }

            rules.push(
                PMCFGRule{ head: lhs, tail, weight, composition: composition.into() }
            );
        }

        Lcfrs{ rules, init: "VROOT1".parse().unwrap() }
    }
}

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

    #[test]
    fn rparse_yield () {
        let ys = vec![
            ("[[[false]]]", vec![vec![false]]),
            ("[[[false], [true]]]", vec![vec![false], vec![true]]),
            ("[[[false, true, false], [false], [true, false, false]]]", vec![vec![false, true, false], vec![false], vec![true, false, false]]),
        ];
        for (s, y) in ys {
            assert_eq!(
                y,
                parse_rparse_yield(s).unwrap().1
            );
        }
    }

    #[test]
    fn rparse_clauses () {
        let ds = vec![
            ("10925 0.66:VROOT1 --> S1 $.1 [[[false, true]]]", (0.66, "VROOT1".to_owned(), Rhs::Binary("S1".to_owned(), "$.1".to_owned()), vec![vec![false, true]])),
            ("1 6.047046018020197E-5:VROOT1 --> ADV1 $(1 [[[false, true]]]", (6.047046018020197E-5, "VROOT1".to_owned(), Rhs::Binary("ADV1".to_owned(), "$(1".to_owned()), vec![vec![false, true]])),
            ("2 0.006557377049180328:PP2 --> @^PP2^VP3-APPRART1X2  [[[false], [false]]]", (0.006557377049180328, "PP2".to_owned(), Rhs::Chain("@^PP2^VP3-APPRART1X2".to_owned()), vec![vec![false], vec![false]]))
        ];
        for (s, deriv) in ds {
            assert_eq!( (parse_rparse_clauses(s).unwrap().1).0, vec![deriv] );
        }
    }

    #[test]
    fn conversion () {
        let clauses = vec![
            (0.66, "VROOT1".to_owned(), Rhs::Binary("S1".to_owned(), "$.1".to_owned()), vec![vec![false, true]]),
            (6.047046018020197E-5, "VROOT1".to_owned(), Rhs::Binary("ADV1".to_owned(), "$(1".to_owned()), vec![vec![false, true]]),
            (0.006557377049180328, "PP2".to_owned(), Rhs::Chain("@^PP2^VP3-APPRART1X2".to_owned()), vec![vec![false], vec![false]])
        ];
        let rules: Vec<PMCFGRule<String, (), f64>> = vec![
            PMCFGRule{ head: "VROOT1".to_owned(), tail: vec!["S1".to_owned(), "$.1".to_owned()], weight: 0.66, composition: vec![vec![VarT::Var(0,0), VarT::Var(1,0)]].into() },
            PMCFGRule{ head: "VROOT1".to_owned(), tail: vec!["ADV1".to_owned(), "$(1".to_owned()], weight: 6.047046018020197E-5, composition: vec![vec![VarT::Var(0,0), VarT::Var(1,0)]].into() },
            PMCFGRule{ head: "PP2".to_owned(), tail: vec!["@^PP2^VP3-APPRART1X2".to_owned()], weight: 0.006557377049180328, composition: vec![vec![VarT::Var(0,0)], vec![VarT::Var(0,1)]].into() },
        ];

        let conv: Lcfrs<String, (), f64> = RparseClauses(clauses).into();
        assert_eq!(conv.rules, rules);
        assert_eq!(conv.init, "VROOT1".to_owned());
    }
}<|endoftext|>


<commit_before>//! A thin wrapper around `ThreadPool` to make sure that we join all things
//! properly.
use crossbeam_channel::Sender;

pub(crate) struct TaskPool<T> {
    sender: Sender<T>,
    inner: threadpool::ThreadPool,
}

impl<T> TaskPool<T> {
    pub(crate) fn new(sender: Sender<T>) -> TaskPool<T> {
        TaskPool { sender, inner: threadpool::ThreadPool::default() }
    }

    pub(crate) fn spawn<F>(&mut self, task: F)
    where
        F: FnOnce() -> T + Send + 'static,
        T: Send + 'static,
    {
        self.inner.execute({
            let sender = self.sender.clone();
            move || sender.send(task()).unwrap()
        })
    }

    pub(crate) fn spawn_with_sender<F>(&mut self, task: F)
    where
        F: FnOnce(Sender<T>) + Send + 'static,
        T: Send + 'static,
    {
        self.inner.execute({
            let sender = self.sender.clone();
            move || task(sender)
        })
    }

    pub(crate) fn len(&self) -> usize {
        self.inner.queued_count()
    }
}

impl<T> Drop for TaskPool<T> {
    fn drop(&mut self) {
        self.inner.join()
    }
}
<commit_msg>Auto merge of #12466 - lnicola:worker-thread-stack, r=lnicola<commit_after>//! A thin wrapper around `ThreadPool` to make sure that we join all things
//! properly.
use crossbeam_channel::Sender;

pub(crate) struct TaskPool<T> {
    sender: Sender<T>,
    inner: threadpool::ThreadPool,
}

impl<T> TaskPool<T> {
    pub(crate) fn new(sender: Sender<T>) -> TaskPool<T> {
        const STACK_SIZE: usize = 8 * 1024 * 1024;

        let inner = threadpool::Builder::new()
            .thread_name("Worker".into())
            .thread_stack_size(STACK_SIZE)
            .build();
        TaskPool { sender, inner }
    }

    pub(crate) fn spawn<F>(&mut self, task: F)
    where
        F: FnOnce() -> T + Send + 'static,
        T: Send + 'static,
    {
        self.inner.execute({
            let sender = self.sender.clone();
            move || sender.send(task()).unwrap()
        })
    }

    pub(crate) fn spawn_with_sender<F>(&mut self, task: F)
    where
        F: FnOnce(Sender<T>) + Send + 'static,
        T: Send + 'static,
    {
        self.inner.execute({
            let sender = self.sender.clone();
            move || task(sender)
        })
    }

    pub(crate) fn len(&self) -> usize {
        self.inner.queued_count()
    }
}

impl<T> Drop for TaskPool<T> {
    fn drop(&mut self) {
        self.inner.join()
    }
}
<|endoftext|>