<commit_before>use std::vec::Vec;
use regex::Regex;
use matching::*;
use files::*;
use tokens::*;
use support::*;

pub fn get_token_types<'a>() -> Vec<(&'a str, &'a str)>
{
    // TODO: Read types from rules file
    let mut token_types: Vec<(&str, &str)> = Vec::new();

    token_types.push(("comment.line",       	r"//[^\n]*"));
    token_types.push(("comment.block",      	r"/\*([^\*]|(\*[^/]))*\*/"));
    token_types.push(("control",            	r"\.|\(|\)|\{|}|\[|]|;|,"));
    token_types.push(("literal.int",        	r"(0(x|b|o|d))?[:digit:]+"));
    token_types.push(("literal.long",       	r"(0(x|b|o|d))?[:digit:]+[lL]"));
    token_types.push(("literal.float",      	r"(\.(\d+)(f|F)?)|((\d+)\.(\d+)(f|F)?)|((\d+)(f|F))"));
    token_types.push(("literal.double",     	r"[:digit:]*\.[:digit:]+"));
    token_types.push(("literal.char",       	r"'[a-z A-Z]?'"));
    token_types.push(("literal.string",     	"\"([^\"\n\r]|\\.)*\""));
    token_types.push(("literal.boolean",    	r"true|false"));
    token_types.push(("literal.null",       	r"null"));
    token_types.push(("block.generics.args",	r"<( )*([a-zA-Z],?( )*)+( )*>"));
    token_types.push(("operator.unary",     	r"(\+\+)|(--)"));
    token_types.push(("operator.binary",    	r"((\+|<<|>>|-|/|\*|\||&)=?)|="));
    token_types.push(("operator.comparator",	r">|>=|<|<=|&&|\|\||==|instanceof"));
    token_types.push(("type",               	r"boolean|long|int|byte|short|char|double|float|void"));
    token_types.push(("mod.permission",     	r"public|private|protected"));
    token_types.push(("mod.access",    			r"static"));
    token_types.push(("mod.behaviour", 			r"final|volitile|transient|synchronized|native|abstract|throws"));
    token_types.push(("mod.inheritance",		r"extends|implements"));
    token_types.push(("action",             	r"return|continue|break|throw|new|assert|strictfp"));
    token_types.push(("construct.conditional", 	r"if|else"));
    token_types.push(("construct.handles",		r"try|catch|finally"));
    token_types.push(("construct.switch", 		r"switch|case:|default:"));
    token_types.push(("construct.loop",		 	r"do|while|for"));
    token_types.push(("construct.type", 		r"class|interface|enum"));
    token_types.push(("special.package",      	r"package"));
    token_types.push(("special.reserved",   	r"goto|const"));
    token_types.push(("special.import",     	r"import( +static)?( )+([a-zA-Z\._])+\*?"));
    token_types.push(("identifier",				r"([:alpha:]|[\$_])+([:alnum:]|[\$_])*"));

    token_types
}

pub fn get_invalid_token_values<'a>() -> Vec<&'a str>
{
    // TODO: Read invalid types from rules file
    let mut invalid_tokens: Vec<&str> = Vec::new();

    invalid_tokens.push("enum");
    invalid_tokens.push("interface");

    invalid_tokens
}

pub fn get_invalid_token_types<'a>() -> Vec<&'a str>
{
    // TODO: Read invalid types from rules file
    let mut invalid_types: Vec<&str> = Vec::new();

    invalid_types.push("literal.null");
    invalid_types.push("block.generics.args");
    invalid_types.push("literal.string");
    invalid_types.push("literal.char");
    invalid_types.push("literal.float");
    invalid_types.push("literal.double");
    invalid_types.push("special.reserved");
    invalid_types.push("construct.conditional");
    invalid_types.push("construct.handles");
    invalid_types.push("construct.switch");
    invalid_types.push("construct.loop");

    invalid_types
}

pub fn lex_file<'a>(file_path: &str, debug: bool) -> Vec<Token<'a>>
{
    let input = read_in(file_path);
    lex_string(input, debug)
}

pub fn lex_string<'a>(input: String, debug: bool) -> Vec<Token<'a>>
{
    // List the first match from each matcher; the index of the match will correspond to an index in matchers
    let mut matches: Vec<MatchResult> = Vec::new();
    let mut tokens: Vec<Token> = Vec::new();

    let token_types: Vec<(&str, &str)> = get_token_types();
    let matchers: Vec<Regex> = assemble_matchers(&token_types);

    let mut string_index = 0;
    while string_index < input.len()
    {
        let string = &input[string_index..];
        for (index, matcher) in matchers.iter().enumerate()
        {
            let token_name = token_types[index].0;
            let result = matcher.find(string);
            let match_result = MatchResult::parse(token_name, result, index);
            matches.push(match_result);
        }

        // print matches
        if debug
        {
            println!("\nMatches on {}:", string);
            for result in matches.iter()
            {
                println!("\t{}\t({}, {})\t{}", result.token_name, result.start, result.end, result.valid);
            }
        }

        // Find the first match and add it as a token; stop when there are no tokens to be found
        let (valid, index) = find_first_match(&matches);
        if valid
        {
            {
                let match_result = &matches[index];
                let start = match_result.start + string_index;
                let end = match_result.end + string_index;
                let value = slice_of(&input, (start, end));
                let token = Token{name: match_result.token_name, range: (start, end), value: value};
                string_index = end;

                if debug
                {
                    println!("\tThe dominant token is: {} at index: {} = {} with value: {}", matches[index].token_name, index, matches[index].index, token.value);
                    println!("\tRange: ({}, {})", start, end);
                }

                tokens.push(token);
            }
            matches.clear();
        }
        else
        {
            if debug {println!("no matches found");}
            break;
        }
    }

    tokens
}
<commit_msg>Allow conditionals and loops<commit_after>use std::vec::Vec;
use regex::Regex;
use matching::*;
use files::*;
use tokens::*;
use support::*;

pub fn get_token_types<'a>() -> Vec<(&'a str, &'a str)>
{
    // TODO: Read types from rules file
    let mut token_types: Vec<(&str, &str)> = Vec::new();

    token_types.push(("comment.line",       	r"//[^\n]*"));
    token_types.push(("comment.block",      	r"/\*([^\*]|(\*[^/]))*\*/"));
    token_types.push(("control",            	r"\.|\(|\)|\{|}|\[|]|;|,"));
    token_types.push(("literal.int",        	r"(0(x|b|o|d))?[:digit:]+"));
    token_types.push(("literal.long",       	r"(0(x|b|o|d))?[:digit:]+[lL]"));
    token_types.push(("literal.float",      	r"(\.(\d+)(f|F)?)|((\d+)\.(\d+)(f|F)?)|((\d+)(f|F))"));
    token_types.push(("literal.double",     	r"[:digit:]*\.[:digit:]+"));
    token_types.push(("literal.char",       	r"'[a-z A-Z]?'"));
    token_types.push(("literal.string",     	"\"([^\"\n\r]|\\.)*\""));
    token_types.push(("literal.boolean",    	r"true|false"));
    token_types.push(("literal.null",       	r"null"));
    token_types.push(("block.generics.args",	r"<( )*([a-zA-Z],?( )*)+( )*>"));
    token_types.push(("operator.unary",     	r"(\+\+)|(--)"));
    token_types.push(("operator.binary",    	r"((\+|<<|>>|-|/|\*|\||&)=?)|="));
    token_types.push(("operator.comparator",	r">|>=|<|<=|&&|\|\||==|instanceof"));
    token_types.push(("type",               	r"boolean|long|int|byte|short|char|double|float|void"));
    token_types.push(("mod.permission",     	r"public|private|protected"));
    token_types.push(("mod.access",    			r"static"));
    token_types.push(("mod.behaviour", 			r"final|volitile|transient|synchronized|native|abstract|throws"));
    token_types.push(("mod.inheritance",		r"extends|implements"));
    token_types.push(("action",             	r"return|continue|break|throw|new|assert|strictfp"));
    token_types.push(("construct.conditional", 	r"if|else"));
    token_types.push(("construct.handles",		r"try|catch|finally"));
    token_types.push(("construct.switch", 		r"switch|case:|default:"));
    token_types.push(("construct.loop",		 	r"do|while|for"));
    token_types.push(("construct.type", 		r"class|interface|enum"));
    token_types.push(("special.package",      	r"package"));
    token_types.push(("special.reserved",   	r"goto|const"));
    token_types.push(("special.import",     	r"import( +static)?( )+([a-zA-Z\._])+\*?"));
    token_types.push(("identifier",				r"([:alpha:]|[\$_])+([:alnum:]|[\$_])*"));

    token_types
}

pub fn get_invalid_token_values<'a>() -> Vec<&'a str>
{
    // TODO: Read invalid types from rules file
    let mut invalid_tokens: Vec<&str> = Vec::new();

    invalid_tokens.push("enum");
    invalid_tokens.push("interface");

    invalid_tokens
}

pub fn get_invalid_token_types<'a>() -> Vec<&'a str>
{
    // TODO: Read invalid types from rules file
    let mut invalid_types: Vec<&str> = Vec::new();

    invalid_types.push("literal.null");
    invalid_types.push("block.generics.args");
    invalid_types.push("literal.string");
    invalid_types.push("literal.char");
    invalid_types.push("literal.float");
    invalid_types.push("literal.double");
    invalid_types.push("special.reserved");
    invalid_types.push("construct.handles");
    invalid_types.push("construct.switch");

    invalid_types
}

pub fn lex_file<'a>(file_path: &str, debug: bool) -> Vec<Token<'a>>
{
    let input = read_in(file_path);
    lex_string(input, debug)
}

pub fn lex_string<'a>(input: String, debug: bool) -> Vec<Token<'a>>
{
    // List the first match from each matcher; the index of the match will correspond to an index in matchers
    let mut matches: Vec<MatchResult> = Vec::new();
    let mut tokens: Vec<Token> = Vec::new();

    let token_types: Vec<(&str, &str)> = get_token_types();
    let matchers: Vec<Regex> = assemble_matchers(&token_types);

    let mut string_index = 0;
    while string_index < input.len()
    {
        let string = &input[string_index..];
        for (index, matcher) in matchers.iter().enumerate()
        {
            let token_name = token_types[index].0;
            let result = matcher.find(string);
            let match_result = MatchResult::parse(token_name, result, index);
            matches.push(match_result);
        }

        // print matches
        if debug
        {
            println!("\nMatches on {}:", string);
            for result in matches.iter()
            {
                println!("\t{}\t({}, {})\t{}", result.token_name, result.start, result.end, result.valid);
            }
        }

        // Find the first match and add it as a token; stop when there are no tokens to be found
        let (valid, index) = find_first_match(&matches);
        if valid
        {
            {
                let match_result = &matches[index];
                let start = match_result.start + string_index;
                let end = match_result.end + string_index;
                let value = slice_of(&input, (start, end));
                let token = Token{name: match_result.token_name, range: (start, end), value: value};
                string_index = end;

                if debug
                {
                    println!("\tThe dominant token is: {} at index: {} = {} with value: {}", matches[index].token_name, index, matches[index].index, token.value);
                    println!("\tRange: ({}, {})", start, end);
                }

                tokens.push(token);
            }
            matches.clear();
        }
        else
        {
            if debug {println!("no matches found");}
            break;
        }
    }

    tokens
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use cgmath;
use gfx;
use gfx_phase;

/// Culled result on an entity.
#[derive(Clone)]
pub struct CullEntity<'a, R: 'a + gfx::Resources, M: 'a, V> where
    R::Buffer: 'a,
    R::ArrayBuffer: 'a,
    R::Shader: 'a,
    R::Program: 'a,
    R::FrameBuffer: 'a,
    R::Surface: 'a,
    R::Texture: 'a,
    R::Sampler: 'a,
{
    mesh: &'a gfx::Mesh<R>,
    slice: &'a gfx::Slice<R>,
    material: &'a M,
    view_info: V,
}

/// Culling iterator.
pub struct CullIterator<'a, 'b, R, M, W, B, V, I, C> where
    R: gfx::Resources,
    W: ::World + 'a,
    B: cgmath::Bound<W::Scalar>,
    I: Iterator<Item = &'a ::Entity<R, M, W, B>>,
    C: Culler<W::Scalar, B> + 'b,
{
    entities: I,
    world: &'a W,
    culler: &'b mut C,
    cam_inverse: W::Transform,
    projection: cgmath::Matrix4<W::Scalar>,
    dummy: PhantomData<V>,
}

impl<'a, 'c, R, M, W, B, V, I, C> Iterator for CullIterator<'a, 'c, R, M, W, B, V, I, C> where
    R: gfx::Resources,
    R::Buffer: 'a,
    R::ArrayBuffer: 'a,
    R::Shader: 'a,
    R::Program: 'a,
    R::FrameBuffer: 'a,
    R::Surface: 'a,
    R::Texture: 'a,
    R::Sampler: 'a,
    W: ::World + 'a,
    W::Transform: 'a,
    W::NodePtr: 'a,
    W::SkeletonPtr: 'a,
    B: cgmath::Bound<W::Scalar>,
    V: ::ViewInfo<W::Scalar, W::Transform>,
    I: Iterator<Item = &'a ::Entity<R, M, W, B>>,
    C: Culler<W::Scalar, B> + 'c,
{
    type Item = CullEntity<'a, R, M, V>;

    fn next(&mut self) -> Option<CullEntity<'a, R, M, V>> {
        use cgmath::{Matrix, ToMatrix4, Transform};
        while let Some(ent) = self.entities.next() {
            let model = self.world.get_transform(&ent.node);
            let view = self.cam_inverse.concat(&model);
            let mvp = self.projection.mul_m(&model.to_matrix4());
            if self.culler.cull(&ent.bound, &mvp) != cgmath::Relation::Out {
                return Some(CullEntity {
                    mesh: &ent.mesh,
                    slice: &ent.slice,
                    material: &ent.material,
                    view_info: ::ViewInfo::new(mvp, view, model),
                })
            }
        }
        None
    }
}

