<commit_before>use syntax_definition::*;
use scope::*;
use onig::{self, Region};
use std::usize;
use std::i32;

#[derive(Debug, Clone)]
pub struct ParseState {
    stack: Vec<StateLevel>,
    pub scope_stack: ScopeStack,
    first_line: bool,
}

#[derive(Debug, Clone)]
struct StateLevel {
    context: ContextPtr,
    prototype: Option<ContextPtr>,
    captures: Option<(Region, String)>,
}

#[derive(Debug)]
struct RegexMatch {
    regions: Region,
    context: ContextPtr,
    pat_index: usize,
}

impl ParseState {
    pub fn new(syntax: &SyntaxDefinition) -> ParseState {
        let start_state = StateLevel {
            context: syntax.contexts["main"].clone(),
            prototype: None,
            captures: None,
        };
        let mut scope_stack = ScopeStack::new();
        scope_stack.push(syntax.scope);
        ParseState {
            stack: vec![start_state],
            scope_stack: scope_stack,
            first_line: true,
        }
    }

    pub fn parse_line(&mut self, line: &str) -> Vec<(usize, ScopeStackOp)> {
        assert!(self.stack.len() > 0,
                "Somehow main context was popped from the stack");
        let mut match_start = 0;
        let mut res = Vec::new();
        // TODO push file syntax on first line
        // TODO set regex parameters correctly for start of file
        while self.parse_next_token(line, &mut match_start, &mut res) {
        }
        // apply operations to our scope to keep up
        // TODO do we even need to keep a scope stack in the parser state?
        for &(_, ref op) in res.iter() {
            self.scope_stack.apply(op);
        }
        return res;
    }

    fn parse_next_token(&mut self,
                        line: &str,
                        start: &mut usize,
                        ops: &mut Vec<(usize, ScopeStackOp)>)
                        -> bool {
        let cur_match = {
            let cur_level = &self.stack[self.stack.len() - 1];
            let mut min_start = usize::MAX;
            let mut cur_match: Option<RegexMatch> = None;
            let context_chain = self.stack
                .iter()
                .filter_map(|lvl| lvl.prototype.as_ref().map(|x| x.clone()))
                .chain(Some(cur_level.context.clone()).into_iter());
            for ctx in context_chain {
                for (pat_context_ptr, pat_index) in context_iter(ctx) {
                    let pat_context = pat_context_ptr.borrow();
                    let match_pat = pat_context.match_at(pat_index);

                    // println!("{:?}", match_pat.regex_str);
                    let refs_regex = if cur_level.captures.is_some() && match_pat.regex.is_none() {
                        let &(ref region, ref s) = cur_level.captures.as_ref().unwrap();
                        Some(match_pat.compile_with_refs(region, s))
                    } else {
                        None
                    };
                    let regex = if let Some(ref rgx) = refs_regex {
                        rgx
                    } else {
                        match_pat.regex.as_ref().unwrap()
                    };
                    let mut regions = Region::new();
                    // TODO caching
                    let matched = regex.search_with_options(line,
                                                            *start,
                                                            line.len(),
                                                            onig::SEARCH_OPTION_NONE,
                                                            Some(&mut regions));
                    if let Some(match_start) = matched {
                        let match_end = regions.pos(0).unwrap().1;
                        // this is necessary to avoid infinite looping on dumb patterns
                        let does_something = match match_pat.operation {
                            MatchOperation::None => match_start != match_end,
                            _ => true,
                        };
                        if match_start < min_start && does_something {
                            min_start = match_start;
                            // TODO pass by immutable ref and re-use context and regions
                            cur_match = Some(RegexMatch {
                                regions: regions,
                                context: pat_context_ptr.clone(),
                                pat_index: pat_index,
                            });
                        }
                    }
                }
            }
            cur_match
        };

        if let Some(reg_match) = cur_match {
            let (_, match_end) = reg_match.regions.pos(0).unwrap();
            *start = match_end;
            self.exec_pattern(line, reg_match, ops);
            true
        } else {
            false
        }
    }

    fn exec_pattern(&mut self,
                    line: &str,
                    reg_match: RegexMatch,
                    ops: &mut Vec<(usize, ScopeStackOp)>) {
        let (match_start, match_end) = reg_match.regions.pos(0).unwrap();
        let context = reg_match.context.borrow();
        let pat = context.match_at(reg_match.pat_index);
        // println!("running pattern {}", pat.regex_str);

        self.push_meta_ops(true, match_start, &*context, &pat.operation, ops);
        for s in pat.scope.iter() {
            ops.push((match_start, ScopeStackOp::Push(s.clone())));
        }
        if let Some(ref capture_map) = pat.captures {
            // captures could appear in an arbitrary order, have to produce ops in right order
            // ex: ((bob)|(hi))* could match hibob in wrong order, and outer has to push first
            // we don't have to handle a capture matching multiple times, Sublime doesn't
            let mut map: Vec<((usize, i32), ScopeStackOp)> = Vec::new();
            for (cap_index, scopes) in capture_map.iter() {
                if let Some((cap_start, cap_end)) = reg_match.regions.pos(*cap_index) {
                    for scope in scopes.iter() {
                        map.push(((cap_start, -((cap_end - cap_start) as i32)),
                                  ScopeStackOp::Push(scope.clone())));
                    }
                    map.push(((cap_end, i32::MIN), ScopeStackOp::Pop(scopes.len())));
                }
            }
            map.sort_by(|a, b| a.0.cmp(&b.0));
            for ((index, _), op) in map.into_iter() {
                ops.push((index, op));
            }
        }
        if !pat.scope.is_empty() {
            ops.push((match_end, ScopeStackOp::Pop(pat.scope.len())));
        }
        self.push_meta_ops(false, match_end, &*context, &pat.operation, ops);

        self.perform_op(line, &reg_match.regions, pat);
    }

    fn push_meta_ops(&self,
                     initial: bool,
                     index: usize,
                     cur_context: &Context,
                     match_op: &MatchOperation,
                     ops: &mut Vec<(usize, ScopeStackOp)>) {
        match match_op {
            &MatchOperation::Push(ref context_refs) |
            &MatchOperation::Set(ref context_refs) => {
                for r in context_refs {
                    let ctx_ptr = r.resolve();
                    let ctx = ctx_ptr.borrow();
                    let v = if initial {
                        &ctx.meta_scope
                    } else {
                        &ctx.meta_content_scope
                    };
                    for scope in v.iter() {
                        ops.push((index, ScopeStackOp::Push(scope.clone())));
                    }
                }
            }
            &MatchOperation::Pop => {
                let v = if initial {
                    &cur_context.meta_content_scope
                } else {
                    &cur_context.meta_scope
                };
                if !v.is_empty() {
                    ops.push((index, ScopeStackOp::Pop(v.len())));
                }
            }
            &MatchOperation::None => (),
        }
    }

    fn perform_op(&mut self, line: &str, regions: &Region, pat: &MatchPattern) {
        let ctx_refs = match pat.operation {
            MatchOperation::Push(ref ctx_refs) => ctx_refs,
            MatchOperation::Set(ref ctx_refs) => {
                self.stack.pop();
                ctx_refs
            }
            MatchOperation::Pop => {
                self.stack.pop();
                return;
            }
            MatchOperation::None => return,
        };
        for (i, r) in ctx_refs.iter().enumerate() {
            let proto = if i == 0 {
                pat.with_prototype.clone()
            } else {
                None
            };
            let ctx_ptr = r.resolve();
            let captures = {
                let ctx = ctx_ptr.borrow();
                if ctx.uses_backrefs {
                    // TODO maybe move the Region instead of cloning
                    Some((regions.clone(), line.to_owned()))
                } else {
                    None
                }
            };
            self.stack.push(StateLevel {
                context: ctx_ptr,
                prototype: proto,
                captures: captures,
            });
        }
    }
}

#[cfg(test)]
mod tests {
    use package_set::PackageSet;
    use parser::*;
    use scope::*;
    use util::debug_print_ops;

