<commit_before>use collections::hashmap::{HashMap, Keys};
use collections::hashmap::HashSet;
use std::cast;
use cgmath::point::{Point2};
use cgmath::vector::{Vec2};
use dijkstra;
use fov::Fov;

#[deriving(Eq)]
pub enum TerrainType {
    Floor,
    Water,
    Magma,
    Downstairs,
    Wall,
    RockWall,
    Rock,
    Tree,
    Grass,
    Stalagmite,
    Portal,
}

impl TerrainType {
    pub fn is_wall(self) -> bool {
        match self {
            Wall | RockWall | Rock => true,
            _ => false
        }
    }

    pub fn is_opaque(self) -> bool {
        match self {
            Wall | RockWall | Rock => true,
            _ => false
        }
    }

    pub fn blocks_shot(self) -> bool {
        match self {
            Wall | RockWall | Rock | Tree | Stalagmite => true,
            _ => false
        }
    }

    pub fn is_walkable(self) -> bool {
        match self {
            Floor | Grass | Downstairs | Portal => true,
            _ => false
        }

    }
}

pub struct Area {
    default: TerrainType,
    set: HashMap<Location, TerrainType>,
}

pub type DijkstraMap = HashMap<Location, uint>;

pub fn uphill(map: &DijkstraMap, loc: Location) -> Option<Location> {
    let mut ret = None;
    let mut score = 0;
    for p in DIRECTIONS6.iter().map(|&d| loc + d) {
        let val = map.find(&p);
        match (val, ret) {
            (Some(&s), None) => { score = s; ret = Some(p); },
            (Some(&s), _) => { if s < score { score = s; ret = Some(p); } },
            _ => ()
        };
    }
    ret
}

impl Area {
    pub fn new(default: TerrainType) -> Area {
        Area {
            default: default,
            set: HashMap::new(),
        }
    }

    pub fn get(&self, p: Location) -> TerrainType {
        match self.set.find(&p) {
            None => self.default,
            Some(&t) => t
        }
    }

    pub fn set(&mut self, p: Location, t: TerrainType) {
        self.set.insert(p, t);
    }

    pub fn defined(&self, p: Location) -> bool {
        self.set.contains_key(&p)
    }

    pub fn remove(&mut self, p: Location) {
        self.set.remove(&p);
    }

    pub fn dig(&mut self, p: Location) {
        self.set.insert(p, Floor);
    }

    pub fn fill(&mut self, p: Location) {
        self.set.insert(p, self.default);
    }

    pub fn is_opaque(&self, p: Location) -> bool { self.get(p).is_opaque() }

    pub fn is_open(&self, p: Location) -> bool {
        match self.get(p) {
            Floor | Water | Magma | Grass | Downstairs | Portal => true,
            _ => false
        }
    }

    pub fn iter<'a>(&'a self) -> Keys<'a, Location, TerrainType> {
        self.set.keys()
    }

    pub fn walk_neighbors(&self, p: Location) -> Vec<Location> {
        let mut ret = vec!();
        for &v in DIRECTIONS6.iter() {
            if self.get(p + v).is_walkable() {
               ret.push(p + v);
            }
        }
        ret
    }

    pub fn fully_explored(&self, remembered: &Fov) -> bool {
        // XXX: This won't show maps that have unreachable wall structures
        // buried within other wall tiles as fully explored.
        for &loc in self.cover().iter() {
            if !remembered.contains(loc) {
                return false
            }
        }
        true
    }

    pub fn cover(&self) -> HashSet<Location> {
        // Generate the set of locations that comprise this map. Hit the open
        // cells and their neighbors to get the closest walls.
        let mut ret = HashSet::new();
        for &loc in self.set.keys() {
            ret.insert(loc);
            for &d in DIRECTIONS8.iter() {
                ret.insert(loc + d);
            }
        }
        ret
    }

    pub fn explore_map(&self, remembered: &Fov) -> DijkstraMap {
        let mut goals = vec!();
        for &loc in self.cover().iter() {
            if !remembered.contains(loc) {
                goals.push(loc);
            }
        }

        dijkstra::build_map(goals, |&loc| self.walk_neighbors(loc), 256)
    }
}

pub static DIRECTIONS6: &'static [Vec2<int>] = &[
    Vec2 { x: -1, y: -1 },
    Vec2 { x:  0, y: -1 },
    Vec2 { x:  1, y:  0 },
    Vec2 { x:  1, y:  1 },
    Vec2 { x:  0, y:  1 },
    Vec2 { x: -1, y:  0 },
];

pub static DIRECTIONS8: &'static [Vec2<int>] = &[
    Vec2 { x: -1, y: -1 },
    Vec2 { x:  0, y: -1 },
    Vec2 { x:  1, y: -1 },
    Vec2 { x:  1, y:  0 },
    Vec2 { x:  1, y:  1 },
    Vec2 { x:  0, y:  1 },
    Vec2 { x: -1, y:  1 },
    Vec2 { x: -1, y:  0 },
];
// Add third dimension for levels.
#[deriving(Eq, Clone, Hash)]
pub struct Location(Point2<i8>);

impl<'a> Location {
    pub fn p(&'a self) -> &'a Point2<i8> {
        unsafe {
            cast::transmute(self)
        }
    }
}

impl Add<Vec2<int>, Location> for Location {
    fn add(&self, other: &Vec2<int>) -> Location {
        let &Location(p) = self;
        Location(Point2::new(
                (p.x as int + other.x) as i8,
                (p.y as int + other.y) as i8))
    }
}

impl Sub<Location, Vec2<int>> for Location {
    fn sub(&self, other: &Location) -> Vec2<int> {
        let &Location(p) = self;
        let &Location(p2) = other;
        Vec2::new((p.x - p2.x) as int, (p.y - p2.y) as int)
    }
}
<commit_msg>Work around the compiler bug<commit_after>use collections::hashmap::{HashMap, Keys};
use collections::hashmap::HashSet;
use std::cast;
use cgmath::point::{Point2};
use cgmath::vector::{Vec2};
use dijkstra;
use fov::Fov;

#[deriving(Eq)]
pub enum TerrainType {
    Floor,
    Water,
    Magma,
    Downstairs,
    Wall,
    RockWall,
    Rock,
    Tree,
    Grass,
    Stalagmite,
    Portal,
}

impl TerrainType {
    pub fn is_wall(self) -> bool {
        match self {
            Wall | RockWall | Rock => true,
            _ => false
        }
    }

    pub fn is_opaque(self) -> bool {
        match self {
            Wall | RockWall | Rock => true,
            _ => false
        }
    }

    pub fn blocks_shot(self) -> bool {
        match self {
            Wall | RockWall | Rock | Tree | Stalagmite => true,
            _ => false
        }
    }

    pub fn is_walkable(self) -> bool {
        match self {
            Floor | Grass | Downstairs | Portal => true,
            _ => false
        }

    }
}

pub struct Area {
    default: TerrainType,
    set: HashMap<Location, TerrainType>,
}

pub type DijkstraMap = HashMap<Location, uint>;

pub fn uphill(map: &DijkstraMap, loc: Location) -> Option<Location> {
    let mut ret = None;
    let mut score = 0;
    for p in DIRECTIONS6.iter().map(|&d| loc + d) {
        let val = map.find(&p);
        match (val, ret) {
            (Some(&s), None) => { score = s; ret = Some(p); },
            (Some(&s), _) => { if s < score { score = s; ret = Some(p); } },
            _ => ()
        };
    }
    ret
}

impl Area {
    pub fn new(default: TerrainType) -> Area {
        Area {
            default: default,
            set: HashMap::new(),
        }
    }

    pub fn get(&self, p: Location) -> TerrainType {
        match self.set.find(&p) {
            None => self.default,
            Some(&t) => t
        }
    }

    pub fn set(&mut self, p: Location, t: TerrainType) {
        self.set.insert(p, t);
    }

    pub fn defined(&self, p: Location) -> bool {
        self.set.contains_key(&p)
    }

    pub fn remove(&mut self, p: Location) {
        self.set.remove(&p);
    }

    pub fn dig(&mut self, p: Location) {
        self.set.insert(p, Floor);
    }

    pub fn fill(&mut self, p: Location) {
        self.set.insert(p, self.default);
    }

    pub fn is_opaque(&self, p: Location) -> bool { self.get(p).is_opaque() }

    pub fn is_open(&self, p: Location) -> bool {
        match self.get(p) {
            Floor | Water | Magma | Grass | Downstairs | Portal => true,
            _ => false
        }
    }

    pub fn iter<'a>(&'a self) -> Keys<'a, Location, TerrainType> {
        self.set.keys()
    }

    pub fn walk_neighbors(&self, p: Location) -> Vec<Location> {
        let mut ret = vec!();
        for &v in DIRECTIONS6.iter() {
            if self.get(p + v).is_walkable() {
               ret.push(p + v);
            }
        }
        ret
    }

    pub fn fully_explored(&self, remembered: &Fov) -> bool {
        // XXX: This won't show maps that have unreachable wall structures
        // buried within other wall tiles as fully explored.
        for &loc in self.cover().iter() {
            if !remembered.contains(loc) {
                return false
            }
        }
        true
    }

    pub fn cover(&self) -> HashSet<Location> {
        // Generate the set of locations that comprise this map. Hit the open
        // cells and their neighbors to get the closest walls.
        let mut ret = HashSet::new();
        for &loc in self.set.keys() {
            ret.insert(loc);
            for &d in DIRECTIONS8.iter() {
                ret.insert(loc + d);
            }
        }
        ret
    }

    pub fn explore_map(&self, remembered: &Fov) -> DijkstraMap {
        let mut goals = vec!();
        for &loc in self.cover().iter() {
            if !remembered.contains(loc) {
                goals.push(loc);
            }
        }

        dijkstra::build_map(goals, |&loc| self.walk_neighbors(loc), 256)
    }
}

pub static DIRECTIONS6: [Vec2<int>, ..6] = [
    Vec2 { x: -1, y: -1 },
    Vec2 { x:  0, y: -1 },
    Vec2 { x:  1, y:  0 },
    Vec2 { x:  1, y:  1 },
    Vec2 { x:  0, y:  1 },
    Vec2 { x: -1, y:  0 },
];

pub static DIRECTIONS8: [Vec2<int>, ..8] = [
    Vec2 { x: -1, y: -1 },
    Vec2 { x:  0, y: -1 },
    Vec2 { x:  1, y: -1 },
    Vec2 { x:  1, y:  0 },
    Vec2 { x:  1, y:  1 },
    Vec2 { x:  0, y:  1 },
    Vec2 { x: -1, y:  1 },
    Vec2 { x: -1, y:  0 },
];
// Add third dimension for levels.
#[deriving(Eq, Clone, Hash)]
pub struct Location(Point2<i8>);

impl<'a> Location {
    pub fn p(&'a self) -> &'a Point2<i8> {
        unsafe {
            cast::transmute(self)
        }
    }
}

impl Add<Vec2<int>, Location> for Location {
    fn add(&self, other: &Vec2<int>) -> Location {
        let &Location(p) = self;
        Location(Point2::new(
                (p.x as int + other.x) as i8,
                (p.y as int + other.y) as i8))
    }
}

impl Sub<Location, Vec2<int>> for Location {
    fn sub(&self, other: &Location) -> Vec2<int> {
        let &Location(p) = self;
        let &Location(p2) = other;
        Vec2::new((p.x - p2.x) as int, (p.y - p2.y) as int)
    }
}
<|endoftext|>


<commit_before>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
extern crate sync;
extern crate rand;
mod buffer;

enum SqlType {
	Char(uint),
	Varchar(uint),
	Integer,
}