/// Generic bound culler.
pub trait Culler<S, B: cgmath::Bound<S>> {
    /// Start a new culling session.
    fn init(&mut self);
    /// Cull a bound with a given transformation matrix.
    fn cull(&mut self, &B, &cgmath::Matrix4<S>) -> cgmath::Relation;
    /// Process the whole scene, calling a function for every success.
    fn process<'a, 'c, R, M, T, W, P, V, I>(&'c mut self, entities: I, world: &'a W,
               camera: &::Camera<P, W::NodePtr>)
               -> CullIterator<'a, 'c, R, M, W, B, V, I, Self> where
        R: gfx::Resources,
        S: cgmath::BaseFloat,
        T: cgmath::Transform3<S> + Clone,   // shouldn't be needed
        W: ::World<Scalar = S, Transform = T> + 'a,
        P: cgmath::Projection<S>,
        I: Iterator<Item = &'a ::Entity<R, M, W, B>>,
        Self: Sized,    // magic!
    {
        use cgmath::{Matrix, ToMatrix4, Transform};
        let cam_inverse = world.get_transform(&camera.node)
                               .invert().unwrap();
        let projection = camera.projection.to_matrix4()
                               .mul_m(&cam_inverse.to_matrix4());
        self.init();
        CullIterator {
            entities: entities,
            world: world,
            culler: self,
            cam_inverse: cam_inverse,
            projection: projection,
            dummy: PhantomData,
        }
    }
}

impl<S, B: cgmath::Bound<S>> Culler<S, B> for () {
    fn init(&mut self) {}
    fn cull(&mut self, _: &B, _: &cgmath::Matrix4<S>) -> cgmath::Relation {
        cgmath::Relation::Cross
    }
}

/// Frustum culler.
pub struct Frustum<S, B>(PhantomData<(S, B)>);

impl<S, B> Frustum<S, B> {
    /// Create a new frustum culler.
    pub fn new() -> Frustum<S, B> {
        Frustum(PhantomData)
    }
}

impl<S: cgmath::BaseFloat, B: cgmath::Bound<S>> Culler<S, B> for Frustum<S, B> {
    fn init(&mut self) {}
    fn cull(&mut self, bound: &B, mvp: &cgmath::Matrix4<S>) -> cgmath::Relation {
        bound.relate_clip_space(mvp)
    }
}
/*
impl<'a, R, M, V, I> ::AbstractScene<R> for I where
    R: gfx::Resources,
    R::Buffer: 'a,
    R::ArrayBuffer: 'a,
    R::Shader: 'a,
    R::Program: 'a,
    R::FrameBuffer: 'a,
    R::Surface: 'a,
    R::Texture: 'a,
    R::Sampler: 'a,
    V, gfx_phase::ToDepth,
    I: Iterator<Item = CullEntity<'a, V, R, M>>,
{
    type ViewInfo = V;
    type Material = M;
    type Camera = ();

    fn draw<H, S>(&self, phase: &mut H, _: &(), stream: &mut S)
            -> Result<::FailCount, ::Error> where
        H: gfx_phase::AbstractPhase<R, Self::Material, Self::ViewInfo>,
        S: gfx::Stream<R>
    {
        let mut fail = 0;
        // enqueue entities
        for e in self {
            match phase.enqueue(e.mesh, e.slice, e.material, &e.view_info) {
                Ok(true) => (),
                Ok(false) => fail += 1,
                Err(e) => return Err(::Error::Batch(e)),
            }
        }
        // flush into the renderer
        match phase.flush(stream) {
            Ok(()) => Ok(fail),
            Err(e) => Err(::Error::Flush(e)),
        }
    }
}*/

/// Draw culled entities, specified by an iterator.
pub fn draw<'a, R, M, V, I, H, S>(entities: I, phase: &mut H, stream: &mut S)
            -> Result<::FailCount, ::Error> where
    R: gfx::Resources + 'a,
    R::Buffer: 'a,
    R::ArrayBuffer: 'a,
    R::Shader: 'a,
    R::Program: 'a,
    R::FrameBuffer: 'a,
    R::Surface: 'a,
    R::Texture: 'a,
    R::Sampler: 'a,
    M: 'a,
    V: gfx_phase::ToDepth,
    I: Iterator<Item = CullEntity<'a, R, M, V>>,
    H: gfx_phase::AbstractPhase<R, M, V>,
    S: gfx::Stream<R>
{
    let mut fail = 0;
    // enqueue entities
    for e in entities {
        match phase.enqueue(e.mesh, e.slice, e.material, &e.view_info) {
            Ok(true) => (),
            Ok(false) => fail += 1,
            Err(e) => return Err(::Error::Batch(e)),
        }
    }
    // flush into the renderer
    match phase.flush(stream) {
        Ok(()) => Ok(fail),
        Err(e) => Err(::Error::Flush(e)),
    }
}
<commit_msg>Cleaned up the deprecated AbstractScene implementation for a vector<commit_after>use std::marker::PhantomData;
use cgmath;
use gfx;
use gfx_phase;

/// Culled result on an entity.
#[derive(Clone)]
pub struct CullEntity<'a, R: 'a + gfx::Resources, M: 'a, V> where
    R::Buffer: 'a,
    R::ArrayBuffer: 'a,
    R::Shader: 'a,
    R::Program: 'a,
    R::FrameBuffer: 'a,
    R::Surface: 'a,
    R::Texture: 'a,
    R::Sampler: 'a,
{
    mesh: &'a gfx::Mesh<R>,
    slice: &'a gfx::Slice<R>,
    material: &'a M,
    view_info: V,
}

/// Culling iterator.
pub struct CullIterator<'a, 'b, R, M, W, B, V, I, C> where
    R: gfx::Resources,
    W: ::World + 'a,
    B: cgmath::Bound<W::Scalar>,
    I: Iterator<Item = &'a ::Entity<R, M, W, B>>,
    C: Culler<W::Scalar, B> + 'b,
{
    entities: I,
    world: &'a W,
    culler: &'b mut C,
    cam_inverse: W::Transform,
    projection: cgmath::Matrix4<W::Scalar>,
    dummy: PhantomData<V>,
}

impl<'a, 'c, R, M, W, B, V, I, C> Iterator for CullIterator<'a, 'c, R, M, W, B, V, I, C> where
    R: gfx::Resources,
    R::Buffer: 'a,
    R::ArrayBuffer: 'a,
    R::Shader: 'a,
    R::Program: 'a,
    R::FrameBuffer: 'a,
    R::Surface: 'a,
    R::Texture: 'a,
    R::Sampler: 'a,
    W: ::World + 'a,
    W::Transform: 'a,
    W::NodePtr: 'a,
    W::SkeletonPtr: 'a,
    B: cgmath::Bound<W::Scalar>,
    V: ::ViewInfo<W::Scalar, W::Transform>,
    I: Iterator<Item = &'a ::Entity<R, M, W, B>>,
    C: Culler<W::Scalar, B> + 'c,
{
    type Item = CullEntity<'a, R, M, V>;

    fn next(&mut self) -> Option<CullEntity<'a, R, M, V>> {
        use cgmath::{Matrix, ToMatrix4, Transform};
        while let Some(ent) = self.entities.next() {
            let model = self.world.get_transform(&ent.node);
            let view = self.cam_inverse.concat(&model);
            let mvp = self.projection.mul_m(&model.to_matrix4());
            if self.culler.cull(&ent.bound, &mvp) != cgmath::Relation::Out {
                return Some(CullEntity {
                    mesh: &ent.mesh,
                    slice: &ent.slice,
                    material: &ent.material,
                    view_info: ::ViewInfo::new(mvp, view, model),
                })
            }
        }
        None
    }
}

/// Generic bound culler.
pub trait Culler<S, B: cgmath::Bound<S>> {
    /// Start a new culling session.
    fn init(&mut self);
    /// Cull a bound with a given transformation matrix.
    fn cull(&mut self, &B, &cgmath::Matrix4<S>) -> cgmath::Relation;
    /// Process the whole scene, calling a function for every success.
    fn process<'a, 'c, R, M, T, W, P, V, I>(&'c mut self, entities: I, world: &'a W,
               camera: &::Camera<P, W::NodePtr>)
               -> CullIterator<'a, 'c, R, M, W, B, V, I, Self> where
        R: gfx::Resources,
        S: cgmath::BaseFloat,
        T: cgmath::Transform3<S> + Clone,   // shouldn't be needed
        W: ::World<Scalar = S, Transform = T> + 'a,
        P: cgmath::Projection<S>,
        I: Iterator<Item = &'a ::Entity<R, M, W, B>>,
        Self: Sized,    // magic!
    {
        use cgmath::{Matrix, ToMatrix4, Transform};
        let cam_inverse = world.get_transform(&camera.node)
                               .invert().unwrap();
        let projection = camera.projection.to_matrix4()
                               .mul_m(&cam_inverse.to_matrix4());
        self.init();
        CullIterator {
            entities: entities,
            world: world,
            culler: self,
            cam_inverse: cam_inverse,
            projection: projection,
            dummy: PhantomData,
        }
    }
}

impl<S, B: cgmath::Bound<S>> Culler<S, B> for () {
    fn init(&mut self) {}
    fn cull(&mut self, _: &B, _: &cgmath::Matrix4<S>) -> cgmath::Relation {
        cgmath::Relation::Cross
    }
}

/// Frustum culler.
pub struct Frustum<S, B>(PhantomData<(S, B)>);

impl<S, B> Frustum<S, B> {
    /// Create a new frustum culler.
    pub fn new() -> Frustum<S, B> {
        Frustum(PhantomData)
    }
}

impl<S: cgmath::BaseFloat, B: cgmath::Bound<S>> Culler<S, B> for Frustum<S, B> {
    fn init(&mut self) {}
    fn cull(&mut self, bound: &B, mvp: &cgmath::Matrix4<S>) -> cgmath::Relation {
        bound.relate_clip_space(mvp)
    }
}

/// Draw culled entities, specified by an iterator.
pub fn draw<'a, R, M, V, I, H, S>(entities: I, phase: &mut H, stream: &mut S)
            -> Result<::FailCount, ::Error> where
    R: gfx::Resources + 'a,
    R::Buffer: 'a,
    R::ArrayBuffer: 'a,
    R::Shader: 'a,
    R::Program: 'a,
    R::FrameBuffer: 'a,
    R::Surface: 'a,
    R::Texture: 'a,
    R::Sampler: 'a,
    M: 'a,
    V: gfx_phase::ToDepth,
    I: Iterator<Item = CullEntity<'a, R, M, V>>,
    H: gfx_phase::AbstractPhase<R, M, V>,
    S: gfx::Stream<R>
{
    let mut fail = 0;
    // enqueue entities
    for e in entities {
        match phase.enqueue(e.mesh, e.slice, e.material, &e.view_info) {
            Ok(true) => (),
            Ok(false) => fail += 1,
            Err(e) => return Err(::Error::Batch(e)),
        }
    }
    // flush into the renderer
    match phase.flush(stream) {
        Ok(()) => Ok(fail),
        Err(e) => Err(::Error::Flush(e)),
    }
}
<|endoftext|>