    #[test]
    fn can_parse() {
        use scope::ScopeStackOp::{Push, Pop};
        let ps = PackageSet::load_from_folder("testdata/Packages").unwrap();
        let mut state = {
            let syntax = ps.find_syntax_by_name("Ruby on Rails").unwrap();
            ParseState::new(syntax)
        };
        let mut state2 = {
            let syntax = ps.find_syntax_by_name("HTML (Rails)").unwrap();
            ParseState::new(syntax)
        };

        let line = "module Bob::Wow::Troll::Five; 5; end";
        let ops = state.parse_line(line);
        debug_print_ops(line, &ops);

        let test_ops = vec![
            (0, Push(Scope::new("meta.module.ruby").unwrap())),
            (0, Push(Scope::new("keyword.control.module.ruby").unwrap())),
            (6, Pop(1)),
            (7, Push(Scope::new("entity.name.type.module.ruby").unwrap())),
            (7, Push(Scope::new("entity.other.inherited-class.module.first.ruby").unwrap())),
            (10, Push(Scope::new("punctuation.separator.inheritance.ruby").unwrap())),
            (12, Pop(1)),
            (12, Pop(1)),
        ];
        assert_eq!(&ops[0..test_ops.len()], &test_ops[..]);

        let line2 = "def lol(wow = 5)";
        let ops2 = state.parse_line(line2);
        debug_print_ops(line2, &ops2);
        let test_ops2 =
            vec![(0, Push(Scope::new("meta.function.method.with-arguments.ruby").unwrap())),
                 (0, Push(Scope::new("keyword.control.def.ruby").unwrap())),
                 (3, Pop(1)),
                 (4, Push(Scope::new("entity.name.function.ruby").unwrap())),
                 (7, Pop(1)),
                 (7, Push(Scope::new("punctuation.definition.parameters.ruby").unwrap())),
                 (8, Pop(1)),
                 (8, Push(Scope::new("variable.parameter.function.ruby").unwrap())),
                 (12, Push(Scope::new("keyword.operator.assignment.ruby").unwrap())),
                 (13, Pop(1)),
                 (14, Push(Scope::new("constant.numeric.ruby").unwrap())),
                 (15, Pop(1)),
                 (15, Pop(1)),
                 (15, Push(Scope::new("punctuation.definition.parameters.ruby").unwrap())),
                 (16, Pop(1)),
                 (16, Pop(1))];
        assert_eq!(ops2, test_ops2);

        let line3 = "<script>var lol = '<% def wow(";
        let ops3 = state2.parse_line(line3);
        debug_print_ops(line3, &ops3);
        let mut test_stack = ScopeStack::new();
        test_stack.push(Scope::new("text.html.ruby").unwrap());
        test_stack.push(Scope::new("text.html.basic").unwrap());
        test_stack.push(Scope::new("source.js.embedded.html").unwrap());
        test_stack.push(Scope::new("string.quoted.single.js").unwrap());
        test_stack.push(Scope::new("source.ruby.rails.embedded.html").unwrap());
        test_stack.push(Scope::new("meta.function.method.with-arguments.ruby").unwrap());
        test_stack.push(Scope::new("variable.parameter.function.ruby").unwrap());
        println!("{:?}", state2.scope_stack);
        println!("{:?}", test_stack);
        assert_eq!(state2.scope_stack, test_stack);

        // for testing backrefs
        let line4 = "lol = <<-END wow END";
        let ops4 = state.parse_line(line4);
        debug_print_ops(line4, &ops4);
        let test_ops4 = vec![
            (4, Push(Scope::new("keyword.operator.assignment.ruby").unwrap())),
            (5, Pop(1)),
            (6, Push(Scope::new("string.unquoted.heredoc.ruby").unwrap())),
            (6, Push(Scope::new("punctuation.definition.string.begin.ruby").unwrap())),
            (12, Pop(1)),
            (16, Push(Scope::new("punctuation.definition.string.end.ruby").unwrap())),
            (20, Pop(1)),
            (20, Pop(1)),
        ];
        assert_eq!(ops4, test_ops4);

        // assert!(false);
    }
}
<commit_msg>Fix not popping meta scopes on set operation<commit_after>use syntax_definition::*;
use scope::*;
use onig::{self, Region};
use std::usize;
use std::i32;

#[derive(Debug, Clone)]
pub struct ParseState {
    stack: Vec<StateLevel>,
    pub scope_stack: ScopeStack,
    first_line: bool,
}

#[derive(Debug, Clone)]
struct StateLevel {
    context: ContextPtr,
    prototype: Option<ContextPtr>,
    captures: Option<(Region, String)>,
}

#[derive(Debug)]
struct RegexMatch {
    regions: Region,
    context: ContextPtr,
    pat_index: usize,
}

impl ParseState {
    pub fn new(syntax: &SyntaxDefinition) -> ParseState {
        let start_state = StateLevel {
            context: syntax.contexts["main"].clone(),
            prototype: None,
            captures: None,
        };
        let mut scope_stack = ScopeStack::new();
        scope_stack.push(syntax.scope);
        ParseState {
            stack: vec![start_state],
            scope_stack: scope_stack,
            first_line: true,
        }
    }

    pub fn parse_line(&mut self, line: &str) -> Vec<(usize, ScopeStackOp)> {
        assert!(self.stack.len() > 0,
                "Somehow main context was popped from the stack");
        let mut match_start = 0;
        let mut res = Vec::new();
        // TODO push file syntax on first line
        // TODO set regex parameters correctly for start of file
        while self.parse_next_token(line, &mut match_start, &mut res) {
        }
        // apply operations to our scope to keep up
        // TODO do we even need to keep a scope stack in the parser state?
        for &(_, ref op) in res.iter() {
            self.scope_stack.apply(op);
        }
        return res;
    }

    fn parse_next_token(&mut self,
                        line: &str,
                        start: &mut usize,
                        ops: &mut Vec<(usize, ScopeStackOp)>)
                        -> bool {
        let cur_match = {
            let cur_level = &self.stack[self.stack.len() - 1];
            let mut min_start = usize::MAX;
            let mut cur_match: Option<RegexMatch> = None;
            let context_chain = self.stack
                .iter()
                .filter_map(|lvl| lvl.prototype.as_ref().map(|x| x.clone()))
                .chain(Some(cur_level.context.clone()).into_iter());
            for ctx in context_chain {
                for (pat_context_ptr, pat_index) in context_iter(ctx) {
                    let pat_context = pat_context_ptr.borrow();
                    let match_pat = pat_context.match_at(pat_index);

                    // println!("{:?}", match_pat.regex_str);
                    let refs_regex = if cur_level.captures.is_some() && match_pat.regex.is_none() {
                        let &(ref region, ref s) = cur_level.captures.as_ref().unwrap();
                        Some(match_pat.compile_with_refs(region, s))
                    } else {
                        None
                    };
                    let regex = if let Some(ref rgx) = refs_regex {
                        rgx
                    } else {
                        match_pat.regex.as_ref().unwrap()
                    };
                    let mut regions = Region::new();
                    // TODO caching
                    let matched = regex.search_with_options(line,
                                                            *start,
                                                            line.len(),
                                                            onig::SEARCH_OPTION_NONE,
                                                            Some(&mut regions));
                    if let Some(match_start) = matched {
                        let match_end = regions.pos(0).unwrap().1;
                        // this is necessary to avoid infinite looping on dumb patterns
                        let does_something = match match_pat.operation {
                            MatchOperation::None => match_start != match_end,
                            _ => true,
                        };
                        if match_start < min_start && does_something {
                            min_start = match_start;
                            // TODO pass by immutable ref and re-use context and regions
                            cur_match = Some(RegexMatch {
                                regions: regions,
                                context: pat_context_ptr.clone(),
                                pat_index: pat_index,
                            });
                        }
                    }
                }
            }
            cur_match
        };

        if let Some(reg_match) = cur_match {
            let (_, match_end) = reg_match.regions.pos(0).unwrap();
            *start = match_end;
            self.exec_pattern(line, reg_match, ops);
            true
        } else {
            false
        }
    }

    fn exec_pattern(&mut self,
                    line: &str,
                    reg_match: RegexMatch,
                    ops: &mut Vec<(usize, ScopeStackOp)>) {
        let (match_start, match_end) = reg_match.regions.pos(0).unwrap();
        let context = reg_match.context.borrow();
        let pat = context.match_at(reg_match.pat_index);
        // println!("running pattern {:?}", pat);

        self.push_meta_ops(true, match_start, &*context, &pat.operation, ops);
        for s in pat.scope.iter() {
            // println!("pushing {:?} at {}", s, match_start);
            ops.push((match_start, ScopeStackOp::Push(s.clone())));
        }
        if let Some(ref capture_map) = pat.captures {
            // captures could appear in an arbitrary order, have to produce ops in right order
            // ex: ((bob)|(hi))* could match hibob in wrong order, and outer has to push first
            // we don't have to handle a capture matching multiple times, Sublime doesn't
            let mut map: Vec<((usize, i32), ScopeStackOp)> = Vec::new();
            for (cap_index, scopes) in capture_map.iter() {
                if let Some((cap_start, cap_end)) = reg_match.regions.pos(*cap_index) {
                    for scope in scopes.iter() {
                        map.push(((cap_start, -((cap_end - cap_start) as i32)),
                                  ScopeStackOp::Push(scope.clone())));
                    }
                    map.push(((cap_end, i32::MIN), ScopeStackOp::Pop(scopes.len())));
                }
            }
            map.sort_by(|a, b| a.0.cmp(&b.0));
            for ((index, _), op) in map.into_iter() {
                ops.push((index, op));
            }
        }
        if !pat.scope.is_empty() {
            ops.push((match_end, ScopeStackOp::Pop(pat.scope.len())));
        }
        self.push_meta_ops(false, match_end, &*context, &pat.operation, ops);

        self.perform_op(line, &reg_match.regions, pat);
    }