enum SqlAttribute {
	Null,
	NotNull,
}

struct Column {
	name: ~str,
	datatype: SqlType,
	attributes: Vec<SqlAttribute>,
}

struct Relation {
	name: ~str,
	columns: Vec<Column>,
}

impl Relation {
	pub fn new(name: ~str) -> Relation {
		Relation {name: name, columns: Vec::new()}
	}

	pub fn add_column(&mut self, column: Column) {
		self.columns.push(column);
	}
}

struct Schema {
	relations: Vec<Relation>,
}

impl Schema {
	pub fn new() -> Schema {
		Schema {relations: Vec::new()}
	}

	pub fn new_from_disk() {
	}

	pub fn add_relation(&mut self, relation: Relation) {
		self.relations.push(relation);
	}
}

struct Record {
	// TODO: do we even need this?
	len: uint,
	data: Vec<u8>,
}

impl Record {
	/* move semantics, no copy */
	pub fn new(len: uint, data: Vec<u8>) -> Record {
		Record {len: len, data: data}
	}

	pub fn get_data<'a>(&'a self) -> &'a [u8] {
		self.data.as_slice()
	}
}

struct SPSegment;

/* our newtype struct: create a TID type as an alias to u64 */
struct TID(u64);

impl SPSegment {
	pub fn insert(r: Record) -> TID {
		TID(0_u64)
	}

	pub fn remove(tid: TID) -> bool {
		false
	}

	pub fn lookup(tid: TID) -> Record {
		// TODO
		Record {len: 1, data: vec!(1)}
	}

	pub fn update(tid: TID, r: Record) -> bool {
		false
	}
}

#[test]
fn main() {
}

#[test]
fn create_schema() {
	let name = Column {name: ~"name", datatype: Varchar(128), attributes: vec!(NotNull)};
	let age = Column {name: ~"age", datatype: Integer, attributes: vec!(NotNull)};
	let mut relation = Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	let mut schema = Schema::new();
	schema.add_relation(relation);
}
<commit_msg>dded additional constructor to read a Schema from disk<commit_after>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
extern crate sync;
extern crate rand;
mod buffer;

enum SqlType {
	Char(uint),
	Varchar(uint),
	Integer,
}

enum SqlAttribute {
	Null,
	NotNull,
}

struct Column {
	name: ~str,
	datatype: SqlType,
	attributes: Vec<SqlAttribute>,
}

struct Relation {
	name: ~str,
	columns: Vec<Column>,
}

impl Relation {
	pub fn new(name: ~str) -> Relation {
		Relation {name: name, columns: Vec::new()}
	}

	pub fn add_column(&mut self, column: Column) {
		self.columns.push(column);
	}
}

struct Schema {
	relations: Vec<Relation>,
}

impl Schema {
	pub fn new() -> Schema {
		Schema {relations: Vec::new()}
	}

	pub fn new_from_disk(bufmanager: buffer::BufferManager) -> Schema {
		// TODO
		Schema {relations: Vec::new()}
	}

	pub fn add_relation(&mut self, relation: Relation) {
		self.relations.push(relation);
	}
}

struct Record {
	// TODO: do we even need this?
	len: uint,
	data: Vec<u8>,
}

impl Record {
	/* move semantics, no copy */
	pub fn new(len: uint, data: Vec<u8>) -> Record {
		Record {len: len, data: data}
	}

	pub fn get_data<'a>(&'a self) -> &'a [u8] {
		self.data.as_slice()
	}
}

struct SPSegment;

/* our newtype struct: create a TID type as an alias to u64 */
struct TID(u64);

impl SPSegment {
	pub fn insert(r: Record) -> TID {
		TID(0_u64)
	}

	pub fn remove(tid: TID) -> bool {
		false
	}

	pub fn lookup(tid: TID) -> Record {
		// TODO
		Record {len: 1, data: vec!(1)}
	}

	pub fn update(tid: TID, r: Record) -> bool {
		false
	}
}

#[test]
fn main() {
}

#[test]
fn create_schema() {
	let name = Column {name: ~"name", datatype: Varchar(128), attributes: vec!(NotNull)};
	let age = Column {name: ~"age", datatype: Integer, attributes: vec!(NotNull)};
	let mut relation = Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	let mut schema = Schema::new();
	schema.add_relation(relation);
}
<|endoftext|>


<commit_before>#![feature(plugin, path_ext, path_relative_from)]
#![plugin(serde_macros, docopt_macros)]

extern crate iron;
extern crate regex;
extern crate conduit_mime_types;
extern crate mustache;
extern crate libc;
extern crate num_cpus;
extern crate serde;
#[macro_use]
extern crate lazy_static;
extern crate docopt;
extern crate rustc_serialize;

use std::{ env, fs, process };
use std::path::{ Path, PathBuf };
use std::io::{ Read, Write };
use std::error::Error;
use std::fs::{ File, PathExt };
use std::sync::Arc;
use std::borrow::Borrow;

use regex::Regex;

use conduit_mime_types::Types;

use serde::json::{ self, Value };

use iron::prelude::*;
use iron::status;
use iron::mime::{ Mime, TopLevel, SubLevel };
use iron::headers::ContentType;
use iron::modifiers::Header;

use mustache::{ Template, VecBuilder, MapBuilder };

use constants::*;

pub mod constants;

docopt!(Args derive Debug, "
A minimal static file server, written in Rust with Iron.
Usage: sersve [options]

Options:
    -h, --help                  Show this message.
    -v, --version               Show the version of sersve (duh).
    -c, --config FILE           Provide a configuration file (JSON).
    -a, --address HOST          The address to bind to.
    -p, --port PORT             The port to serve.
    -r, --root ROOT             The uppermost directory to serve.
    -f, --filter REGEX          A regular expression to filter the filenames.
    -s, --size BYTES            The maximum size of a file that will be served.
    -t, --template TEMPLATE     A Mustache template to use for rendering.
    --threads THREADS           Amount of threads to use for serving.
    --fork                      Fork sersve into a background process.",
    flag_help: bool,
    flag_version: bool,
    flag_config: Option<String>,
    flag_address: Option<String>,
    flag_port: Option<u16>,
    flag_root: Option<String>,
    flag_filter: Option<String>,
    flag_size: Option<u64>,
    flag_template: Option<String>,
    flag_threads: Option<usize>,
    flag_fork: bool
);

#[derive(Clone)]
struct State {
    template: Template,
    root: Option<PathBuf>,
    mime_types: Arc<Types>
}

const HOST: &'static str = "0.0.0.0";
const PORT: u16 = 8080;

static UNITS: &'static [&'static str] = &["B", "kB", "MB", "GB", "TB"];

const KEY_TITLE: &'static str = "title";
const KEY_CONTENT: &'static str = "content";
const KEY_URL: &'static str = "url";
const KEY_SIZE: &'static str = "size";
const KEY_NAME: &'static str = "name";

const DEF_LEN: usize = 10000;

lazy_static! {
    static ref ARGS: Args = {
        let mut args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

        if let Some(ref flag_config) = args.flag_config {
            let conf = File::open(&flag_config)
                            .and_then(|mut f| {
                                let mut out = String::new();
                                f.read_to_string(&mut out).map(|_| out)
                            }).map_err(|e| error(e.description()))
                            .unwrap();

            // cannot if-let, because typesafe errors are helpful
            let json = match json::from_str(&conf) {
                Ok(Value::Object(o)) => o,
                _ => panic!("Invalid configuration file. Doesn't contain valid top-level object.")
            };
            args.flag_address = args.flag_address.or(match json.get("address") {
                Some(&Value::String(ref s)) => Some((*s).clone()),
                None => None,
                _ => panic!("Invalid configuration file. `address` field must be a string.")
            });
            args.flag_port = args.flag_port.or(match json.get("port") {
                Some(&Value::U64(u)) => Some(u as u16),
                None => None,
                _ => panic!("Invalid configuration file. `port` field must be an unsigned integer.")
            });
            args.flag_root = args.flag_root.or(match json.get("root") {
                Some(&Value::String(ref s)) => Some(s.clone()),
                None => None,
                _ => panic!("Invalid configuration file. `root` field must be a string.")
            });
            args.flag_filter = args.flag_filter.or(match json.get("filter") {
                Some(&Value::String(ref s)) => Some((*s).clone()),
                None => None,
                _ => panic!("Invalid configuration file. `filter` field must be a string.")
            });
            args.flag_size = args.flag_size.or(match json.get("size") {
                Some(&Value::U64(u)) => Some(u),
                None => None,
                _ => panic!("Invalid configuration file. `size` field must be an unsigned integer.")
            });
            args.flag_template = args.flag_template.or(match json.get("template") {
                Some(&Value::String(ref s)) => Some((*s).clone()),
                None => None,
                _ => panic!("Invalid configuration file. `template` field must be a string.")
            });
            args.flag_fork = args.flag_fork || match json.get("fork") {
                Some(&Value::Bool(b)) => b,
                None => false,
                _ => panic!("Invalid configuration file. `fork` field must be a boolean")
            };
            args.flag_threads = args.flag_threads.or(match json.get("threads") {
                Some(&Value::U64(u)) => Some(u as usize),
                None => None,
                _ => panic!("Invalid configuration file. `threads` field must be a string.")
            })
        };

        args
    };

    static ref STATE: State = State {
        template: mustache::compile_str(&ARGS.flag_template.as_ref().unwrap_or(&OPT_TEMPLATE.to_owned())),
        root: ARGS.flag_root.clone().map(|p| Path::new(&p).to_path_buf()),
        mime_types: Arc::new(Types::new().ok().unwrap())
    };
}

fn error(e: &str) -> ! {
    println!("Error: {}", e);
    process::exit(-1);
}

fn fork() {
    unsafe {
        let pid = libc::funcs::posix88::unistd::fork();
        if pid == 0 {
            // we are child, now get to work
            return;
        } else if pid > 0 {
            // fork succeeded, die
            process::exit(0);
        } else if pid < 0 {
            // unsuccessful, don't die
            return;
        }
    }
}

fn size_with_unit(mut size: u64) -> String {
    let mut frac = 0;
    let mut index = 0;

    while size > 1000 && index + 1 < UNITS.len() {
        frac = size % 1000;
        size /= 1000;
        index += 1;
    }

    format!("{}.{} {}", size, frac, UNITS[index])
}

fn render<'a, W: Write>(mut out: W, template: Template, root: PathBuf, dir: PathBuf, files: Vec<PathBuf>, filter: Option<Regex>) {
    let data = MapBuilder::new()
        .insert_str(KEY_TITLE, format!("{}", dir.display()))
        .insert_vec(KEY_CONTENT, |mut vec: VecBuilder| {
            let item = |map: MapBuilder, url: &Path, size: u64, name: String| {
                map.insert(KEY_URL, &format!("{}", url.display())).unwrap()
                   .insert(KEY_SIZE, &size_with_unit(size)).unwrap()
                   .insert_str(KEY_NAME, name)
            };

            // add `..` entry if necessary
            let mut up = dir.to_path_buf();
            up.pop();
            if up.starts_with(&root) {
                vec = vec.push_map(|map: MapBuilder| item(map, &up.relative_from(&root).unwrap(), 0, "..".to_owned()));
            }

            for file in files.iter() {
                let relative = file.relative_from(&root).unwrap();
                let stat = file.metadata().unwrap();
                let filename = file.file_name()
                    .expect("Cannot get filename").to_string_lossy().into_owned();
                if filter.as_ref().map_or(true, |f| f.is_match(&filename)) {
                    vec = vec.push_map(|map| item(map, &relative, stat.len(), filename.clone()));
                }
            }
            vec
        }).build();

    template.render_data(&mut out, &data);
}