<commit_before>mod log;
use capnp;
use rand;
use raft_capnp::{append_entries, append_entries_reply,
                 request_vote, request_vote_reply};
use rpc::{RpcError};
use rpc::server::{RpcObject, RpcServer};
use std::net::{SocketAddr};
use std::time::{Duration, Instant};
use std::thread;
use std::sync::{Arc, Mutex, MutexGuard};
use std::sync::mpsc::{channel, Sender, Receiver};

use self::log::{Log, MemoryLog, Entry};
use std::time;
use std::io::Error as IoError;
use rand::distributions::{IndependentSample, Range};
use std::collections::HashMap;

// Constants
// TODO: Many of these should be overwritable by Config
const ELECTION_TIMEOUT_MIN: u64 = 150; // min election timeout wait value in m.s.
const ELECTION_TIMEOUT_MAX: u64 = 300; // min election timeout wait value in m.s.
const HEARTBEAT_INTERVAL: u64    = 75; // time between hearbeats

pub struct Config {
    // Each server has a unique 64bit integer id that and a socket address
    // These mappings MUST be identical for eaah server in the cluster
    cluster: HashMap<u64, SocketAddr>,
    leader: u64,
    me: (u64, SocketAddr),
    heartbeat_timeout: Duration,
}

impl Config {
    pub fn new (cluster: HashMap<u64, SocketAddr>, leader: u64, my_id: u64,
                my_addr: SocketAddr, heartbeat_timeout: Duration) -> Config {
        Config {
            cluster: cluster,
            leader: leader,
            me: (my_id, my_addr),
            heartbeat_timeout: heartbeat_timeout,
        }
    }

    // TODO eventually implement
    // pub fn fromFile (file: String) -> Config {
    //
    // }
}

// States that each machine can be in!
#[derive(PartialEq)]
pub enum State {
    CANDIDATE,
    LEADER,
    FOLLOWER,
}

enum RpcType {
    APPEND_ENTRIES,
    REQUEST_VOTE,
}

//#[derive(Clone)]
struct AppendEntriesMessage {
    term: u64,
    leader_id: u64,
    prev_log_index: u64,
    prev_log_term: u64,
    entries: Entry,
    leader_commit: u64,
}

struct AppendEntriesReply {
    term: u64,
    commit_index: u64,
    peer_addr: SocketAddr, // or some other identifying field
    success: u64,
}

#[derive(Copy, Clone)]
struct RequestVoteMessage {
    term: u64,
    candidate_id: u64,
    last_log_index: u64,
    last_log_term: u64,
}

struct RequestVoteReply {
    term: u64,
    vote_granted: u64,
}

struct ClientAppendRequest {
    entry: Entry,
}

enum PeerThreadMessage {
    AppendEntries (AppendEntriesMessage),
    RequestVote (RequestVoteMessage),
}

enum MainThreadMessage {
    AppendEntriesReply (AppendEntriesReply),
    RequestVoteReply (RequestVoteReply),
    ClientAppendRequest (ClientAppendRequest),
}

pub struct PeerHandle {
    to_peer: Sender<PeerThreadMessage>,
}

pub struct Peer {
    addr: SocketAddr,
    commit_index: u64,
    pending_entries: Vec<Entry>,
    to_main: Sender<MainThreadMessage>,
    from_main: Receiver<PeerThreadMessage>,
}

impl Peer {
    fn start (addr: SocketAddr, to_main: Sender<MainThreadMessage>) -> PeerHandle {
        let (to_peer, from_main) = channel();
        //let (to_main, from_peer) = channel();
        let commit_index = 0;

        thread::spawn(move || {
            let peer = Peer {
                addr: addr,
                commit_index: commit_index,
                pending_entries: vec![],
                to_main: to_main,
                from_main: from_main,
            };
            peer.main();
        });

        PeerHandle {
            to_peer: to_peer,
            //from_peer: from_peer,
        }
    }

    pub fn send_append_entries (&mut self, entry: AppendEntriesMessage) {
        // TODO (syd)
        // 1. Construct an empty append_entries rpc
        // 2. Copy in entries from |ro_log| if peer commit index is behind.
        unimplemented!();
    }

    pub fn send_request_vote (&self, vote: RequestVoteMessage) {
        unimplemented!()
    }

    // Main loop for this machine to push to Peers.
    fn main (mut self) {
        loop {
            match self.from_main.recv().unwrap() { // If recv fails, we in deep shit already, so just unwrap
                PeerThreadMessage::AppendEntries(entry) => self.send_append_entries(entry),
                PeerThreadMessage::RequestVote(vote) => self.send_request_vote(vote)
            }
        }
    }
}

// Store's the state that the server is currently in along with the current_term
// and current_id. This fields should all share a lock.
struct ServerState {
    // TODO: state and term must be persisted to disk
    current_state: State,
    current_term: u64,
    current_index: u64,
    last_leader_contact: Instant,
    voted_for: Option<u64>
}

// TODO: RW locks?
pub struct Server {
    state: Arc<Mutex<ServerState>>,
    log: Arc<Mutex<Log>>,
    peers: Vec<PeerHandle>,
    me: (u64, SocketAddr),
    last_heartbeat: Instant,
}

///
/// Starts up a new raft server with the given config.
/// This is mostly just a bootstrapper for now. It probably won't end up in the public API
/// As of right now this function does not return. It just runs the state machine as long as it's
/// in a live thread.
///
pub fn start_server (config: Config) -> ! {
    let (tx, rx) = channel();
    let mut server = Server::new(config, tx).unwrap();

    // NB: This thread handles all state changes EXCEPT for those that move us back into the
    // follower state from either the candidate or leader state. Those are both handled in the
    // AppendEntriesRpcHandler

    // The server starts up in a follower state. Set a timeout to become a candidate.
    loop {
        let mut state = server.state.lock().unwrap(); // panics if any other threads have panicked.
        match state.current_state {
            State::FOLLOWER => {
                let btwn = Range::new(ELECTION_TIMEOUT_MIN, ELECTION_TIMEOUT_MAX);
                let mut range = rand::thread_rng();
                // TODO(jason): Subtract time since last_leader_contact from wait time
                let timeout = Duration::from_millis(btwn.ind_sample(&mut range));
                drop(state);
                thread::sleep(timeout);
                state = server.state.lock().unwrap();

                let now = Instant::now();
                let last_leader_contact = state.last_leader_contact;
                if now.duration_since(last_leader_contact) >= timeout {
                    // we have not heard from the leader for one timeout duration.
                    // start an election
                    server.start_election(state);
                }
            },
            State::CANDIDATE => {
                server.start_election(state);
                unimplemented!()
            },
            State::LEADER => {
                let heartbeat_wait = Duration::from_millis(HEARTBEAT_INTERVAL);
                let duration_since_last_heartbeat = Instant::now().duration_since(server.last_heartbeat);
                // TODO (sydli) : use checked_sub here (possible underflow)
                let next_heartbeat = heartbeat_wait - duration_since_last_heartbeat;
                // Timed wait on leader message pipe.
                let message = match rx.recv_timeout(next_heartbeat) {
                    Ok(message) => message,
                    // If we timed out, just send a heartbeat.
                    Err(e) => {
                        server.send_append_entries();
                        continue;
                    },
                };
                match message {
                    MainThreadMessage::AppendEntriesReply(m) => {
                        server.aggregate_append_entries_reply(m);
                        server.update_commit_index();
                    },
                    MainThreadMessage::ClientAppendRequest(m) => {
                        server.send_append_entries();
                    },
                    _ => unimplemented!(),
                };
            },
        } // end match server.state
    } // end loop
}

impl Server {
    fn new (config: Config, tx: Sender<MainThreadMessage>) -> Result<Server, IoError> {
        let me = config.me;
        // 1. Start RPC request handlers
        let append_entries_handler: Box<RpcObject> = Box::new(AppendEntriesHandler {});
        let services = vec![
            (1, append_entries_handler),
        ];
        let mut server = RpcServer::new_with_services(services);
        try!(
            server.bind((config.me.1.ip(), config.me.1.port()))
            .and_then(|_| {
                server.repl()
            })
        );

        // TODO: Should peers be a map of id->PeerHandle. I.E. Will we ever need to send a message
        // to a specific peer?

        // 2. Start peer threads.
        let peers = config.cluster.into_iter()
            .filter(|&(id, addr)| id != me.0) // filter all computers that aren't me
            .map(|(id, addr)| Peer::start(addr, tx.clone()))
            .collect::<Vec<PeerHandle>>();

        let log = Arc::new(Mutex::new(MemoryLog::new()));

        let state = Arc::new(Mutex::new(ServerState {
            current_state: State::FOLLOWER,
            current_term: 0,
            current_index: 0,
            voted_for: None,
            last_leader_contact: Instant::now()
        }));

        // 3. Construct server state object.
        Ok(Server {
            state: state,
            log: log,
            peers: peers,
            me: me,
            last_heartbeat: Instant::now()
        })
    }

    ///
    /// Write |entry| to the log and try to replicate it across all servers.
    /// This function is non-blocking; it simply forwards AppendEntries messages
    /// to all known peers.
    ///
    fn send_append_entries(&/*mut*/ self) {
        unimplemented!();
        //self.last_heartbeat = Instant::now();
    }

    ///
    /// Aggregate peer's append entries response into server state
    ///
    fn aggregate_append_entries_reply(&self, message: AppendEntriesReply) {
        unimplemented!();
    }

    ///
    /// Update commit_index count to the most recent log entry with quorum.
    ///
    fn update_commit_index(&self) {
        unimplemented!();
    }

    ///
    /// Starts a new election by requesting votes from all peers
    /// If the election is successful then the server transitions into the LEADER state
    /// Otherwise the leader stays in the candidate state.
    /// The assumption is that the caller will start another election
    ///
    fn start_election(&self, mut state: MutexGuard<ServerState>) {
        { // state lock scope
            // move the lock into this scope
            let mut locked_state = state;
            // transition to the candidate state
            let last_log_index = locked_state.current_index;
            let last_log_term = locked_state.current_term;
            locked_state.current_state = State::CANDIDATE;
            locked_state.current_term += 1;
            locked_state.current_index = 0;
            locked_state.voted_for = Some(self.me.0); // vote for ourselves
            // tell each peer to send out RequestToVote RPCs
            let request_vote_message = RequestVoteMessage {
                term: locked_state.current_term,
                candidate_id: self.me.0,
                last_log_index: last_log_index,
                last_log_term: last_log_term
            };
            let ref peers = self.peers;
            for peer in peers {
                peer.to_peer.send(PeerThreadMessage::RequestVote(request_vote_message))
                    .unwrap(); // panic if the peer thread is down
            }
        }
        unimplemented!();
    }
}

struct AppendEntriesHandler {}

impl RpcObject for AppendEntriesHandler {
    fn handle_rpc (&self, params: capnp::any_pointer::Reader, result: capnp::any_pointer::Builder)
        -> Result<(), RpcError>
    {
        // TODO: If this is a valid rpc from the leader, update last_leader_contact

        // TODO: If we're in the CANDIDATE state and this leader's term is >= our current term
        //

        // TODO (syd) implement
        // 1. Ensure prevLogIndex matches our own.
        // 2. Append outstanding log entries.
        // 3. Construct reply.
        params.get_as::<append_entries::Reader>()
           .map(|append_entries| {
               result.init_as::<append_entries_reply::Builder>().set_success(true);
           })
           .map_err(RpcError::Capnp)
    }
}
<commit_msg>WIP: log replication<commit_after>mod log;
use capnp;
use rand;
use raft_capnp::{append_entries, append_entries_reply,
                 request_vote, request_vote_reply};
use rpc::{RpcError};
use rpc::server::{RpcObject, RpcServer};
use std::net::{SocketAddr};
use std::time::{Duration, Instant};
use std::thread;
use std::sync::{Arc, Mutex, MutexGuard};
use std::sync::mpsc::{channel, Sender, Receiver};