    fn push_meta_ops(&self,
                     initial: bool,
                     index: usize,
                     cur_context: &Context,
                     match_op: &MatchOperation,
                     ops: &mut Vec<(usize, ScopeStackOp)>) {
        let involves_pop = match match_op {
            &MatchOperation::Pop => true,
            &MatchOperation::Set(_) => true,
            &MatchOperation::Push(_) => false,
            &MatchOperation::None => false,
        };
        if involves_pop {
            let v = if initial {
                &cur_context.meta_content_scope
            } else {
                &cur_context.meta_scope
            };
            if !v.is_empty() {
                ops.push((index, ScopeStackOp::Pop(v.len())));
            }
        }
        match match_op {
            &MatchOperation::Push(ref context_refs) |
            &MatchOperation::Set(ref context_refs) => {
                for r in context_refs {
                    let ctx_ptr = r.resolve();
                    let ctx = ctx_ptr.borrow();
                    let v = if initial {
                        &ctx.meta_scope
                    } else {
                        &ctx.meta_content_scope
                    };
                    for scope in v.iter() {
                        ops.push((index, ScopeStackOp::Push(scope.clone())));
                    }
                }
            }
            &MatchOperation::None |
            &MatchOperation::Pop => (),
        }
    }

    fn perform_op(&mut self, line: &str, regions: &Region, pat: &MatchPattern) {
        let ctx_refs = match pat.operation {
            MatchOperation::Push(ref ctx_refs) => ctx_refs,
            MatchOperation::Set(ref ctx_refs) => {
                self.stack.pop();
                ctx_refs
            }
            MatchOperation::Pop => {
                self.stack.pop();
                return;
            }
            MatchOperation::None => return,
        };
        for (i, r) in ctx_refs.iter().enumerate() {
            let proto = if i == 0 {
                pat.with_prototype.clone()
            } else {
                None
            };
            let ctx_ptr = r.resolve();
            let captures = {
                let ctx = ctx_ptr.borrow();
                if ctx.uses_backrefs {
                    // TODO maybe move the Region instead of cloning
                    Some((regions.clone(), line.to_owned()))
                } else {
                    None
                }
            };
            self.stack.push(StateLevel {
                context: ctx_ptr,
                prototype: proto,
                captures: captures,
            });
        }
    }
}

#[cfg(test)]
mod tests {
    use package_set::PackageSet;
    use parser::*;
    use scope::*;
    use util::debug_print_ops;

    #[test]
    fn can_parse() {
        use scope::ScopeStackOp::{Push, Pop};
        let ps = PackageSet::load_from_folder("testdata/Packages").unwrap();
        let mut state = {
            let syntax = ps.find_syntax_by_name("Ruby on Rails").unwrap();
            ParseState::new(syntax)
        };
        let mut state2 = {
            let syntax = ps.find_syntax_by_name("HTML (Rails)").unwrap();
            ParseState::new(syntax)
        };

        let line = "module Bob::Wow::Troll::Five; 5; end";
        let ops = state.parse_line(line);
        debug_print_ops(line, &ops);

        let test_ops = vec![
            (0, Push(Scope::new("meta.module.ruby").unwrap())),
            (0, Push(Scope::new("keyword.control.module.ruby").unwrap())),
            (6, Pop(1)),
            (7, Push(Scope::new("entity.name.type.module.ruby").unwrap())),
            (7, Push(Scope::new("entity.other.inherited-class.module.first.ruby").unwrap())),
            (10, Push(Scope::new("punctuation.separator.inheritance.ruby").unwrap())),
            (12, Pop(1)),
            (12, Pop(1)),
        ];
        assert_eq!(&ops[0..test_ops.len()], &test_ops[..]);

        let line2 = "def lol(wow = 5)";
        let ops2 = state.parse_line(line2);
        debug_print_ops(line2, &ops2);
        let test_ops2 =
            vec![(0, Push(Scope::new("meta.function.method.with-arguments.ruby").unwrap())),
                 (0, Push(Scope::new("keyword.control.def.ruby").unwrap())),
                 (3, Pop(1)),
                 (4, Push(Scope::new("entity.name.function.ruby").unwrap())),
                 (7, Pop(1)),
                 (7, Push(Scope::new("punctuation.definition.parameters.ruby").unwrap())),
                 (8, Pop(1)),
                 (8, Push(Scope::new("variable.parameter.function.ruby").unwrap())),
                 (12, Push(Scope::new("keyword.operator.assignment.ruby").unwrap())),
                 (13, Pop(1)),
                 (14, Push(Scope::new("constant.numeric.ruby").unwrap())),
                 (15, Pop(1)),
                 (15, Pop(1)),
                 (15, Push(Scope::new("punctuation.definition.parameters.ruby").unwrap())),
                 (16, Pop(1)),
                 (16, Pop(1))];
        assert_eq!(ops2, test_ops2);

        let line3 = "<script>var lol = '<% def wow(";
        let ops3 = state2.parse_line(line3);
        debug_print_ops(line3, &ops3);
        let mut test_stack = ScopeStack::new();
        test_stack.push(Scope::new("text.html.ruby").unwrap());
        test_stack.push(Scope::new("text.html.basic").unwrap());
        test_stack.push(Scope::new("source.js.embedded.html").unwrap());
        test_stack.push(Scope::new("string.quoted.single.js").unwrap());
        test_stack.push(Scope::new("source.ruby.rails.embedded.html").unwrap());
        test_stack.push(Scope::new("meta.function.method.with-arguments.ruby").unwrap());
        test_stack.push(Scope::new("variable.parameter.function.ruby").unwrap());
        println!("{:?}", state2.scope_stack);
        println!("{:?}", test_stack);
        assert_eq!(state2.scope_stack, test_stack);

        // for testing backrefs
        let line4 = "lol = <<-END wow END";
        let ops4 = state.parse_line(line4);
        debug_print_ops(line4, &ops4);
        let test_ops4 = vec![
            (4, Push(Scope::new("keyword.operator.assignment.ruby").unwrap())),
            (5, Pop(1)),
            (6, Push(Scope::new("string.unquoted.heredoc.ruby").unwrap())),
            (6, Push(Scope::new("punctuation.definition.string.begin.ruby").unwrap())),
            (12, Pop(1)),
            (16, Push(Scope::new("punctuation.definition.string.end.ruby").unwrap())),
            (20, Pop(1)),
            (20, Pop(1)),
        ];
        assert_eq!(ops4, test_ops4);

        // assert!(false);
    }
}
<|endoftext|>


<commit_before>//! Endpoints for tagging rooms.
<commit_msg>Add tagging endpoints.<commit_after>//! Endpoints for tagging rooms.

/// PUT /_matrix/client/r0/user/{userId}/rooms/{roomId}/tags/{tag}
///
/// [Matrix spec link](http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-user-userid-rooms-roomid-tags-tag)
pub mod add_tag {
    use ruma_identifiers::{UserId, RoomId};
    use ruma_events::tag::TagInfo;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct PathParams {
        pub user_id: UserId,
        pub room_id: RoomId,
        pub tag: String
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = TagInfo;
        type PathParams = PathParams;
        type QueryParams = ();
        type Response = ();

        fn method() -> ::Method {
            ::Method::Put
        }

        fn request_path(params: Self::PathParams) -> String {
            format!(
                "/_matrix/client/r0/user/{}/rooms/{}/tags/{}",
                params.user_id,
                params.room_id,
                params.tag
            )
        }

        fn router_path() -> String {
            "/_matrix/client/r0/user/:user_id/rooms/:room_id/tags/:tag".to_string()
        }
    }
}

/// GET /_matrix/client/r0/user/{userId}/rooms/{roomId}/tags
///
/// [Matrix spec link](http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-user-userid-rooms-roomid-tags)
pub mod get_tags {
    use ruma_identifiers::{UserId, RoomId};
    use ruma_events::tag::TagEventContent;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct PathParams {
        pub user_id: UserId,
        pub room_id: RoomId
    }

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Response {
        pub tags: TagEventContent,
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = PathParams;
        type QueryParams = ();
        type Response = Response;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(params: Self::PathParams) -> String {
            format!(
                "/_matrix/client/r0/user/{}/rooms/{}/tags",
                params.user_id,
                params.room_id
            )
        }

        fn router_path() -> String {
            "/_matrix/client/r0/user/:user_id/rooms/:room_id/tags".to_string()
        }
    }
}