fn plain(content: &[u8]) -> IronResult<Response> {
    Ok(Response::with((status::Ok, content)))
}

fn html(content: &[u8]) -> IronResult<Response> {
    plain(content).map(|r| r.set(Header(ContentType(Mime(TopLevel::Text, SubLevel::Html, Vec::new())))))
}

fn from_path(path: &Path) -> IronResult<Response> {
    Ok(Response::with((status::Ok, path)))
}

fn serve(req: &mut Request) -> IronResult<Response> {
    let (filter_str, max_size) = (
        ARGS.flag_filter.clone(),
        ARGS.flag_size
    );

    let (template, root, mime_types) = (
        STATE.template.clone(),
        STATE.root.clone().unwrap_or_else(|| env::current_dir().ok().unwrap()),
        STATE.mime_types.clone()
    );

    let mut path = root.clone();
    for part in req.url.path.iter() { path.push(part) }
    if !path.exists() { return html(b"Well, no... We don't have that today."); }

    let filter = filter_str.and_then(|s| Regex::new(&s).ok());

    if path.is_file() && path.starts_with(&root) {
        let stat = path.metadata();
        if stat.as_ref().ok().is_some() && max_size.is_some() && stat.ok().unwrap().len() > max_size.unwrap() {
            return html(b"I'm afraid, I'm too lazy to serve the requested file. It's pretty big...")
        }
        /*let content = match File::open(&path).read_to_end() {
            Ok(s) => s,
            Err(e) => return html(e.desc)
        };*/

        if filter.as_ref().map_or(false, |f| !f.is_match(path.file_name().unwrap().to_string_lossy().borrow())) {
            return html(b"I don't think you're allowed to do this.");
        }
        let mime: Option<iron::mime::Mime> = path.extension().map(|s| s.to_string_lossy().to_owned())
            .map_or(None, |e| mime_types.get_mime_type(e.borrow()))
            .and_then(|m| m.parse().ok());
        if mime.as_ref().is_some() {
            from_path(&path).map(|r| r.set(Header(ContentType((*mime.as_ref().unwrap()).clone()))))
        } else {
            from_path(path.as_path())
        }
    } else {
        let mut content: Vec<PathBuf> = match fs::read_dir(&path) {
            Ok(s) => s.filter_map(Result::ok).map(|s| s.path()).collect(),
            Err(e) => return html(e.description().as_bytes())
        };
        content.sort_by(|a, b| a.to_string_lossy().cmp(&b.to_string_lossy()));
        let mut out = Vec::with_capacity(DEF_LEN);
        render(&mut out, template, root, path, content, filter);
        html(&out)
    }
}

fn main() {
    let (host, port, threads) = {
        (ARGS.flag_address.clone().unwrap_or(HOST.into()),
         ARGS.flag_port.clone().unwrap_or(PORT),
         ARGS.flag_threads.unwrap_or(num_cpus::get()))
    };

    if ARGS.flag_fork {
        fork();
    }

    match Iron::new(serve).listen_with((host.as_ref(), port), threads, iron::Protocol::Http) {
        Ok(_) => (),
        Err(e) => println!("I'm sorry, I failed you.\nError: {:?}", e)
    }
}
<commit_msg>Trying to fix weird behaviour when used remotely (properly)<commit_after>#![feature(plugin, path_ext, path_relative_from)]
#![plugin(serde_macros, docopt_macros)]

extern crate iron;
extern crate regex;
extern crate conduit_mime_types;
extern crate mustache;
extern crate libc;
extern crate num_cpus;
extern crate serde;
#[macro_use]
extern crate lazy_static;
extern crate docopt;
extern crate rustc_serialize;

use std::{ env, fs, process };
use std::path::{ Path, PathBuf };
use std::io::{ Read, Write };
use std::error::Error;
use std::fs::{ File, PathExt };
use std::sync::Arc;
use std::borrow::Borrow;

use regex::Regex;

use conduit_mime_types::Types;

use serde::json::{ self, Value };

use iron::prelude::*;
use iron::status;
use iron::mime::{ Mime, TopLevel, SubLevel };
use iron::headers::ContentType;
use iron::modifiers::Header;

use mustache::{ Template, VecBuilder, MapBuilder };

use constants::*;

pub mod constants;

docopt!(Args derive Debug, "
A minimal static file server, written in Rust with Iron.
Usage: sersve [options]

Options:
    -h, --help                  Show this message.
    -v, --version               Show the version of sersve (duh).
    -c, --config FILE           Provide a configuration file (JSON).
    -a, --address HOST          The address to bind to.
    -p, --port PORT             The port to serve.
    -r, --root ROOT             The uppermost directory to serve.
    -f, --filter REGEX          A regular expression to filter the filenames.
    -s, --size BYTES            The maximum size of a file that will be served.
    -t, --template TEMPLATE     A Mustache template to use for rendering.
    --threads THREADS           Amount of threads to use for serving.
    --fork                      Fork sersve into a background process.",
    flag_help: bool,
    flag_version: bool,
    flag_config: Option<String>,
    flag_address: Option<String>,
    flag_port: Option<u16>,
    flag_root: Option<String>,
    flag_filter: Option<String>,
    flag_size: Option<u64>,
    flag_template: Option<String>,
    flag_threads: Option<usize>,
    flag_fork: bool
);

#[derive(Clone)]
struct State {
    template: Template,
    root: Option<PathBuf>,
    mime_types: Arc<Types>
}

const HOST: &'static str = "0.0.0.0";
const PORT: u16 = 8080;

static UNITS: &'static [&'static str] = &["B", "kB", "MB", "GB", "TB"];

const KEY_TITLE: &'static str = "title";
const KEY_CONTENT: &'static str = "content";
const KEY_URL: &'static str = "url";
const KEY_SIZE: &'static str = "size";
const KEY_NAME: &'static str = "name";

const DEF_LEN: usize = 10000;

lazy_static! {
    static ref ARGS: Args = {
        let mut args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

        if let Some(ref flag_config) = args.flag_config {
            let conf = File::open(&flag_config)
                            .and_then(|mut f| {
                                let mut out = String::new();
                                f.read_to_string(&mut out).map(|_| out)
                            }).map_err(|e| error(e.description()))
                            .unwrap();

            // cannot if-let, because typesafe errors are helpful
            let json = match json::from_str(&conf) {
                Ok(Value::Object(o)) => o,
                _ => panic!("Invalid configuration file. Doesn't contain valid top-level object.")
            };
            args.flag_address = args.flag_address.or(match json.get("address") {
                Some(&Value::String(ref s)) => Some((*s).clone()),
                None => None,
                _ => panic!("Invalid configuration file. `address` field must be a string.")
            });
            args.flag_port = args.flag_port.or(match json.get("port") {
                Some(&Value::U64(u)) => Some(u as u16),
                None => None,
                _ => panic!("Invalid configuration file. `port` field must be an unsigned integer.")
            });
            args.flag_root = args.flag_root.or(match json.get("root") {
                Some(&Value::String(ref s)) => Some(s.clone()),
                None => None,
                _ => panic!("Invalid configuration file. `root` field must be a string.")
            });
            args.flag_filter = args.flag_filter.or(match json.get("filter") {
                Some(&Value::String(ref s)) => Some((*s).clone()),
                None => None,
                _ => panic!("Invalid configuration file. `filter` field must be a string.")
            });
            args.flag_size = args.flag_size.or(match json.get("size") {
                Some(&Value::U64(u)) => Some(u),
                None => None,
                _ => panic!("Invalid configuration file. `size` field must be an unsigned integer.")
            });
            args.flag_template = args.flag_template.or(match json.get("template") {
                Some(&Value::String(ref s)) => Some((*s).clone()),
                None => None,
                _ => panic!("Invalid configuration file. `template` field must be a string.")
            });
            args.flag_fork = args.flag_fork || match json.get("fork") {
                Some(&Value::Bool(b)) => b,
                None => false,
                _ => panic!("Invalid configuration file. `fork` field must be a boolean")
            };
            args.flag_threads = args.flag_threads.or(match json.get("threads") {
                Some(&Value::U64(u)) => Some(u as usize),
                None => None,
                _ => panic!("Invalid configuration file. `threads` field must be a string.")
            })
        };

        args
    };

    static ref STATE: State = State {
        template: mustache::compile_str(&ARGS.flag_template.as_ref().unwrap_or(&OPT_TEMPLATE.to_owned())),
        root: ARGS.flag_root.clone().map(|p| Path::new(&p).to_path_buf()),
        mime_types: Arc::new(Types::new().ok().unwrap())
    };
}

fn error(e: &str) -> ! {
    println!("Error: {}", e);
    process::exit(-1);
}

fn fork() {
    unsafe {
        let pid = libc::funcs::posix88::unistd::fork();
        if pid == 0 {
            // we are child, now get to work
            return;
        } else if pid > 0 {
            // fork succeeded, die
            process::exit(0);
        } else if pid < 0 {
            // unsuccessful, don't die
            return;
        }
    }
}

fn size_with_unit(mut size: u64) -> String {
    let mut frac = 0;
    let mut index = 0;

    while size > 1000 && index + 1 < UNITS.len() {
        frac = size % 1000;
        size /= 1000;
        index += 1;
    }

    format!("{}.{} {}", size, frac, UNITS[index])
}

fn render<'a, W: Write>(mut out: W, template: Template, root: PathBuf, dir: PathBuf, files: Vec<PathBuf>, filter: Option<Regex>) {
    let data = MapBuilder::new()
        .insert_str(KEY_TITLE, format!("{}", dir.display()))
        .insert_vec(KEY_CONTENT, |mut vec: VecBuilder| {
            let item = |map: MapBuilder, url: &Path, size: u64, name: String| {
                map.insert(KEY_URL, &format!("{}", url.display())).unwrap()
                   .insert(KEY_SIZE, &size_with_unit(size)).unwrap()
                   .insert_str(KEY_NAME, name)
            };

            // add `..` entry if necessary
            let mut up = dir.to_path_buf();
            up.pop();
            if up.starts_with(&root) {
                vec = vec.push_map(|map: MapBuilder| item(map, &up.relative_from(&root).unwrap(), 0, "..".to_owned()));
            }

            for file in files.iter() {
                let relative = file.relative_from(&root).unwrap();
                let stat = file.metadata().unwrap();
                let filename = file.file_name()
                    .expect("Cannot get filename").to_string_lossy().into_owned();
                if filter.as_ref().map_or(true, |f| f.is_match(&filename)) {
                    vec = vec.push_map(|map| item(map, &relative, stat.len(), filename.clone()));
                }
            }
            vec
        }).build();

    template.render_data(&mut out, &data);
}

fn plain(content: &[u8]) -> IronResult<Response> {
    Ok(Response::with((status::Ok, content)))
}

fn html(content: &[u8]) -> IronResult<Response> {
    plain(content).map(|r| r.set(Header(ContentType(Mime(TopLevel::Text, SubLevel::Html, vec![])))))
}

fn from_path(path: &Path) -> IronResult<Response> {
    Ok(Response::with((status::Ok, path)))
}