use self::log::{Log, MemoryLog, Entry};
use std::time;
use std::io::Error as IoError;
use rand::distributions::{IndependentSample, Range};
use std::collections::HashMap;

// Constants
// TODO: Many of these should be overwritable by Config
const ELECTION_TIMEOUT_MIN: u64 = 150; // min election timeout wait value in m.s.
const ELECTION_TIMEOUT_MAX: u64 = 300; // min election timeout wait value in m.s.
const HEARTBEAT_INTERVAL: u64    = 75; // time between hearbeats

pub struct Config {
    // Each server has a unique 64bit integer id that and a socket address
    // These mappings MUST be identical for eaah server in the cluster
    cluster: HashMap<u64, SocketAddr>,
    leader: u64,
    me: (u64, SocketAddr),
    heartbeat_timeout: Duration,
}

impl Config {
    pub fn new (cluster: HashMap<u64, SocketAddr>, leader: u64, my_id: u64,
                my_addr: SocketAddr, heartbeat_timeout: Duration) -> Config {
        Config {
            cluster: cluster,
            leader: leader,
            me: (my_id, my_addr),
            heartbeat_timeout: heartbeat_timeout,
        }
    }

    // TODO eventually implement
    // pub fn fromFile (file: String) -> Config {
    //
    // }
}

// States that each machine can be in!
#[derive(PartialEq, Clone)]
pub enum State {
    CANDIDATE,
    LEADER,
    FOLLOWER,
}

enum RpcType {
    APPEND_ENTRIES,
    REQUEST_VOTE,
}

//#[derive(Clone)]
struct AppendEntriesMessage {
    term: u64,
    leader_id: u64,
    prev_log_index: u64,
    prev_log_term: u64,
    entries: Entry,
    leader_commit: u64,
}

struct AppendEntriesReply {
    term: u64,
    commit_index: u64,
    peer_addr: SocketAddr, // or some other identifying field
    success: u64,
}

#[derive(Copy, Clone)]
struct RequestVoteMessage {
    term: u64,
    candidate_id: u64,
    last_log_index: u64,
    last_log_term: u64,
}

struct RequestVoteReply {
    term: u64,
    vote_granted: u64,
}

struct ClientAppendRequest {
    entry: Entry,
}

enum PeerThreadMessage {
    AppendEntries (AppendEntriesMessage),
    RequestVote (RequestVoteMessage),
}

enum MainThreadMessage {
    AppendEntriesReply (AppendEntriesReply),
    RequestVoteReply (RequestVoteReply),
    ClientAppendRequest (ClientAppendRequest),
}

pub struct PeerHandle {
    to_peer: Sender<PeerThreadMessage>,
}

pub struct Peer {
    addr: SocketAddr,
    commit_index: u64,
    pending_entries: Vec<Entry>,
    to_main: Sender<MainThreadMessage>,
    from_main: Receiver<PeerThreadMessage>,
}

impl Peer {
    fn start (addr: SocketAddr, to_main: Sender<MainThreadMessage>) -> PeerHandle {
        let (to_peer, from_main) = channel();
        //let (to_main, from_peer) = channel();
        let commit_index = 0;

        thread::spawn(move || {
            let peer = Peer {
                addr: addr,
                commit_index: commit_index,
                pending_entries: vec![],
                to_main: to_main,
                from_main: from_main,
            };
            peer.main();
        });

        PeerHandle {
            to_peer: to_peer,
            //from_peer: from_peer,
        }
    }

    pub fn send_append_entries (&mut self, entry: AppendEntriesMessage) {
        // TODO (syd)
        // 1. Construct an empty append_entries rpc
        // 2. Copy in entries from |ro_log| if peer commit index is behind.
        unimplemented!();
    }

    pub fn send_request_vote (&self, vote: RequestVoteMessage) {
        unimplemented!()
    }

    // Main loop for this machine to push to Peers.
    fn main (mut self) {
        loop {
            match self.from_main.recv().unwrap() { // If recv fails, we in deep shit already, so just unwrap
                PeerThreadMessage::AppendEntries(entry) => self.send_append_entries(entry),
                PeerThreadMessage::RequestVote(vote) => self.send_request_vote(vote)
            }
        }
    }
}

// Store's the state that the server is currently in along with the current_term
// and current_id. This fields should all share a lock.
struct ServerState {
    // TODO: state and term must be persisted to disk
    current_state: State,
    current_term: u64,
    current_index: u64,
    last_leader_contact: Instant,
    voted_for: Option<u64>
}

// TODO: RW locks?
pub struct Server {
    state: Arc<Mutex<ServerState>>,
    log: Arc<Mutex<Log>>,
    peers: Vec<PeerHandle>,
    me: (u64, SocketAddr),
    last_heartbeat: Instant,
}

///
/// Starts up a new raft server with the given config.
/// This is mostly just a bootstrapper for now. It probably won't end up in the public API
/// As of right now this function does not return. It just runs the state machine as long as it's
/// in a live thread.
///
pub fn start_server (config: Config) -> ! {
    let (tx, rx) = channel();
    let mut server = Server::new(config, tx).unwrap();

    // NB: This thread handles all state changes EXCEPT for those that move us back into the
    // follower state from either the candidate or leader state. Those are both handled in the
    // AppendEntriesRpcHandler

    // The server starts up in a follower state. Set a timeout to become a candidate.
    loop {
        let current_state = { server.state.lock().unwrap().current_state.clone() };
        match current_state {
            State::FOLLOWER => {
                let btwn = Range::new(ELECTION_TIMEOUT_MIN, ELECTION_TIMEOUT_MAX);
                let mut range = rand::thread_rng();
                // TODO(jason): Subtract time since last_leader_contact from wait time
                let timeout = Duration::from_millis(btwn.ind_sample(&mut range));
                thread::sleep(timeout);
                let state = server.state.lock().unwrap();

                let now = Instant::now();
                let last_leader_contact = state.last_leader_contact;
                if now.duration_since(last_leader_contact) >= timeout {
                    // we have not heard from the leader for one timeout duration.
                    // start an election
                    server.start_election(state);
                }
            },
            State::CANDIDATE => {
                let state = server.state.lock().unwrap();
                server.start_election(state);
                unimplemented!()
            },
            State::LEADER => {
                let heartbeat_wait = Duration::from_millis(HEARTBEAT_INTERVAL);
                let since_last_heartbeat = Instant::now()
                                               .duration_since(server.last_heartbeat);
                // TODO (sydli) : use checked_sub here (possible underflow)
                let next_heartbeat = heartbeat_wait - since_last_heartbeat;
                // Timed wait on leader message pipe.
                let message = match rx.recv_timeout(next_heartbeat) {
                    Ok(message) => message,
                    // If we timed out, just send a heartbeat.
                    Err(e) => {
                        server.send_append_entries();
                        continue;
                    },
                };
                match message {
                    MainThreadMessage::AppendEntriesReply(m) => {
                        server.aggregate_append_entries_reply(m);
                        server.update_commit_index();
                    },
                    MainThreadMessage::ClientAppendRequest(m) => {
                        server.send_append_entries();
                    },
                    _ => unimplemented!(),
                };
            },
        } // end match server.state
    } // end loop
}

impl Server {
    fn new (config: Config, tx: Sender<MainThreadMessage>) -> Result<Server, IoError> {
        let me = config.me;
        // 1. Start RPC request handlers
        let append_entries_handler: Box<RpcObject> = Box::new(
            AppendEntriesHandler { to_main: Mutex::new(tx.clone()) });
        let services = vec![
            (1, append_entries_handler),
        ];
        let mut server = RpcServer::new_with_services(services);
        try!(
            server.bind((config.me.1.ip(), config.me.1.port()))
            .and_then(|_| {
                server.repl()
            })
        );

        // TODO: Should peers be a map of id->PeerHandle. I.E. Will we ever need to send a message
        // to a specific peer?

        // 2. Start peer threads.
        let peers = config.cluster.into_iter()
            .filter(|&(id, addr)| id != me.0) // filter all computers that aren't me
            .map(|(id, addr)| Peer::start(addr, tx.clone()))
            .collect::<Vec<PeerHandle>>();

        let log = Arc::new(Mutex::new(MemoryLog::new()));

        let state = Arc::new(Mutex::new(ServerState {
            current_state: State::FOLLOWER,
            current_term: 0,
            current_index: 0,
            voted_for: None,
            last_leader_contact: Instant::now()
        }));

        // 3. Construct server state object.
        Ok(Server {
            state: state,
            log: log,
            peers: peers,
            me: me,
            last_heartbeat: Instant::now()
        })
    }

    ///
    /// Write |entry| to the log and try to replicate it across all servers.
    /// This function is non-blocking; it simply forwards AppendEntries messages
    /// to all known peers.
    ///
    fn send_append_entries(&mut self) {
        unimplemented!();
        //self.last_heartbeat = Instant::now();
    }

    ///
    /// Aggregate peer's append entries response into server state
    ///
    fn aggregate_append_entries_reply(&self, message: AppendEntriesReply) {
        unimplemented!();
    }

    ///
    /// Update commit_index count to the most recent log entry with quorum.
    ///
    fn update_commit_index(&self) {
        unimplemented!();
    }

    ///
    /// Starts a new election by requesting votes from all peers
    /// If the election is successful then the server transitions into the LEADER state
    /// Otherwise the leader stays in the candidate state.
    /// The assumption is that the caller will start another election
    ///
    fn start_election(&self, mut state: MutexGuard<ServerState>) {
        { // state lock scope
            // move the lock into this scope
            let mut locked_state = state;
            // transition to the candidate state
            let last_log_index = locked_state.current_index;
            let last_log_term = locked_state.current_term;
            locked_state.current_state = State::CANDIDATE;
            locked_state.current_term += 1;
            locked_state.current_index = 0;
            locked_state.voted_for = Some(self.me.0); // vote for ourselves
            // tell each peer to send out RequestToVote RPCs
            let request_vote_message = RequestVoteMessage {
                term: locked_state.current_term,
                candidate_id: self.me.0,
                last_log_index: last_log_index,
                last_log_term: last_log_term
            };
            let ref peers = self.peers;
            for peer in peers {
                peer.to_peer.send(PeerThreadMessage::RequestVote(request_vote_message))
                    .unwrap(); // panic if the peer thread is down
            }
        }
        unimplemented!();
    }
}

struct AppendEntriesHandler {
    to_main: Mutex<Sender<MainThreadMessage>>,
}

impl RpcObject for AppendEntriesHandler {
    fn handle_rpc (&self, params: capnp::any_pointer::Reader, result: capnp::any_pointer::Builder)
        -> Result<(), RpcError>
    {
        // TODO: If this is a valid rpc from the leader, update last_leader_contact

        // TODO: If we're in the CANDIDATE state and this leader's term is >= our current term
        //

        // TODO (syd) implement
        // 1. Ensure prevLogIndex matches our own.
        // 2. Append outstanding log entries.
        // 3. Construct reply.
        params.get_as::<append_entries::Reader>()
           .map(|append_entries| {
               result.init_as::<append_entries_reply::Builder>().set_success(true);
           })
           .map_err(RpcError::Capnp)
    }
}
<|endoftext|>


<commit_before>extern crate cgmath;
extern crate froggy;
#[macro_use]
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;

use std::{mem, time};
use cgmath::{Angle, EuclideanSpace, One, Rotation3, Transform, Zero};
use gfx::traits::{Device, Factory, FactoryExt};

pub type ColorFormat = gfx::format::Srgba8;
pub type DepthFormat = gfx::format::DepthStencil;

gfx_defines!{
    vertex Vertex {
        pos: [f32; 4] = "a_Pos",
        normal: [i8; 4] = "a_Normal",
    }

    vertex Instance {
        offset_scale: [f32; 4] = "a_OffsetScale",
        rotation: [f32; 4] = "a_Rotation",
        color: [f32; 4] = "a_Color",
    }

    constant Globals {
        projection: [[f32; 4]; 4] = "u_Projection",
        camera_pos: [f32; 4] = "u_CameraPos",
        light_pos: [f32; 4] = "u_LightPos",
        light_color: [f32; 4] = "u_LightColor",
    }

    pipeline pipe {
        vert_buf: gfx::VertexBuffer<Vertex> = (),
        inst_buf: gfx::InstanceBuffer<Instance> = (),
        globals: gfx::ConstantBuffer<Globals> = "b_Globals",
        out_color: gfx::RenderTarget<ColorFormat> = "Target0",
        out_depth: gfx::DepthTarget<DepthFormat> = gfx::preset::depth::LESS_EQUAL_WRITE,
    }
}