/// DELETE /_matrix/client/r0/user/{userId}/rooms/{roomId}/tags/{tag}
///
/// [Matrix spec link](http://matrix.org/docs/spec/client_server/r0.2.0.html#delete-matrix-client-r0-user-userid-rooms-roomid-tags-tag)
pub mod del_tag {
    use ruma_identifiers::{UserId, RoomId};

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct PathParams {
        pub user_id: UserId,
        pub room_id: RoomId,
        pub tag: String
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = PathParams;
        type QueryParams = ();
        type Response = ();

        fn method() -> ::Method {
            ::Method::Delete
        }

        fn request_path(params: Self::PathParams) -> String {
            format!(
                "/_matrix/client/r0/user/{}/rooms/{}/tags/{}",
                params.user_id,
                params.room_id,
                params.tag
            )
        }

        fn router_path() -> String {
            "/_matrix/client/r0/user/:user_id/rooms/:room_id/tags/:tag".to_string()
        }
    }
}
<|endoftext|>


<commit_before>use std::marker;
use std::ffi::CString;
use std::mem;
use std::ptr;

use libc::{c_char, size_t, c_uint, c_int};

use {raw, Error, Repository, Oid, Signature, Index, MergeOptions};
use build::CheckoutBuilder;
use util::Binding;

/// A structure representing a [rebase][1]
///
/// [1]: https://libgit2.github.com/libgit2/#HEAD/type/git_rebase
///
/// It has a lifetime of the repository it is attached to.
pub struct Rebase<'repo> {
    raw: *mut raw::git_rebase,
    _marker: marker::PhantomData<&'repo Repository>,
}

/// A structure representing a single [operation][2] to be performed during the rebase.
///
/// [2]: https://libgit2.github.com/libgit2/#HEAD/type/git_rebase_operation
///
/// It has a lifetime of the rebase it belongs to.
pub struct RebaseOperation<'rebase, 'repo: 'rebase> {
    raw: *mut raw::git_rebase_operation,
    _marker: marker::PhantomData<&'rebase Rebase<'repo>>,
}

/// Type of rebase operation
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum RebaseOperationType {
    /// The given commit is to be cherry-picked.
    /// The client should commit the changes and continue if there are no conflicts.
    Pick,
    /// The given commit is to be cherry-picked, but the client should prompt
    /// the user to provide an updated commit message.
    Reword,
    /// The given commit is to be cherry-picked, but the client should stop
    /// to allow the user to edit the changes before committing them.
    Edit,
    /// The given commit is to be squashed into the previous commit.
    /// The commit message will be merged with the previous message.
    Squash,
    /// The given commit is to be squashed into the previous commit.
    /// The commit message from this commit will be discarded.
    FixUp,
    /// No commit will be cherry-picked.  The client should run the given
    /// command and (if successful) continue
    Exec,
}

/// A structure representing options for a `rebase`
pub struct RebaseOptions<'a> {
    /// Version of rebase options, defined by `GIT_REBASE_OPTIONS_VERSION`
    pub version: usize,

    /// this will instruct other clients working
    /// on this `rebase` that you want a quiet rebase experience.
    /// This is provided for interoperability between Git tools
    pub quiet: bool,

    /// Perform an in-memory rebase, will not updated the repository to be in a rebasing-state
    /// or modify the working directory.
    pub in_memory: bool,

    /// The name of the notes reference used to rewrite notes
    /// for rebased commits when finishing the rebase
    pub rewrite_notes_ref: Option<CString>,

    /// Options to control how trees are merged during a `rebase`.
    pub merge_options: Option<MergeOptions>,

    /// Options to control how files are written during a `rebase`.
    pub checkout_options: Option<CheckoutBuilder<'a>>,
}

impl<'repo> Rebase<'repo> {
    /// Returns the number of applied operations.
    pub fn operation_count(&self) -> usize {
        unsafe { raw::git_rebase_operation_entrycount(self.raw) }
    }

    /// Aborts a rebase that is currently in progress,
    /// resetting the repository and working directory to their state before rebase began.
    pub fn abort(&mut self) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_rebase_abort(self.raw));
        }
        Ok(())
    }

    /// Commits the current patch.
    /// You must have resolved any conflicts
    /// that were introduced during the patch application from the `next` invocation.
    pub fn commit(&mut self,
                  author: &Signature,
                  committer: &Signature,
                  message: &str)
                  -> Result<Oid, Error> {
        let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] };
        let message = try!(CString::new(message));
        unsafe {
            try_call!(raw::git_rebase_commit(&mut raw,
                                             self.raw,
                                             author.raw(),
                                             committer.raw(),
                                             0 as *const c_char,
                                             message));
            Ok(Binding::from_raw(&raw as *const _))
        }
    }

    /// Finishes a rebase that is currently in progress once all patches have been applied.
    pub fn finish(&mut self, signature: &Signature) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_rebase_finish(self.raw, signature.raw()));
        }
        Ok(())
    }
    /// Gets the index produced by the last operation.
    /// This is useful for resolving conflicts in an in-memory rebase before committing them.
    pub fn inmemory_index(&self) -> Result<Index, Error> {
        let mut ret = 0 as *mut raw::git_index;
        unsafe {
            try_call!(raw::git_rebase_inmemory_index(&mut ret, self.raw));
            Ok(Binding::from_raw(ret))
        }
    }

    /// Performs the next rebase operation and returns the `RebaseOperation` about it.
    pub fn next(&mut self) -> Result<RebaseOperation, Error> {
        let mut ret = 0 as *mut raw::git_rebase_operation;
        unsafe {
            try_call!(raw::git_rebase_next(&mut ret, self.raw));
            Ok(Binding::from_raw(ret))
        }
    }

    /// Gets the rebase operation specified by the given index.
    pub fn operation_at_index(&self, index: usize) -> Option<RebaseOperation> {
        unsafe {
            let ptr = raw::git_rebase_operation_byindex(self.raw, index as size_t);
            if ptr.is_null() {
                None
            } else {
                Some(Binding::from_raw(ptr))
            }
        }
    }

    /// Gets the index of the rebase operation that is currently being applied.
    /// If the first operation has not yet been applied it returns `None`.
    pub fn current_operation_index(&self) -> Option<usize> {
        unsafe {
            let index = raw::git_rebase_operation_current(self.raw);
            if index == raw::GIT_REBASE_NO_OPERATION {
                None
            } else {
                Some(index as usize)
            }
        }
    }

    /// Convenience function to get the operation at the current index.
    /// Returns none if the first operation has not yet been applied.
    pub fn current_operation(&self) -> Option<RebaseOperation> {
        if let Some(index) = self.current_operation_index() {
            self.operation_at_index(index)
        } else {
            None
        }
    }
}

impl<'repo> Binding for Rebase<'repo> {
    type Raw = *mut raw::git_rebase;
    unsafe fn from_raw(raw: *mut raw::git_rebase) -> Rebase<'repo> {
        Rebase {
            raw: raw,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_rebase {
        self.raw
    }
}

impl<'repo> Drop for Rebase<'repo> {
    fn drop(&mut self) {
        unsafe { raw::git_rebase_free(self.raw) }
    }
}

impl<'rebase, 'repo: 'rebase> Binding for RebaseOperation<'rebase, 'repo> {
    type Raw = *mut raw::git_rebase_operation;
    unsafe fn from_raw(raw: *mut raw::git_rebase_operation) -> RebaseOperation<'rebase, 'repo> {
        RebaseOperation {
            raw: raw,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_rebase_operation {
        self.raw
    }
}

impl<'a> RebaseOptions<'a> {
    /// Initiate default set of rebase options.
    pub fn new() -> RebaseOptions<'a> {
        RebaseOptions {
            version: raw::GIT_REBASE_OPTIONS_VERSION as usize,
            quiet: false,
            in_memory: false,
            rewrite_notes_ref: None,
            merge_options: None,
            checkout_options: None,
        }
    }

    /// raw value of options
    pub unsafe fn raw(&mut self) -> Result<raw::git_rebase_options, Error> {
        let mut checkout_options: raw::git_checkout_options = mem::zeroed();
        try_call!(raw::git_checkout_init_options(&mut checkout_options,
                                                 raw::GIT_CHECKOUT_OPTIONS_VERSION));
        if let Some(ref mut opts) = self.checkout_options {
            opts.configure(&mut checkout_options);
        }
        let mut merge_options: raw::git_merge_options = mem::zeroed();
        if let Some(ref opts) = self.merge_options {
            ptr::copy(opts.raw(), &mut merge_options, 1);
        }

        Ok(raw::git_rebase_options {
               version: self.version as c_uint,
               quiet: self.quiet as c_int,
               inmemory: self.in_memory as c_int,
               rewrite_notes_ref: ::call::convert(&self.rewrite_notes_ref),
               merge_options: merge_options,
               checkout_options: checkout_options,
           })
    }
}

impl<'rebase, 'repo: 'rebase> RebaseOperation<'rebase, 'repo> {
    /// The type of `rebase` operation
    pub fn kind(&self) -> RebaseOperationType {
        unsafe { Binding::from_raw((*self.raw).kind) }
    }