fn serve(req: &mut Request) -> IronResult<Response> {
    let (filter_str, max_size) = (
        ARGS.flag_filter.clone(),
        ARGS.flag_size
    );

    let (template, root, mime_types) = (
        STATE.template.clone(),
        STATE.root.clone().unwrap_or_else(|| env::current_dir().ok().unwrap()),
        STATE.mime_types.clone()
    );

    let mut path = root.clone();
    for part in req.url.path.iter() { path.push(part) }
    if !path.exists() { return html(format!("Error, `{}` does not exist.", path.display()).as_bytes()); }

    let filter = filter_str.and_then(|s| Regex::new(&s).ok());

    if path.is_file() && path.starts_with(&root) {
        let stat = path.metadata();
        if stat.as_ref().ok().is_some()
            && max_size.is_some()
            && stat.ok().unwrap().len() > max_size.unwrap() {
            return html(b"I'm afraid, I'm too lazy to serve the requested file. It's pretty big...")
        }

        if filter.as_ref().map_or(false,
                  |f| !f.is_match(path.file_name().unwrap().to_string_lossy().borrow())) {
            return html(b"I don't think you're allowed to do this.");
        }
        let mime: Option<iron::mime::Mime> = path.extension()
            .map(|s| s.to_string_lossy().to_owned())
            .map_or(None, |e| mime_types.get_mime_type(e.borrow()))
            .and_then(|m| m.parse().ok());
        if mime.as_ref().is_some() {
            from_path(&path).map(|r| r.set(Header(ContentType((*mime.as_ref().unwrap()).clone()))))
        } else {
            from_path(path.as_path())
        }
    } else {
        let mut content: Vec<PathBuf> = match fs::read_dir(&path) {
            Ok(s) => s.filter_map(Result::ok).map(|s| s.path()).collect(),
            Err(e) => return html(e.description().as_bytes())
        };
        content.sort_by(|a, b| a.to_string_lossy().cmp(&b.to_string_lossy()));
        let mut out = Vec::with_capacity(DEF_LEN);
        render(&mut out, template, root, path, content, filter);
        html(&out)
    }
}

