<commit_before>#![feature(slice_patterns)]
mod lexer;
use lexer::{Token, Lexer};

#[derive(Debug, PartialEq, Clone)]
pub enum CC {
    // condition codes
    E, L, LE, G, GE,
}

#[derive(Debug, Clone)]
pub enum Ast<'input> {
    Symbol(&'input str),
    Number(i64),
    Bool(bool),
    List(Vec<Ast<'input>>),
    FuncName(&'input str),  // for closure-conversion

    Define(&'input str, Vec<&'input str>, Box<Ast<'input>>),
    If(Box<Ast<'input>>,     // cnd
       Box<Ast<'input>>,     // thn
       Box<Ast<'input>>),    // els
    Let(Vec<(&'input str, Ast<'input>)>, Box<Ast<'input>>),
    Lambda(Vec<&'input str>, Box<Ast<'input>>),
    Tuple(Vec<Ast<'input>>),
    Cmp(CC, Box<Ast<'input>>, Box<Ast<'input>>),
    App(Box<Ast<'input>>, Vec<Ast<'input>>)
}

pub struct Parser<'input> {
    lexer: Lexer<'input>
}

impl<'input> Parser<'input> {
    pub fn new(source: &'input str) -> Parser<'input> {
        Parser {
            lexer: Lexer::new(source)
        }
    }

    pub fn get_list(&mut self) -> Vec<Ast<'input>> {
        match self.get_expr() {
            Some(expr) => match self.lexer.next() {
                None => vec![],
                Some(Token::RParen) => vec![expr],
                Some(tok) => {
                    self.lexer.unread(tok);
                    let mut seq = self.get_list();
                    seq.insert(0, expr);

                    return seq;
                }
            },
            None => vec![],
        }
    }

    pub fn get_expr(&mut self) -> Option<Ast<'input>> {
        match self.lexer.next() {
            Some(Token::Symbol(s)) => Some(Ast::Symbol(s)),
            Some(Token::Number(n)) => Some(Ast::Number(n)),
            Some(Token::LParen) => Some(Ast::List(self.get_list())),
            Some(Token::RParen) => panic!("line {}: {} unmatched ')'",
                                          self.lexer.line_num,
                                          self.lexer.col),
            _ => None,
        }
    }

    pub fn get_arg_names(args: &[Ast<'input>]) -> Vec<&'input str> {
        let arg_names : Vec<&'input str> = args.iter().map(|arg| match arg {
            Ast::Symbol(name) => *name,
            _ => panic!("invalid arg"),
        }).collect();

        arg_names
    }

    pub fn get_ast(expr: &Ast<'input>) -> Ast<'input> {
        match expr {
            &Ast::Symbol(sym) =>
                match &sym[..] {
                    "#f" => Ast::Bool(false),
                    "#t" => Ast::Bool(true),
                    _ => Ast::Symbol(sym)
                },
            &Ast::List(ref elts) =>
                match &elts[..] {
                    &[Ast::Symbol(k), Ast::List(ref defelts), ref body]
                        if k == "define" => {
                            let name = &defelts[0];
                            let args = &defelts[1..];

                            if let Ast::Symbol(name) = name {
                                Ast::Define(name,
                                            Parser::get_arg_names(args),
                                            Box::new(Parser::get_ast(&body)))
                            } else {
                                panic!("invalid function prototype");
                            }
                        },
                    &[Ast::Symbol(k), ref cnd, ref thn, ref els]
                        if k == "if" => {
                            Ast::If(Box::new(Parser::get_ast(cnd)),
                                    Box::new(Parser::get_ast(thn)),
                                    Box::new(Parser::get_ast(els)))
                        },
                    &[Ast::Symbol(k), Ast::List(ref bindings), ref body]
                        if k == "let" => {
                            let mut astified_bindings = vec![];
                            for bind_pair in bindings {
                                if let Ast::List(kv) = bind_pair {
                                    let (key, val) =
                                        if kv.len() == 2 {
                                            let astified_val = Parser::get_ast(&kv[1]);
                                            let keyname =
                                                if let Ast::Symbol(k) = kv[0] {
                                                    k
                                                } else {
                                                    panic!("let binding key is not symbol");
                                                };
                                            (keyname, astified_val)
                                        } else {
                                            panic!("invalid let binding syntax");
                                        };

                                    astified_bindings.push((key, val));
                                }
                            }

                            Ast::Let(astified_bindings,
                                     Box::new(Parser::get_ast(&body)))
                        },
                    &[Ast::Symbol(k), Ast::List(ref args), ref body]
                        if k == "lambda" => {
                            Ast::Lambda(Parser::get_arg_names(args),
                                        Box::new(Parser::get_ast(body)))
                        },
                    &[Ast::Symbol(k), _..]
                        if k == "tuple" => {
                            let tuple_elts = elts[1..].iter()
                                .map(|e| Parser::get_ast(e))
                                .collect();
                            Ast::Tuple(tuple_elts)
                        },
                    &[Ast::Symbol(cmp), ref left, ref right]
                        if (cmp == ">" || cmp == "<" ||
                            cmp == "<=" || cmp == ">=" ||
                            cmp == "=") => {
                            let cc = match &cmp[..] {
                                ">" => CC::G,
                                "<" => CC::L,
                                ">=" => CC::GE,
                                "<=" => CC::LE,
                                "=" => CC::E,
                                &_ => panic!("invalid cmp op"),
                            };

                            Ast::Cmp(cc,
                                     Box::new(Parser::get_ast(left)),
                                     Box::new(Parser::get_ast(right)))
                        },
                    &[ref f, _..] => {
                        let args = elts[1..].iter().map(|e| Parser::get_ast(e))
                            .collect();

                        Ast::App(Box::new(f.clone()), args)
                    }
                    _ => Ast::Number(42),
                },
            _ => expr.clone(),
        }
    }

    pub fn read(&mut self) -> Option<Ast<'input>> {
        match self.get_expr() {
            Some(expr) => Some(Parser::get_ast(&expr)),
            None => None,
        }
    }
}

impl<'input> Iterator for Parser<'input> {
    type Item = Ast<'input>;

    fn next(&mut self) -> Option<Ast<'input>> {
        self.read()
    }
}

fn main() {
    let mut p = Parser::new("(if #t 42 (define (foo x y) (+ (* 1 2) 2)))");
    println!("{:?}", Parser::get_ast(&p.get_expr().unwrap()));

    let mut p2 = Parser::new("(let ((x 10) (y 2)) (+ x y))");
    println!("{:?}", Parser::get_ast(&p2.get_expr().unwrap()));

    let mut p3 = Parser::new("(lambda (x y) (+ x y))");
    println!("{:?}", Parser::get_ast(&p3.get_expr().unwrap()));

    let mut p4 = Parser::new("(tuple 1 2 3)");
    println!("{:?}", Parser::get_ast(&p4.get_expr().unwrap()));

    let mut p5 = Parser::new("(> 1 2)");
    println!("{:?}", Parser::get_ast(&p5.get_expr().unwrap()));

    let mut p6 = Parser::new("(+ 1 2)");
    println!("{:?}", Parser::get_ast(&p6.get_expr().unwrap()));

    let mut ps = Parser::new("(> 1 2) (+ 1 2)");
    for a in ps {
        println!("{:?}", a);
    }
}
<commit_msg>Change Ast to use String's instead of str references<commit_after>#![feature(bind_by_move_pattern_guards)]
// mod lexer;
use lexer::{Token, Lexer};

#[derive(Debug, PartialEq, Clone)]
pub enum CC {
    // condition codes
    E, L, LE, G, GE,
}

#[derive(Debug, Clone)]
pub enum Ast {
    Symbol(String),
    Number(i64),
    Bool(bool),
    List(Vec<Ast>),
    FuncName(String),  // for closure-conversion

    Define(String, Vec<String>, Box<Ast>),
    If(Box<Ast>,     // cnd
       Box<Ast>,     // thn
       Box<Ast>),    // els
    Let(Vec<(String, Ast)>, Box<Ast>),
    Lambda(Vec<String>, Box<Ast>),
    Tuple(Vec<Ast>),
    Cmp(CC, Box<Ast>, Box<Ast>),
    App(Box<Ast>, Vec<Ast>),
    Nil,
}

pub struct Parser<'input> {
    lexer: Lexer<'input>
}

impl<'input> Parser<'input> {
    pub fn new(source: &'input str) -> Parser<'input> {
        Parser {
            lexer: Lexer::new(source)
        }
    }

    pub fn get_list(&mut self) -> Vec<Ast> {
        match self.get_expr() {
            Some(expr) => match self.lexer.next() {
                None => vec![],
                Some(Token::RParen) => vec![expr],
                Some(tok) => {
                    self.lexer.unread(tok);
                    let mut seq = self.get_list();
                    seq.insert(0, expr);

                    return seq;
                }
            },
            None => vec![],
        }
    }

    pub fn get_expr(&mut self) -> Option<Ast> {
        match self.lexer.next() {
            Some(Token::Symbol(s)) => Some(Ast::Symbol(s.to_string())),
            Some(Token::Number(n)) => Some(Ast::Number(n)),
            Some(Token::LParen) => Some(Ast::List(self.get_list())),
            Some(Token::RParen) => panic!("line {}: {} unmatched ')'",
                                          self.lexer.line_num,
                                          self.lexer.col),
            _ => None,
        }
    }

    pub fn get_arg_names(args: &[Ast]) -> Vec<String> {
        let arg_names : Vec<String> =
            args.iter().map(|arg| match arg {
                Ast::Symbol(name) => name.to_string(),
                _ => panic!("invalid arg"),
            }).collect();

        arg_names
    }

    pub fn get_ast(expr: &Ast) -> Ast {
        match expr {
            Ast::Symbol(sym) =>
                match &sym[..] {
                    "#f" => Ast::Bool(false),
                    "#t" => Ast::Bool(true),
                    _ => Ast::Symbol(sym.to_string())
                },
            Ast::List(elts) =>
                match &elts[..] {
                    [Ast::Symbol(k), Ast::List(defelts), body]
                        if k == "define" => {
                            let name = &defelts[0];
                            let args = &defelts[1..];

                            if let Ast::Symbol(name) = name {
                                Ast::Define(name.to_string(),
                                            Parser::get_arg_names(args),
                                            Box::new(Parser::get_ast(body)))
                            } else {
                                panic!("invalid function prototype");
                            }
                        },
                    [Ast::Symbol(k), cnd, thn, els]
                        if k == "if" => {
                            Ast::If(Box::new(Parser::get_ast(cnd)),
                                    Box::new(Parser::get_ast(thn)),
                                    Box::new(Parser::get_ast(els)))
                        },
                    [Ast::Symbol(k), Ast::List(bindings), body]
                        if k == "let" => {
                            let mut astified_bindings = vec![];
                            for bind_pair in bindings {
                                if let Ast::List(kv) = bind_pair {
                                    let (key, val) =
                                        if kv.len() == 2 {
                                            let astified_val = Parser::get_ast(&kv[1]);
                                            let keyname =
                                                if let Ast::Symbol(k) = kv[0].clone() {
                                                    k
                                                } else {
                                                    panic!("let binding key is not symbol");
                                                };
                                            (keyname, astified_val)
                                        } else {
                                            panic!("invalid let binding syntax");
                                        };

                                    astified_bindings.push((key, val));
                                }
                            }

                            Ast::Let(astified_bindings,
                                     Box::new(Parser::get_ast(body)))
                        },
                    [Ast::Symbol(k), Ast::List(args), body]
                        if k == "lambda" => {
                            Ast::Lambda(Parser::get_arg_names(&args),
                                        Box::new(Parser::get_ast(body)))
                        },
                    [Ast::Symbol(k), _..]
                        if k == "tuple" => {
                            let tuple_elts = elts[1..].iter()
                            // TODO: move?
                                .map(|e| Parser::get_ast(e))
                                .collect();
                            Ast::Tuple(tuple_elts)
                        },
                    [Ast::Symbol(cmp), left, right]
                        if (cmp == ">" || cmp == "<" ||
                            cmp == "<=" || cmp == ">=" ||
                            cmp == "=") => {
                            let cc = match &cmp[..] {
                                ">" => CC::G,
                                "<" => CC::L,
                                ">=" => CC::GE,
                                "<=" => CC::LE,
                                "=" => CC::E,
                                &_ => panic!("invalid cmp op"),
                            };

                            Ast::Cmp(cc,
                                     Box::new(Parser::get_ast(left)),
                                     Box::new(Parser::get_ast(right)))
                        },
                    [f, _..] => {
                        let args = elts[1..].iter().map(|e| Parser::get_ast(e)) // TODO: move
                            .collect();

                        Ast::App(Box::new(f.clone()), args)
                    }
                    _ => Ast::Nil,
                },
            _ => expr.clone(),
        }
    }

    pub fn read(&mut self) -> Option<Ast> {
        match self.get_expr() {
            Some(expr) => Some(Parser::get_ast(&expr)),
            None => None,
        }
    }
}

impl<'input> Iterator for Parser<'input> {
    type Item = Ast;

    fn next(&mut self) -> Option<Ast> {
        self.read()
    }
}

fn main() {
    let mut p = Parser::new("(if #t 42 (define (foo x y) (+ (* 1 2) 2)))");
    println!("{:?}", Parser::get_ast(&p.get_expr().unwrap()));

    let mut p2 = Parser::new("(let ((x 10) (y 2)) (+ x y))");
    println!("{:?}", Parser::get_ast(&p2.get_expr().unwrap()));

    let mut p3 = Parser::new("(lambda (x y) (+ x y))");
    println!("{:?}", Parser::get_ast(&p3.get_expr().unwrap()));

    let mut p4 = Parser::new("(tuple 1 2 3)");
    println!("{:?}", Parser::get_ast(&p4.get_expr().unwrap()));

    let mut p5 = Parser::new("(> 1 2)");
    println!("{:?}", Parser::get_ast(&p5.get_expr().unwrap()));

    let mut p6 = Parser::new("(+ 1 2)");
    println!("{:?}", Parser::get_ast(&p6.get_expr().unwrap()));

    let ps = Parser::new("(> 1 2) (+ 1 2)");
    for a in ps {
        println!("{:?}", a);
    }
}
<|endoftext|>


<commit_before>//! Endpoints for creating events.

use std::convert::{TryFrom, TryInto};

use bodyparser;
use diesel::{Connection, ExecuteDsl, FindDsl, LoadDsl, insert};
use iron::{Chain, Handler, IronError, IronResult, Plugin, Request, Response, status};
use router::Router;
use ruma_identifiers::{EventId, RoomId};
use ruma_events::{CustomRoomEvent, EventType};
use ruma_events::call::answer::AnswerEvent;
use ruma_events::call::candidates::CandidatesEvent;
use ruma_events::call::hangup::HangupEvent;
use ruma_events::call::invite::InviteEvent;
use ruma_events::room::message::MessageEvent;
use serde::Deserialize;
use serde_json::{Value, from_value};

use db::DB;
use config::Config;
use error::{ApiError, MapApiError};
use event::NewEvent;
use middleware::{AccessTokenAuth, JsonRequest};
use modifier::SerializableResponse;
use room::Room;
use schema::{events, rooms};
use user::User;

#[derive(Debug, Serialize)]
struct SendMessageEventResponse {
    event_id: String,
}

/// The /rooms/:room_id/send/:event_type/:transaction_id endpoint.
pub struct SendMessageEvent;

impl SendMessageEvent {
    /// Create a `SendMessageEvent` with all necessary middleware.
    pub fn chain() -> Chain {
        let mut chain = Chain::new(SendMessageEvent);

        chain.link_before(JsonRequest);
        chain.link_before(AccessTokenAuth);

        chain
    }
}

impl Handler for SendMessageEvent {
    fn handle(&self, request: &mut Request) -> IronResult<Response> {
        let params = request.extensions.get::<Router>().expect("Params object is missing").clone();

        let room_id = match params.find("room_id") {
            Some(room_id) => RoomId::try_from(room_id).map_api_err(|_| {
                ApiError::not_found(Some(&format!("No room found with ID {}", room_id)))
            })?,
            None => {
                let error = ApiError::missing_param("room_id");

                return Err(IronError::new(error.clone(), error));
            }
        };

        let event_type = params
            .find("event_type")
            .ok_or(ApiError::missing_param("event_type"))
            .map(EventType::from)?;

        let transaction_id = params
            .find("transaction_id")
            .ok_or(ApiError::missing_param("transaction_id"));

        let user = request.extensions.get::<User>()
            .expect("AccessTokenAuth should ensure a user").clone();

        let event_content = request
            .get::<bodyparser::Json>()
            .expect("JsonRequest verifies the Result is Ok")
            .expect("JsonRequest verifies the Option is Some");
        let config = Config::from_request(request)?;
        let event_id = EventId::new(&config.domain).map_api_err(|_| {
            ApiError::unknown(Some("Failed to generated event ID for the new event."))
        })?;

        let room_event: NewEvent = match event_type {
            EventType::CallAnswer => {
                AnswerEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::CallCandidates => {
                CandidatesEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::CallHangup => {
                HangupEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::CallInvite => {
                InviteEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::RoomMessage => {
                MessageEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::Custom(ref custom_event_type) => {
                CustomRoomEvent {
                    content: event_content,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: EventType::Custom(custom_event_type.clone()),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            _ => {
                let error = ApiError::bad_event(
                    Some(&format!("Events of type {} cannot be created with this API.", event_type))
                );

                return Err(IronError::new(error.clone(), error));
            }
        };

        let connection = DB::from_request(request)?;

        connection.transaction(|| {
            let room = rooms::table.find(room_id.to_string()).first::<Room>(&*connection)?;
            let power_levels = room.current_power_levels(&*connection)?;
            let user_power_level = power_levels
                .users
                .get(&user.id)
                .unwrap_or(&power_levels.users_default);
            let required_power_level = power_levels
                .events
                .get(&event_type)
                .unwrap_or(&power_levels.events_default);

            if required_power_level > user_power_level {
                return Err(ApiError::unauthorized(None));
            }

            insert(&room_event)
                .into(events::table)
                .execute(&*connection)
                .map_err(ApiError::from)
        }).map_err(ApiError::from)?;

        let response = SendMessageEventResponse {
            event_id: event_id.opaque_id().to_string(),
        };

        Ok(Response::with((status::Ok, SerializableResponse(response))))
    }
}

fn extract_event_content<T: Deserialize>(event_content: Value, event_type: &EventType)
-> Result<T, ApiError> {
    from_value(event_content).map_api_err(|_| {
        ApiError::bad_event(
            Some(
                &format!(
                    "Event content did not match expected structure for event of type {}.",
                    event_type
                )
            )
        )
    })
}

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

    #[test]
    fn create_message_event() {
        let test = Test::new();
        let access_token = test.create_access_token();
        let room_id = test.create_room(&access_token);

        let create_event_path = format!(
            "/_matrix/client/r0/rooms/{}/send/m.room.message/1?access_token={}",
            room_id,
            access_token
        );

        let response = test.put(&create_event_path, r#"{"body":"Hi","msgtype":"m.text"}"#);

        assert!(response.json().find("event_id").unwrap().as_str().is_some());
    }

    #[test]
    fn event_content_does_not_match_event_type() {
        let test = Test::new();
        let access_token = test.create_access_token();
        let room_id = test.create_room(&access_token);

        let create_event_path = format!(
            "/_matrix/client/r0/rooms/{}/send/m.call.answer/1?access_token={}",
            room_id,
            access_token
        );

        let response = test.put(&create_event_path, r#"{"body":"Hi","msgtype":"m.text"}"#);

        let json = response.json();

        assert_eq!(json.find("errcode").unwrap().as_str().unwrap(), "IO_RUMA_BAD_EVENT");
        assert_eq!(
            json.find("error").unwrap().as_str().unwrap(),
            "Event content did not match expected structure for event of type m.call.answer."
        );
    }

    #[test]
    fn non_message_event_type() {
        let test = Test::new();
        let access_token = test.create_access_token();
        let room_id = test.create_room(&access_token);

        let create_event_path = format!(
            "/_matrix/client/r0/rooms/{}/send/m.room.topic/1?access_token={}",
            room_id,
            access_token
        );

        let response = test.put(&create_event_path, r#"{"topic":"fail"}"#);

        let json = response.json();

        assert_eq!(json.find("errcode").unwrap().as_str().unwrap(), "IO_RUMA_BAD_EVENT");
        assert_eq!(
            json.find("error").unwrap().as_str().unwrap(),
            "Events of type m.room.topic cannot be created with this API."
        );
    }

    #[test]
    fn custom_message_event() {
        let test = Test::new();
        let access_token = test.create_access_token();
        let room_id = test.create_room(&access_token);

        let create_event_path = format!(
            "/_matrix/client/r0/rooms/{}/send/io.ruma.test/1?access_token={}",
            room_id,
            access_token
        );

        let response = test.put(&create_event_path, r#"{"foo":"bar"}"#);

        assert!(response.json().find("event_id").unwrap().as_str().is_some());
    }
}
<commit_msg>Improve error message when user with insufficient power tries to create an event.<commit_after>//! Endpoints for creating events.

use std::convert::{TryFrom, TryInto};

use bodyparser;
use diesel::{Connection, ExecuteDsl, FindDsl, LoadDsl, insert};
use iron::{Chain, Handler, IronError, IronResult, Plugin, Request, Response, status};
use router::Router;
use ruma_identifiers::{EventId, RoomId};
use ruma_events::{CustomRoomEvent, EventType};
use ruma_events::call::answer::AnswerEvent;
use ruma_events::call::candidates::CandidatesEvent;
use ruma_events::call::hangup::HangupEvent;
use ruma_events::call::invite::InviteEvent;
use ruma_events::room::message::MessageEvent;
use serde::Deserialize;
use serde_json::{Value, from_value};

use db::DB;
use config::Config;
use error::{ApiError, MapApiError};
use event::NewEvent;
use middleware::{AccessTokenAuth, JsonRequest};
use modifier::SerializableResponse;
use room::Room;
use schema::{events, rooms};
use user::User;

#[derive(Debug, Serialize)]
struct SendMessageEventResponse {
    event_id: String,
}

/// The /rooms/:room_id/send/:event_type/:transaction_id endpoint.
pub struct SendMessageEvent;

impl SendMessageEvent {
    /// Create a `SendMessageEvent` with all necessary middleware.
    pub fn chain() -> Chain {
        let mut chain = Chain::new(SendMessageEvent);

        chain.link_before(JsonRequest);
        chain.link_before(AccessTokenAuth);

        chain
    }
}

impl Handler for SendMessageEvent {
    fn handle(&self, request: &mut Request) -> IronResult<Response> {
        let params = request.extensions.get::<Router>().expect("Params object is missing").clone();

        let room_id = match params.find("room_id") {
            Some(room_id) => RoomId::try_from(room_id).map_api_err(|_| {
                ApiError::not_found(Some(&format!("No room found with ID {}", room_id)))
            })?,
            None => {
                let error = ApiError::missing_param("room_id");

                return Err(IronError::new(error.clone(), error));
            }
        };

        let event_type = params
            .find("event_type")
            .ok_or(ApiError::missing_param("event_type"))
            .map(EventType::from)?;

        let transaction_id = params
            .find("transaction_id")
            .ok_or(ApiError::missing_param("transaction_id"));

        let user = request.extensions.get::<User>()
            .expect("AccessTokenAuth should ensure a user").clone();

        let event_content = request
            .get::<bodyparser::Json>()
            .expect("JsonRequest verifies the Result is Ok")
            .expect("JsonRequest verifies the Option is Some");
        let config = Config::from_request(request)?;
        let event_id = EventId::new(&config.domain).map_api_err(|_| {
            ApiError::unknown(Some("Failed to generated event ID for the new event."))
        })?;

        let room_event: NewEvent = match event_type {
            EventType::CallAnswer => {
                AnswerEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::CallCandidates => {
                CandidatesEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::CallHangup => {
                HangupEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::CallInvite => {
                InviteEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::RoomMessage => {
                MessageEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::Custom(ref custom_event_type) => {
                CustomRoomEvent {
                    content: event_content,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: EventType::Custom(custom_event_type.clone()),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            _ => {
                let error = ApiError::bad_event(
                    Some(&format!("Events of type {} cannot be created with this API.", event_type))
                );

                return Err(IronError::new(error.clone(), error));
            }
        };

        let connection = DB::from_request(request)?;

        connection.transaction(|| {
            let room = rooms::table.find(room_id.to_string()).first::<Room>(&*connection)?;
            let power_levels = room.current_power_levels(&*connection)?;
            let user_power_level = power_levels
                .users
                .get(&user.id)
                .unwrap_or(&power_levels.users_default);
            let required_power_level = power_levels
                .events
                .get(&event_type)
                .unwrap_or(&power_levels.events_default);

            if required_power_level > user_power_level {
                return Err(
                    ApiError::unauthorized(Some("Insufficient power level to create this event."))
                );
            }

            insert(&room_event)
                .into(events::table)
                .execute(&*connection)
                .map_err(ApiError::from)
        }).map_err(ApiError::from)?;

        let response = SendMessageEventResponse {
            event_id: event_id.opaque_id().to_string(),
        };

        Ok(Response::with((status::Ok, SerializableResponse(response))))
    }
}

fn extract_event_content<T: Deserialize>(event_content: Value, event_type: &EventType)
-> Result<T, ApiError> {
    from_value(event_content).map_api_err(|_| {
        ApiError::bad_event(
            Some(
                &format!(
                    "Event content did not match expected structure for event of type {}.",
                    event_type
                )
            )
        )
    })
}

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

    #[test]
    fn create_message_event() {
        let test = Test::new();
        let access_token = test.create_access_token();
        let room_id = test.create_room(&access_token);

        let create_event_path = format!(
            "/_matrix/client/r0/rooms/{}/send/m.room.message/1?access_token={}",
            room_id,
            access_token
        );

        let response = test.put(&create_event_path, r#"{"body":"Hi","msgtype":"m.text"}"#);

        assert!(response.json().find("event_id").unwrap().as_str().is_some());
    }

    #[test]
    fn event_content_does_not_match_event_type() {
        let test = Test::new();
        let access_token = test.create_access_token();
        let room_id = test.create_room(&access_token);

        let create_event_path = format!(
            "/_matrix/client/r0/rooms/{}/send/m.call.answer/1?access_token={}",
            room_id,
            access_token
        );

        let response = test.put(&create_event_path, r#"{"body":"Hi","msgtype":"m.text"}"#);

        let json = response.json();

        assert_eq!(json.find("errcode").unwrap().as_str().unwrap(), "IO_RUMA_BAD_EVENT");
        assert_eq!(
            json.find("error").unwrap().as_str().unwrap(),
            "Event content did not match expected structure for event of type m.call.answer."
        );
    }

    #[test]
    fn non_message_event_type() {
        let test = Test::new();
        let access_token = test.create_access_token();
        let room_id = test.create_room(&access_token);

        let create_event_path = format!(
            "/_matrix/client/r0/rooms/{}/send/m.room.topic/1?access_token={}",
            room_id,
            access_token
        );

        let response = test.put(&create_event_path, r#"{"topic":"fail"}"#);

        let json = response.json();

        assert_eq!(json.find("errcode").unwrap().as_str().unwrap(), "IO_RUMA_BAD_EVENT");
        assert_eq!(
            json.find("error").unwrap().as_str().unwrap(),
            "Events of type m.room.topic cannot be created with this API."
        );
    }

    #[test]
    fn custom_message_event() {
        let test = Test::new();
        let access_token = test.create_access_token();
        let room_id = test.create_room(&access_token);

        let create_event_path = format!(
            "/_matrix/client/r0/rooms/{}/send/io.ruma.test/1?access_token={}",
            room_id,
            access_token
        );

        let response = test.put(&create_event_path, r#"{"foo":"bar"}"#);

        assert!(response.json().find("event_id").unwrap().as_str().is_some());
    }
}
<|endoftext|>


<commit_before>use crate::{
    consumer::Consumer,
    message::{BasicGetMessage, Delivery},
    queue::{Queue, QueueState},
    types::ShortString,
    BasicProperties, Channel, Error, PromiseResolver, Result,
};
use parking_lot::Mutex;
use std::{collections::HashMap, fmt, sync::Arc};

#[derive(Clone, Default)]
pub(crate) struct Queues {
    queues: Arc<Mutex<HashMap<ShortString, QueueState>>>,
}

impl Queues {
    pub(crate) fn register(&self, queue: QueueState) {
        self.queues.lock().insert(queue.name(), queue);
    }

    pub(crate) fn deregister(&self, queue: &str) {
        self.queues.lock().remove(queue);
    }

    fn with_queue<F: FnOnce(&mut QueueState) -> Result<()>>(
        &self,
        queue: &str,
        f: F,
    ) -> Result<()> {
        f(self
            .queues
            .lock()
            .entry(queue.into())
            .or_insert_with(|| Queue::new(queue.into(), 0, 0).into()))
    }

    pub(crate) fn register_consumer(
        &self,
        queue: &str,
        consumer_tag: ShortString,
        consumer: Consumer,
    ) {
        self.with_queue(queue, |queue| {
            queue.register_consumer(consumer_tag, consumer);
            Ok(())
        })
        .expect("register_consumer cannot fail");
    }

    pub(crate) fn deregister_consumer(&self, consumer_tag: &str) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(|queue| queue.deregister_consumer(consumer_tag))
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn drop_prefetched_messages(&self) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(QueueState::drop_prefetched_messages)
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn cancel_consumers(&self) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(QueueState::cancel_consumers)
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn error_consumers(&self, error: Error) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(|queue| queue.error_consumers(error.clone()))
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn start_consumer_delivery(
        &self,
        consumer_tag: &str,
        message: Delivery,
    ) -> Option<ShortString> {
        for queue in self.queues.lock().values_mut() {
            if let Some(consumer) = queue.get_consumer(consumer_tag) {
                consumer.start_new_delivery(message);
                return Some(queue.name());
            }
        }
        None
    }

    pub(crate) fn start_basic_get_delivery(
        &self,
        queue: &str,
        message: BasicGetMessage,
        resolver: PromiseResolver<Option<BasicGetMessage>>,
    ) {
        self.with_queue(queue, |queue| {
            queue.start_new_delivery(message, resolver);
            Ok(())
        })
        .expect("start_basic_get_delivery cannot fail");
    }

    pub(crate) fn handle_content_header_frame(
        &self,
        channel: &Channel,
        queue: &str,
        consumer_tag: Option<ShortString>,
        size: u64,
        properties: BasicProperties,
    ) -> Result<()> {
        self.with_queue(queue, |queue| {
            match consumer_tag {
                Some(consumer_tag) => {
                    if let Some(consumer) = queue.get_consumer(&consumer_tag) {
                        consumer.set_delivery_properties(properties);
                        if size == 0 {
                            consumer.new_delivery_complete(channel.clone())?;
                        }
                    }
                }
                None => {
                    queue.set_delivery_properties(properties);
                    if size == 0 {
                        queue.new_delivery_complete();
                    }
                }
            }
            Ok(())
        })
    }

    pub(crate) fn handle_body_frame(
        &self,
        channel: &Channel,
        queue: &str,
        consumer_tag: Option<ShortString>,
        remaining_size: usize,
        payload: Vec<u8>,
    ) -> Result<()> {
        self.with_queue(queue, |queue| {
            match consumer_tag {
                Some(consumer_tag) => {
                    if let Some(consumer) = queue.get_consumer(&consumer_tag) {
                        consumer.receive_delivery_content(payload);
                        if remaining_size == 0 {
                            consumer.new_delivery_complete(channel.clone())?;
                        }
                    }
                }
                None => {
                    queue.receive_delivery_content(payload);
                    if remaining_size == 0 {
                        queue.new_delivery_complete();
                    }
                }
            }
            Ok(())
        })
    }
}

impl fmt::Debug for Queues {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut debug = f.debug_tuple("Queues");
        if let Some(queues) = self.queues.try_lock() {
            debug.field(&*queues);
        }
        debug.finish()
    }
}
<commit_msg>Avoid replacing the existing QueueState when a queue is re-declared.<commit_after>use crate::{
    consumer::Consumer,
    message::{BasicGetMessage, Delivery},
    queue::{Queue, QueueState},
    types::ShortString,
    BasicProperties, Channel, Error, PromiseResolver, Result,
};
use parking_lot::Mutex;
use std::{collections::HashMap, fmt, sync::Arc};

#[derive(Clone, Default)]
pub(crate) struct Queues {
    queues: Arc<Mutex<HashMap<ShortString, QueueState>>>,
}

impl Queues {
    pub(crate) fn register(&self, queue: QueueState) {
        // QueueState tracks the consumers associated with a queue.
        //
        // If a queue is re-declared (e.g. to get the number of outstanding messages)
        // we do not want to _replace_ the entry in the `queues` hashmap.
        // If we do replace it we lose track of what consumers are associated with that queue:
        // we have no way to error/cancel them, we have no way to send them incoming messages.
        //
        // This can be avoided with an "insert-if-missing" operation.
        self.queues.lock().entry(queue.name()).or_insert(queue);
    }

    pub(crate) fn deregister(&self, queue: &str) {
        self.queues.lock().remove(queue);
    }

    fn with_queue<F: FnOnce(&mut QueueState) -> Result<()>>(
        &self,
        queue: &str,
        f: F,
    ) -> Result<()> {
        f(self
            .queues
            .lock()
            .entry(queue.into())
            .or_insert_with(|| Queue::new(queue.into(), 0, 0).into()))
    }

    pub(crate) fn register_consumer(
        &self,
        queue: &str,
        consumer_tag: ShortString,
        consumer: Consumer,
    ) {
        self.with_queue(queue, |queue| {
            queue.register_consumer(consumer_tag, consumer);
            Ok(())
        })
        .expect("register_consumer cannot fail");
    }

    pub(crate) fn deregister_consumer(&self, consumer_tag: &str) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(|queue| queue.deregister_consumer(consumer_tag))
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn drop_prefetched_messages(&self) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(QueueState::drop_prefetched_messages)
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn cancel_consumers(&self) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(QueueState::cancel_consumers)
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn error_consumers(&self, error: Error) -> Result<()> {
        self.queues
            .lock()
            .values_mut()
            .map(|queue| queue.error_consumers(error.clone()))
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn start_consumer_delivery(
        &self,
        consumer_tag: &str,
        message: Delivery,
    ) -> Option<ShortString> {
        for queue in self.queues.lock().values_mut() {
            if let Some(consumer) = queue.get_consumer(consumer_tag) {
                consumer.start_new_delivery(message);
                return Some(queue.name());
            }
        }
        None
    }

    pub(crate) fn start_basic_get_delivery(
        &self,
        queue: &str,
        message: BasicGetMessage,
        resolver: PromiseResolver<Option<BasicGetMessage>>,
    ) {
        self.with_queue(queue, |queue| {
            queue.start_new_delivery(message, resolver);
            Ok(())
        })
        .expect("start_basic_get_delivery cannot fail");
    }

    pub(crate) fn handle_content_header_frame(
        &self,
        channel: &Channel,
        queue: &str,
        consumer_tag: Option<ShortString>,
        size: u64,
        properties: BasicProperties,
    ) -> Result<()> {
        self.with_queue(queue, |queue| {
            match consumer_tag {
                Some(consumer_tag) => {
                    if let Some(consumer) = queue.get_consumer(&consumer_tag) {
                        consumer.set_delivery_properties(properties);
                        if size == 0 {
                            consumer.new_delivery_complete(channel.clone())?;
                        }
                    }
                }
                None => {
                    queue.set_delivery_properties(properties);
                    if size == 0 {
                        queue.new_delivery_complete();
                    }
                }
            }
            Ok(())
        })
    }

    pub(crate) fn handle_body_frame(
        &self,
        channel: &Channel,
        queue: &str,
        consumer_tag: Option<ShortString>,
        remaining_size: usize,
        payload: Vec<u8>,
    ) -> Result<()> {
        self.with_queue(queue, |queue| {
            match consumer_tag {
                Some(consumer_tag) => {
                    if let Some(consumer) = queue.get_consumer(&consumer_tag) {
                        consumer.receive_delivery_content(payload);
                        if remaining_size == 0 {
                            consumer.new_delivery_complete(channel.clone())?;
                        }
                    }
                }
                None => {
                    queue.receive_delivery_content(payload);
                    if remaining_size == 0 {
                        queue.new_delivery_complete();
                    }
                }
            }
            Ok(())
        })
    }
}

impl fmt::Debug for Queues {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut debug = f.debug_tuple("Queues");
        if let Some(queues) = self.queues.try_lock() {
            debug.field(&*queues);
        }
        debug.finish()
    }
}
<|endoftext|>


<commit_before>//! Path rasterization.

use crate::{gpu::GpuVertex, Result, P2};
use lyon_path::Builder;
use lyon_tessellation::{
    BuffersBuilder, FillAttributes, FillOptions, FillTessellator, StrokeAttributes, StrokeOptions,
    StrokeTessellator, VertexBuffers,
};
use palette::LinSrgba;

/// The method by which the rasterizer will rasterize the vector path.
#[derive(Debug, Clone, Copy)]
pub enum Method {
    /// In fill method, the rasterizer will treat all the area inside the path as part of the
    /// raster area. In this method, paths are automatically closed by assuming an edge from the
    /// last to the first vertex.
    Fill,
    /// In stroke method, the rasterizer will treat the area immediately adjacent the path within
    /// the given width as part of the rastered area. In this method, paths are left open
    /// and no edge between the last and first vertex is assumed.
    Stroke(f32),
}

pub fn raster_path(
    builder: Builder,
    method: Method,
    color: LinSrgba,
) -> Result<(Vec<GpuVertex>, Vec<u32>)> {
    match method {
        Method::Fill => {
            let ctor = |v: P2, _: FillAttributes| -> P2 { v };
            let mut buffers: VertexBuffers<P2, u32> = VertexBuffers::new();
            let mut buffers_builder = BuffersBuilder::new(&mut buffers, ctor);

            let mut tessellator = FillTessellator::new();
            let result = tessellator.tessellate_path(
                &builder.build(),
                &FillOptions::default().with_tolerance(0.05),
                &mut buffers_builder,
            );
            match result {
                Ok(_) => {}
                Err(e) => panic!("Tessellation failed: {:?}", e),
            }

            Ok((
                buffers
                    .vertices
                    .into_iter()
                    .map(|v| GpuVertex {
                        vpos: [v.x, v.y],
                        vcol: [
                            color.color.red,
                            color.color.green,
                            color.color.blue,
                            color.alpha,
                        ],
                    })
                    .collect(),
                buffers.indices,
            ))
        }
        Method::Stroke(width) => {
            let ctor = |v: P2, _: StrokeAttributes| -> P2 { v };
            let mut buffers: VertexBuffers<P2, u32> = VertexBuffers::new();
            let mut buffers_builder = BuffersBuilder::new(&mut buffers, ctor);

            let mut tessellator = StrokeTessellator::new();
            tessellator
                .tessellate_path(
                    &builder.build(),
                    &StrokeOptions::default()
                        .with_line_width(width)
                        .with_tolerance(0.05),
                    &mut buffers_builder,
                )
                .expect("TODO: wrap error");

            Ok((
                buffers
                    .vertices
                    .into_iter()
                    .map(|v| GpuVertex {
                        vpos: [v.x, v.y],
                        vcol: [
                            color.color.red,
                            color.color.green,
                            color.color.blue,
                            color.alpha,
                        ],
                    })
                    .collect(),
                buffers.indices,
            ))
        }
    }
}
<commit_msg>Clip Miter line joins<commit_after>//! Path rasterization.

use crate::{gpu::GpuVertex, Result, P2};
use lyon_path::Builder;
use lyon_tessellation::{
    BuffersBuilder, FillAttributes, FillOptions, FillTessellator, LineJoin, StrokeAttributes,
    StrokeOptions, StrokeTessellator, VertexBuffers,
};
use palette::LinSrgba;

/// The method by which the rasterizer will rasterize the vector path.
#[derive(Debug, Clone, Copy)]
pub enum Method {
    /// In fill method, the rasterizer will treat all the area inside the path as part of the
    /// raster area. In this method, paths are automatically closed by assuming an edge from the
    /// last to the first vertex.
    Fill,
    /// In stroke method, the rasterizer will treat the area immediately adjacent the path within
    /// the given width as part of the rastered area. In this method, paths are left open
    /// and no edge between the last and first vertex is assumed.
    Stroke(f32),
}

pub fn raster_path(
    builder: Builder,
    method: Method,
    color: LinSrgba,
) -> Result<(Vec<GpuVertex>, Vec<u32>)> {
    match method {
        Method::Fill => {
            let ctor = |v: P2, _: FillAttributes| -> P2 { v };
            let mut buffers: VertexBuffers<P2, u32> = VertexBuffers::new();
            let mut buffers_builder = BuffersBuilder::new(&mut buffers, ctor);

            let mut tessellator = FillTessellator::new();
            let result = tessellator.tessellate_path(
                &builder.build(),
                &FillOptions::default().with_tolerance(0.05),
                &mut buffers_builder,
            );
            match result {
                Ok(_) => {}
                Err(e) => panic!("Tessellation failed: {:?}", e),
            }

            Ok((
                buffers
                    .vertices
                    .into_iter()
                    .map(|v| GpuVertex {
                        vpos: [v.x, v.y],
                        vcol: [
                            color.color.red,
                            color.color.green,
                            color.color.blue,
                            color.alpha,
                        ],
                    })
                    .collect(),
                buffers.indices,
            ))
        }
        Method::Stroke(width) => {
            let ctor = |v: P2, _: StrokeAttributes| -> P2 { v };
            let mut buffers: VertexBuffers<P2, u32> = VertexBuffers::new();
            let mut buffers_builder = BuffersBuilder::new(&mut buffers, ctor);

            let mut tessellator = StrokeTessellator::new();
            tessellator
                .tessellate_path(
                    &builder.build(),
                    &StrokeOptions::default()
                        .with_line_join(LineJoin::MiterClip)
                        .with_line_width(width)
                        .with_tolerance(0.05),
                    &mut buffers_builder,
                )
                .expect("TODO: wrap error");

            Ok((
                buffers
                    .vertices
                    .into_iter()
                    .map(|v| GpuVertex {
                        vpos: [v.x, v.y],
                        vcol: [
                            color.color.red,
                            color.color.green,
                            color.color.blue,
                            color.alpha,
                        ],
                    })
                    .collect(),
                buffers.indices,
            ))
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::sync::mpsc::{Receiver, Sender, SyncSender, channel};
use std::error::Error;
use item::Item;
use std::sync::{Arc, RwLock};
use std::process::{Command, Stdio, Child};
use std::io::{stdin, BufRead, BufReader};
use event::{Event, EventArg};
use std::thread::JoinHandle;
use std::thread;
use std::time::Duration;
use std::collections::HashMap;
use std::mem;

use std::io::Write;
use getopts;
use regex::Regex;
use sender::CachedSender;

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

struct ReaderOption {
    pub use_ansi_color: bool,
    pub default_arg: String,
    pub transform_fields: Vec<FieldRange>,
    pub matching_fields: Vec<FieldRange>,
    pub delimiter: Regex,
    pub replace_str: String,
}

impl ReaderOption {
    pub fn new() -> Self {
        ReaderOption {
            use_ansi_color: false,
            default_arg: String::new(),
            transform_fields: Vec::new(),
            matching_fields: Vec::new(),
            delimiter: Regex::new(r".*?\t").unwrap(),
            replace_str: "{}".to_string(),
        }
    }

    pub fn parse_options(&mut self, options: &getopts::Matches) {
        if options.opt_present("ansi") {
            self.use_ansi_color = true;
        }

        if let Some(delimiter) = options.opt_str("d") {
            self.delimiter = Regex::new(&(".*?".to_string() + &delimiter))
                .unwrap_or(Regex::new(r".*?\t").unwrap());
        }

        if let Some(transform_fields) = options.opt_str("with-nth") {
            self.transform_fields = transform_fields.split(',')
                .map(|string| {
                    parse_range(string)
                })
                .filter(|range| range.is_some())
                .map(|range| range.unwrap())
                .collect();
        }

        if let Some(matching_fields) = options.opt_str("nth") {
            self.matching_fields = matching_fields.split(',')
                .map(|string| {
                    parse_range(string)
                })
                .filter(|range| range.is_some())
                .map(|range| range.unwrap())
                .collect();
        }
    }
}

pub struct Reader {
    rx_cmd: Receiver<(Event, EventArg)>,
    tx_item: SyncSender<(Event, EventArg)>,
    option: Arc<RwLock<ReaderOption>>,
}

impl Reader {
    pub fn new(rx_cmd: Receiver<(Event, EventArg)>, tx_item: SyncSender<(Event, EventArg)>) -> Self {
        Reader {
            rx_cmd: rx_cmd,
            tx_item: tx_item,
            option: Arc::new(RwLock::new(ReaderOption::new()))
        }
    }

    pub fn parse_options(&mut self, options: &getopts::Matches) {
        let mut option = self.option.write().unwrap();
        option.parse_options(options);
    }

    pub fn run(&mut self) {
        // event loop
        let mut thread_reader: Option<JoinHandle<()>> = None;
        let mut tx_reader: Option<Sender<bool>> = None;

        let mut last_command = "".to_string();
        let mut last_query = "".to_string();

        // start sender
        let (tx_sender, rx_sender) = channel();
        let tx_item = self.tx_item.clone();
        let mut sender = CachedSender::new(rx_sender, tx_item);
        thread::spawn(move || {
            sender.run();
        });

        while let Ok((ev, arg)) = self.rx_cmd.recv() {
            match ev {
                Event::EvReaderRestart => {
                    // close existing command or file if exists
                    let (cmd, query) = *arg.downcast::<(String, String)>().unwrap();
                    if cmd == last_command && query == last_query { continue; }

                    // restart command with new `command`
                    if cmd != last_command {
                        // stop existing command
                        tx_reader.take().map(|tx| {tx.send(true)});
                        thread_reader.take().map(|thrd| {thrd.join()});

                        // create needed data for thread
                        let (tx, rx_reader) = channel();
                        tx_reader = Some(tx);
                        let cmd_clone = cmd.clone();
                        let option_clone = self.option.clone();
                        let tx_sender_clone = tx_sender.clone();
                        let query_clone = query.clone();

                        // start the new command
                        thread::spawn(move || {
                            let _ = tx_sender_clone.send((Event::EvReaderStarted, Box::new(true)));
                            let _ = tx_sender_clone.send((Event::EvSenderRestart, Box::new(query_clone)));

                            reader(&cmd_clone, rx_reader, &tx_sender_clone, option_clone);

                            let _ = tx_sender_clone.send((Event::EvReaderStopped, Box::new(true)));
                        });
                    } else {
                        // tell sender to restart
                        let _ = tx_sender.send((Event::EvSenderRestart, Box::new(query.clone())));
                    }

                    last_command = cmd;
                    last_query = query;
                }
                _ => {
                    // do nothing
                }
            }
        }
    }
}

fn get_command_output(cmd: &str) -> Result<(Option<Child>, Box<BufRead>), Box<Error>> {
    let mut command = try!(Command::new("sh")
                       .arg("-c")
                       .arg(cmd)
                       .stdout(Stdio::piped())
                       .stderr(Stdio::null())
                       .spawn());
    let stdout = try!(command.stdout.take().ok_or("command output: unwrap failed".to_owned()));
    Ok((Some(command), Box::new(BufReader::new(stdout))))
}

// Consider that you invoke a command with different arguments several times
// If you select some items each time, how will skim remeber it?
// => Well, we'll give each invokation a number, i.e. RUN_NUM
// What if you invoke the same command and same arguments twice?
// => We use NUM_MAP to specify the same run number.
lazy_static! {
    static ref RUN_NUM: RwLock<usize> = RwLock::new(0);
    static ref NUM_MAP: RwLock<HashMap<String, usize>> = RwLock::new(HashMap::new());
}

fn reader(cmd: &str,
          rx_cmd: Receiver<bool>,
          tx_sender: &Sender<(Event, EventArg)>,
          option: Arc<RwLock<ReaderOption>>) {
    let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;

    let (command, mut source): (Option<Child>, Box<BufRead>) = if istty {
        get_command_output(cmd).expect("command not found")
    } else {
        (None, Box::new(BufReader::new(stdin())))
    };

    let (tx_control, rx_control) = channel();

    thread::spawn(move || {
        // listen to `rx` for command to quit reader
        // kill command if it is got
        loop {
            if rx_cmd.try_recv().is_ok() {
                // clean up resources
                command.map(|mut x| {
                    let _ = x.kill();
                    let _ = x.wait();
                });
                break;
            }

            if rx_control.recv_timeout(Duration::from_millis(10)).is_ok() {
                command.map(|mut x| {
                    let _ = x.kill();
                    let _ = x.wait();
                });
                break;
            }
        }
    });

    let opt = option.read().unwrap();

    // set the proper run number
    let run_num = {*RUN_NUM.read().unwrap()};
    let run_num = *NUM_MAP.write()
            .unwrap()
            .entry(cmd.to_string())
            .or_insert_with(|| {
                *(RUN_NUM.write().unwrap()) = run_num + 1;
                run_num + 1
            });

    let mut index = 0;
    let mut item_group = Vec::new();
    loop {
        // start reading
        let mut input = String::new();
        match source.read_line(&mut input) {
            Ok(n) => {
                if n == 0 { break; }

                if input.ends_with('\n') {
                    input.pop();
                    if input.ends_with('\r') {
                        input.pop();
                    }
                }
                let item = Item::new(input,
                                     opt.use_ansi_color,
                                     &opt.transform_fields,
                                     &opt.matching_fields,
                                     &opt.delimiter,
                                     (run_num, index));
                item_group.push(Arc::new(item));
                index += 1;

                if index & 0xFFF == 0 {
                    let _ = tx_sender.send((Event::EvReaderNewItem, Box::new(mem::replace(&mut item_group, Vec::new()))));
                }
            }
            Err(_err) => {} // String not UTF8 or other error, skip.
        }
    }

    if !item_group.is_empty() {
        let _ = tx_sender.send((Event::EvReaderNewItem, Box::new(mem::replace(&mut item_group, Vec::new()))));
    }

    let _ = tx_control.send(true);
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum FieldRange {
    Single(i64),
    LeftInf(i64),
    RightInf(i64),
    Both(i64, i64),
}

// range: "start..end", end is excluded.
// "0", "0..", "..10", "1..10", etc.
fn parse_range(range: &str) -> Option<FieldRange> {
    use self::FieldRange::*;

    if range == ".." {
        return Some(RightInf(0));
    }

    let range_string: Vec<&str> = range.split("..").collect();
    if range_string.is_empty() || range_string.len() > 2 {
        return None;
    }

    let start = range_string.get(0).and_then(|x| x.parse::<i64>().ok());
    let end = range_string.get(1).and_then(|x| x.parse::<i64>().ok());

    if range_string.len() == 1 {
        return if start.is_none() {None} else {Some(Single(start.unwrap()))};
    }

    if start.is_none() && end.is_none() {
        None
    } else if end.is_none() {
        // 1..
        Some(RightInf(start.unwrap()))
    } else if start.is_none() {
        // ..1
        Some(LeftInf(end.unwrap()))
    } else {
        Some(Both(start.unwrap(), end.unwrap()))
    }
}

#[cfg(test)]
mod test {
    use super::FieldRange::*;
    #[test]
    fn test_parse_range() {
        assert_eq!(super::parse_range("1"), Some(Single(1)));
        assert_eq!(super::parse_range("-1"), Some(Single(-1)));

        assert_eq!(super::parse_range("1.."), Some(RightInf(1)));
        assert_eq!(super::parse_range("-1.."), Some(RightInf(-1)));

        assert_eq!(super::parse_range("..1"), Some(LeftInf(1)));
        assert_eq!(super::parse_range("..-1"), Some(LeftInf(-1)));

        assert_eq!(super::parse_range("1..3"), Some(Both(1, 3)));
        assert_eq!(super::parse_range("-1..-3"), Some(Both(-1, -3)));

        assert_eq!(super::parse_range(".."), Some(RightInf(0)));
        assert_eq!(super::parse_range("a.."), None);
        assert_eq!(super::parse_range("..b"), None);
        assert_eq!(super::parse_range("a..b"), None);
    }
}
<commit_msg>[reader] fix: synchronization between invokation.<commit_after>extern crate libc;

use std::sync::mpsc::{Receiver, Sender, SyncSender, channel};
use std::error::Error;
use item::Item;
use std::sync::{Arc, RwLock};
use std::process::{Command, Stdio, Child};
use std::io::{stdin, BufRead, BufReader};
use event::{Event, EventArg};
use std::thread::JoinHandle;
use std::thread;
use std::time::Duration;
use std::collections::HashMap;
use std::mem;

use std::io::Write;
use getopts;
use regex::Regex;
use sender::CachedSender;

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

struct ReaderOption {
    pub use_ansi_color: bool,
    pub default_arg: String,
    pub transform_fields: Vec<FieldRange>,
    pub matching_fields: Vec<FieldRange>,
    pub delimiter: Regex,
    pub replace_str: String,
}

impl ReaderOption {
    pub fn new() -> Self {
        ReaderOption {
            use_ansi_color: false,
            default_arg: String::new(),
            transform_fields: Vec::new(),
            matching_fields: Vec::new(),
            delimiter: Regex::new(r".*?\t").unwrap(),
            replace_str: "{}".to_string(),
        }
    }

    pub fn parse_options(&mut self, options: &getopts::Matches) {
        if options.opt_present("ansi") {
            self.use_ansi_color = true;
        }

        if let Some(delimiter) = options.opt_str("d") {
            self.delimiter = Regex::new(&(".*?".to_string() + &delimiter))
                .unwrap_or(Regex::new(r".*?\t").unwrap());
        }

        if let Some(transform_fields) = options.opt_str("with-nth") {
            self.transform_fields = transform_fields.split(',')
                .map(|string| {
                    parse_range(string)
                })
                .filter(|range| range.is_some())
                .map(|range| range.unwrap())
                .collect();
        }

        if let Some(matching_fields) = options.opt_str("nth") {
            self.matching_fields = matching_fields.split(',')
                .map(|string| {
                    parse_range(string)
                })
                .filter(|range| range.is_some())
                .map(|range| range.unwrap())
                .collect();
        }
    }
}

pub struct Reader {
    rx_cmd: Receiver<(Event, EventArg)>,
    tx_item: SyncSender<(Event, EventArg)>,
    option: Arc<RwLock<ReaderOption>>,
}

impl Reader {
    pub fn new(rx_cmd: Receiver<(Event, EventArg)>, tx_item: SyncSender<(Event, EventArg)>) -> Self {
        Reader {
            rx_cmd: rx_cmd,
            tx_item: tx_item,
            option: Arc::new(RwLock::new(ReaderOption::new()))
        }
    }

    pub fn parse_options(&mut self, options: &getopts::Matches) {
        let mut option = self.option.write().unwrap();
        option.parse_options(options);
    }

    pub fn run(&mut self) {
        // event loop
        let mut thread_reader: Option<JoinHandle<()>> = None;
        let mut tx_reader: Option<Sender<bool>> = None;

        let mut last_command = "".to_string();
        let mut last_query = "".to_string();

        // start sender
        let (tx_sender, rx_sender) = channel();
        let tx_item = self.tx_item.clone();
        let mut sender = CachedSender::new(rx_sender, tx_item);
        thread::spawn(move || {
            sender.run();
        });

        while let Ok((ev, arg)) = self.rx_cmd.recv() {
            match ev {
                Event::EvReaderRestart => {
                    // close existing command or file if exists
                    let (cmd, query) = *arg.downcast::<(String, String)>().unwrap();
                    if cmd == last_command && query == last_query { continue; }

                    // restart command with new `command`
                    if cmd != last_command {
                        // stop existing command
                        tx_reader.take().map(|tx| {tx.send(true)});
                        thread_reader.take().map(|thrd| {thrd.join()});

                        // create needed data for thread
                        let (tx, rx_reader) = channel();
                        tx_reader = Some(tx);
                        let cmd_clone = cmd.clone();
                        let option_clone = self.option.clone();
                        let tx_sender_clone = tx_sender.clone();
                        let query_clone = query.clone();

                        // start the new command
                        thread_reader = Some(thread::spawn(move || {
                            let _ = tx_sender_clone.send((Event::EvReaderStarted, Box::new(true)));
                            let _ = tx_sender_clone.send((Event::EvSenderRestart, Box::new(query_clone)));

                            reader(&cmd_clone, rx_reader, &tx_sender_clone, option_clone);

                            let _ = tx_sender_clone.send((Event::EvReaderStopped, Box::new(true)));
                        }));
                    } else {
                        // tell sender to restart
                        let _ = tx_sender.send((Event::EvSenderRestart, Box::new(query.clone())));
                    }

                    last_command = cmd;
                    last_query = query;
                }
                _ => {
                    // do nothing
                }
            }
        }
    }
}

fn get_command_output(cmd: &str) -> Result<(Option<Child>, Box<BufRead>), Box<Error>> {
    let mut command = try!(Command::new("sh")
                       .arg("-c")
                       .arg(cmd)
                       .stdout(Stdio::piped())
                       .stderr(Stdio::null())
                       .spawn());
    let stdout = try!(command.stdout.take().ok_or("command output: unwrap failed".to_owned()));
    Ok((Some(command), Box::new(BufReader::new(stdout))))
}

// Consider that you invoke a command with different arguments several times
// If you select some items each time, how will skim remeber it?
// => Well, we'll give each invokation a number, i.e. RUN_NUM
// What if you invoke the same command and same arguments twice?
// => We use NUM_MAP to specify the same run number.
lazy_static! {
    static ref RUN_NUM: RwLock<usize> = RwLock::new(0);
    static ref NUM_MAP: RwLock<HashMap<String, usize>> = RwLock::new(HashMap::new());
}

fn reader(cmd: &str,
          rx_cmd: Receiver<bool>,
          tx_sender: &Sender<(Event, EventArg)>,
          option: Arc<RwLock<ReaderOption>>) {
    let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;

    let (command, mut source): (Option<Child>, Box<BufRead>) = if istty {
        get_command_output(cmd).expect("command not found")
    } else {
        (None, Box::new(BufReader::new(stdin())))
    };

    let (tx_control, rx_control) = channel();

    thread::spawn(move || {
        // listen to `rx` for command to quit reader
        // kill command if it is got
        loop {
            if rx_cmd.try_recv().is_ok() {
                // clean up resources
                command.map(|mut x| {
                    let _ = x.kill();
                    let _ = x.wait();
                });
                break;
            }

            if rx_control.recv_timeout(Duration::from_millis(10)).is_ok() {
                command.map(|mut x| {
                    let _ = x.kill();
                    let _ = x.wait();
                });
                break;
            }
        }
    });

    let opt = option.read().unwrap();

    // set the proper run number
    let run_num = {*RUN_NUM.read().unwrap()};
    let run_num = *NUM_MAP.write()
            .unwrap()
            .entry(cmd.to_string())
            .or_insert_with(|| {
                *(RUN_NUM.write().unwrap()) = run_num + 1;
                run_num + 1
            });

    let mut index = 0;
    let mut item_group = Vec::new();
    loop {
        // start reading
        let mut input = String::new();
        match source.read_line(&mut input) {
            Ok(n) => {
                if n == 0 { break; }

                if input.ends_with('\n') {
                    input.pop();
                    if input.ends_with('\r') {
                        input.pop();
                    }
                }
                let item = Item::new(input,
                                     opt.use_ansi_color,
                                     &opt.transform_fields,
                                     &opt.matching_fields,
                                     &opt.delimiter,
                                     (run_num, index));
                item_group.push(Arc::new(item));
                index += 1;

                if index & 0xFFF == 0 {
                    let _ = tx_sender.send((Event::EvReaderNewItem, Box::new(mem::replace(&mut item_group, Vec::new()))));
                }
            }
            Err(_err) => {} // String not UTF8 or other error, skip.
        }
    }

    if !item_group.is_empty() {
        let _ = tx_sender.send((Event::EvReaderNewItem, Box::new(mem::replace(&mut item_group, Vec::new()))));
    }

    let _ = tx_control.send(true);
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum FieldRange {
    Single(i64),
    LeftInf(i64),
    RightInf(i64),
    Both(i64, i64),
}

// range: "start..end", end is excluded.
// "0", "0..", "..10", "1..10", etc.
fn parse_range(range: &str) -> Option<FieldRange> {
    use self::FieldRange::*;

    if range == ".." {
        return Some(RightInf(0));
    }

    let range_string: Vec<&str> = range.split("..").collect();
    if range_string.is_empty() || range_string.len() > 2 {
        return None;
    }

    let start = range_string.get(0).and_then(|x| x.parse::<i64>().ok());
    let end = range_string.get(1).and_then(|x| x.parse::<i64>().ok());

    if range_string.len() == 1 {
        return if start.is_none() {None} else {Some(Single(start.unwrap()))};
    }

    if start.is_none() && end.is_none() {
        None
    } else if end.is_none() {
        // 1..
        Some(RightInf(start.unwrap()))
    } else if start.is_none() {
        // ..1
        Some(LeftInf(end.unwrap()))
    } else {
        Some(Both(start.unwrap(), end.unwrap()))
    }
}

#[cfg(test)]
mod test {
    use super::FieldRange::*;
    #[test]
    fn test_parse_range() {
        assert_eq!(super::parse_range("1"), Some(Single(1)));
        assert_eq!(super::parse_range("-1"), Some(Single(-1)));

        assert_eq!(super::parse_range("1.."), Some(RightInf(1)));
        assert_eq!(super::parse_range("-1.."), Some(RightInf(-1)));

        assert_eq!(super::parse_range("..1"), Some(LeftInf(1)));
        assert_eq!(super::parse_range("..-1"), Some(LeftInf(-1)));

        assert_eq!(super::parse_range("1..3"), Some(Both(1, 3)));
        assert_eq!(super::parse_range("-1..-3"), Some(Both(-1, -3)));

        assert_eq!(super::parse_range(".."), Some(RightInf(0)));
        assert_eq!(super::parse_range("a.."), None);
        assert_eq!(super::parse_range("..b"), None);
        assert_eq!(super::parse_range("a..b"), None);
    }
}
<|endoftext|>


<commit_before>use std;
use std::io::prelude::*;
use std::io::{Error, ErrorKind};
use std::net::TcpStream;

/// Reads bytes from the TCP stream until CRLF is found or the given limit is
/// reached.
pub fn read_line(stream: &TcpStream, limit: usize) -> std::io::Result<String> {
  let mut result = String::with_capacity(limit);

  for byte in stream.take(limit as u64).bytes() {
    let raw = try!(byte);
    let chr = raw as char;

    result.push(chr);

    if chr == '\n' {
      break;
    }
  }

  if result.ends_with("\r\n") {
    // .truncate() panics if the new length is not at char boundary. Since we
    // know the string ends with \r\n, that won't happen.
    let new_len = result.len() - 2;
    result.truncate(new_len);

    // Return the result.
    Ok(result)
  } else if result.len() == limit {
    // The line did not fit in the given limit.
    Err(Error::new(ErrorKind::Other, "Line too long."))
  } else {
    // The line ending was invalid or missing.
    Err(Error::new(ErrorKind::Other, "The line must end in CRLF sequence."))
  }
}

/// Reads the given number of bytes from the stream into a Vec<u8> or returns
/// an error if the exact number of bytes cannot be read.
pub fn read_bytes(stream: &TcpStream, amount: usize) -> std::io::Result<Vec<u8>> {
  let mut buf: Vec<u8> = vec![];
  let read = try!(stream.take(amount as u64).read_to_end(&mut buf));

  if read < amount {
    Err(Error::new(ErrorKind::Other, "Unexpected end of stream."))
  } else {
    Ok(buf)
  }
}

/// Reads four bytes from the stream and combines them together to form a 32 bit
/// unsigned integer.
pub fn read_u32(stream: &TcpStream) -> std::io::Result<u32> {
  let buf = try!(read_bytes(stream, 4));

  Ok(buf.iter().enumerate().fold(0, |result, (i, value)| {
    result | ((*value as u32) << (3 - i) * 8)
  }))
}

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

  #[test]
  fn test_readline_basic() {
    let stream = create_tcp_stream("foo\r\n".as_bytes());
    assert_eq!(read_line(&stream, 255).unwrap(), "foo");
  }

  #[test]
  fn test_readline_empty_line() {
    let stream = create_tcp_stream("\r\n".as_bytes());
    assert_eq!(read_line(&stream, 255).unwrap(), "");
  }

  #[test]
  fn test_readline_multiple_lines_reads_only_first() {
    let stream = create_tcp_stream("bar\r\nfoo\r\n".as_bytes());
    assert_eq!(read_line(&stream, 255).unwrap(), "bar");
    assert_eq!(read_line(&stream, 255).unwrap(), "foo");
  }

  #[test]
  fn test_readline_line_too_long() {
    let stream = create_tcp_stream("barbazfoo\r\n".as_bytes());
    assert!(read_line(&stream, 5).is_err());
  }

  #[test]
  fn test_readline_line_at_limit() {
    let stream = create_tcp_stream("123\r\n".as_bytes());
    assert_eq!(read_line(&stream, 5).unwrap(), "123");
  }

  #[test]
  fn test_readline_no_cr_before_lf() {
    let stream = create_tcp_stream("barbazfoo\n".as_bytes());
    assert!(read_line(&stream, 255).is_err());
  }

  #[test]
  fn test_readline_no_crlf() {
    let stream = create_tcp_stream("barbazfoo".as_bytes());
    assert!(read_line(&stream, 255).is_err());
  }

  #[test]
  fn test_readline_no_lf() {
    let stream = create_tcp_stream("barb\razfoo".as_bytes());
    assert!(read_line(&stream, 255).is_err());
  }

  #[test]
  fn test_readline_empty() {
    let stream = create_tcp_stream("".as_bytes());
    assert!(read_line(&stream, 255).is_err());
  }

  #[test]
  fn test_readline_only_lf() {
    let stream = create_tcp_stream("\n".as_bytes());
    assert!(read_line(&stream, 255).is_err());
  }

  #[test]
  fn test_read_u32_basic() {
    let stream = create_tcp_stream(&[0x29, 0xb7, 0xf4, 0xaa, 0xff, 0xff]);
    assert_eq!(read_u32(&stream).unwrap(), 0x29b7f4aa);
  }

  #[test]
  fn test_read_u32_basic_zeroes() {
    let stream = create_tcp_stream(&[0x29, 0x00, 0xf4, 0xaa, 0xff, 0xff]);
    assert_eq!(read_u32(&stream).unwrap(), 0x2900f4aa);
  }

  #[test]
  fn test_read_u32_too_little_data() {
    let stream = create_tcp_stream(&[0x29, 0xb7, 0xf4]);
    assert!(read_u32(&stream).is_err());
  }

  #[test]
  fn test_read_bytes_basic() {
    let stream = create_tcp_stream(&[1,2,3,4,5,6]);
    assert_eq!(read_bytes(&stream, 2).unwrap(), [1,2]);
    assert_eq!(read_bytes(&stream, 3).unwrap(), [3,4,5]);
    assert_eq!(read_bytes(&stream, 1).unwrap(), [6]);
  }

  #[test]
  fn test_read_bytes_too_little_data() {
    let stream = create_tcp_stream(&[1,2,3,4,5,6]);
    assert!(read_bytes(&stream, 10).is_err())
  }
}
<commit_msg>Make the reader methods take a T: Read instead of TcpStream.<commit_after>use std;
use std::io::prelude::*;
use std::io::{Error, ErrorKind};

/// Reads bytes from the TCP stream until CRLF is found or the given limit is
/// reached.
pub fn read_line<T: Read>(stream: T, limit: usize) -> std::io::Result<String> {
  let mut result = String::with_capacity(limit);

  for byte in stream.take(limit as u64).bytes() {
    let raw = try!(byte);
    let chr = raw as char;

    result.push(chr);

    if chr == '\n' {
      break;
    }
  }

  if result.ends_with("\r\n") {
    // .truncate() panics if the new length is not at char boundary. Since we
    // know the string ends with \r\n, that won't happen.
    let new_len = result.len() - 2;
    result.truncate(new_len);

    // Return the result.
    Ok(result)
  } else if result.len() == limit {
    // The line did not fit in the given limit.
    Err(Error::new(ErrorKind::Other, "Line too long."))
  } else {
    // The line ending was invalid or missing.
    Err(Error::new(ErrorKind::Other, "The line must end in CRLF sequence."))
  }
}

/// Reads the given number of bytes from the stream into a Vec<u8> or returns
/// an error if the exact number of bytes cannot be read.
pub fn read_bytes<T: Read>(stream: T, amount: usize) -> std::io::Result<Vec<u8>> {
  let mut buf: Vec<u8> = vec![];
  let read = try!(stream.take(amount as u64).read_to_end(&mut buf));

  if read < amount {
    Err(Error::new(ErrorKind::Other, "Unexpected end of stream."))
  } else {
    Ok(buf)
  }
}

/// Reads four bytes from the stream and combines them together to form a 32 bit
/// unsigned integer.
pub fn read_u32<T: Read>(stream: T) -> std::io::Result<u32> {
  let buf = try!(read_bytes(stream, 4));

  Ok(buf.iter().enumerate().fold(0, |result, (i, value)| {
    result | ((*value as u32) << (3 - i) * 8)
  }))
}

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

  #[test]
  fn test_readline_basic() {
    let stream = create_tcp_stream("foo\r\n".as_bytes());
    assert_eq!(read_line(&stream, 255).unwrap(), "foo");
  }

  #[test]
  fn test_readline_empty_line() {
    let stream = create_tcp_stream("\r\n".as_bytes());
    assert_eq!(read_line(&stream, 255).unwrap(), "");
  }

  #[test]
  fn test_readline_multiple_lines_reads_only_first() {
    let stream = create_tcp_stream("bar\r\nfoo\r\n".as_bytes());
    assert_eq!(read_line(&stream, 255).unwrap(), "bar");
    assert_eq!(read_line(&stream, 255).unwrap(), "foo");
  }

  #[test]
  fn test_readline_line_too_long() {
    let stream = create_tcp_stream("barbazfoo\r\n".as_bytes());
    assert!(read_line(&stream, 5).is_err());
  }

  #[test]
  fn test_readline_line_at_limit() {
    let stream = create_tcp_stream("123\r\n".as_bytes());
    assert_eq!(read_line(&stream, 5).unwrap(), "123");
  }

  #[test]
  fn test_readline_no_cr_before_lf() {
    let stream = create_tcp_stream("barbazfoo\n".as_bytes());
    assert!(read_line(&stream, 255).is_err());
  }

  #[test]
  fn test_readline_no_crlf() {
    let stream = create_tcp_stream("barbazfoo".as_bytes());
    assert!(read_line(&stream, 255).is_err());
  }

  #[test]
  fn test_readline_no_lf() {
    let stream = create_tcp_stream("barb\razfoo".as_bytes());
    assert!(read_line(&stream, 255).is_err());
  }

  #[test]
  fn test_readline_empty() {
    let stream = create_tcp_stream("".as_bytes());
    assert!(read_line(&stream, 255).is_err());
  }

  #[test]
  fn test_readline_only_lf() {
    let stream = create_tcp_stream("\n".as_bytes());
    assert!(read_line(&stream, 255).is_err());
  }

  #[test]
  fn test_read_u32_basic() {
    let stream = create_tcp_stream(&[0x29, 0xb7, 0xf4, 0xaa, 0xff, 0xff]);
    assert_eq!(read_u32(&stream).unwrap(), 0x29b7f4aa);
  }

  #[test]
  fn test_read_u32_basic_zeroes() {
    let stream = create_tcp_stream(&[0x29, 0x00, 0xf4, 0xaa, 0xff, 0xff]);
    assert_eq!(read_u32(&stream).unwrap(), 0x2900f4aa);
  }

  #[test]
  fn test_read_u32_too_little_data() {
    let stream = create_tcp_stream(&[0x29, 0xb7, 0xf4]);
    assert!(read_u32(&stream).is_err());
  }

  #[test]
  fn test_read_bytes_basic() {
    let stream = create_tcp_stream(&[1,2,3,4,5,6]);
    assert_eq!(read_bytes(&stream, 2).unwrap(), [1,2]);
    assert_eq!(read_bytes(&stream, 3).unwrap(), [3,4,5]);
    assert_eq!(read_bytes(&stream, 1).unwrap(), [6]);
  }

  #[test]
  fn test_read_bytes_too_little_data() {
    let stream = create_tcp_stream(&[1,2,3,4,5,6]);
    assert!(read_bytes(&stream, 10).is_err())
  }
}
<|endoftext|>


<commit_before>//! AWS Regions and helper functions.
//!
//! Mostly used for translating the Region enum to a string AWS accepts.
//!
//! For example: `UsEast1` to "us-east-1"

use std::error::Error;
use std::str::FromStr;
use std::fmt::{Display, Error as FmtError, Formatter};

/// An AWS region.
/// `CnNorth1` is currently untested due to Rusoto maintainers not having access to AWS China.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Region {
    ApNortheast1,
    ApNortheast2,
    ApSouth1,
    ApSoutheast1,
    ApSoutheast2,
    CaCentral1,
    EuCentral1,
    EuWest1,
    SaEast1,
    UsEast1,
    UsWest1,
    UsWest2,
    CnNorth1,
}

/// An error produced when attempting to convert a `str` into a `Region` fails.
#[derive(Debug,PartialEq)]
pub struct ParseRegionError {
    message: String,
}

impl Display for Region {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        let region_str = match *self {
            Region::ApNortheast1 => "ap-northeast-1",
            Region::ApNortheast2 => "ap-northeast-2",
            Region::ApSouth1 => "ap-south-1",
            Region::ApSoutheast1 => "ap-southeast-1",
            Region::ApSoutheast2 => "ap-southeast-2",
            Region::CaCentral1 => "ca-central-1",
            Region::EuCentral1 => "eu-central-1",
            Region::EuWest1 => "eu-west-1",
            Region::SaEast1 => "sa-east-1",
            Region::UsEast1 => "us-east-1",
            Region::UsWest1 => "us-west-1",
            Region::UsWest2 => "us-west-2",
            Region::CnNorth1 => "cn-north-1",
        };

        write!(f, "{}", region_str)
    }
}

impl FromStr for Region {
    type Err = ParseRegionError;

    fn from_str(s: &str) -> Result<Region, ParseRegionError> {
        match s {
            "ap-northeast-1" => Ok(Region::ApNortheast1),
            "ap-northeast-2" => Ok(Region::ApNortheast2),
            "ap-south-1" => Ok(Region::ApSouth1),
            "ap-southeast-1" => Ok(Region::ApSoutheast1),
            "ap-southeast-2" => Ok(Region::ApSoutheast2),
            "ca-central-1" => Ok(Region::CaCentral1),
            "eu-central-1" => Ok(Region::EuCentral1),
            "eu-west-1" => Ok(Region::EuWest1),
            "sa-east-1" => Ok(Region::SaEast1),
            "us-east-1" => Ok(Region::UsEast1),
            "us-west-1" => Ok(Region::UsWest1),
            "us-west-2" => Ok(Region::UsWest2),
            "cn-north-1" => Ok(Region::CnNorth1),
            s => Err(ParseRegionError::new(s))
        }
    }
}

impl ParseRegionError {
    pub fn new(input: &str) -> Self {
        ParseRegionError {
            message: format!("Not a valid AWS region: {}", input)
        }
    }
}

impl Error for ParseRegionError {
    fn description(&self) -> &str {
        &self.message
    }
}

impl Display for ParseRegionError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{}", self.message)
    }
}

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

    #[test]
    fn from_str() {
        assert_eq!(
            "foo".parse::<Region>().err().expect(
                "Parsing foo as a Region was not an error"
            ).to_string(),
            "Not a valid AWS region: foo".to_owned()
        );
        assert_eq!("ap-northeast-1".parse(), Ok(Region::ApNortheast1));
        assert_eq!("ap-northeast-2".parse(), Ok(Region::ApNortheast2));
        assert_eq!("ap-south-1".parse(), Ok(Region::ApSouth1));
        assert_eq!("ap-southeast-1".parse(), Ok(Region::ApSoutheast1));
        assert_eq!("ap-southeast-2".parse(), Ok(Region::ApSoutheast2));
        assert_eq!("ca-central-1".parse(), Ok(Region::CaCentral1));
        assert_eq!("eu-central-1".parse(), Ok(Region::EuCentral1));
        assert_eq!("eu-west-1".parse(), Ok(Region::EuWest1));
        assert_eq!("sa-east-1".parse(), Ok(Region::SaEast1));
        assert_eq!("us-east-1".parse(), Ok(Region::UsEast1));
        assert_eq!("us-west-1".parse(), Ok(Region::UsWest1));
        assert_eq!("us-west-2".parse(), Ok(Region::UsWest2));
        assert_eq!("cn-north-1".parse(), Ok(Region::CnNorth1));
    }

    #[test]
    fn region_display() {
        assert_eq!(Region::ApNortheast1.to_string(), "ap-northeast-1".to_owned());
        assert_eq!(Region::ApNortheast2.to_string(), "ap-northeast-2".to_owned());
        assert_eq!(Region::ApSouth1.to_string(), "ap-south-1".to_owned());
        assert_eq!(Region::ApSoutheast1.to_string(), "ap-southeast-1".to_owned());
        assert_eq!(Region::ApSoutheast2.to_string(), "ap-southeast-2".to_owned());
        assert_eq!(Region::CaCentral1.to_string(), "ca-central-1".to_owned());
        assert_eq!(Region::EuCentral1.to_string(), "eu-central-1".to_owned());
        assert_eq!(Region::EuWest1.to_string(), "eu-west-1".to_owned());
        assert_eq!(Region::SaEast1.to_string(), "sa-east-1".to_owned());
        assert_eq!(Region::UsEast1.to_string(), "us-east-1".to_owned());
        assert_eq!(Region::UsWest1.to_string(), "us-west-1".to_owned());
        assert_eq!(Region::UsWest2.to_string(), "us-west-2".to_owned());
        assert_eq!(Region::CnNorth1.to_string(), "cn-north-1".to_owned());
    }
}
<commit_msg>Add Region us-east-2 and eu-west-2<commit_after>//! AWS Regions and helper functions.
//!
//! Mostly used for translating the Region enum to a string AWS accepts.
//!
//! For example: `UsEast1` to "us-east-1"

use std::error::Error;
use std::str::FromStr;
use std::fmt::{Display, Error as FmtError, Formatter};

/// An AWS region.
/// `CnNorth1` is currently untested due to Rusoto maintainers not having access to AWS China.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Region {
    ApNortheast1,
    ApNortheast2,
    ApSouth1,
    ApSoutheast1,
    ApSoutheast2,
    CaCentral1,
    EuCentral1,
    EuWest1,
    EuWest2,
    SaEast1,
    UsEast1,
    UsEast2,
    UsWest1,
    UsWest2,
    CnNorth1,
}

/// An error produced when attempting to convert a `str` into a `Region` fails.
#[derive(Debug,PartialEq)]
pub struct ParseRegionError {
    message: String,
}

impl Display for Region {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        let region_str = match *self {
            Region::ApNortheast1 => "ap-northeast-1",
            Region::ApNortheast2 => "ap-northeast-2",
            Region::ApSouth1 => "ap-south-1",
            Region::ApSoutheast1 => "ap-southeast-1",
            Region::ApSoutheast2 => "ap-southeast-2",
            Region::CaCentral1 => "ca-central-1",
            Region::EuCentral1 => "eu-central-1",
            Region::EuWest1 => "eu-west-1",
            Region::EuWest2 => "eu-west-2",
            Region::SaEast1 => "sa-east-1",
            Region::UsEast1 => "us-east-1",
            Region::UsEast2 => "us-east-2",
            Region::UsWest1 => "us-west-1",
            Region::UsWest2 => "us-west-2",
            Region::CnNorth1 => "cn-north-1",
        };

        write!(f, "{}", region_str)
    }
}

impl FromStr for Region {
    type Err = ParseRegionError;

    fn from_str(s: &str) -> Result<Region, ParseRegionError> {
        match s {
            "ap-northeast-1" => Ok(Region::ApNortheast1),
            "ap-northeast-2" => Ok(Region::ApNortheast2),
            "ap-south-1" => Ok(Region::ApSouth1),
            "ap-southeast-1" => Ok(Region::ApSoutheast1),
            "ap-southeast-2" => Ok(Region::ApSoutheast2),
            "ca-central-1" => Ok(Region::CaCentral1),
            "eu-central-1" => Ok(Region::EuCentral1),
            "eu-west-1" => Ok(Region::EuWest1),
            "eu-west-2" => Ok(Region::EuWest2),
            "sa-east-1" => Ok(Region::SaEast1),
            "us-east-1" => Ok(Region::UsEast1),
            "us-east-2" => Ok(Region::UsEast2),
            "us-west-1" => Ok(Region::UsWest1),
            "us-west-2" => Ok(Region::UsWest2),
            "cn-north-1" => Ok(Region::CnNorth1),
            s => Err(ParseRegionError::new(s))
        }
    }
}

impl ParseRegionError {
    pub fn new(input: &str) -> Self {
        ParseRegionError {
            message: format!("Not a valid AWS region: {}", input)
        }
    }
}

impl Error for ParseRegionError {
    fn description(&self) -> &str {
        &self.message
    }
}

impl Display for ParseRegionError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{}", self.message)
    }
}

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

    #[test]
    fn from_str() {
        assert_eq!(
            "foo".parse::<Region>().err().expect(
                "Parsing foo as a Region was not an error"
            ).to_string(),
            "Not a valid AWS region: foo".to_owned()
        );
        assert_eq!("ap-northeast-1".parse(), Ok(Region::ApNortheast1));
        assert_eq!("ap-northeast-2".parse(), Ok(Region::ApNortheast2));
        assert_eq!("ap-south-1".parse(), Ok(Region::ApSouth1));
        assert_eq!("ap-southeast-1".parse(), Ok(Region::ApSoutheast1));
        assert_eq!("ap-southeast-2".parse(), Ok(Region::ApSoutheast2));
        assert_eq!("ca-central-1".parse(), Ok(Region::CaCentral1));
        assert_eq!("eu-central-1".parse(), Ok(Region::EuCentral1));
        assert_eq!("eu-west-1".parse(), Ok(Region::EuWest1));
        assert_eq!("eu-west-2".parse(), Ok(Region::EuWest2));
        assert_eq!("sa-east-1".parse(), Ok(Region::SaEast1));
        assert_eq!("us-east-1".parse(), Ok(Region::UsEast1));
        assert_eq!("us-east-2".parse(), Ok(Region::UsEast2));
        assert_eq!("us-west-1".parse(), Ok(Region::UsWest1));
        assert_eq!("us-west-2".parse(), Ok(Region::UsWest2));
        assert_eq!("cn-north-1".parse(), Ok(Region::CnNorth1));
    }

    #[test]
    fn region_display() {
        assert_eq!(Region::ApNortheast1.to_string(), "ap-northeast-1".to_owned());
        assert_eq!(Region::ApNortheast2.to_string(), "ap-northeast-2".to_owned());
        assert_eq!(Region::ApSouth1.to_string(), "ap-south-1".to_owned());
        assert_eq!(Region::ApSoutheast1.to_string(), "ap-southeast-1".to_owned());
        assert_eq!(Region::ApSoutheast2.to_string(), "ap-southeast-2".to_owned());
        assert_eq!(Region::CaCentral1.to_string(), "ca-central-1".to_owned());
        assert_eq!(Region::EuCentral1.to_string(), "eu-central-1".to_owned());
        assert_eq!(Region::EuWest1.to_string(), "eu-west-1".to_owned());
        assert_eq!(Region::EuWest2.to_string(), "eu-west-2".to_owned());
        assert_eq!(Region::SaEast1.to_string(), "sa-east-1".to_owned());
        assert_eq!(Region::UsEast1.to_string(), "us-east-1".to_owned());
        assert_eq!(Region::UsEast2.to_string(), "us-east-2".to_owned());
        assert_eq!(Region::UsWest1.to_string(), "us-west-1".to_owned());
        assert_eq!(Region::UsWest2.to_string(), "us-west-2".to_owned());
        assert_eq!(Region::CnNorth1.to_string(), "cn-north-1".to_owned());
    }
}
<|endoftext|>