    /// The commit ID being cherry-picked.  This will be populated for
    /// all operations except those of type `Exec`
    pub fn id(&self) -> Oid {
        unsafe { Binding::from_raw(&(*self.raw).id as *const raw::git_oid) }
    }
    /// The executable the user has requested be run.  This will only
    /// be populated for operations of type `Exec`
    pub fn exec(&self) -> Option<CString> {
        unsafe {
            if !(*self.raw).exec.is_null() {
                Some(CString::from_raw((*self.raw).exec as *mut c_char))
            } else {
                None
            }
        }
    }
}

impl Binding for RebaseOperationType {
    type Raw = raw::git_rebase_operation_t;
    unsafe fn from_raw(raw: raw::git_rebase_operation_t) -> RebaseOperationType {
        match raw {
            raw::GIT_REBASE_OPERATION_PICK => RebaseOperationType::Pick,
            raw::GIT_REBASE_OPERATION_REWORD => RebaseOperationType::Reword,
            raw::GIT_REBASE_OPERATION_EDIT => RebaseOperationType::Edit,
            raw::GIT_REBASE_OPERATION_SQUASH => RebaseOperationType::Squash,
            raw::GIT_REBASE_OPERATION_FIXUP => RebaseOperationType::FixUp,
            raw::GIT_REBASE_OPERATION_EXEC => RebaseOperationType::Exec,
            _ => panic!("Unknown rebase operation type: {}", raw),
        }
    }

    fn raw(&self) -> raw::git_rebase_operation_t {
        match *self {
            RebaseOperationType::Pick => raw::GIT_REBASE_OPERATION_PICK,
            RebaseOperationType::Reword => raw::GIT_REBASE_OPERATION_REWORD,
            RebaseOperationType::Edit => raw::GIT_REBASE_OPERATION_EDIT,
            RebaseOperationType::Squash => raw::GIT_REBASE_OPERATION_SQUASH,
            RebaseOperationType::FixUp => raw::GIT_REBASE_OPERATION_FIXUP,
            RebaseOperationType::Exec => raw::GIT_REBASE_OPERATION_EXEC,
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn smoke() {
    }
}
<commit_msg>Make signature optional in rebase finish<commit_after>use std::marker;
use std::ffi::CString;
use std::mem;
use std::ptr;

use libc::{c_char, size_t, c_uint, c_int};

use {raw, Error, Repository, Oid, Signature, Index, MergeOptions};
use build::CheckoutBuilder;
use util::Binding;

/// A structure representing a [rebase][1]
///
/// [1]: https://libgit2.github.com/libgit2/#HEAD/type/git_rebase
///
/// It has a lifetime of the repository it is attached to.
pub struct Rebase<'repo> {
    raw: *mut raw::git_rebase,
    _marker: marker::PhantomData<&'repo Repository>,
}

/// A structure representing a single [operation][2] to be performed during the rebase.
///
/// [2]: https://libgit2.github.com/libgit2/#HEAD/type/git_rebase_operation
///
/// It has a lifetime of the rebase it belongs to.
pub struct RebaseOperation<'rebase, 'repo: 'rebase> {
    raw: *mut raw::git_rebase_operation,
    _marker: marker::PhantomData<&'rebase Rebase<'repo>>,
}

/// Type of rebase operation
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum RebaseOperationType {
    /// The given commit is to be cherry-picked.
    /// The client should commit the changes and continue if there are no conflicts.
    Pick,
    /// The given commit is to be cherry-picked, but the client should prompt
    /// the user to provide an updated commit message.
    Reword,
    /// The given commit is to be cherry-picked, but the client should stop
    /// to allow the user to edit the changes before committing them.
    Edit,
    /// The given commit is to be squashed into the previous commit.
    /// The commit message will be merged with the previous message.
    Squash,
    /// The given commit is to be squashed into the previous commit.
    /// The commit message from this commit will be discarded.
    FixUp,
    /// No commit will be cherry-picked.  The client should run the given
    /// command and (if successful) continue
    Exec,
}

/// A structure representing options for a `rebase`
pub struct RebaseOptions<'a> {
    /// Version of rebase options, defined by `GIT_REBASE_OPTIONS_VERSION`
    pub version: usize,

    /// this will instruct other clients working
    /// on this `rebase` that you want a quiet rebase experience.
    /// This is provided for interoperability between Git tools
    pub quiet: bool,

    /// Perform an in-memory rebase, will not updated the repository to be in a rebasing-state
    /// or modify the working directory.
    pub in_memory: bool,

    /// The name of the notes reference used to rewrite notes
    /// for rebased commits when finishing the rebase
    pub rewrite_notes_ref: Option<CString>,

    /// Options to control how trees are merged during a `rebase`.
    pub merge_options: Option<MergeOptions>,

    /// Options to control how files are written during a `rebase`.
    pub checkout_options: Option<CheckoutBuilder<'a>>,
}

impl<'repo> Rebase<'repo> {
    /// Returns the number of applied operations.
    pub fn operation_count(&self) -> usize {
        unsafe { raw::git_rebase_operation_entrycount(self.raw) }
    }

    /// Aborts a rebase that is currently in progress,
    /// resetting the repository and working directory to their state before rebase began.
    pub fn abort(&mut self) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_rebase_abort(self.raw));
        }
        Ok(())
    }

    /// Commits the current patch.
    /// You must have resolved any conflicts
    /// that were introduced during the patch application from the `next` invocation.
    pub fn commit(&mut self,
                  author: &Signature,
                  committer: &Signature,
                  message: &str)
                  -> Result<Oid, Error> {
        let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] };
        let message = try!(CString::new(message));
        unsafe {
            try_call!(raw::git_rebase_commit(&mut raw,
                                             self.raw,
                                             author.raw(),
                                             committer.raw(),
                                             0 as *const c_char,
                                             message));
            Ok(Binding::from_raw(&raw as *const _))
        }
    }

    /// Finishes a rebase that is currently in progress once all patches have been applied.
    pub fn finish(&mut self, signature: Option<&Signature>) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_rebase_finish(self.raw,
                                             signature
                                                 .map(|s| {
                                                          s.raw() as *const raw::git_signature
                                                      })
                                                 .unwrap_or(0 as *const raw::git_signature)));
        }
        Ok(())
    }
    /// Gets the index produced by the last operation.
    /// This is useful for resolving conflicts in an in-memory rebase before committing them.
    pub fn inmemory_index(&self) -> Result<Index, Error> {
        let mut ret = 0 as *mut raw::git_index;
        unsafe {
            try_call!(raw::git_rebase_inmemory_index(&mut ret, self.raw));
            Ok(Binding::from_raw(ret))
        }
    }

    /// Performs the next rebase operation and returns the `RebaseOperation` about it.
    pub fn next(&mut self) -> Result<RebaseOperation, Error> {
        let mut ret = 0 as *mut raw::git_rebase_operation;
        unsafe {
            try_call!(raw::git_rebase_next(&mut ret, self.raw));
            Ok(Binding::from_raw(ret))
        }
    }

    /// Gets the rebase operation specified by the given index.
    pub fn operation_at_index(&self, index: usize) -> Option<RebaseOperation> {
        unsafe {
            let ptr = raw::git_rebase_operation_byindex(self.raw, index as size_t);
            if ptr.is_null() {
                None
            } else {
                Some(Binding::from_raw(ptr))
            }
        }
    }

    /// Gets the index of the rebase operation that is currently being applied.
    /// If the first operation has not yet been applied it returns `None`.
    pub fn current_operation_index(&self) -> Option<usize> {
        unsafe {
            let index = raw::git_rebase_operation_current(self.raw);
            if index == raw::GIT_REBASE_NO_OPERATION {
                None
            } else {
                Some(index as usize)
            }
        }
    }

    /// Convenience function to get the operation at the current index.
    /// Returns none if the first operation has not yet been applied.
    pub fn current_operation(&self) -> Option<RebaseOperation> {
        if let Some(index) = self.current_operation_index() {
            self.operation_at_index(index)
        } else {
            None
        }
    }
}