fn vertex(x: i8, y: i8, z: i8, nx: i8, ny: i8, nz: i8) -> Vertex {
    Vertex {
        pos: [x as f32, y as f32, z as f32, 1.0],
        normal: [nx, ny, nz, 0],
    }
}

fn create_geometry<R: gfx::Resources, F: gfx::Factory<R>>(factory: &mut F)
                   -> (gfx::handle::Buffer<R, Vertex>, gfx::Slice<R>)
{
    let vertices = [
        // bottom
        vertex(1, 1, 0, 0, 0, -1),
        vertex(1, -1, 0, 0, 0, -1),
        vertex(-1, -1, 0, 0, 0, -1),
        vertex(-1, 1, 0, 0, 0, -1),
        // top
        vertex(1, 1, 2, 0, 0, 1),
        vertex(1, -1, 2, 0, 0, 1),
        vertex(-1, -1, 2, 0, 0, 1),
        vertex(-1, 1, 2, 0, 0, 1),
        // left
        vertex(-1, 1, 2, -1, 0, 0),
        vertex(-1, 1, 0, -1, 0, 0),
        vertex(-1, -1, 0, -1, 0, 0),
        vertex(-1, -1, 2, -1, 0, 0),
        // right
        vertex(1, 1, 2, 1, 0, 0),
        vertex(1, 1, 0, 1, 0, 0),
        vertex(1, -1, 0, 1, 0, 0),
        vertex(1, -1, 2, 1, 0, 0),
        // front
        vertex(1, -1, 2, 0, -1, 0),
        vertex(1, -1, 0, 0, -1, 0),
        vertex(-1, -1, 0, 0, -1, 0),
        vertex(-1, -1, 2, 0, -1, 0),
        // back
        vertex(1, 1, 2, 0, 1, 0),
        vertex(1, 1, 0, 0, 1, 0),
        vertex(-1, 1, 0, 0, 1, 0),
        vertex(-1, 1, 2, 0, 1, 0),
    ];

    let indices = [
        0u16, 1, 2, 0, 2, 3,
        4, 5, 6, 4, 6, 7,
        8, 9, 10, 8, 10, 11,
        12, 13, 14, 12, 14, 15,
        16, 17, 18, 16, 18, 19,
        20, 21, 22, 20, 22, 23,
    ];

    factory.create_vertex_buffer_with_slice(&vertices, &indices[..])
}

type Space = cgmath::Decomposed<cgmath::Vector3<f32>, cgmath::Quaternion<f32>>;

#[derive(Clone)]
struct Level {
    color: [f32; 4],
    speed: f32,
}

struct Node {
    local: Space,
    world: Space,
    parent: Option<froggy::Pointer<Node>>,
}

struct Cube {
    node: froggy::Pointer<Node>,
    level: froggy::Pointer<Level>,
}

fn create_cubes(mut nodes: froggy::WriteLock<Node>,
                level_pointers: &[froggy::Pointer<Level>])
                -> Vec<Cube>
{
    let mut list = vec![
        Cube {
            node: nodes.create(Node {
                local: Space {
                    disp: cgmath::Vector3::zero(),
                    rot: cgmath::Quaternion::one(),
                    scale: 2.0,
                },
                world: Space::one(),
                parent: None,
            }),
            level: level_pointers[0].clone(),
        }
    ];
    struct Stack {
        parent: froggy::Pointer<Node>,
        level_id: usize,
    }
    let mut stack = vec![
        Stack {
            parent: list[0].node.clone(),
            level_id: 0,
        }
    ];

    let axis = [cgmath::Vector3::unit_z(),
                cgmath::Vector3::unit_x(), -cgmath::Vector3::unit_x(),
                cgmath::Vector3::unit_y(), -cgmath::Vector3::unit_y()];
    let children: Vec<_> = axis.iter().map(|&axe| {
        Space {
            disp: cgmath::vec3(0.0, 0.0, 1.0),
            rot: cgmath::Quaternion::from_axis_angle(axe, cgmath::Rad::turn_div_4()),
            scale: 1.0,
        }.concat(&Space {
            disp: cgmath::vec3(0.0, 0.0, 1.0),
            rot: cgmath::Quaternion::one(),
            scale: 0.4,
        })
    }).collect();

    while let Some(next) = stack.pop() {
        let level = match level_pointers.get(next.level_id + 1) {
            Some(ref level) => level.clone(),
            None => continue,
        };
        for child in children.iter() {
            let cube = Cube {
                node: nodes.create(Node {
                    local: child.clone(),
                    world: Space::one(),
                    parent: Some(next.parent.clone()),
                }),
                level: level.clone(),
            };
            stack.push(Stack {
                parent: cube.node.clone(),
                level_id: next.level_id + 1,
            });
            list.push(cube);
        }
    }

    list
}

fn make_globals(camera_pos: cgmath::Point3<f32>, aspect: f32) -> Globals {
    let mx_proj = {
        let fovy = cgmath::Deg(60.0);
        let perspective = cgmath::perspective(fovy, aspect, 1.0, 100.0);
        let focus = cgmath::Point3::new(0.0, 0.0, 3.0);
        let view = cgmath::Matrix4::look_at(
            camera_pos, focus, cgmath::Vector3::unit_z());
        perspective * view
    };
    Globals {
        projection: mx_proj.into(),
        camera_pos: camera_pos.to_vec().extend(1.0).into(),
        light_pos: [0.0, -10.0, 10.0, 1.0],
        light_color: [1.0, 1.0, 1.0, 1.0],
    }
}

fn main() {
    // feed Froggy
    let node_store = froggy::Storage::new();
    let level_store = froggy::Storage::new();

    let level_pointers = {
        let mut levels = level_store.write();
        [
            levels.create(Level {
                color: [1.0, 1.0, 0.5, 1.0],
                speed: 0.7,
            }),
            levels.create(Level {
                color: [0.5, 0.5, 1.0, 1.0],
                speed: -1.0,
            }),
            levels.create(Level {
                color: [0.5, 1.0, 0.5, 1.0],
                speed: 1.5,
            }),
            levels.create(Level {
                color: [1.0, 0.5, 0.5, 1.0],
                speed: -2.0,
            }),
            levels.create(Level {
                color: [0.5, 1.0, 1.0, 1.0],
                speed: 2.5,
            }),
            levels.create(Level {
                color: [1.0, 0.5, 1.0, 1.0],
                speed: -3.0,
            }),
        ]
    };
    let mut cubes = create_cubes(node_store.write(), &level_pointers);
    println!("Initialized {} cubes on {} levels", cubes.len(), level_pointers.len());

    // init window and graphics
    let builder = glutin::WindowBuilder::new()
        .with_title("Froggy Cubes demo".to_string())
        .with_vsync();
    let (window, mut device, mut factory, main_color, main_depth) =
        gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder);
    let mut encoder = gfx::Encoder::from(factory.create_command_buffer());

    let (cube_vbuf, mut cube_slice) = create_geometry(&mut factory);
    let cube_ibuf = factory.create_buffer(cubes.len(),
        gfx::buffer::Role::Vertex, gfx::memory::Usage::Dynamic, gfx::Bind::empty()
        ).unwrap();

    // init global parameters
    let camera_pos = cgmath::Point3::new(-1.8, -8.0, 3.0);
    let globals = {
        let (w, h, _, _) = main_color.get_dimensions();
        make_globals(camera_pos, w as f32 / h as f32)
    };
    let global_buf = factory.create_constant_buffer(1);
    encoder.update_constant_buffer(&global_buf, &globals);

    // init pipeline states
    let pso = factory.create_pipeline_simple(
        include_bytes!("vert.glsl"),
        include_bytes!("frag.glsl"),
        pipe::new()
        ).unwrap();
    let mut data = pipe::Data {
        vert_buf: cube_vbuf,
        inst_buf: cube_ibuf,
        globals: global_buf,
        out_color: main_color,
        out_depth: main_depth,
    };

    let mut instances = Vec::new();
    let mut moment = time::Instant::now();

    'main: loop {
        // process events
        for event in window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::Closed => break 'main,
                glutin::Event::Resized(width, height) => {
                    gfx_window_glutin::update_views(&window, &mut data.out_color, &mut data.out_depth);
                    let globals = make_globals(camera_pos, width as f32 / height as f32);
                    encoder.update_constant_buffer(&data.globals, &globals);
                },
                _ => (),
            }
        }
        // get time delta
        let duration = moment.elapsed();
        let delta = duration.as_secs() as f32 + (duration.subsec_nanos() as f32 * 1.0e-9);
        moment = time::Instant::now();

        // Note: the following 3 passes could be combined into one for efficiency.
        // This is not the goal of the demo though. It is made with an assuption that
        // the scenegraph and its logic is separate from the main game, and that
        // more processing is done in parallel.

        // animate local spaces
        {
            let mut nodes = node_store.write();
            let levels = level_store.read();
            for cube in cubes.iter_mut() {
                let node = nodes.access(&cube.node);
                let level = levels.access(&cube.level);
                let angle = cgmath::Rad(delta * level.speed);
                node.local.concat_self(&Space {
                    disp: cgmath::Vector3::zero(),
                    rot: cgmath::Quaternion::from_angle_z(angle),
                    scale: 1.0,
                });
            }
        }

        // re-compute world spaces
        {
            let mut nodes = node_store.write();
            let mut dummy = Node {
                local: Space::one(),
                world: Space::one(),
                parent: None,
            };
            for i in 0 .. nodes.len() {
                // replacing with dummy instead of cloning here - to avoid the refcount bumps
                let mut node = mem::replace(&mut nodes[i], dummy);
                node.world = match node.parent {
                    Some(ref parent) => nodes.access(parent).world.concat(&node.local),
                    None => node.local,
                };
                dummy = mem::replace(&mut nodes[i], node);
            }
        }

        // update instancing CPU info
        instances.clear();
        {
            let mut nodes = node_store.write();
            let levels = level_store.read();
            for cube in cubes.iter_mut() {
                let level = levels.access(&cube.level);
                let space = &nodes.access(&cube.node).world;
                instances.push(Instance {
                    offset_scale: space.disp.extend(space.scale).into(),
                    rotation: space.rot.v.extend(space.rot.s).into(),
                    color: level.color,
                });
            }
        }

        // update instancing GPU info
        cube_slice.instances = Some((instances.len() as gfx::InstanceCount, 0));
        encoder.update_buffer(&data.inst_buf, &instances, 0).unwrap();

        // draw -- start
        encoder.clear_depth(&data.out_depth, 1.0);
        encoder.clear(&data.out_color, [0.1, 0.2, 0.3, 1.0]);
        encoder.draw(&cube_slice, &pso, &data);
        // draw -- end
        encoder.flush(&mut device);
        window.swap_buffers().unwrap();
        device.cleanup();
    }
}
<commit_msg>Cubes - moved out the materials from levels<commit_after>extern crate cgmath;
extern crate froggy;
#[macro_use]
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;

use std::{mem, time};
use cgmath::{Angle, EuclideanSpace, One, Rotation3, Transform, Zero};
use gfx::traits::{Device, Factory, FactoryExt};

pub type ColorFormat = gfx::format::Srgba8;
pub type DepthFormat = gfx::format::DepthStencil;

gfx_defines!{
    vertex Vertex {
        pos: [f32; 4] = "a_Pos",
        normal: [i8; 4] = "a_Normal",
    }

    vertex Instance {
        offset_scale: [f32; 4] = "a_OffsetScale",
        rotation: [f32; 4] = "a_Rotation",
        color: [f32; 4] = "a_Color",
    }

    constant Globals {
        projection: [[f32; 4]; 4] = "u_Projection",
        camera_pos: [f32; 4] = "u_CameraPos",
        light_pos: [f32; 4] = "u_LightPos",
        light_color: [f32; 4] = "u_LightColor",
    }

    pipeline pipe {
        vert_buf: gfx::VertexBuffer<Vertex> = (),
        inst_buf: gfx::InstanceBuffer<Instance> = (),
        globals: gfx::ConstantBuffer<Globals> = "b_Globals",
        out_color: gfx::RenderTarget<ColorFormat> = "Target0",
        out_depth: gfx::DepthTarget<DepthFormat> = gfx::preset::depth::LESS_EQUAL_WRITE,
    }
}