fn main() {
    let (host, port, threads) = {
        (ARGS.flag_address.clone().unwrap_or(HOST.into()),
         ARGS.flag_port.clone().unwrap_or(PORT),
         ARGS.flag_threads.unwrap_or(num_cpus::get()))
    };

    if ARGS.flag_fork { fork() }

    match Iron::new(serve).listen_with((host.as_ref(), port), threads, iron::Protocol::Http) {
        Ok(_) => (),
        Err(e) => println!("I'm sorry, I failed you.\nError: {:?}", e)
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate futures;
extern crate tokio_core as tokio;
extern crate tokio_service as service;
extern crate tokio_proto as proto;
extern crate tokio_timer;
extern crate env_logger;
extern crate vastatrix;

use std::net::SocketAddr;
use std::time::Duration;

use tokio::reactor::Core;
use futures::Future;
use vastatrix::LogPos;

use vastatrix::hosting::*;

#[test]
fn smoketest_single_node() {
    env_logger::init().unwrap_or(());

    let mut core = Core::new().unwrap();
    let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();
    let timeout = Duration::from_millis(1000);

    let local_anon_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();

    let server = build_server(
                                        &core.handle(),
                                        local_anon_addr.clone(),
                                        local_anon_addr.clone())
                     .expect("start server");
    println!("running: {:?}", server);

    info!("Head at: {:?}, tail at: {:?}",
          server.head,
          server.tail);
    let client = vastatrix::ThickClient::new(core.handle(),
                                             &server.head,
                                             &server.tail);

    let f = client.log_item(b"hello".to_vec())
                  .and_then(|pos0| {
                      client.log_item(b"world".to_vec()).map(move |pos1| (pos0, pos1))
                  });
    let (wpos0, wpos1) = core.run(timer.timeout(f, timeout)).expect("run write");

    info!("Wrote to offset:{:?}", (wpos0, wpos1));

    let item_f = client.fetch_next(LogPos::zero())
                       .and_then(|(pos0, val0)| {
                           client.fetch_next(pos0).map(move |second| vec![(pos0, val0), second])
                       });

    let read = core.run(timer.timeout(item_f, timeout)).expect("run read");
    info!("Got: {:?}", read);

    assert_eq!(read,
               vec![(wpos0, b"hello".to_vec()), (wpos1, b"world".to_vec())]);
}

#[test]
fn smoketest_two_member_chain() {
    env_logger::init().unwrap_or(());
    let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();
    let timeout = Duration::from_millis(1000);
    let mut core = Core::new().unwrap();

    let local_anon_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();

    let server0 = build_server(
                      &core.handle(),
                      local_anon_addr.clone(),
                      local_anon_addr.clone())
        .expect("start server");
    println!("running: {:?}", server0);

    let server1 = build_server(
                      &core.handle(),
                      local_anon_addr.clone(),
                      local_anon_addr.clone())
        .expect("start server");

    println!("running: {:?}", server1);

    let client = vastatrix::ThickClient::new(core.handle(), &server0.head, &server1.tail);

    let f = client.add_peer(server1.clone())
        .and_then(|_| client.log_item(b"hello".to_vec()))
        .and_then(|pos0| client.log_item(b"world".to_vec()).map(move |pos1| (pos0, pos1)));
    let (wpos0, wpos1) = core.run(timer.timeout(f, timeout)).expect("run write");

    info!("Wrote to offset:{:?}", (wpos0, wpos1));

    let item_f = client.fetch_next(LogPos::zero())
        .and_then(|(pos0, val0)| {
            client.fetch_next(pos0).map(move |second| vec![(pos0, val0), second])
        });

    let read = core.run(timer.timeout(item_f, timeout)).expect("run read");
    info!("Got: {:?}", read);

    assert_eq!(read,
               vec![(wpos0, b"hello".to_vec()), (wpos1, b"world".to_vec())]);
}
<commit_msg>Note failing test for three member chain.<commit_after>#[macro_use]
extern crate log;
extern crate futures;
extern crate tokio_core as tokio;
extern crate tokio_service as service;
extern crate tokio_proto as proto;
extern crate tokio_timer;
extern crate env_logger;
extern crate vastatrix;

use std::net::SocketAddr;
use std::time::Duration;

use tokio::reactor::Core;
use futures::Future;
use vastatrix::LogPos;

use vastatrix::hosting::*;

#[test]
fn smoketest_single_node() {
    env_logger::init().unwrap_or(());

    let mut core = Core::new().unwrap();
    let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();
    let timeout = Duration::from_millis(1000);

    let local_anon_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();

    let server = build_server(
                                        &core.handle(),
                                        local_anon_addr.clone(),
                                        local_anon_addr.clone())
                     .expect("start server");
    println!("running: {:?}", server);

    info!("Head at: {:?}, tail at: {:?}",
          server.head,
          server.tail);
    let client = vastatrix::ThickClient::new(core.handle(),
                                             &server.head,
                                             &server.tail);

    let f = client.log_item(b"hello".to_vec())
                  .and_then(|pos0| {
                      client.log_item(b"world".to_vec()).map(move |pos1| (pos0, pos1))
                  });
    let (wpos0, wpos1) = core.run(timer.timeout(f, timeout)).expect("run write");

    info!("Wrote to offset:{:?}", (wpos0, wpos1));

    let item_f = client.fetch_next(LogPos::zero())
                       .and_then(|(pos0, val0)| {
                           client.fetch_next(pos0).map(move |second| vec![(pos0, val0), second])
                       });

    let read = core.run(timer.timeout(item_f, timeout)).expect("run read");
    info!("Got: {:?}", read);

    assert_eq!(read,
               vec![(wpos0, b"hello".to_vec()), (wpos1, b"world".to_vec())]);
}

#[test]
fn smoketest_two_member_chain() {
    env_logger::init().unwrap_or(());
    let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();
    let timeout = Duration::from_millis(1000);
    let mut core = Core::new().unwrap();

    let local_anon_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();

    let server0 = build_server(
                      &core.handle(),
                      local_anon_addr.clone(),
                      local_anon_addr.clone())
        .expect("start server");
    println!("running: {:?}", server0);

    let server1 = build_server(
                      &core.handle(),
                      local_anon_addr.clone(),
                      local_anon_addr.clone())
        .expect("start server");

    println!("running: {:?}", server1);

    let client = vastatrix::ThickClient::new(core.handle(), &server0.head, &server1.tail);

    let f = client.add_peer(server1.clone())
        .and_then(|_| client.log_item(b"hello".to_vec()))
        .and_then(|pos0| client.log_item(b"world".to_vec()).map(move |pos1| (pos0, pos1)));
    let (wpos0, wpos1) = core.run(timer.timeout(f, timeout)).expect("run write");

    info!("Wrote to offset:{:?}", (wpos0, wpos1));

    let item_f = client.fetch_next(LogPos::zero())
        .and_then(|(pos0, val0)| {
            client.fetch_next(pos0).map(move |second| vec![(pos0, val0), second])
        });

    let read = core.run(timer.timeout(item_f, timeout)).expect("run read");
    info!("Got: {:?}", read);

    assert_eq!(read,
               vec![(wpos0, b"hello".to_vec()), (wpos1, b"world".to_vec())]);
}

#[test]
#[ignore]
fn smoketest_three_member_chain() {
    env_logger::init().unwrap_or(());
    let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();
    let timeout = Duration::from_millis(1000);
    let mut core = Core::new().unwrap();

    let local_anon_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
    let mut head_addr = local_anon_addr.clone();
    let mut tail_addr = local_anon_addr.clone();

    head_addr.set_port(11000);
    tail_addr.set_port(11001);
    let server0 = build_server(
                      &core.handle(),
                      head_addr.clone(),
                      tail_addr.clone())
        .expect("start server");
    println!("running: {:?}", server0);

    head_addr.set_port(11010);
    tail_addr.set_port(11011);
    let server1 = build_server(
                      &core.handle(),
                      head_addr.clone(),
                      tail_addr.clone())
        .expect("start server");

    println!("running: {:?}", server1);

    head_addr.set_port(11020);
    tail_addr.set_port(11021);
    let server2 = build_server(
                      &core.handle(),
                      head_addr.clone(),
                      tail_addr.clone())
        .expect("start server");
    println!("running: {:?}", server2);

    let client = vastatrix::ThickClient::new(core.handle(), &server0.head, &server2.tail);

    let f = client.add_peer(server1.clone())
        .and_then(|_| client.log_item(b"hello".to_vec()))
        .and_then(|_| client.add_peer(server2.clone()))
        .and_then(|pos0| client.log_item(b"world".to_vec()).map(move |pos1| (pos0, pos1)));
    let (wpos0, wpos1) = core.run(timer.timeout(f, timeout)).expect("run write");

    info!("Wrote to offset:{:?}", (wpos0, wpos1));

    let item_f = client.fetch_next(LogPos::zero())
        .and_then(|(pos0, val0)| {
            client.fetch_next(pos0).map(move |second| vec![(pos0, val0), second])
        });

    let res = core.run(timer.timeout(item_f, timeout));
    let read = res.expect("run read");
    info!("Got: {:?}", read);

    assert_eq!(read,
               vec![(wpos0, b"hello".to_vec()), (wpos1, b"world".to_vec())]);
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::panic::catch_unwind;
use std::panic::AssertUnwindSafe;
use std::any::Any;

use httpbis::HttpError;
use httpbis::Header;
use httpbis::StaticHeader;
use httpbis::server::HttpServer;

use futures;
use futures::Future;
use futures::stream;
use futures::stream::Stream;

use method::*;
use error::*;
use futures_grpc::*;
use httpbis::futures_misc::*;
use httpbis::solicit_misc::*;
use grpc::*;
use grpc_frame::*;
use httpbis::http_common::*;
use httpbis::server_conf::*;

pub trait MethodHandler<Req, Resp> {
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp>;
}

pub struct MethodHandlerUnary<F> {
    f: Arc<F>
}

pub struct MethodHandlerServerStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerClientStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerBidi<F> {
    f: Arc<F>
}

impl<F> GrpcStreamingFlavor for MethodHandlerUnary<F> {
    type Flavor = GrpcStreamingUnary;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::Unary
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerClientStreaming<F> {
    type Flavor = GrpcStreamingClientStreaming;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::ClientStreaming
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerServerStreaming<F> {
    type Flavor = GrpcStreamingServerStreaming;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::ServerStreaming
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerBidi<F> {
    type Flavor = GrpcStreamingBidi;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::Bidi
    }
}

impl<F> MethodHandlerUnary<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(Req) -> GrpcFutureSend<Resp> + Send + Sync,
    {
        MethodHandlerUnary {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerClientStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(GrpcStreamSend<Req>) -> GrpcFutureSend<Resp> + Send + Sync,
    {
        MethodHandlerClientStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerServerStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(Req) -> GrpcStreamSend<Resp> + Send + Sync,
    {
        MethodHandlerServerStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerBidi<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> + Send + Sync,
    {
        MethodHandlerBidi {
            f: Arc::new(f),
        }
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerUnary<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(Req) -> GrpcFutureSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        let f = self.f.clone();
        Box::new(
            stream_single(req)
                .and_then(move |req| f(req))
                .into_stream())
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerClientStreaming<F>
    where
        Resp : Send + 'static,
        F : Fn(GrpcStreamSend<Req>) -> GrpcFutureSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        Box::new(((self.f)(req)).into_stream())
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerServerStreaming<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(Req) -> GrpcStreamSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        let f = self.f.clone();
        Box::new(
            stream_single(req)
                .map(move |req| f(req))
                .flatten_stream())
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerBidi<F>
    where
        Resp : Send + 'static,
        F : Fn(GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        Box::new((self.f)(req))
    }
}

trait MethodHandlerDispatch {
    fn start_request(&self, req: GrpcStreamSend<Vec<u8>>) -> GrpcStreamSend<Vec<u8>>;
}

struct MethodHandlerDispatchImpl<Req, Resp> {
    desc: Arc<MethodDescriptor<Req, Resp>>,
    method_handler: Box<MethodHandler<Req, Resp> + Sync + Send>,
}

fn any_to_string(any: Box<Any + Send + 'static>) -> String {
    if any.is::<String>() {
        *any.downcast::<String>().unwrap()
    } else if any.is::<&str>() {
        (*any.downcast::<&str>().unwrap()).to_owned()
    } else {
        "unknown any".to_owned()
    }
}

impl<Req, Resp> MethodHandlerDispatch for MethodHandlerDispatchImpl<Req, Resp>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
{
    fn start_request(&self, req_grpc_frames: GrpcStreamSend<Vec<u8>>) -> GrpcStreamSend<Vec<u8>> {
        let desc = self.desc.clone();
        let req = req_grpc_frames.and_then(move |frame| desc.req_marshaller.read(&frame));
        let resp =
            catch_unwind(AssertUnwindSafe(|| self.method_handler.handle(Box::new(req))));
        match resp {
            Ok(resp) => {
                let desc_copy = self.desc.clone();
                Box::new(resp
                    .and_then(move |resp| desc_copy.resp_marshaller.write(&resp)))
            }
            Err(e) => {
                let message = any_to_string(e);
                Box::new(futures::failed(GrpcError::Panic(message)).into_stream())
            }
        }
    }
}

pub struct ServerMethod {
    name: String,
    dispatch: Box<MethodHandlerDispatch + Sync + Send>,
}

impl ServerMethod {
    pub fn new<Req, Resp, H>(method: Arc<MethodDescriptor<Req, Resp>>, handler: H) -> ServerMethod
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            H : MethodHandler<Req, Resp> + 'static + Sync + Send,
    {
        ServerMethod {
            name: method.name.clone(),
            dispatch: Box::new(MethodHandlerDispatchImpl {
                desc: method,
                method_handler: Box::new(handler),
            }),
        }
    }
}

pub struct ServerServiceDefinition {
    methods: Vec<ServerMethod>,
}

impl ServerServiceDefinition {
    pub fn new(methods: Vec<ServerMethod>) -> ServerServiceDefinition {
        ServerServiceDefinition {
            methods: methods,
        }
    }

    /// Join multiple service definitions into one
    pub fn join<I>(iter: I) -> ServerServiceDefinition
        where I : IntoIterator<Item=ServerServiceDefinition>
    {
        ServerServiceDefinition {
            methods: iter.into_iter().flat_map(|s| s.methods).collect()
        }
    }

    pub fn find_method(&self, name: &str) -> &ServerMethod {
        self.methods.iter()
            .filter(|m| m.name == name)
            .next()
            .expect(&format!("unknown method: {}", name))
    }

    pub fn handle_method(&self, name: &str, message: GrpcStreamSend<Vec<u8>>) -> GrpcStreamSend<Vec<u8>> {
        self.find_method(name).dispatch.start_request(message)
    }
}

#[derive(Default, Debug, Clone)]
pub struct GrpcServerConf {
    http: HttpServerConf,
}

pub struct GrpcServer {
    server: HttpServer,
}

impl GrpcServer {
    pub fn new<A: ToSocketAddrs>(addr: A, conf: GrpcServerConf, service_definition: ServerServiceDefinition) -> GrpcServer {
        let mut conf = conf;
        conf.http.thread_name =
            Some(conf.http.thread_name.unwrap_or_else(|| "grpc-server-loop".to_owned()));

        let service_definition = Arc::new(service_definition);
        GrpcServer {
            server: HttpServer::new(addr, conf.http, GrpcHttpServerHandlerFactory {
                service_definition: service_definition.clone(),
            })
        }
    }

    pub fn local_addr(&self) -> &SocketAddr {
        self.server.local_addr()
    }
}

struct GrpcHttpServerHandlerFactory {
    service_definition: Arc<ServerServiceDefinition>,
}

fn stream_500(message: &str) -> HttpPartFutureStreamSend {
    Box::new(stream::once(Ok(HttpStreamPart::last_headers(vec![
        Header::new(":status", "500"),
        Header::new(HEADER_GRPC_MESSAGE, message.to_owned()),
    ]))))
}

impl HttpService for GrpcHttpServerHandlerFactory {
    fn new_request(&self, headers: Vec<StaticHeader>, req: HttpPartFutureStreamSend) -> HttpPartFutureStreamSend {

        let path = match slice_get_header(&headers, ":path") {
            Some(path) => path.to_owned(),
            None => return stream_500("no :path header"),
        };

        let grpc_request = GrpcFrameFromHttpFramesStreamRequest::new(req);

        // TODO: catch unwind
        let grpc_frames = self.service_definition.handle_method(&path, Box::new(grpc_request));

        let s1 = stream::once(Ok(HttpStreamPart::intermediate_headers(vec![
            Header::new(":status", "200"),
        ])));

        let s2 = grpc_frames
            .map(|frame| HttpStreamPart::intermediate_data(write_grpc_frame_to_vec(&frame)))
            .then(|result| {
                match result {
                    Ok(part) => {
                        let r: Result<_, HttpError> = Ok(part);
                        r
                    }
                    Err(e) =>
                        Ok(HttpStreamPart::last_headers(vec![
                            Header::new(":status", "500"),
                            Header::new(HEADER_GRPC_MESSAGE, format!("error: {:?}", e)),
                        ]))
                }
            });

        let s3 = stream::once(Ok(HttpStreamPart::last_headers(vec![
            Header::new(HEADER_GRPC_STATUS, "0"),
        ])));

        let http_parts = s1.chain(s2).chain(s3);

        Box::new(http_parts)
    }
}
<commit_msg>Make GrpcServerConf.http field public<commit_after>use std::sync::Arc;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::panic::catch_unwind;
use std::panic::AssertUnwindSafe;
use std::any::Any;

use httpbis::HttpError;
use httpbis::Header;
use httpbis::StaticHeader;
use httpbis::server::HttpServer;

use futures;
use futures::Future;
use futures::stream;
use futures::stream::Stream;

use method::*;
use error::*;
use futures_grpc::*;
use httpbis::futures_misc::*;
use httpbis::solicit_misc::*;
use grpc::*;
use grpc_frame::*;
use httpbis::http_common::*;
use httpbis::server_conf::*;

pub trait MethodHandler<Req, Resp> {
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp>;
}

pub struct MethodHandlerUnary<F> {
    f: Arc<F>
}

pub struct MethodHandlerServerStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerClientStreaming<F> {
    f: Arc<F>
}

pub struct MethodHandlerBidi<F> {
    f: Arc<F>
}

impl<F> GrpcStreamingFlavor for MethodHandlerUnary<F> {
    type Flavor = GrpcStreamingUnary;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::Unary
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerClientStreaming<F> {
    type Flavor = GrpcStreamingClientStreaming;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::ClientStreaming
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerServerStreaming<F> {
    type Flavor = GrpcStreamingServerStreaming;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::ServerStreaming
    }
}

impl<F> GrpcStreamingFlavor for MethodHandlerBidi<F> {
    type Flavor = GrpcStreamingBidi;

    fn streaming() -> GrpcStreaming {
        GrpcStreaming::Bidi
    }
}

impl<F> MethodHandlerUnary<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(Req) -> GrpcFutureSend<Resp> + Send + Sync,
    {
        MethodHandlerUnary {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerClientStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(GrpcStreamSend<Req>) -> GrpcFutureSend<Resp> + Send + Sync,
    {
        MethodHandlerClientStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerServerStreaming<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(Req) -> GrpcStreamSend<Resp> + Send + Sync,
    {
        MethodHandlerServerStreaming {
            f: Arc::new(f),
        }
    }
}

impl<F> MethodHandlerBidi<F> {
    pub fn new<Req, Resp>(f: F) -> Self
        where F : Fn(GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> + Send + Sync,
    {
        MethodHandlerBidi {
            f: Arc::new(f),
        }
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerUnary<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(Req) -> GrpcFutureSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        let f = self.f.clone();
        Box::new(
            stream_single(req)
                .and_then(move |req| f(req))
                .into_stream())
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerClientStreaming<F>
    where
        Resp : Send + 'static,
        F : Fn(GrpcStreamSend<Req>) -> GrpcFutureSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        Box::new(((self.f)(req)).into_stream())
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerServerStreaming<F>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
        F : Fn(Req) -> GrpcStreamSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        let f = self.f.clone();
        Box::new(
            stream_single(req)
                .map(move |req| f(req))
                .flatten_stream())
    }
}

impl<Req, Resp, F> MethodHandler<Req, Resp> for MethodHandlerBidi<F>
    where
        Resp : Send + 'static,
        F : Fn(GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> + Send + Sync + 'static,
{
    fn handle(&self, req: GrpcStreamSend<Req>) -> GrpcStreamSend<Resp> {
        Box::new((self.f)(req))
    }
}

trait MethodHandlerDispatch {
    fn start_request(&self, req: GrpcStreamSend<Vec<u8>>) -> GrpcStreamSend<Vec<u8>>;
}

struct MethodHandlerDispatchImpl<Req, Resp> {
    desc: Arc<MethodDescriptor<Req, Resp>>,
    method_handler: Box<MethodHandler<Req, Resp> + Sync + Send>,
}

fn any_to_string(any: Box<Any + Send + 'static>) -> String {
    if any.is::<String>() {
        *any.downcast::<String>().unwrap()
    } else if any.is::<&str>() {
        (*any.downcast::<&str>().unwrap()).to_owned()
    } else {
        "unknown any".to_owned()
    }
}

impl<Req, Resp> MethodHandlerDispatch for MethodHandlerDispatchImpl<Req, Resp>
    where
        Req : Send + 'static,
        Resp : Send + 'static,
{
    fn start_request(&self, req_grpc_frames: GrpcStreamSend<Vec<u8>>) -> GrpcStreamSend<Vec<u8>> {
        let desc = self.desc.clone();
        let req = req_grpc_frames.and_then(move |frame| desc.req_marshaller.read(&frame));
        let resp =
            catch_unwind(AssertUnwindSafe(|| self.method_handler.handle(Box::new(req))));
        match resp {
            Ok(resp) => {
                let desc_copy = self.desc.clone();
                Box::new(resp
                    .and_then(move |resp| desc_copy.resp_marshaller.write(&resp)))
            }
            Err(e) => {
                let message = any_to_string(e);
                Box::new(futures::failed(GrpcError::Panic(message)).into_stream())
            }
        }
    }
}

pub struct ServerMethod {
    name: String,
    dispatch: Box<MethodHandlerDispatch + Sync + Send>,
}

impl ServerMethod {
    pub fn new<Req, Resp, H>(method: Arc<MethodDescriptor<Req, Resp>>, handler: H) -> ServerMethod
        where
            Req : Send + 'static,
            Resp : Send + 'static,
            H : MethodHandler<Req, Resp> + 'static + Sync + Send,
    {
        ServerMethod {
            name: method.name.clone(),
            dispatch: Box::new(MethodHandlerDispatchImpl {
                desc: method,
                method_handler: Box::new(handler),
            }),
        }
    }
}

pub struct ServerServiceDefinition {
    methods: Vec<ServerMethod>,
}

impl ServerServiceDefinition {
    pub fn new(methods: Vec<ServerMethod>) -> ServerServiceDefinition {
        ServerServiceDefinition {
            methods: methods,
        }
    }

    /// Join multiple service definitions into one
    pub fn join<I>(iter: I) -> ServerServiceDefinition
        where I : IntoIterator<Item=ServerServiceDefinition>
    {
        ServerServiceDefinition {
            methods: iter.into_iter().flat_map(|s| s.methods).collect()
        }
    }

    pub fn find_method(&self, name: &str) -> &ServerMethod {
        self.methods.iter()
            .filter(|m| m.name == name)
            .next()
            .expect(&format!("unknown method: {}", name))
    }

    pub fn handle_method(&self, name: &str, message: GrpcStreamSend<Vec<u8>>) -> GrpcStreamSend<Vec<u8>> {
        self.find_method(name).dispatch.start_request(message)
    }
}

#[derive(Default, Debug, Clone)]
pub struct GrpcServerConf {
    pub http: HttpServerConf,
}

pub struct GrpcServer {
    server: HttpServer,
}

impl GrpcServer {
    pub fn new<A: ToSocketAddrs>(addr: A, conf: GrpcServerConf, service_definition: ServerServiceDefinition) -> GrpcServer {
        let mut conf = conf;
        conf.http.thread_name =
            Some(conf.http.thread_name.unwrap_or_else(|| "grpc-server-loop".to_owned()));

        let service_definition = Arc::new(service_definition);
        GrpcServer {
            server: HttpServer::new(addr, conf.http, GrpcHttpServerHandlerFactory {
                service_definition: service_definition.clone(),
            })
        }
    }

    pub fn local_addr(&self) -> &SocketAddr {
        self.server.local_addr()
    }
}

struct GrpcHttpServerHandlerFactory {
    service_definition: Arc<ServerServiceDefinition>,
}

fn stream_500(message: &str) -> HttpPartFutureStreamSend {
    Box::new(stream::once(Ok(HttpStreamPart::last_headers(vec![
        Header::new(":status", "500"),
        Header::new(HEADER_GRPC_MESSAGE, message.to_owned()),
    ]))))
}

impl HttpService for GrpcHttpServerHandlerFactory {
    fn new_request(&self, headers: Vec<StaticHeader>, req: HttpPartFutureStreamSend) -> HttpPartFutureStreamSend {

        let path = match slice_get_header(&headers, ":path") {
            Some(path) => path.to_owned(),
            None => return stream_500("no :path header"),
        };

        let grpc_request = GrpcFrameFromHttpFramesStreamRequest::new(req);

        // TODO: catch unwind
        let grpc_frames = self.service_definition.handle_method(&path, Box::new(grpc_request));

        let s1 = stream::once(Ok(HttpStreamPart::intermediate_headers(vec![
            Header::new(":status", "200"),
        ])));

        let s2 = grpc_frames
            .map(|frame| HttpStreamPart::intermediate_data(write_grpc_frame_to_vec(&frame)))
            .then(|result| {
                match result {
                    Ok(part) => {
                        let r: Result<_, HttpError> = Ok(part);
                        r
                    }
                    Err(e) =>
                        Ok(HttpStreamPart::last_headers(vec![
                            Header::new(":status", "500"),
                            Header::new(HEADER_GRPC_MESSAGE, format!("error: {:?}", e)),
                        ]))
                }
            });

        let s3 = stream::once(Ok(HttpStreamPart::last_headers(vec![
            Header::new(HEADER_GRPC_STATUS, "0"),
        ])));

        let http_parts = s1.chain(s2).chain(s3);

        Box::new(http_parts)
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::sync::{Arc,RwLock,mpsc};

use super::libcoinche::{bid,cards,pos,game};

pub enum ServerError {
    BadPlayerId,
    PlayInAuction,
    BidInGame,
    Bid(bid::BidError),
    Play(game::PlayError),
}

pub enum Action {
    Bid(bid::Contract),
    Coinche,
    Pass,
    Play(cards::Card),
}

#[derive(Clone)]
pub enum PlayerEvent {
    Bidded(bid::Contract),
    Coinched,
    Passed,
    CardPlayed(cards::Card),
}

#[derive(Clone)]
pub enum Event {
    PlayerEvent(pos::PlayerPos, PlayerEvent),

    // Bid over: contains the contract and the author
    BidOver(pos::PlayerPos, bid::Contract),
    BidCancelled,

    // Trick over: contains the winner
    TrickOver(pos::PlayerPos),

    // New game: contains the first player, and the player's hand
    NewGame(pos::PlayerPos, cards::Hand),

    // Game over: contains scores
    GameOver([i32;2], pos::Team, [i32;2]),

    // The party is cancelled. Contains an optional explanation.
    PartyCancelled(String),
}

pub struct Order {
    pub author: pos::PlayerPos,
    pub action: Action
}

pub struct Server {
    party_list: RwLock<PartyList>,
}

pub enum Game {
    Bidding(bid::Auction),
    Playing(game::GameState),
}

pub struct Party {
    game: Game,
    events: Vec<Event>,
    observers: Vec<mpsc::Sender<Event>>,
}

pub struct PlayerInfo {
    pub party: Arc<RwLock<Party>>,
    pub pos: pos::PlayerPos,
}

pub struct PartyList {
    pub player_map: HashMap<u32,PlayerInfo>,
}

pub fn play_card(server: &Server, player_id: u32, card: cards::Card) -> Result<Event,ServerError> {
    let list = server.party_list.read().unwrap();

    if !list.player_map.contains_key(&player_id) {
        // Bad player id!

        return Err(ServerError::BadPlayerId);
    }

    let info = list.player_map.get(&player_id).unwrap();

    let mut party = info.party.write().unwrap();

    match &mut party.game {
        &mut Game::Bidding(_) => {
            // Bad time for a card play!
            return Err(ServerError::PlayInAuction);
        },
        &mut Game::Playing(ref mut game) => {
            match game.play_card(info.pos, card) {
                Ok(result) => {
                    // Ok, propagate the event
                },
                Err(err) => {
                    // Nothing to see here
                    return Err(ServerError::Play(err));
                },
            }
        },
    }

    // Dummy event before handling the real case
    Ok(Event::BidCancelled)
}

enum WaitResult {
    Ready(Event),
    Waiting(mpsc::Receiver<Event>),
}

pub fn wait(server: &Server, player_id: u32, event_id: usize) -> Result<Event,ServerError> {
    let res = get_wait_result(server, player_id, event_id);

    let event = match res {
        None => return Err(ServerError::BadPlayerId),
        Some(WaitResult::Ready(event)) => event,
        Some(WaitResult::Waiting(rx)) => rx.recv().unwrap(),
    };

    Ok(event)
}

fn get_wait_result(server: &Server, player_id: u32, event_id: usize) -> Option<WaitResult> {
    let list = server.party_list.read().unwrap();
    if !list.player_map.contains_key(&player_id) {
        return None;
    }

    let info = list.player_map.get(&player_id).unwrap();
    let mut party = info.party.write().unwrap();

    if party.events.len() >= event_id {
        return Some(WaitResult::Ready(party.events[event_id].clone()));
    }

    let (tx, rx) = mpsc::channel();
    party.observers.push(tx);

    Some(WaitResult::Waiting(rx))
}
<commit_msg>Event now carry their event_id<commit_after>use std::collections::HashMap;
use std::sync::{Arc,RwLock,mpsc};

use super::libcoinche::{bid,cards,pos,game};

pub enum ServerError {
    BadPlayerId,
    PlayInAuction,
    BidInGame,
    Bid(bid::BidError),
    Play(game::PlayError),
}

pub enum Action {
    Bid(bid::Contract),
    Coinche,
    Pass,
    Play(cards::Card),
}

#[derive(Clone)]
pub enum PlayerEvent {
    Bidded(bid::Contract),
    Coinched,
    Passed,
    CardPlayed(cards::Card),
}

// Player just joined a new party. He's given a player id, and his position.
pub struct NewPartyInfo {
    pub player_id: u32,
    pub player_pos: pos::PlayerPos,
}

// Represents an event that can happen during the game.
#[derive(Clone)]
pub enum EventType {
    // The party is cancelled. Contains an optional explanation.
    PartyCancelled(String),

    // A player did something!
    PlayerEvent(pos::PlayerPos, PlayerEvent),

    // Bid over: contains the contract and the author
    BidOver(pos::PlayerPos, bid::Contract),
    // The bid was cancelled, probably because no one bidded anything.
    // A new game is probably on its way.
    BidCancelled,

    // Trick over: contains the winner
    TrickOver(pos::PlayerPos),

    // New game: contains the first player, and the player's hand
    NewGame(pos::PlayerPos, [cards::Hand;4]),

    // Game over: contains scores
    GameOver([i32;2], pos::Team, [i32;2]),
}

pub struct Event {
    pub event: EventType,
    pub id: usize,
}

pub struct Order {
    pub author: pos::PlayerPos,
    pub action: Action
}

pub struct Server {
    party_list: RwLock<PartyList>,
}

pub enum Game {
    Bidding(bid::Auction),
    Playing(game::GameState),
}

pub struct Party {
    game: Game,
    events: Vec<EventType>,
    observers: Vec<mpsc::Sender<Event>>,
}

pub struct PlayerInfo {
    pub party: Arc<RwLock<Party>>,
    pub pos: pos::PlayerPos,
}

pub struct PartyList {
    pub player_map: HashMap<u32,PlayerInfo>,
}

enum WaitResult {
    Ready(Event),
    Waiting(mpsc::Receiver<Event>),
}

impl Server {
    pub fn join(&self) -> Option<NewPartyInfo> {

        None
    }

    // Play a card in the current game
    pub fn play_card(&self, player_id: u32, card: cards::Card) -> Result<Event,ServerError> {
        let list = self.party_list.read().unwrap();

        if !list.player_map.contains_key(&player_id) {
            // Bad player id!

            return Err(ServerError::BadPlayerId);
        }

        let info = list.player_map.get(&player_id).unwrap();

        let mut party = info.party.write().unwrap();

        match &mut party.game {
            &mut Game::Bidding(_) => {
                // Bad time for a card play!
                return Err(ServerError::PlayInAuction);
            },
            &mut Game::Playing(ref mut game) => {
                match game.play_card(info.pos, card) {
                    Ok(result) => {
                        // Ok, propagate the event
                    },
                    Err(err) => {
                        // Nothing to see here
                        return Err(ServerError::Play(err));
                    },
                }
            },
        }

        // Dummy event before handling the real case
        Ok(Event{
            event: EventType::BidCancelled,
            id:0
        })
    }

    // Waits until the given event_id happens
    pub fn wait(&self, player_id: u32, event_id: usize) -> Result<Event,ServerError> {
        let res = self.get_wait_result(player_id, event_id);

        let event = match res {
            None => return Err(ServerError::BadPlayerId),
            Some(WaitResult::Ready(event)) => event,
            Some(WaitResult::Waiting(rx)) => rx.recv().unwrap(),
        };

        Ok(event)
    }

    // Check if the event ID is already available. If not, returns a channel that will produce it one
    // day, so that we don't keep the locks while waiting.
    fn get_wait_result(&self, player_id: u32, event_id: usize) -> Option<WaitResult> {
        let list = self.party_list.read().unwrap();
        if !list.player_map.contains_key(&player_id) {
            return None;
        }

        let info = list.player_map.get(&player_id).unwrap();
        let mut party = info.party.write().unwrap();

        if party.events.len() > event_id {
            return Some(WaitResult::Ready(Event {
                event: party.events[event_id].clone(),
                id: event_id,
            }));
        } else if event_id > party.events.len() {
            // We are too ambitious! One event at a time!
            return None;
        }

        let (tx, rx) = mpsc::channel();
        party.observers.push(tx);

        Some(WaitResult::Waiting(rx))
    }

}

<|endoftext|>


<commit_before>use std::ops::Deref;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::visit::FnKind;

use rustc::lint::{Context, LintArray, LintPass};
use rustc::middle::def::Def::{DefVariant, DefStruct};

use utils::{in_external_macro, snippet, span_lint};

declare_lint!(pub SHADOW_SAME, Allow,
    "rebinding a name to itself, e.g. `let mut x = &mut x`");
declare_lint!(pub SHADOW_REUSE, Allow,
    "rebinding a name to an expression that re-uses the original value, e.g. \
    `let x = x + 1`");
declare_lint!(pub SHADOW_UNRELATED, Warn,
    "The name is re-bound without even using the original value");

#[derive(Copy, Clone)]
pub struct ShadowPass;

impl LintPass for ShadowPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl,
            block: &Block, _: Span, _: NodeId) {
        if in_external_macro(cx, block.span) { return; }
        check_fn(cx, decl, block);
    }
}

fn check_fn(cx: &Context, decl: &FnDecl, block: &Block) {
    let mut bindings = Vec::new();
    for arg in &decl.inputs {
        if let PatIdent(_, ident, _) = arg.pat.node {
            bindings.push(ident.node.name)
        }
    }
    check_block(cx, block, &mut bindings);
}

fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) {
    let len = bindings.len();
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) => check_decl(cx, decl, bindings),
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                check_expr(cx, e, bindings),
            _ => ()
        }
    }
    if let Some(ref o) = block.expr { check_expr(cx, o, bindings); }
    bindings.truncate(len);
}

fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, decl.span) { return; }
    if let DeclLocal(ref local) = decl.node {
        let Local{ ref pat, ref ty, ref init, id: _, span } = **local;
        if let &Some(ref t) = ty { check_ty(cx, t, bindings) }
        if let &Some(ref o) = init {
            check_expr(cx, o, bindings);
            check_pat(cx, pat, &Some(o), span, bindings);
        } else {
            check_pat(cx, pat, &None, span, bindings);
        }
    }
}

fn is_binding(cx: &Context, pat: &Pat) -> bool {
    match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
        Some(DefVariant(..)) | Some(DefStruct(..)) => false,
        _ => true
    }
}

fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span,
        bindings: &mut Vec<Name>) {
    //TODO: match more stuff / destructuring
    match pat.node {
        PatIdent(_, ref ident, ref inner) => {
            let name = ident.node.name;
            if is_binding(cx, pat) {
                if bindings.contains(&name) {
                    lint_shadow(cx, name, span, pat.span, init);
                } else {
                    bindings.push(name);
                }
            }
            if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); }
        },
        //PatEnum(Path, Option<Vec<P<Pat>>>),
        PatStruct(_, ref pfields, _) =>
            if let Some(ref init_struct) = *init {
                if let ExprStruct(_, ref efields, _) = init_struct.node {
                    for field in pfields {
                        let ident = field.node.ident;
                        let efield = efields.iter()
                            .find(|ref f| f.ident.node == ident)
                            .map(|f| &*f.expr);
                        check_pat(cx, &field.node.pat, &efield, span, bindings);
                    }
                } else {
                    for field in pfields {
                        check_pat(cx, &field.node.pat, init, span, bindings);
                    }
                }
            } else {
                for field in pfields {
                    check_pat(cx, &field.node.pat, &None, span, bindings);
                }
            },
        PatTup(ref inner) =>
            if let Some(ref init_tup) = *init {
                if let ExprTup(ref tup) = init_tup.node {
                    for (i, p) in inner.iter().enumerate() {
                        check_pat(cx, p, &Some(&tup[i]), p.span, bindings);
                    }
                } else {
                    for p in inner {
                        check_pat(cx, p, init, span, bindings);
                    }
                }
            } else {
                for p in inner {
                    check_pat(cx, p, &None, span, bindings);
                }
            },
        PatBox(ref inner) => {
            if let Some(ref initp) = *init {
                match initp.node {
                    ExprBox(_, ref inner_init) =>
                        check_pat(cx, inner, &Some(&**inner_init), span, bindings),
                    //TODO: ExprCall on Box::new
                    _ => check_pat(cx, inner, init, span, bindings),
                }
            } else {
                check_pat(cx, inner, init, span, bindings);
            }
        },
        //PatRegion(P<Pat>, Mutability),
        //PatRange(P<Expr>, P<Expr>),
        //PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
        _ => (),
    }
}

fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init:
        &Option<T>) where T: Deref<Target=Expr> {
    if let &Some(ref expr) = init {
        if is_self_shadow(name, expr) {
            span_lint(cx, SHADOW_SAME, span, &format!(
                "{} is shadowed by itself in {}",
                snippet(cx, lspan, "_"),
                snippet(cx, expr.span, "..")));
        } else {
            if contains_self(name, expr) {
                span_lint(cx, SHADOW_REUSE, span, &format!(
                    "{} is shadowed by {} which reuses the original value",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            } else {
                span_lint(cx, SHADOW_UNRELATED, span, &format!(
                    "{} is shadowed by {} in this declaration",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            }
        }
    } else {
        span_lint(cx, SHADOW_UNRELATED, span, &format!(
            "{} is shadowed in this declaration", snippet(cx, lspan, "_")));
    }
}

fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, expr.span) { return; }
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(None, ref e)
            => { check_expr(cx, e, bindings) },
        ExprBox(Some(ref place), ref e) => {
            check_expr(cx, place, bindings); check_expr(cx, e, bindings) }
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            { check_block(cx, block, bindings) },
        //ExprCall
        //ExprMethodCall
        ExprVec(ref v) | ExprTup(ref v) =>
            for ref e in v { check_expr(cx, e, bindings) },
        ExprIf(ref cond, ref then, ref otherwise) => {
            check_expr(cx, cond, bindings);
            check_block(cx, then, bindings);
            if let &Some(ref o) = otherwise { check_expr(cx, o, bindings); }
        },
        ExprWhile(ref cond, ref block, _) => {
            check_expr(cx, cond, bindings);
            check_block(cx, block, bindings);
        },
        ExprMatch(ref init, ref arms, _) => {
            check_expr(cx, init, bindings);
            let len = bindings.len();
            for ref arm in arms {
                for ref pat in &arm.pats {
                    check_pat(cx, &pat, &Some(&**init), pat.span, bindings);
                    //TODO: This is ugly, but needed to get the right type
                }
                if let Some(ref guard) = arm.guard {
                    check_expr(cx, guard, bindings);
                }
                check_expr(cx, &arm.body, bindings);
                bindings.truncate(len);
            }
        },
        _ => ()
    }
}

fn check_ty(cx: &Context, ty: &Ty, bindings: &mut Vec<Name>) {
    match ty.node {
        TyParen(ref sty) | TyObjectSum(ref sty, _) |
        TyVec(ref sty) => check_ty(cx, sty, bindings),
        TyFixedLengthVec(ref fty, ref expr) => {
            check_ty(cx, fty, bindings);
            check_expr(cx, expr, bindings);
        },
        TyPtr(MutTy{ ty: ref mty, .. }) |
        TyRptr(_, MutTy{ ty: ref mty, .. }) => check_ty(cx, mty, bindings),
        TyTup(ref tup) => { for ref t in tup { check_ty(cx, t, bindings) } },
        TyTypeof(ref expr) => check_expr(cx, expr, bindings),
        _ => (),
    }
}

fn is_self_shadow(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprBox(_, ref inner) |
        ExprParen(ref inner) |
        ExprAddrOf(_, ref inner) => is_self_shadow(name, inner),
        ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref().
            map_or(false, |ref e| is_self_shadow(name, e)),
        ExprUnary(op, ref inner) => (UnUniq == op || UnDeref == op) &&
            is_self_shadow(name, inner),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false,
    }
}

fn path_eq_name(name: Name, path: &Path) -> bool {
    !path.global && path.segments.len() == 1 &&
        path.segments[0].identifier.name == name
}

fn contains_self(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(_, ref e)
            => contains_self(name, e),
        ExprBinary(_, ref l, ref r) =>
            contains_self(name, l) || contains_self(name, r),
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            contains_block_self(name, block),
        ExprCall(ref fun, ref args) => contains_self(name, fun) ||
            args.iter().any(|ref a| contains_self(name, a)),
        ExprMethodCall(_, _, ref args) =>
            args.iter().any(|ref a| contains_self(name, a)),
        ExprVec(ref v) | ExprTup(ref v) =>
            v.iter().any(|ref e| contains_self(name, e)),
        ExprIf(ref cond, ref then, ref otherwise) =>
            contains_self(name, cond) || contains_block_self(name, then) ||
            otherwise.as_ref().map_or(false, |ref e| contains_self(name, e)),
        ExprWhile(ref e, ref block, _)  =>
            contains_self(name, e) || contains_block_self(name, block),
        ExprMatch(ref e, ref arms, _) =>
            arms.iter().any(|ref arm| arm.pats.iter().any(|ref pat|
                contains_pat_self(name, pat))) || contains_self(name, e),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false
    }
}

fn contains_block_self(name: Name, block: &Block) -> bool {
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) =>
            if let DeclLocal(ref local) = decl.node {
                //TODO: We don't currently handle the case where the name
                //is shadowed wiithin the block; this means code including this
                //degenerate pattern will get the wrong warning.
                if let Some(ref init) = local.init {
                    if contains_self(name, init) { return true; }
                }
            },
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                if contains_self(name, e) { return true },
            _ => ()
        }
    }
    if let Some(ref e) = block.expr { contains_self(name, e) } else { false }
}