impl<'repo> Binding for Rebase<'repo> {
    type Raw = *mut raw::git_rebase;
    unsafe fn from_raw(raw: *mut raw::git_rebase) -> Rebase<'repo> {
        Rebase {
            raw: raw,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_rebase {
        self.raw
    }
}

impl<'repo> Drop for Rebase<'repo> {
    fn drop(&mut self) {
        unsafe { raw::git_rebase_free(self.raw) }
    }
}

impl<'rebase, 'repo: 'rebase> Binding for RebaseOperation<'rebase, 'repo> {
    type Raw = *mut raw::git_rebase_operation;
    unsafe fn from_raw(raw: *mut raw::git_rebase_operation) -> RebaseOperation<'rebase, 'repo> {
        RebaseOperation {
            raw: raw,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_rebase_operation {
        self.raw
    }
}

impl<'a> RebaseOptions<'a> {
    /// Initiate default set of rebase options.
    pub fn new() -> RebaseOptions<'a> {
        RebaseOptions {
            version: raw::GIT_REBASE_OPTIONS_VERSION as usize,
            quiet: false,
            in_memory: false,
            rewrite_notes_ref: None,
            merge_options: None,
            checkout_options: None,
        }
    }

    /// raw value of options
    pub unsafe fn raw(&mut self) -> Result<raw::git_rebase_options, Error> {
        let mut checkout_options: raw::git_checkout_options = mem::zeroed();
        try_call!(raw::git_checkout_init_options(&mut checkout_options,
                                                 raw::GIT_CHECKOUT_OPTIONS_VERSION));
        if let Some(ref mut opts) = self.checkout_options {
            opts.configure(&mut checkout_options);
        }
        let mut merge_options: raw::git_merge_options = mem::zeroed();
        if let Some(ref opts) = self.merge_options {
            ptr::copy(opts.raw(), &mut merge_options, 1);
        }

        Ok(raw::git_rebase_options {
               version: self.version as c_uint,
               quiet: self.quiet as c_int,
               inmemory: self.in_memory as c_int,
               rewrite_notes_ref: ::call::convert(&self.rewrite_notes_ref),
               merge_options: merge_options,
               checkout_options: checkout_options,
           })
    }
}

impl<'rebase, 'repo: 'rebase> RebaseOperation<'rebase, 'repo> {
    /// The type of `rebase` operation
    pub fn kind(&self) -> RebaseOperationType {
        unsafe { Binding::from_raw((*self.raw).kind) }
    }

    /// The commit ID being cherry-picked.  This will be populated for
    /// all operations except those of type `Exec`
    pub fn id(&self) -> Oid {
        unsafe { Binding::from_raw(&(*self.raw).id as *const raw::git_oid) }
    }
    /// The executable the user has requested be run.  This will only
    /// be populated for operations of type `Exec`
    pub fn exec(&self) -> Option<CString> {
        unsafe {
            if !(*self.raw).exec.is_null() {
                Some(CString::from_raw((*self.raw).exec as *mut c_char))
            } else {
                None
            }
        }
    }
}

impl Binding for RebaseOperationType {
    type Raw = raw::git_rebase_operation_t;
    unsafe fn from_raw(raw: raw::git_rebase_operation_t) -> RebaseOperationType {
        match raw {
            raw::GIT_REBASE_OPERATION_PICK => RebaseOperationType::Pick,
            raw::GIT_REBASE_OPERATION_REWORD => RebaseOperationType::Reword,
            raw::GIT_REBASE_OPERATION_EDIT => RebaseOperationType::Edit,
            raw::GIT_REBASE_OPERATION_SQUASH => RebaseOperationType::Squash,
            raw::GIT_REBASE_OPERATION_FIXUP => RebaseOperationType::FixUp,
            raw::GIT_REBASE_OPERATION_EXEC => RebaseOperationType::Exec,
            _ => panic!("Unknown rebase operation type: {}", raw),
        }
    }