fn vertex(x: i8, y: i8, z: i8, nx: i8, ny: i8, nz: i8) -> Vertex {
    Vertex {
        pos: [x as f32, y as f32, z as f32, 1.0],
        normal: [nx, ny, nz, 0],
    }
}

fn create_geometry<R: gfx::Resources, F: gfx::Factory<R>>(factory: &mut F)
                   -> (gfx::handle::Buffer<R, Vertex>, gfx::Slice<R>)
{
    let vertices = [
        // bottom
        vertex(1, 1, 0, 0, 0, -1),
        vertex(1, -1, 0, 0, 0, -1),
        vertex(-1, -1, 0, 0, 0, -1),
        vertex(-1, 1, 0, 0, 0, -1),
        // top
        vertex(1, 1, 2, 0, 0, 1),
        vertex(1, -1, 2, 0, 0, 1),
        vertex(-1, -1, 2, 0, 0, 1),
        vertex(-1, 1, 2, 0, 0, 1),
        // left
        vertex(-1, 1, 2, -1, 0, 0),
        vertex(-1, 1, 0, -1, 0, 0),
        vertex(-1, -1, 0, -1, 0, 0),
        vertex(-1, -1, 2, -1, 0, 0),
        // right
        vertex(1, 1, 2, 1, 0, 0),
        vertex(1, 1, 0, 1, 0, 0),
        vertex(1, -1, 0, 1, 0, 0),
        vertex(1, -1, 2, 1, 0, 0),
        // front
        vertex(1, -1, 2, 0, -1, 0),
        vertex(1, -1, 0, 0, -1, 0),
        vertex(-1, -1, 0, 0, -1, 0),
        vertex(-1, -1, 2, 0, -1, 0),
        // back
        vertex(1, 1, 2, 0, 1, 0),
        vertex(1, 1, 0, 0, 1, 0),
        vertex(-1, 1, 0, 0, 1, 0),
        vertex(-1, 1, 2, 0, 1, 0),
    ];

    let indices = [
        0u16, 1, 2, 0, 2, 3,
        4, 5, 6, 4, 6, 7,
        8, 9, 10, 8, 10, 11,
        12, 13, 14, 12, 14, 15,
        16, 17, 18, 16, 18, 19,
        20, 21, 22, 20, 22, 23,
    ];

    factory.create_vertex_buffer_with_slice(&vertices, &indices[..])
}

type Space = cgmath::Decomposed<cgmath::Vector3<f32>, cgmath::Quaternion<f32>>;

struct Level {
    speed: f32,
}

struct Material {
    color: [f32; 4],
}

struct Node {
    local: Space,
    world: Space,
    parent: Option<froggy::Pointer<Node>>,
}

struct Cube {
    node: froggy::Pointer<Node>,
    material: froggy::Pointer<Material>,
    level: froggy::Pointer<Level>,
}

fn create_cubes(mut nodes: froggy::WriteLock<Node>,
                materials: froggy::ReadLock<Material>,
                levels: froggy::ReadLock<Level>)
                -> Vec<Cube>
{
    let mut list = vec![
        Cube {
            node: nodes.create(Node {
                local: Space {
                    disp: cgmath::Vector3::zero(),
                    rot: cgmath::Quaternion::one(),
                    scale: 2.0,
                },
                world: Space::one(),
                parent: None,
            }),
            material: materials.pin(0).unwrap(),
            level: levels.pin(0).unwrap(),
        }
    ];
    struct Stack {
        parent: froggy::Pointer<Node>,
        level_id: usize,
    }
    let mut stack = vec![
        Stack {
            parent: list[0].node.clone(),
            level_id: 0,
        }
    ];

    let axis = [cgmath::Vector3::unit_z(),
                cgmath::Vector3::unit_x(), -cgmath::Vector3::unit_x(),
                cgmath::Vector3::unit_y(), -cgmath::Vector3::unit_y()];
    let children: Vec<_> = axis.iter().map(|&axe| {
        Space {
            disp: cgmath::vec3(0.0, 0.0, 1.0),
            rot: cgmath::Quaternion::from_axis_angle(axe, cgmath::Rad::turn_div_4()),
            scale: 1.0,
        }.concat(&Space {
            disp: cgmath::vec3(0.0, 0.0, 1.0),
            rot: cgmath::Quaternion::one(),
            scale: 0.4,
        })
    }).collect();

    while let Some(next) = stack.pop() {
        //HACK: materials are indexed the same way as levels
        // it's fine for demostration purposes
        let material = match materials.pin(next.level_id + 1) {
            Some(material) => material,
            None => continue,
        };
        let level = match levels.pin(next.level_id + 1) {
            Some(level) => level,
            None => continue,
        };
        for child in children.iter() {
            let cube = Cube {
                node: nodes.create(Node {
                    local: child.clone(),
                    world: Space::one(),
                    parent: Some(next.parent.clone()),
                }),
                material: material.clone(),
                level: level.clone(),
            };
            stack.push(Stack {
                parent: cube.node.clone(),
                level_id: next.level_id + 1,
            });
            list.push(cube);
        }
    }

    list
}

fn make_globals(camera_pos: cgmath::Point3<f32>, aspect: f32) -> Globals {
    let mx_proj = {
        let fovy = cgmath::Deg(60.0);
        let perspective = cgmath::perspective(fovy, aspect, 1.0, 100.0);
        let focus = cgmath::Point3::new(0.0, 0.0, 3.0);
        let view = cgmath::Matrix4::look_at(
            camera_pos, focus, cgmath::Vector3::unit_z());
        perspective * view
    };
    Globals {
        projection: mx_proj.into(),
        camera_pos: camera_pos.to_vec().extend(1.0).into(),
        light_pos: [0.0, -10.0, 10.0, 1.0],
        light_color: [1.0, 1.0, 1.0, 1.0],
    }
}

const COLORS: [[f32; 4]; 6] = [
    [1.0, 1.0, 0.5, 1.0],
    [0.5, 0.5, 1.0, 1.0],
    [0.5, 1.0, 0.5, 1.0],
    [1.0, 0.5, 0.5, 1.0],
    [0.5, 1.0, 1.0, 1.0],
    [1.0, 0.5, 1.0, 1.0],
];

const SPEEDS: [f32; 6] = [
    0.7, -1.0, 1.3, -1.6, 1.9, -2.2
];

fn main() {
    // feed Froggy
    let node_store = froggy::Storage::new();
    let material_store = froggy::Storage::new();
    {
        let mut materials = material_store.write();
        for &color in COLORS.iter() {
            materials.create(Material {
                color: color,
            });
        }
    }
    let level_store = froggy::Storage::new();
    {
        let mut levels = level_store.write();
        for &speed in SPEEDS.iter() {
            levels.create(Level {
                speed: speed,
            });
        }
    }

    //Note: we populated the storages, but the returned pointers are already dropped.
    // Thus, all will be lost if we lock for writing now, but locking for reading retains the
    // contents, and cube creation will add references to them, so they will stay alive.
    let mut cubes = create_cubes(node_store.write(), material_store.read(), level_store.read());
    println!("Initialized {} cubes on {} levels", cubes.len(), SPEEDS.len());

    // init window and graphics
    let builder = glutin::WindowBuilder::new()
        .with_title("Froggy Cube-seption".to_string())
        .with_vsync();
    let (window, mut device, mut factory, main_color, main_depth) =
        gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder);
    let mut encoder = gfx::Encoder::from(factory.create_command_buffer());

    let (cube_vbuf, mut cube_slice) = create_geometry(&mut factory);
    let cube_ibuf = factory.create_buffer(cubes.len(),
        gfx::buffer::Role::Vertex, gfx::memory::Usage::Dynamic, gfx::Bind::empty()
        ).unwrap();

    // init global parameters
    let camera_pos = cgmath::Point3::new(-1.8, -8.0, 3.0);
    let globals = {
        let (w, h, _, _) = main_color.get_dimensions();
        make_globals(camera_pos, w as f32 / h as f32)
    };
    let global_buf = factory.create_constant_buffer(1);
    encoder.update_constant_buffer(&global_buf, &globals);

    // init pipeline states
    let pso = factory.create_pipeline_simple(
        include_bytes!("vert.glsl"),
        include_bytes!("frag.glsl"),
        pipe::new()
        ).unwrap();
    let mut data = pipe::Data {
        vert_buf: cube_vbuf,
        inst_buf: cube_ibuf,
        globals: global_buf,
        out_color: main_color,
        out_depth: main_depth,
    };

    let mut instances = Vec::new();
    let mut moment = time::Instant::now();

    'main: loop {
        // process events
        for event in window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::Closed => break 'main,
                glutin::Event::Resized(width, height) => {
                    gfx_window_glutin::update_views(&window, &mut data.out_color, &mut data.out_depth);
                    let globals = make_globals(camera_pos, width as f32 / height as f32);
                    encoder.update_constant_buffer(&data.globals, &globals);
                },
                _ => (),
            }
        }
        // get time delta
        let duration = moment.elapsed();
        let delta = duration.as_secs() as f32 + (duration.subsec_nanos() as f32 * 1.0e-9);
        moment = time::Instant::now();

        // Note: the following 3 passes could be combined into one for efficiency.
        // This is not the goal of the demo though. It is made with an assuption that
        // the scenegraph and its logic is separate from the main game, and that
        // more processing is done in parallel.

        // animate local spaces
        {
            let mut nodes = node_store.write();
            let levels = level_store.read();
            for cube in cubes.iter_mut() {
                let node = nodes.access(&cube.node);
                let level = levels.access(&cube.level);
                let angle = cgmath::Rad(delta * level.speed);
                node.local.concat_self(&Space {
                    disp: cgmath::Vector3::zero(),
                    rot: cgmath::Quaternion::from_angle_z(angle),
                    scale: 1.0,
                });
            }
        }

        // re-compute world spaces
        {
            let mut nodes = node_store.write();
            let mut dummy = Node {
                local: Space::one(),
                world: Space::one(),
                parent: None,
            };
            for i in 0 .. nodes.len() {
                // replacing with dummy instead of cloning here - to avoid the refcount bumps
                let mut node = mem::replace(&mut nodes[i], dummy);
                node.world = match node.parent {
                    Some(ref parent) => nodes.access(parent).world.concat(&node.local),
                    None => node.local,
                };
                dummy = mem::replace(&mut nodes[i], node);
            }
        }

        // update instancing CPU info
        instances.clear();
        {
            let mut nodes = node_store.write();
            let materials = material_store.read();
            for cube in cubes.iter_mut() {
                let material = materials.access(&cube.material);
                let space = &nodes.access(&cube.node).world;
                instances.push(Instance {
                    offset_scale: space.disp.extend(space.scale).into(),
                    rotation: space.rot.v.extend(space.rot.s).into(),
                    color: material.color,
                });
            }
        }

        // update instancing GPU info
        cube_slice.instances = Some((instances.len() as gfx::InstanceCount, 0));
        encoder.update_buffer(&data.inst_buf, &instances, 0).unwrap();

        // draw -- start
        encoder.clear_depth(&data.out_depth, 1.0);
        encoder.clear(&data.out_color, [0.1, 0.2, 0.3, 1.0]);
        encoder.draw(&cube_slice, &pso, &data);
        // draw -- end
        encoder.flush(&mut device);
        window.swap_buffers().unwrap();
        device.cleanup();
    }
}
<|endoftext|>


<commit_before>use node;
use time;
use std::collections::VecDeque;

pub const POLL_FREQUENCY_MS: u64 = 50;
pub const TRIES: u8 = 5;

#[test]
fn node_ping() {
   let alpha = node::Node::new().unwrap();
   let beta  = node::Node::new().unwrap();
   let beta_seed = beta.local_info();
   let span = time::Duration::seconds(1);

   // Bootstrapping alpha:
   assert!(alpha.bootstrap_until(beta_seed, 1).is_ok());

   let beta_receptions = alpha.receptions().during(span).from(beta.id().clone());

   // Alpha pings beta.
   assert!(alpha.ping(beta.resources.id.clone()).is_ok());
   assert_eq!(1, beta_receptions.count());
}