fn contains_pat_self(name: Name, pat: &Pat) -> bool {
    match pat.node {
        PatIdent(_, ref ident, ref inner) => name == ident.node.name ||
            inner.as_ref().map_or(false, |ref p| contains_pat_self(name, p)),
        PatEnum(_, ref opats) => opats.as_ref().map_or(false,
            |pats| pats.iter().any(|p| contains_pat_self(name, p))),
        PatQPath(_, ref path) => path_eq_name(name, path),
        PatStruct(_, ref fieldpats, _) => fieldpats.iter().any(
            |ref fp| contains_pat_self(name, &fp.node.pat)),
        PatTup(ref ps) => ps.iter().any(|ref p| contains_pat_self(name, p)),
        PatBox(ref p) |
        PatRegion(ref p, _) => contains_pat_self(name, p),
        PatRange(ref from, ref until) =>
            contains_self(name, from) || contains_self(name, until),
        PatVec(ref pre, ref opt, ref post) =>
            pre.iter().any(|ref p| contains_pat_self(name, p)) ||
                opt.as_ref().map_or(false, |ref p| contains_pat_self(name, p)) ||
                post.iter().any(|ref p| contains_pat_self(name, p)),
        _ => false,
    }
}
<commit_msg>match region patterns<commit_after>use std::ops::Deref;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::visit::FnKind;