    fn raw(&self) -> raw::git_rebase_operation_t {
        match *self {
            RebaseOperationType::Pick => raw::GIT_REBASE_OPERATION_PICK,
            RebaseOperationType::Reword => raw::GIT_REBASE_OPERATION_REWORD,
            RebaseOperationType::Edit => raw::GIT_REBASE_OPERATION_EDIT,
            RebaseOperationType::Squash => raw::GIT_REBASE_OPERATION_SQUASH,
            RebaseOperationType::FixUp => raw::GIT_REBASE_OPERATION_FIXUP,
            RebaseOperationType::Exec => raw::GIT_REBASE_OPERATION_EXEC,
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn smoke() {}
}
<|endoftext|>


<commit_before>extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate lazy_static;
extern crate nalgebra;
extern crate rand;

use nalgebra::ToHomogeneous;

use cube;
use cube::{Cube, Node, Spatial};
use math::{IntoSpace, FMatrix4, FPoint3, FScalar, FVector3, FVector4};

pub type Index = u32;

gfx_pipeline!{
    pipeline {
        vertex_buffer: gfx::VertexBuffer<RawVertex> = (),
        transform: gfx::Global<[[f32; 4]; 4]> = "u_transform",
        output: gfx::RenderTarget<gfx::format::Rgba8> = "f_target0",
    }
}

gfx_vertex_struct!{
    RawVertex {
        position: [f32; 3] = "a_position",
        color: [f32; 4] = "a_color",
    }
}

impl From<Vertex> for RawVertex {
    fn from(vertex: Vertex) -> Self {
        RawVertex {
            position: *vertex.position.as_ref(),
            color: *vertex.color.as_ref(),
        }
    }
}

struct Vertex {
    pub position: FPoint3,
    pub color: FVector4,
}

impl Vertex {
    pub fn new(position: FPoint3, color: FVector4) -> Self {
        Vertex {
            position: position,
            color: color,
        }
    }
}

pub fn vertex_buffer_from_cube<R, F>(cube: &Cube<&Node>,
                                     factory: &mut F)
                                     -> (gfx::handle::Buffer<R, RawVertex>, gfx::Slice<R>)
    where R: gfx::Resources,
          F: gfx::traits::FactoryExt<R>
{
    let mut points = Vec::new();
    let mut indeces = Vec::new();
    for (n, cube) in cube.iter().enumerate() {
        if let Node::Leaf(ref leaf) = *cube {
            let width = cube.partition().width();
            let origin: FVector3 = cube.partition().origin().to_vector().into_space();
            let units = leaf.geometry.points();
            points.extend(units.iter()
                .map(|point| (point * cube::exp(width) as FScalar) + origin)
                .map(|point| RawVertex::from(Vertex::new(point, random_color()))));
            indeces.extend(leaf.geometry
                .indeces()
                .iter()
                .map(|index| ((units.len() * n) as Index + *index)));
        }
    }
    factory.create_vertex_buffer_with_slice(points.as_slice(), indeces.as_slice())
}

pub fn projection_from_window(window: &glutin::Window) -> FMatrix4 {
    let aspect = {
        let (width, height) = window.get_inner_size_pixels().unwrap();
        width as f32 / height as f32
    };
    nalgebra::PerspectiveMatrix3::new(aspect, 1.0, -1.0, 1.0).to_matrix()
}

pub fn look_at_cube<C>(cube: &C, from: &FPoint3) -> FMatrix4
    where C: Spatial
{
    nalgebra::Isometry3::look_at_rh(from,
                                    &cube.partition().midpoint().into_space(),
                                    &FVector3::new(0.0, 0.0, 1.0))
        .to_homogeneous()
}

fn random_color() -> FVector4 {
    FVector4::new(rand::random::<f32>(),
                  rand::random::<f32>(),
                  rand::random::<f32>(),
                  1.0)
}

#[cfg(test)]
mod tests {
    use super::*;
}
<commit_msg>Fix rendering color and index buffer.<commit_after>extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate lazy_static;
extern crate nalgebra;
extern crate rand;

use nalgebra::ToHomogeneous;

use cube;
use cube::{Cube, Node, Spatial};
use math::{IntoSpace, FMatrix4, FPoint3, FScalar, FVector3, FVector4};

pub type Index = u32;

gfx_pipeline!{
    pipeline {
        vertex_buffer: gfx::VertexBuffer<RawVertex> = (),
        transform: gfx::Global<[[f32; 4]; 4]> = "u_transform",
        output: gfx::RenderTarget<gfx::format::Rgba8> = "f_target0",
    }
}

gfx_vertex_struct!{
    RawVertex {
        position: [f32; 3] = "a_position",
        color: [f32; 4] = "a_color",
    }
}

impl From<Vertex> for RawVertex {
    fn from(vertex: Vertex) -> Self {
        RawVertex {
            position: *vertex.position.as_ref(),
            color: *vertex.color.as_ref(),
        }
    }
}

struct Vertex {
    pub position: FPoint3,
    pub color: FVector4,
}

impl Vertex {
    pub fn new(position: FPoint3, color: FVector4) -> Self {
        Vertex {
            position: position,
            color: color,
        }
    }
}

pub fn vertex_buffer_from_cube<R, F>(cube: &Cube<&Node>,
                                     factory: &mut F)
                                     -> (gfx::handle::Buffer<R, RawVertex>, gfx::Slice<R>)
    where R: gfx::Resources,
          F: gfx::traits::FactoryExt<R>
{
    let mut points = Vec::new();
    let mut indeces = Vec::new();
    for (n, cube) in cube.iter().filter(|cube| cube.is_leaf()).enumerate() {
        if let Node::Leaf(ref leaf) = *cube {
            let width = cube.partition().width();
            let origin: FVector3 = cube.partition().origin().to_vector().into_space();
            let units = leaf.geometry.points();
            let color = random_color();
            // TODO: The ordering of the points must agree with the indeces.
            //       This seems to be broken (and can be seen when using more
            //       elaborate colors). Reversing the `Vec` seems to help, but
            //       this may still be broken, and using `rev` shouldn't be
            //       required of clients in any case.
            points.extend(units.iter().rev()
                .map(|point| (point * cube::exp(width) as FScalar) + origin)
                .map(|point| RawVertex::from(Vertex::new(point, color))));
            indeces.extend(leaf.geometry
                .indeces()
                .iter()
                .map(|index| ((units.len() * n) as Index + *index)));
        }
    }
    factory.create_vertex_buffer_with_slice(points.as_slice(), indeces.as_slice())
}

pub fn projection_from_window(window: &glutin::Window) -> FMatrix4 {
    let aspect = {
        let (width, height) = window.get_inner_size_pixels().unwrap();
        width as f32 / height as f32
    };
    nalgebra::PerspectiveMatrix3::new(aspect, 1.0, -1.0, 1.0).to_matrix()
}

pub fn look_at_cube<C>(cube: &C, from: &FPoint3) -> FMatrix4
    where C: Spatial
{
    nalgebra::Isometry3::look_at_rh(from,
                                    &cube.partition().midpoint().into_space(),
                                    &FVector3::new(0.0, 0.0, 1.0))
        .to_homogeneous()
}

fn random_color() -> FVector4 {
    FVector4::new(rand::random::<FScalar>(),
                  rand::random::<FScalar>(),
                  rand::random::<FScalar>(),
                  1.0)
}

#[cfg(test)]
mod tests {
    use super::*;
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Mutex;
use std::thread;

use hyper::header::{ContentType, CacheControl, CacheDirective};
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use hyper::method::Method;
use hyper::Result;
use hyper::server::{Handler, Listening, Request, Response, Server};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;

use command::{WebDriverMessage, WebDriverCommand};
use error::{WebDriverResult, WebDriverError, ErrorStatus};
use httpapi::{WebDriverHttpApi, WebDriverExtensionRoute, VoidWebDriverExtensionRoute};
use response::{CloseWindowResponse, WebDriverResponse};

enum DispatchMessage<U: WebDriverExtensionRoute> {
    HandleWebDriver(WebDriverMessage<U>, Sender<WebDriverResult<WebDriverResponse>>),
    Quit
}

#[derive(PartialEq, Clone)]
pub struct Session {
    id: String
}

impl Session {
    fn new(id: String) -> Session {
        Session {
            id: id
        }
    }
}

pub trait WebDriverHandler<U: WebDriverExtensionRoute=VoidWebDriverExtensionRoute> : Send {
    fn handle_command(&mut self, session: &Option<Session>, msg: WebDriverMessage<U>) -> WebDriverResult<WebDriverResponse>;
    fn delete_session(&mut self, session: &Option<Session>);
}

struct Dispatcher<T: WebDriverHandler<U>,
                  U: WebDriverExtensionRoute> {
    handler: T,
    session: Option<Session>,
    extension_type: PhantomData<U>,
}

impl<T: WebDriverHandler<U>, U: WebDriverExtensionRoute> Dispatcher<T, U> {
    fn new(handler: T) -> Dispatcher<T, U> {
        Dispatcher {
            handler: handler,
            session: None,
            extension_type: PhantomData,
        }
    }

    fn run(&mut self, msg_chan: Receiver<DispatchMessage<U>>) {
        loop {
            match msg_chan.recv() {
                Ok(DispatchMessage::HandleWebDriver(msg, resp_chan)) => {
                    let resp = match self.check_session(&msg) {
                        Ok(_) => self.handler.handle_command(&self.session, msg),
                        Err(e) => Err(e),
                    };

                    match resp {
                        Ok(WebDriverResponse::NewSession(ref new_session)) => {
                            self.session = Some(Session::new(new_session.sessionId.clone()));
                        }
                        Ok(WebDriverResponse::CloseWindow(CloseWindowResponse { ref window_handles })) => {
                            if window_handles.len() == 0 {
                                debug!("Last window was closed, deleting session");
                                self.delete_session();
                            }
                        }
                        Ok(WebDriverResponse::DeleteSession) => self.delete_session(),
                        Err(ref x) if x.delete_session => self.delete_session(),
                        _ => {}
                    }

                    if resp_chan.send(resp).is_err() {
                        error!("Sending response to the main thread failed");
                    };
                }
                Ok(DispatchMessage::Quit) => break,
                Err(_) => panic!("Error receiving message in handler"),
            }
        }
    }

    fn delete_session(&mut self) {
        debug!("Deleting session");
        self.handler.delete_session(&self.session);
        self.session = None;
    }

    fn check_session(&self, msg: &WebDriverMessage<U>) -> WebDriverResult<()> {
        match msg.session_id {
            Some(ref msg_session_id) => {
                match self.session {
                    Some(ref existing_session) => {
                        if existing_session.id != *msg_session_id {
                            Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                format!("Got unexpected session id {} expected {}",
                                        msg_session_id,
                                        existing_session.id)))
                        } else {
                            Ok(())
                        }
                    },
                    None => Ok(())
                }
            },
            None => {
                match self.session {
                    Some(_) => {
                        match msg.command {
                            WebDriverCommand::Status => Ok(()),
                            WebDriverCommand::NewSession(_) => {
                                Err(WebDriverError::new(
                                    ErrorStatus::SessionNotCreated,
                                    "Session is already started"))
                            },
                            _ => {
                                //This should be impossible
                                error!("Got a message with no session id");
                                Err(WebDriverError::new(
                                    ErrorStatus::UnknownError,
                                    "Got a command with no session?!"))
                            }
                        }
                    },
                    None => {
                        match msg.command {
                            WebDriverCommand::NewSession(_) => Ok(()),
                            WebDriverCommand::Status => Ok(()),
                            _ => Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                "Tried to run a command before creating a session"))
                        }
                    }
                }
            }
        }
    }
}

struct HttpHandler<U: WebDriverExtensionRoute> {
    chan: Mutex<Sender<DispatchMessage<U>>>,
    api: Mutex<WebDriverHttpApi<U>>
}

impl <U: WebDriverExtensionRoute> HttpHandler<U> {
    fn new(api: WebDriverHttpApi<U>, chan: Sender<DispatchMessage<U>>) -> HttpHandler<U> {
        HttpHandler {
            chan: Mutex::new(chan),
            api: Mutex::new(api)
        }
    }
}

impl<U: WebDriverExtensionRoute> Handler for HttpHandler<U> {
    fn handle(&self, req: Request, res: Response) {
        let mut req = req;
        let mut res = res;

        let mut body = String::new();
        if let Method::Post = req.method {
            req.read_to_string(&mut body).unwrap();
        }

        debug!("-> {} {} {}", req.method, req.uri, body);

        match req.uri {
            AbsolutePath(path) => {
                let msg_result = {
                    // The fact that this locks for basically the whole request doesn't
                    // matter as long as we are only handling one request at a time.
                    match self.api.lock() {
                        Ok(ref api) => api.decode_request(req.method, &path[..], &body[..]),
                        Err(_) => return,
                    }
                };
                let (status, resp_body) = match msg_result {
                    Ok(message) => {
                        let (send_res, recv_res) = channel();
                        match self.chan.lock() {
                            Ok(ref c) => {
                                let res =
                                    c.send(DispatchMessage::HandleWebDriver(message, send_res));
                                match res {
                                    Ok(x) => x,
                                    Err(_) => {
                                        error!("Something terrible happened");
                                        return;
                                    }
                                }
                            }
                            Err(_) => {
                                error!("Something terrible happened");
                                return;
                            }
                        }
                        match recv_res.recv() {
                            Ok(data) => {
                                match data {
                                    Ok(response) => (StatusCode::Ok, response.to_json_string()),
                                    Err(err) => (err.http_status(), err.to_json_string()),
                                }
                            }
                            Err(e) => panic!("Error reading response: {:?}", e),
                        }
                    }
                    Err(err) => (err.http_status(), err.to_json_string()),
                };

                debug!("<- {} {}", status, resp_body);

                {
                    let resp_status = res.status_mut();
                    *resp_status = status;
                }
                res.headers_mut()
                    .set(ContentType(Mime(TopLevel::Application,
                                          SubLevel::Json,
                                          vec![(Attr::Charset, Value::Utf8)])));
                res.headers_mut()
                    .set(CacheControl(vec![CacheDirective::NoCache]));

                res.send(&resp_body.as_bytes()).unwrap();
            }
            _ => {}
        }
    }
}