#[test]
fn reception_iterator_times_out_correctly() {
   let alpha = node::Node::new().unwrap();
   let span = time::Duration::seconds(1);
   let maximum = time::Duration::seconds(3);
   let receptions = alpha.receptions().during(span);

   let before = time::SteadyTime::now();

   // nothing is happening, so this should time out in around a second (not necessarily precise)
   assert_eq!(0, receptions.count());

   let after = time::SteadyTime::now();

   assert!(after - before < maximum);
}

#[test]
fn bootstrapping_and_finding_on_simulated_network() {

   let mut nodes: VecDeque<node::Node> = (0..100).map(|_| { node::Node::new().unwrap() }).collect();
   {
      let origin = node::Node::new().unwrap();
      // Initial handshake pass
      for node in nodes.iter() {
         assert!(node.bootstrap_until(origin.local_info(), 1).is_ok());
      }
      // Actual bootstrapping
      for node in nodes.iter() {
         assert!(node.bootstrap(origin.local_info()).is_ok());
      }
   }

   // Head finds tail in a few steps.
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();

   assert_eq!(head.find_node(tail.id()).unwrap().id, tail.local_info().id);
}

#[test]
fn finding_on_simulated_unresponsive_network() {

   let mut nodes: VecDeque<node::Node> = (0..100).map(|_| { node::Node::new().unwrap() }).collect();

   {
      let origin = node::Node::new().unwrap();

      // Initial handshake pass
      for node in nodes.iter() {
         assert!(node.bootstrap_until(origin.local_info(), 1).is_ok());
      }

      println!("The origin node knows of {} nodes", origin.resources.table.len());
      // Actual bootstrapping
      for node in nodes.iter() {
         assert!(node.bootstrap(origin.local_info()).is_ok());
      }
   }

   nodes.drain(30..70);
   assert_eq!(nodes.len(), 60);

   // Head finds tail in a few steps.
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();

   assert_eq!(head.find_node(tail.id()).unwrap().id, tail.local_info().id);
}

<commit_msg>Removed trace<commit_after>use node;
use time;
use std::collections::VecDeque;

pub const POLL_FREQUENCY_MS: u64 = 50;
pub const TRIES: u8 = 5;

#[test]
fn node_ping() {
   let alpha = node::Node::new().unwrap();
   let beta  = node::Node::new().unwrap();
   let beta_seed = beta.local_info();
   let span = time::Duration::seconds(1);

   // Bootstrapping alpha:
   assert!(alpha.bootstrap_until(beta_seed, 1).is_ok());

   let beta_receptions = alpha.receptions().during(span).from(beta.id().clone());

   // Alpha pings beta.
   assert!(alpha.ping(beta.resources.id.clone()).is_ok());
   assert_eq!(1, beta_receptions.count());
}

#[test]
fn reception_iterator_times_out_correctly() {
   let alpha = node::Node::new().unwrap();
   let span = time::Duration::seconds(1);
   let maximum = time::Duration::seconds(3);
   let receptions = alpha.receptions().during(span);

   let before = time::SteadyTime::now();

   // nothing is happening, so this should time out in around a second (not necessarily precise)
   assert_eq!(0, receptions.count());

   let after = time::SteadyTime::now();

   assert!(after - before < maximum);
}

#[test]
fn bootstrapping_and_finding_on_simulated_network() {

   let mut nodes: VecDeque<node::Node> = (0..100).map(|_| { node::Node::new().unwrap() }).collect();
   {
      let origin = node::Node::new().unwrap();
      // Initial handshake pass
      for node in nodes.iter() {
         assert!(node.bootstrap_until(origin.local_info(), 1).is_ok());
      }
      // Actual bootstrapping
      for node in nodes.iter() {
         assert!(node.bootstrap(origin.local_info()).is_ok());
      }
   }

   // Head finds tail in a few steps.
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();

   assert_eq!(head.find_node(tail.id()).unwrap().id, tail.local_info().id);
}

#[test]
fn finding_on_simulated_unresponsive_network() {

   let mut nodes: VecDeque<node::Node> = (0..100).map(|_| { node::Node::new().unwrap() }).collect();

   {
      let origin = node::Node::new().unwrap();

      // Initial handshake pass
      for node in nodes.iter() {
         assert!(node.bootstrap_until(origin.local_info(), 1).is_ok());
      }

      // Actual bootstrapping
      for node in nodes.iter() {
         assert!(node.bootstrap(origin.local_info()).is_ok());
      }
   }

   nodes.drain(30..70);
   assert_eq!(nodes.len(), 60);

   // Head finds tail in a few steps.
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();

   assert_eq!(head.find_node(tail.id()).unwrap().id, tail.local_info().id);
}

<|endoftext|>


<commit_before>// Portions of this file are Copyright 2014 The Rust Project Developers.
// See http://rust-lang.org/COPYRIGHT.

use libc;
use {Errno, Result};
use std::mem;
use std::ptr;

pub use libc::{
    SIGHUP,
    SIGINT,
    SIGQUIT,
    SIGILL,
    SIGABRT,
    SIGFPE,
    SIGKILL,
    SIGSEGV,
    SIGPIPE,
    SIGALRM,
    SIGTERM,
    SIGTRAP,
    SIGIOT,
    SIGBUS,
    SIGSYS,
    SIGURG,
    SIGSTOP,
    SIGTSTP,
    SIGCONT,
    SIGCHLD,
    SIGTTIN,
    SIGTTOU,
    SIGIO,
    SIGXCPU,
    SIGXFSZ,
    SIGVTALRM,
    SIGPROF,
    SIGWINCH,
    SIGUSR1,
    SIGUSR2,
};

// This doesn't always exist, but when it does, it's 7
pub const SIGEMT: libc::c_int = 7;

pub const NSIG: libc::c_int = 32;

bitflags!{
    flags SaFlags: libc::c_int {
        const SA_NOCLDSTOP = libc::SA_NOCLDSTOP,
        const SA_NOCLDWAIT = libc::SA_NOCLDWAIT,
        const SA_NODEFER   = libc::SA_NODEFER,
        const SA_ONSTACK   = libc::SA_ONSTACK,
        const SA_RESETHAND = libc::SA_RESETHAND,
        const SA_RESTART   = libc::SA_RESTART,
        const SA_SIGINFO   = libc::SA_SIGINFO,
    }
}

bitflags!{
    flags SigFlags: libc::c_int {
        const SIG_BLOCK   = libc::SIG_BLOCK,
        const SIG_UNBLOCK = libc::SIG_UNBLOCK,
        const SIG_SETMASK = libc::SIG_SETMASK,
    }
}

#[derive(Clone, Copy)]
pub struct SigSet {
    sigset: libc::sigset_t
}

pub type SigNum = libc::c_int;

impl SigSet {
    pub fn all() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn empty() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn add(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn clear(&mut self) -> Result<()> {
        let res = unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };

        Errno::result(res).map(drop)
    }

    pub fn remove(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn extend(&mut self, other: &SigSet) -> Result<()> {
        for i in 1..NSIG {
            if try!(other.contains(i)) {
                try!(self.add(i));
            }
        }
        Ok(())
    }

    pub fn contains(&self, signum: SigNum) -> Result<bool> {
        let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signum) };

        match try!(Errno::result(res)) {
            1 => Ok(true),
            0 => Ok(false),
            _ => unreachable!("unexpected value from sigismember"),
        }
    }

    /// Gets the currently blocked (masked) set of signals for the calling thread.
    pub fn thread_get_mask() -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(SigFlags::empty(), None, Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Sets the set of signals as the signal mask for the calling thread.
    pub fn thread_set_mask(&self) -> Result<()> {
        pthread_sigmask(SIG_SETMASK, Some(self), None)
    }

    /// Adds the set of signals to the signal mask for the calling thread.
    pub fn thread_block(&self) -> Result<()> {
        pthread_sigmask(SIG_BLOCK, Some(self), None)
    }

    /// Removes the set of signals from the signal mask for the calling thread.
    pub fn thread_unblock(&self) -> Result<()> {
        pthread_sigmask(SIG_UNBLOCK, Some(self), None)
    }

    /// Sets the set of signals as the signal mask, and returns the old mask.
    pub fn thread_swap_mask(&self, how: SigFlags) -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(how, Some(self), Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Suspends execution of the calling thread until one of the signals in the
    /// signal mask becomes pending, and returns the accepted signal.
    pub fn wait(&self) -> Result<SigNum> {
        let mut signum: SigNum = unsafe { mem::uninitialized() };
        let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };

        Errno::result(res).map(|_| signum)
    }
}

impl AsRef<libc::sigset_t> for SigSet {
    fn as_ref(&self) -> &libc::sigset_t {
        &self.sigset
    }
}

#[allow(unknown_lints)]
#[cfg_attr(not(raw_pointer_derive_allowed), allow(raw_pointer_derive))]
#[derive(Clone, Copy, PartialEq)]
pub enum SigHandler {
    SigDfl,
    SigIgn,
    Handler(extern fn(SigNum)),
    SigAction(extern fn(SigNum, *mut libc::siginfo_t, *mut libc::c_void))
}

pub struct SigAction {
    sigaction: libc::sigaction
}

impl SigAction {
    /// This function will set or unset the flag `SA_SIGINFO` depending on the
    /// type of the `handler` argument.
    pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
        let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
        s.sa_sigaction = match handler {
            SigHandler::SigDfl => unsafe { mem::transmute(libc::SIG_DFL) },
            SigHandler::SigIgn => unsafe { mem::transmute(libc::SIG_IGN) },
            SigHandler::Handler(f) => unsafe { mem::transmute(f) },
            SigHandler::SigAction(f) => unsafe { mem::transmute(f) },
        };
        s.sa_flags = match handler {
            SigHandler::SigAction(_) => (flags | SA_SIGINFO).bits(),
            _ => (flags - SA_SIGINFO).bits(),
        };
        s.sa_mask = mask.sigset;

        SigAction { sigaction: s }
    }
}

pub unsafe fn sigaction(signum: SigNum, sigaction: &SigAction) -> Result<SigAction> {
    let mut oldact = mem::uninitialized::<libc::sigaction>();

    let res =
        libc::sigaction(signum, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);

    Errno::result(res).map(|_| SigAction { sigaction: oldact })
}

/// Manages the signal mask (set of blocked signals) for the calling thread.
///
/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
/// and no modification will take place.
///
/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
///
/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
/// and then it will be updated with `set`.
///
/// If both `set` and `oldset` is None, this function is a no-op.
///
/// For more information, visit the [pthread_sigmask](http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html),
/// or [sigprocmask](http://man7.org/linux/man-pages/man2/sigprocmask.2.html) man pages.
pub fn pthread_sigmask(how: SigFlags,
                       set: Option<&SigSet>,
                       oldset: Option<&mut SigSet>) -> Result<()> {
    if set.is_none() && oldset.is_none() {
        return Ok(())
    }

    let res = unsafe {
        // if set or oldset is None, pass in null pointers instead
        libc::pthread_sigmask(how.bits(),
                             set.map_or_else(|| ptr::null::<libc::sigset_t>(),
                                             |s| &s.sigset as *const libc::sigset_t),
                             oldset.map_or_else(|| ptr::null_mut::<libc::sigset_t>(),
                                                |os| &mut os.sigset as *mut libc::sigset_t))
    };

    Errno::result(res).map(drop)
}

pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
    let res = unsafe { libc::kill(pid, signum) };

    Errno::result(res).map(drop)
}