use rustc::lint::{Context, LintArray, LintPass};
use rustc::middle::def::Def::{DefVariant, DefStruct};

use utils::{in_external_macro, snippet, span_lint};

declare_lint!(pub SHADOW_SAME, Allow,
    "rebinding a name to itself, e.g. `let mut x = &mut x`");
declare_lint!(pub SHADOW_REUSE, Allow,
    "rebinding a name to an expression that re-uses the original value, e.g. \
    `let x = x + 1`");
declare_lint!(pub SHADOW_UNRELATED, Warn,
    "The name is re-bound without even using the original value");

#[derive(Copy, Clone)]
pub struct ShadowPass;

impl LintPass for ShadowPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl,
            block: &Block, _: Span, _: NodeId) {
        if in_external_macro(cx, block.span) { return; }
        check_fn(cx, decl, block);
    }
}

fn check_fn(cx: &Context, decl: &FnDecl, block: &Block) {
    let mut bindings = Vec::new();
    for arg in &decl.inputs {
        if let PatIdent(_, ident, _) = arg.pat.node {
            bindings.push(ident.node.name)
        }
    }
    check_block(cx, block, &mut bindings);
}

fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) {
    let len = bindings.len();
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) => check_decl(cx, decl, bindings),
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                check_expr(cx, e, bindings),
            _ => ()
        }
    }
    if let Some(ref o) = block.expr { check_expr(cx, o, bindings); }
    bindings.truncate(len);
}

fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, decl.span) { return; }
    if let DeclLocal(ref local) = decl.node {
        let Local{ ref pat, ref ty, ref init, id: _, span } = **local;
        if let &Some(ref t) = ty { check_ty(cx, t, bindings) }
        if let &Some(ref o) = init {
            check_expr(cx, o, bindings);
            check_pat(cx, pat, &Some(o), span, bindings);
        } else {
            check_pat(cx, pat, &None, span, bindings);
        }
    }
}

fn is_binding(cx: &Context, pat: &Pat) -> bool {
    match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
        Some(DefVariant(..)) | Some(DefStruct(..)) => false,
        _ => true
    }
}

fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span,
        bindings: &mut Vec<Name>) {
    //TODO: match more stuff / destructuring
    match pat.node {
        PatIdent(_, ref ident, ref inner) => {
            let name = ident.node.name;
            if is_binding(cx, pat) {
                if bindings.contains(&name) {
                    lint_shadow(cx, name, span, pat.span, init);
                } else {
                    bindings.push(name);
                }
            }
            if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); }
        },
        //PatEnum(Path, Option<Vec<P<Pat>>>),
        PatStruct(_, ref pfields, _) =>
            if let Some(ref init_struct) = *init {
                if let ExprStruct(_, ref efields, _) = init_struct.node {
                    for field in pfields {
                        let ident = field.node.ident;
                        let efield = efields.iter()
                            .find(|ref f| f.ident.node == ident)
                            .map(|f| &*f.expr);
                        check_pat(cx, &field.node.pat, &efield, span, bindings);
                    }
                } else {
                    for field in pfields {
                        check_pat(cx, &field.node.pat, init, span, bindings);
                    }
                }
            } else {
                for field in pfields {
                    check_pat(cx, &field.node.pat, &None, span, bindings);
                }
            },
        PatTup(ref inner) =>
            if let Some(ref init_tup) = *init {
                if let ExprTup(ref tup) = init_tup.node {
                    for (i, p) in inner.iter().enumerate() {
                        check_pat(cx, p, &Some(&tup[i]), p.span, bindings);
                    }
                } else {
                    for p in inner {
                        check_pat(cx, p, init, span, bindings);
                    }
                }
            } else {
                for p in inner {
                    check_pat(cx, p, &None, span, bindings);
                }
            },
        PatBox(ref inner) => {
            if let Some(ref initp) = *init {
                if let ExprBox(_, ref inner_init) = initp.node {
                    check_pat(cx, inner, &Some(&**inner_init), span, bindings),
                } else {
                    check_pat(cx, inner, init, span, bindings),
                }
            } else {
                check_pat(cx, inner, init, span, bindings);
            }
        },
        PatRegion(ref inner, _) =>
            check_pat(cx, inner, init, span, bindings),
        //PatRange(P<Expr>, P<Expr>),
        //PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
        _ => (),
    }
}

fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init:
        &Option<T>) where T: Deref<Target=Expr> {
    if let &Some(ref expr) = init {
        if is_self_shadow(name, expr) {
            span_lint(cx, SHADOW_SAME, span, &format!(
                "{} is shadowed by itself in {}",
                snippet(cx, lspan, "_"),
                snippet(cx, expr.span, "..")));
        } else {
            if contains_self(name, expr) {
                span_lint(cx, SHADOW_REUSE, span, &format!(
                    "{} is shadowed by {} which reuses the original value",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            } else {
                span_lint(cx, SHADOW_UNRELATED, span, &format!(
                    "{} is shadowed by {} in this declaration",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            }
        }
    } else {
        span_lint(cx, SHADOW_UNRELATED, span, &format!(
            "{} is shadowed in this declaration", snippet(cx, lspan, "_")));
    }
}

fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, expr.span) { return; }
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(None, ref e)
            => { check_expr(cx, e, bindings) },
        ExprBox(Some(ref place), ref e) => {
            check_expr(cx, place, bindings); check_expr(cx, e, bindings) }
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            { check_block(cx, block, bindings) },
        //ExprCall
        //ExprMethodCall
        ExprVec(ref v) | ExprTup(ref v) =>
            for ref e in v { check_expr(cx, e, bindings) },
        ExprIf(ref cond, ref then, ref otherwise) => {
            check_expr(cx, cond, bindings);
            check_block(cx, then, bindings);
            if let &Some(ref o) = otherwise { check_expr(cx, o, bindings); }
        },
        ExprWhile(ref cond, ref block, _) => {
            check_expr(cx, cond, bindings);
            check_block(cx, block, bindings);
        },
        ExprMatch(ref init, ref arms, _) => {
            check_expr(cx, init, bindings);
            let len = bindings.len();
            for ref arm in arms {
                for ref pat in &arm.pats {
                    check_pat(cx, &pat, &Some(&**init), pat.span, bindings);
                    //TODO: This is ugly, but needed to get the right type
                }
                if let Some(ref guard) = arm.guard {
                    check_expr(cx, guard, bindings);
                }
                check_expr(cx, &arm.body, bindings);
                bindings.truncate(len);
            }
        },
        _ => ()
    }
}

fn check_ty(cx: &Context, ty: &Ty, bindings: &mut Vec<Name>) {
    match ty.node {
        TyParen(ref sty) | TyObjectSum(ref sty, _) |
        TyVec(ref sty) => check_ty(cx, sty, bindings),
        TyFixedLengthVec(ref fty, ref expr) => {
            check_ty(cx, fty, bindings);
            check_expr(cx, expr, bindings);
        },
        TyPtr(MutTy{ ty: ref mty, .. }) |
        TyRptr(_, MutTy{ ty: ref mty, .. }) => check_ty(cx, mty, bindings),
        TyTup(ref tup) => { for ref t in tup { check_ty(cx, t, bindings) } },
        TyTypeof(ref expr) => check_expr(cx, expr, bindings),
        _ => (),
    }
}

fn is_self_shadow(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprBox(_, ref inner) |
        ExprParen(ref inner) |
        ExprAddrOf(_, ref inner) => is_self_shadow(name, inner),
        ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref().
            map_or(false, |ref e| is_self_shadow(name, e)),
        ExprUnary(op, ref inner) => (UnUniq == op || UnDeref == op) &&
            is_self_shadow(name, inner),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false,
    }
}

fn path_eq_name(name: Name, path: &Path) -> bool {
    !path.global && path.segments.len() == 1 &&
        path.segments[0].identifier.name == name
}

fn contains_self(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(_, ref e)
            => contains_self(name, e),
        ExprBinary(_, ref l, ref r) =>
            contains_self(name, l) || contains_self(name, r),
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            contains_block_self(name, block),
        ExprCall(ref fun, ref args) => contains_self(name, fun) ||
            args.iter().any(|ref a| contains_self(name, a)),
        ExprMethodCall(_, _, ref args) =>
            args.iter().any(|ref a| contains_self(name, a)),
        ExprVec(ref v) | ExprTup(ref v) =>
            v.iter().any(|ref e| contains_self(name, e)),
        ExprIf(ref cond, ref then, ref otherwise) =>
            contains_self(name, cond) || contains_block_self(name, then) ||
            otherwise.as_ref().map_or(false, |ref e| contains_self(name, e)),
        ExprWhile(ref e, ref block, _)  =>
            contains_self(name, e) || contains_block_self(name, block),
        ExprMatch(ref e, ref arms, _) =>
            arms.iter().any(|ref arm| arm.pats.iter().any(|ref pat|
                contains_pat_self(name, pat))) || contains_self(name, e),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false
    }
}

fn contains_block_self(name: Name, block: &Block) -> bool {
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) =>
            if let DeclLocal(ref local) = decl.node {
                //TODO: We don't currently handle the case where the name
                //is shadowed wiithin the block; this means code including this
                //degenerate pattern will get the wrong warning.
                if let Some(ref init) = local.init {
                    if contains_self(name, init) { return true; }
                }
            },
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                if contains_self(name, e) { return true },
            _ => ()
        }
    }
    if let Some(ref e) = block.expr { contains_self(name, e) } else { false }
}

fn contains_pat_self(name: Name, pat: &Pat) -> bool {
    match pat.node {
        PatIdent(_, ref ident, ref inner) => name == ident.node.name ||
            inner.as_ref().map_or(false, |ref p| contains_pat_self(name, p)),
        PatEnum(_, ref opats) => opats.as_ref().map_or(false,
            |pats| pats.iter().any(|p| contains_pat_self(name, p))),
        PatQPath(_, ref path) => path_eq_name(name, path),
        PatStruct(_, ref fieldpats, _) => fieldpats.iter().any(
            |ref fp| contains_pat_self(name, &fp.node.pat)),
        PatTup(ref ps) => ps.iter().any(|ref p| contains_pat_self(name, p)),
        PatBox(ref p) |
        PatRegion(ref p, _) => contains_pat_self(name, p),
        PatRange(ref from, ref until) =>
            contains_self(name, from) || contains_self(name, until),
        PatVec(ref pre, ref opt, ref post) =>
            pre.iter().any(|ref p| contains_pat_self(name, p)) ||
                opt.as_ref().map_or(false, |ref p| contains_pat_self(name, p)) ||
                post.iter().any(|ref p| contains_pat_self(name, p)),
        _ => false,
    }
}
<|endoftext|>