pub fn start<T, U>(address: SocketAddr,
                   handler: T,
                   extension_routes: &[(Method, &str, U)])
                   -> Result<Listening>
    where T: 'static + WebDriverHandler<U>,
          U: 'static + WebDriverExtensionRoute
{
    let (msg_send, msg_recv) = channel();

    let api = WebDriverHttpApi::new(extension_routes);
    let http_handler = HttpHandler::new(api, msg_send);
    let mut server = try!(Server::http(address));
    server.keep_alive(None);

    let builder = thread::Builder::new().name("webdriver dispatcher".to_string());
    try!(builder.spawn(move || {
        let mut dispatcher = Dispatcher::new(handler);
        dispatcher.run(msg_recv);
    }));

    server.handle(http_handler)
}
<commit_msg>Don't return existing session id when the wrong one is supplied (#99)<commit_after>use std::io::Read;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Mutex;
use std::thread;

use hyper::header::{ContentType, CacheControl, CacheDirective};
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use hyper::method::Method;
use hyper::Result;
use hyper::server::{Handler, Listening, Request, Response, Server};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;

use command::{WebDriverMessage, WebDriverCommand};
use error::{WebDriverResult, WebDriverError, ErrorStatus};
use httpapi::{WebDriverHttpApi, WebDriverExtensionRoute, VoidWebDriverExtensionRoute};
use response::{CloseWindowResponse, WebDriverResponse};

enum DispatchMessage<U: WebDriverExtensionRoute> {
    HandleWebDriver(WebDriverMessage<U>, Sender<WebDriverResult<WebDriverResponse>>),
    Quit
}

#[derive(PartialEq, Clone)]
pub struct Session {
    id: String
}

impl Session {
    fn new(id: String) -> Session {
        Session {
            id: id
        }
    }
}

pub trait WebDriverHandler<U: WebDriverExtensionRoute=VoidWebDriverExtensionRoute> : Send {
    fn handle_command(&mut self, session: &Option<Session>, msg: WebDriverMessage<U>) -> WebDriverResult<WebDriverResponse>;
    fn delete_session(&mut self, session: &Option<Session>);
}

struct Dispatcher<T: WebDriverHandler<U>,
                  U: WebDriverExtensionRoute> {
    handler: T,
    session: Option<Session>,
    extension_type: PhantomData<U>,
}

impl<T: WebDriverHandler<U>, U: WebDriverExtensionRoute> Dispatcher<T, U> {
    fn new(handler: T) -> Dispatcher<T, U> {
        Dispatcher {
            handler: handler,
            session: None,
            extension_type: PhantomData,
        }
    }

    fn run(&mut self, msg_chan: Receiver<DispatchMessage<U>>) {
        loop {
            match msg_chan.recv() {
                Ok(DispatchMessage::HandleWebDriver(msg, resp_chan)) => {
                    let resp = match self.check_session(&msg) {
                        Ok(_) => self.handler.handle_command(&self.session, msg),
                        Err(e) => Err(e),
                    };

                    match resp {
                        Ok(WebDriverResponse::NewSession(ref new_session)) => {
                            self.session = Some(Session::new(new_session.sessionId.clone()));
                        }
                        Ok(WebDriverResponse::CloseWindow(CloseWindowResponse { ref window_handles })) => {
                            if window_handles.len() == 0 {
                                debug!("Last window was closed, deleting session");
                                self.delete_session();
                            }
                        }
                        Ok(WebDriverResponse::DeleteSession) => self.delete_session(),
                        Err(ref x) if x.delete_session => self.delete_session(),
                        _ => {}
                    }

                    if resp_chan.send(resp).is_err() {
                        error!("Sending response to the main thread failed");
                    };
                }
                Ok(DispatchMessage::Quit) => break,
                Err(_) => panic!("Error receiving message in handler"),
            }
        }
    }

    fn delete_session(&mut self) {
        debug!("Deleting session");
        self.handler.delete_session(&self.session);
        self.session = None;
    }

    fn check_session(&self, msg: &WebDriverMessage<U>) -> WebDriverResult<()> {
        match msg.session_id {
            Some(ref msg_session_id) => {
                match self.session {
                    Some(ref existing_session) => {
                        if existing_session.id != *msg_session_id {
                            Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                format!("Got unexpected session id {}",
                                        msg_session_id)))
                        } else {
                            Ok(())
                        }
                    },
                    None => Ok(())
                }
            },
            None => {
                match self.session {
                    Some(_) => {
                        match msg.command {
                            WebDriverCommand::Status => Ok(()),
                            WebDriverCommand::NewSession(_) => {
                                Err(WebDriverError::new(
                                    ErrorStatus::SessionNotCreated,
                                    "Session is already started"))
                            },
                            _ => {
                                //This should be impossible
                                error!("Got a message with no session id");
                                Err(WebDriverError::new(
                                    ErrorStatus::UnknownError,
                                    "Got a command with no session?!"))
                            }
                        }
                    },
                    None => {
                        match msg.command {
                            WebDriverCommand::NewSession(_) => Ok(()),
                            WebDriverCommand::Status => Ok(()),
                            _ => Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                "Tried to run a command before creating a session"))
                        }
                    }
                }
            }
        }
    }
}

struct HttpHandler<U: WebDriverExtensionRoute> {
    chan: Mutex<Sender<DispatchMessage<U>>>,
    api: Mutex<WebDriverHttpApi<U>>
}

impl <U: WebDriverExtensionRoute> HttpHandler<U> {
    fn new(api: WebDriverHttpApi<U>, chan: Sender<DispatchMessage<U>>) -> HttpHandler<U> {
        HttpHandler {
            chan: Mutex::new(chan),
            api: Mutex::new(api)
        }
    }
}

impl<U: WebDriverExtensionRoute> Handler for HttpHandler<U> {
    fn handle(&self, req: Request, res: Response) {
        let mut req = req;
        let mut res = res;

        let mut body = String::new();
        if let Method::Post = req.method {
            req.read_to_string(&mut body).unwrap();
        }

        debug!("-> {} {} {}", req.method, req.uri, body);

        match req.uri {
            AbsolutePath(path) => {
                let msg_result = {
                    // The fact that this locks for basically the whole request doesn't
                    // matter as long as we are only handling one request at a time.
                    match self.api.lock() {
                        Ok(ref api) => api.decode_request(req.method, &path[..], &body[..]),
                        Err(_) => return,
                    }
                };
                let (status, resp_body) = match msg_result {
                    Ok(message) => {
                        let (send_res, recv_res) = channel();
                        match self.chan.lock() {
                            Ok(ref c) => {
                                let res =
                                    c.send(DispatchMessage::HandleWebDriver(message, send_res));
                                match res {
                                    Ok(x) => x,
                                    Err(_) => {
                                        error!("Something terrible happened");
                                        return;
                                    }
                                }
                            }
                            Err(_) => {
                                error!("Something terrible happened");
                                return;
                            }
                        }
                        match recv_res.recv() {
                            Ok(data) => {
                                match data {
                                    Ok(response) => (StatusCode::Ok, response.to_json_string()),
                                    Err(err) => (err.http_status(), err.to_json_string()),
                                }
                            }
                            Err(e) => panic!("Error reading response: {:?}", e),
                        }
                    }
                    Err(err) => (err.http_status(), err.to_json_string()),
                };

                debug!("<- {} {}", status, resp_body);

                {
                    let resp_status = res.status_mut();
                    *resp_status = status;
                }
                res.headers_mut()
                    .set(ContentType(Mime(TopLevel::Application,
                                          SubLevel::Json,
                                          vec![(Attr::Charset, Value::Utf8)])));
                res.headers_mut()
                    .set(CacheControl(vec![CacheDirective::NoCache]));

                res.send(&resp_body.as_bytes()).unwrap();
            }
            _ => {}
        }
    }
}

pub fn start<T, U>(address: SocketAddr,
                   handler: T,
                   extension_routes: &[(Method, &str, U)])
                   -> Result<Listening>
    where T: 'static + WebDriverHandler<U>,
          U: 'static + WebDriverExtensionRoute
{
    let (msg_send, msg_recv) = channel();

    let api = WebDriverHttpApi::new(extension_routes);
    let http_handler = HttpHandler::new(api, msg_send);
    let mut server = try!(Server::http(address));
    server.keep_alive(None);

    let builder = thread::Builder::new().name("webdriver dispatcher".to_string());
    try!(builder.spawn(move || {
        let mut dispatcher = Dispatcher::new(handler);
        dispatcher.run(msg_recv);
    }));

    server.handle(http_handler)
}
<|endoftext|>