pub fn raise(signum: SigNum) -> Result<()> {
    let res = unsafe { libc::raise(signum) };

    Errno::result(res).map(drop)
}

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

    #[test]
    fn test_contains() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert_eq!(mask.contains(SIGUSR1), Ok(true));
        assert_eq!(mask.contains(SIGUSR2), Ok(false));

        let all = SigSet::all();
        assert_eq!(all.contains(SIGUSR1), Ok(true));
        assert_eq!(all.contains(SIGUSR2), Ok(true));
    }

    #[test]
    fn test_clear() {
        let mut set = SigSet::all();
        set.clear().unwrap();
        for i in 1..NSIG {
            assert_eq!(set.contains(i), Ok(false));
        }
    }

    #[test]
    fn test_extend() {
        let mut one_signal = SigSet::empty();
        one_signal.add(SIGUSR1).unwrap();

        let mut two_signals = SigSet::empty();
        two_signals.add(SIGUSR2).unwrap();
        two_signals.extend(&one_signal).unwrap();

        assert_eq!(two_signals.contains(SIGUSR1), Ok(true));
        assert_eq!(two_signals.contains(SIGUSR2), Ok(true));
    }

    #[test]
    fn test_thread_signal_block() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert!(mask.thread_block().is_ok());
    }

    #[test]
    fn test_thread_signal_swap() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.thread_block().unwrap();

        assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1).unwrap());

        let mask2 = SigSet::empty();
        mask.add(SIGUSR2).unwrap();

        let oldmask = mask2.thread_swap_mask(SIG_SETMASK).unwrap();

        assert!(oldmask.contains(SIGUSR1).unwrap());
        assert!(!oldmask.contains(SIGUSR2).unwrap());
    }

    // TODO(#251): Re-enable after figuring out flakiness.
    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    #[test]
    fn test_sigwait() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.add(SIGUSR2).unwrap();
        mask.thread_block().unwrap();

        raise(SIGUSR1).unwrap();
        assert_eq!(mask.wait().unwrap(), SIGUSR1);
    }
}
<commit_msg>Add missing signals.<commit_after>// Portions of this file are Copyright 2014 The Rust Project Developers.
// See http://rust-lang.org/COPYRIGHT.

use libc;
use {Errno, Result};
use std::mem;
use std::ptr;

pub use libc::{
    SIGHUP,
    SIGINT,
    SIGQUIT,
    SIGILL,
    SIGTRAP,
    SIGABRT,
    SIGBUS,
    SIGFPE,
    SIGKILL,
    SIGUSR1,
    SIGSEGV,
    SIGUSR2,
    SIGPIPE,
    SIGALRM,
    SIGTERM,
    SIGCHLD,
    SIGCONT,
    SIGSTOP,
    SIGTSTP,
    SIGTTIN,
    SIGTTOU,
    SIGURG,
    SIGXCPU,
    SIGXFSZ,
    SIGVTALRM,
    SIGPROF,
    SIGWINCH,
    SIGIO,
    SIGSYS,
};

#[cfg(target_os = "macos")]
pub use libc::{
    SIGEMT,
    SIGINFO,
};

#[cfg(not(target_os = "macos"))]
pub use libc::{
    SIGPWR,
    SIGSTKFLT,
    SIGIOT, // Alias for SIGABRT
    SIGPOLL, // Alias for SIGIO
    SIGUNUSED, // Alias for 31
};

pub const NSIG: libc::c_int = 32;

bitflags!{
    flags SaFlags: libc::c_int {
        const SA_NOCLDSTOP = libc::SA_NOCLDSTOP,
        const SA_NOCLDWAIT = libc::SA_NOCLDWAIT,
        const SA_NODEFER   = libc::SA_NODEFER,
        const SA_ONSTACK   = libc::SA_ONSTACK,
        const SA_RESETHAND = libc::SA_RESETHAND,
        const SA_RESTART   = libc::SA_RESTART,
        const SA_SIGINFO   = libc::SA_SIGINFO,
    }
}

bitflags!{
    flags SigFlags: libc::c_int {
        const SIG_BLOCK   = libc::SIG_BLOCK,
        const SIG_UNBLOCK = libc::SIG_UNBLOCK,
        const SIG_SETMASK = libc::SIG_SETMASK,
    }
}

#[derive(Clone, Copy)]
pub struct SigSet {
    sigset: libc::sigset_t
}

pub type SigNum = libc::c_int;

impl SigSet {
    pub fn all() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn empty() -> SigSet {
        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
        let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn add(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn clear(&mut self) -> Result<()> {
        let res = unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };

        Errno::result(res).map(drop)
    }

    pub fn remove(&mut self, signum: SigNum) -> Result<()> {
        let res = unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signum) };

        Errno::result(res).map(drop)
    }

    pub fn extend(&mut self, other: &SigSet) -> Result<()> {
        for i in 1..NSIG {
            if try!(other.contains(i)) {
                try!(self.add(i));
            }
        }
        Ok(())
    }

    pub fn contains(&self, signum: SigNum) -> Result<bool> {
        let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signum) };

        match try!(Errno::result(res)) {
            1 => Ok(true),
            0 => Ok(false),
            _ => unreachable!("unexpected value from sigismember"),
        }
    }

    /// Gets the currently blocked (masked) set of signals for the calling thread.
    pub fn thread_get_mask() -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(SigFlags::empty(), None, Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Sets the set of signals as the signal mask for the calling thread.
    pub fn thread_set_mask(&self) -> Result<()> {
        pthread_sigmask(SIG_SETMASK, Some(self), None)
    }

    /// Adds the set of signals to the signal mask for the calling thread.
    pub fn thread_block(&self) -> Result<()> {
        pthread_sigmask(SIG_BLOCK, Some(self), None)
    }

    /// Removes the set of signals from the signal mask for the calling thread.
    pub fn thread_unblock(&self) -> Result<()> {
        pthread_sigmask(SIG_UNBLOCK, Some(self), None)
    }

    /// Sets the set of signals as the signal mask, and returns the old mask.
    pub fn thread_swap_mask(&self, how: SigFlags) -> Result<SigSet> {
        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
        try!(pthread_sigmask(how, Some(self), Some(&mut oldmask)));
        Ok(oldmask)
    }

    /// Suspends execution of the calling thread until one of the signals in the
    /// signal mask becomes pending, and returns the accepted signal.
    pub fn wait(&self) -> Result<SigNum> {
        let mut signum: SigNum = unsafe { mem::uninitialized() };
        let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };

        Errno::result(res).map(|_| signum)
    }
}

impl AsRef<libc::sigset_t> for SigSet {
    fn as_ref(&self) -> &libc::sigset_t {
        &self.sigset
    }
}

#[allow(unknown_lints)]
#[cfg_attr(not(raw_pointer_derive_allowed), allow(raw_pointer_derive))]
#[derive(Clone, Copy, PartialEq)]
pub enum SigHandler {
    SigDfl,
    SigIgn,
    Handler(extern fn(SigNum)),
    SigAction(extern fn(SigNum, *mut libc::siginfo_t, *mut libc::c_void))
}

pub struct SigAction {
    sigaction: libc::sigaction
}

impl SigAction {
    /// This function will set or unset the flag `SA_SIGINFO` depending on the
    /// type of the `handler` argument.
    pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
        let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
        s.sa_sigaction = match handler {
            SigHandler::SigDfl => unsafe { mem::transmute(libc::SIG_DFL) },
            SigHandler::SigIgn => unsafe { mem::transmute(libc::SIG_IGN) },
            SigHandler::Handler(f) => unsafe { mem::transmute(f) },
            SigHandler::SigAction(f) => unsafe { mem::transmute(f) },
        };
        s.sa_flags = match handler {
            SigHandler::SigAction(_) => (flags | SA_SIGINFO).bits(),
            _ => (flags - SA_SIGINFO).bits(),
        };
        s.sa_mask = mask.sigset;

        SigAction { sigaction: s }
    }
}

pub unsafe fn sigaction(signum: SigNum, sigaction: &SigAction) -> Result<SigAction> {
    let mut oldact = mem::uninitialized::<libc::sigaction>();

    let res =
        libc::sigaction(signum, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);

    Errno::result(res).map(|_| SigAction { sigaction: oldact })
}

/// Manages the signal mask (set of blocked signals) for the calling thread.
///
/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
/// and no modification will take place.
///
/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
///
/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
/// and then it will be updated with `set`.
///
/// If both `set` and `oldset` is None, this function is a no-op.
///
/// For more information, visit the [pthread_sigmask](http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html),
/// or [sigprocmask](http://man7.org/linux/man-pages/man2/sigprocmask.2.html) man pages.
pub fn pthread_sigmask(how: SigFlags,
                       set: Option<&SigSet>,
                       oldset: Option<&mut SigSet>) -> Result<()> {
    if set.is_none() && oldset.is_none() {
        return Ok(())
    }

    let res = unsafe {
        // if set or oldset is None, pass in null pointers instead
        libc::pthread_sigmask(how.bits(),
                             set.map_or_else(|| ptr::null::<libc::sigset_t>(),
                                             |s| &s.sigset as *const libc::sigset_t),
                             oldset.map_or_else(|| ptr::null_mut::<libc::sigset_t>(),
                                                |os| &mut os.sigset as *mut libc::sigset_t))
    };

    Errno::result(res).map(drop)
}

pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
    let res = unsafe { libc::kill(pid, signum) };

    Errno::result(res).map(drop)
}

pub fn raise(signum: SigNum) -> Result<()> {
    let res = unsafe { libc::raise(signum) };

    Errno::result(res).map(drop)
}

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

    #[test]
    fn test_contains() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert_eq!(mask.contains(SIGUSR1), Ok(true));
        assert_eq!(mask.contains(SIGUSR2), Ok(false));

        let all = SigSet::all();
        assert_eq!(all.contains(SIGUSR1), Ok(true));
        assert_eq!(all.contains(SIGUSR2), Ok(true));
    }

    #[test]
    fn test_clear() {
        let mut set = SigSet::all();
        set.clear().unwrap();
        for i in 1..NSIG {
            assert_eq!(set.contains(i), Ok(false));
        }
    }

    #[test]
    fn test_extend() {
        let mut one_signal = SigSet::empty();
        one_signal.add(SIGUSR1).unwrap();

        let mut two_signals = SigSet::empty();
        two_signals.add(SIGUSR2).unwrap();
        two_signals.extend(&one_signal).unwrap();

        assert_eq!(two_signals.contains(SIGUSR1), Ok(true));
        assert_eq!(two_signals.contains(SIGUSR2), Ok(true));
    }

    #[test]
    fn test_thread_signal_block() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();

        assert!(mask.thread_block().is_ok());
    }

    #[test]
    fn test_thread_signal_swap() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.thread_block().unwrap();

        assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1).unwrap());

        let mask2 = SigSet::empty();
        mask.add(SIGUSR2).unwrap();

        let oldmask = mask2.thread_swap_mask(SIG_SETMASK).unwrap();

        assert!(oldmask.contains(SIGUSR1).unwrap());
        assert!(!oldmask.contains(SIGUSR2).unwrap());
    }

    // TODO(#251): Re-enable after figuring out flakiness.
    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    #[test]
    fn test_sigwait() {
        let mut mask = SigSet::empty();
        mask.add(SIGUSR1).unwrap();
        mask.add(SIGUSR2).unwrap();
        mask.thread_block().unwrap();

        raise(SIGUSR1).unwrap();
        assert_eq!(mask.wait().unwrap(), SIGUSR1);
    }
}
<|endoftext|>


<commit_before>use std::io::{self, ErrorKind, Write};

use futures::{future, Future, BoxFuture};
use tokio_core::io::{Io, Codec, Framed, EasyBuf};
use tokio_proto::TcpServer;
use tokio_proto::pipeline::ServerProto;
use tokio_service::Service;

use tcp::framed::BytesCodec;

<commit_msg>tcp server<commit_after>use std::io::{self, ErrorKind, Write};
use std::sync::Arc;

use tokio_service::{Service, NewService};
use tokio_proto::TcpServer;
use futures::{future, Future, BoxFuture};

use tcp::framed::BytesCodec;
use tcp::proto::BytesProto;

pub type ServerCallback = Fn(Vec<u8>) -> Vec<u8> + Send + Sync;

pub struct Server {
    callback: Arc<Box<ServerCallback>>
}

pub struct NewServer {
    callback: Arc<Box<ServerCallback>>
}

impl Service for Server {

    type Request = Vec<u8>;
    type Response = Vec<u8>;
    type Error = io::Error;
    type Future = BoxFuture<Vec<u8>, io::Error>;

    fn call(&mut self, req: Self::Request) -> Self::Future {
        future::finished((self.callback) (req)).boxed()
    }
}

impl NewService for NewServer {

    type Request = Vec<u8>;
    type Response = Vec<u8>;
    type Error = io::Error;
    type Instance = Server;

    fn new_service(&self) -> io::Result<Self::Instance> {
        Ok(Server{
          callback: self.callback.clone()
        })
    }
}

impl Server {
    pub fn new(addr: String, callback: Box<ServerCallback>) {
        let addr = addr.parse().unwrap();
        let new_server = NewServer {
            callback: Arc::new(callback)
        };
        TcpServer::new(BytesProto, addr).serve(new_server);
    }
}
<|endoftext|>