<commit_before>use reqwest;
use serde::Serialize;
use serde_json::{self, Value};
use serde_json::error::Error as JsonError;

use std::thread;
use std::sync::mpsc::{self, channel};
use std::fmt;
use std::error::Error;
use std::time::Duration;

use websocket::{Message, OwnedMessage};
use websocket::client::ClientBuilder;
use websocket::result::WebSocketError;

#[derive(Debug)]
pub enum ConnectionError {
    FailedToFetchUrl( reqwest::Error ),
    WebSocketError( WebSocketError )
}

impl Error for ConnectionError {
    fn description( &self ) -> &str {
        match *self {
            ConnectionError::FailedToFetchUrl( _ ) => "failed to fetch websocket debugger URL",
            ConnectionError::WebSocketError( _ ) => "web socket error"
        }
    }
}

impl fmt::Display for ConnectionError {
    fn fmt( &self, fmt: &mut fmt::Formatter ) -> fmt::Result {
        match *self {
            ConnectionError::FailedToFetchUrl( ref message ) => write!( fmt, "{}: {}", self.description(), message ),
            ConnectionError::WebSocketError( ref message ) => write!( fmt, "{}: {}", self.description(), message )
        }
    }
}

impl From< reqwest::Error > for ConnectionError {
    fn from( error: reqwest::Error ) -> Self {
        ConnectionError::FailedToFetchUrl( error )
    }
}

impl From< WebSocketError > for ConnectionError {
    fn from( error: WebSocketError ) -> Self {
        ConnectionError::WebSocketError( error )
    }
}

#[derive(Debug)]
pub enum CommunicationError {
    Send( WebSocketError ),
    Recv( WebSocketError )
}

impl Error for CommunicationError {
    fn description( &self ) -> &str {
        match *self {
            CommunicationError::Send( _ ) => "error while sending web socket message",
            CommunicationError::Recv( _ ) => "error while receiving web socket message"
        }
    }
}

impl fmt::Display for CommunicationError {
    fn fmt( &self, fmt: &mut fmt::Formatter ) -> fmt::Result {
        match *self {
            CommunicationError::Send( ref message ) => write!( fmt, "{}: {}", self.description(), message ),
            CommunicationError::Recv( ref message ) => write!( fmt, "{}: {}", self.description(), message )
        }
    }
}

#[derive(Debug)]
pub enum ReplyError {
    Timeout,
    MalformedMessage( &'static str ),
    MalformedJson( JsonError ),
    CommunicationError( CommunicationError )
}

impl Error for ReplyError {
    fn description( &self ) -> &str {
        match *self {
            ReplyError::Timeout => "timeout while waiting for reply",
            ReplyError::MalformedMessage( _ ) => "received malformed message",
            ReplyError::MalformedJson( _ ) => "received malformed JSON",
            ReplyError::CommunicationError( _ ) => "communication error"
        }
    }
}

impl fmt::Display for ReplyError {
    fn fmt( &self, fmt: &mut fmt::Formatter ) -> fmt::Result {
        match *self {
            ReplyError::Timeout => write!( fmt, "{}", self.description() ),
            ReplyError::MalformedMessage( ref error ) => write!( fmt, "{}: {}", self.description(), error ),
            ReplyError::MalformedJson( ref error ) => write!( fmt, "{}: {}", self.description(), error ),
            ReplyError::CommunicationError( ref error ) => write!( fmt, "{}: {}", self.description(), error )
        }
    }
}

impl From< CommunicationError > for ReplyError {
    fn from( error: CommunicationError ) -> Self {
        ReplyError::CommunicationError( error )
    }
}

impl From< JsonError > for ReplyError {
    fn from( error: JsonError ) -> Self {
        ReplyError::MalformedJson( error )
    }
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct RequestId( u64 );

#[derive(Clone, Debug)]
pub enum Reply {
    Event {
        method: String,
        body: Value
    },
    Result {
        id: RequestId,
        body: Value
    },
    Error {
        id: RequestId,
        code: i64,
        message: String
    }
}

pub struct Connection {
    tx: mpsc::Sender< OwnedMessage >,
    rx: mpsc::Receiver< Result< OwnedMessage, CommunicationError > >,
    last_id: u64
}

fn owned_message_to_json( message: Result< OwnedMessage, CommunicationError > ) -> Result< Value, ReplyError > {
    match message? {
        OwnedMessage::Text( text ) => {
            match serde_json::from_str( &text ) {
                Ok( value ) => return Ok( value ),
                Err( error ) => return Err( error.into() )
            }
        },
        _ => return Err( ReplyError::MalformedMessage( "non text message received" ) )
    }
}

impl Connection {
    pub fn connect( json_url: &str ) -> Result< Self , ConnectionError > {
        let mut response = reqwest::get( json_url )?;
        let text = response.text()?;
        let json: Value = serde_json::from_str( &text ).unwrap();
        let url = json.get( 0 ).unwrap().get( "webSocketDebuggerUrl" ).unwrap().as_str().unwrap();
        debug!( "Got websocket debugger URL {}", url );

        let client = ClientBuilder::new( &url ).unwrap().connect_insecure()?;
        debug!( "Connected to: {}", url );

        let (mut receiver, mut sender) = client.split().unwrap();

        let (output_tx, output_rx) = channel();
        let (input_tx, input_rx) = channel();

        let input_tx_clone = input_tx.clone();
        thread::spawn( move || {
            loop {
                let message = match output_rx.recv() {
                    Ok( message ) => message,
                    Err( _ ) => break
                };

                debug!( "Sending: {:?}", message );
                if let Err( error ) = sender.send_message( &message ) {
                    let _ = input_tx_clone.send( Err( CommunicationError::Send( error ) ) );
                    let _ = sender.send_message( &Message::close() );
                    break;
                }

                if let OwnedMessage::Close( _ ) = message {
                    break;
                }
            }
        });

        let output_tx_clone = output_tx.clone();
        thread::spawn( move || {
            for message in receiver.incoming_messages() {
                trace!( "Received: {:?}", message );
                let message = match message {
                    Ok( message ) => message,
                    Err( error ) => {
                        let _ = input_tx.send( Err( CommunicationError::Recv( error ) ) );
                        let _ = output_tx_clone.send( OwnedMessage::Close( None ) );
                        break;
                    }
                };

                match message {
                    message @ OwnedMessage::Close( _ ) => {
                        let _ = output_tx_clone.send( message.clone() );
                        let _ = input_tx.send( Ok( message ) );
                        break;
                    }
                    message @ OwnedMessage::Ping( _ ) => {
                        match output_tx_clone.send( message ) {
                            Ok(()) => {},
                            Err( _ ) => break
                        }
                    }
                    message => {
                        match input_tx.send( Ok( message ) ) {
                            Ok(()) => {},
                            Err( _ ) => break
                        }
                    },
                }
            }
        });

        Ok( Connection {
            tx: output_tx,
            rx: input_rx,
            last_id: 0
        })
    }

    fn raw_send( &mut self, message: OwnedMessage ) {
        let _ = self.tx.send( message );
    }

    pub fn send_cmd< T: Serialize >( &mut self, method: &str, params: T ) -> RequestId {
        #[derive(Serialize)]
        struct Command< T: Serialize > {
            method: String,
            params: T,
            id: u64
        }

        let id = self.last_id;
        let command = Command {
            method: method.to_owned(),
            params,
            id
        };

        self.last_id += 1;
        let message = serde_json::to_string( &command ).unwrap();
        self.raw_send( OwnedMessage::Text( message ) );

        RequestId( id )
    }

    fn raw_try_recv( &mut self, wait_for: Option< Duration > ) -> Option< Result< OwnedMessage, CommunicationError > > {
        if let Some( wait_for ) = wait_for {
            match self.rx.recv_timeout( wait_for ) {
                Ok( message ) => Some( message ),
                Err( _ ) => None
            }
        } else {
            match self.rx.try_recv() {
                Ok( message ) => Some( message ),
                Err( _ ) => None
            }
        }
    }

    fn json_try_recv( &mut self, wait_for: Option< Duration > ) -> Result< Value, ReplyError > {
        let message = self.raw_try_recv( wait_for );
        match message {
            Some( message ) => return owned_message_to_json( message ),
            None => return Err( ReplyError::Timeout )
        }
    }

    pub fn try_recv( &mut self, wait_for: Option< Duration > ) -> Result< Reply, ReplyError > {
        let json = self.json_try_recv( wait_for )?;
        if let Some( error ) = json.get( "error" ) {
            let id = json.get( "id" )
                .ok_or( ReplyError::MalformedMessage( "'id' field not found" ) )?
                .as_u64()
                .ok_or( ReplyError::MalformedMessage( "'id' field is not an integer" ) )?;
            let id = RequestId( id );
            let code = error.get( "code" )
                .ok_or( ReplyError::MalformedMessage( "'error.code' field not found" ) )?
                .as_i64()
                .ok_or( ReplyError::MalformedMessage( "'error.code' field is not an integer" ) )?;
            let message = error.get( "message" )
                .ok_or( ReplyError::MalformedMessage( "'error.message' field not found" ) )?
                .as_str()
                .ok_or( ReplyError::MalformedMessage( "'error.message' field is not an integer" ) )?
                .to_owned();
            Ok( Reply::Error { id, code, message } )
        } else if let Some( id ) = json.get( "id" ) {
            let id = id.as_u64().ok_or( ReplyError::MalformedMessage( "'id' field is not an integer" ) )?;
            let id = RequestId( id );
            let body = json.get( "result" ).ok_or( ReplyError::MalformedMessage( "'body' field not found" ) )?.clone();
            Ok( Reply::Result { id, body } )
        } else {
            let method = json.get( "method" )
                .ok_or( ReplyError::MalformedMessage( "'method' field not found" ) )?
                .as_str()
                .ok_or( ReplyError::MalformedMessage( "'method' field is not a string" ) )?
                .to_owned();
            let body = json.get( "params" ).ok_or( ReplyError::MalformedMessage( "'params' field not found" ) )?.clone();
            Ok( Reply::Event { method, body } )
        }
    }
}

// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-RemoteObject
#[derive(Clone, Deserialize, Debug)]
pub struct RemoteObject {
    #[serde(rename = "type")]
    pub kind: String,
    pub value: Option< Value >,
    #[serde(rename = "className")]
    pub class_name: Option< String >,
    pub description: Option< String >
}

// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#event-consoleAPICalled
#[derive(Clone, Deserialize, Debug)]
pub struct ConsoleApiCalledBody {
    #[serde(rename = "type")]
    pub kind: String,
    pub args: Vec< RemoteObject >
}

// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#event-exceptionThrown
#[derive(Clone, Deserialize, Debug)]
pub struct ExceptionThrownBody {
    #[serde(rename = "exceptionDetails")]
    pub exception_details: ExceptionDetails
}

// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-ExceptionDetails
#[derive(Clone, Deserialize, Debug)]
pub struct ExceptionDetails {
    pub text: String,
    pub exception: Option< RemoteObject >,
    #[serde(rename = "lineNumber")]
    pub line_number: u32,
    #[serde(rename = "columnNumber")]
    pub column_number: u32,
    #[serde(rename = "scriptId")]
    pub script_id: Option< String >,
    pub url: Option< String >
}
<commit_msg>Add extra `debug!` and some expects when connecting to chromium<commit_after>use reqwest;
use serde::Serialize;
use serde_json::{self, Value};
use serde_json::error::Error as JsonError;

use std::thread;
use std::sync::mpsc::{self, channel};
use std::fmt;
use std::error::Error;
use std::time::Duration;

use websocket::{Message, OwnedMessage};
use websocket::client::ClientBuilder;
use websocket::result::WebSocketError;

#[derive(Debug)]
pub enum ConnectionError {
    FailedToFetchUrl( reqwest::Error ),
    WebSocketError( WebSocketError )
}

impl Error for ConnectionError {
    fn description( &self ) -> &str {
        match *self {
            ConnectionError::FailedToFetchUrl( _ ) => "failed to fetch websocket debugger URL",
            ConnectionError::WebSocketError( _ ) => "web socket error"
        }
    }
}

impl fmt::Display for ConnectionError {
    fn fmt( &self, fmt: &mut fmt::Formatter ) -> fmt::Result {
        match *self {
            ConnectionError::FailedToFetchUrl( ref message ) => write!( fmt, "{}: {}", self.description(), message ),
            ConnectionError::WebSocketError( ref message ) => write!( fmt, "{}: {}", self.description(), message )
        }
    }
}

impl From< reqwest::Error > for ConnectionError {
    fn from( error: reqwest::Error ) -> Self {
        ConnectionError::FailedToFetchUrl( error )
    }
}

impl From< WebSocketError > for ConnectionError {
    fn from( error: WebSocketError ) -> Self {
        ConnectionError::WebSocketError( error )
    }
}

#[derive(Debug)]
pub enum CommunicationError {
    Send( WebSocketError ),
    Recv( WebSocketError )
}

impl Error for CommunicationError {
    fn description( &self ) -> &str {
        match *self {
            CommunicationError::Send( _ ) => "error while sending web socket message",
            CommunicationError::Recv( _ ) => "error while receiving web socket message"
        }
    }
}

impl fmt::Display for CommunicationError {
    fn fmt( &self, fmt: &mut fmt::Formatter ) -> fmt::Result {
        match *self {
            CommunicationError::Send( ref message ) => write!( fmt, "{}: {}", self.description(), message ),
            CommunicationError::Recv( ref message ) => write!( fmt, "{}: {}", self.description(), message )
        }
    }
}

#[derive(Debug)]
pub enum ReplyError {
    Timeout,
    MalformedMessage( &'static str ),
    MalformedJson( JsonError ),
    CommunicationError( CommunicationError )
}

impl Error for ReplyError {
    fn description( &self ) -> &str {
        match *self {
            ReplyError::Timeout => "timeout while waiting for reply",
            ReplyError::MalformedMessage( _ ) => "received malformed message",
            ReplyError::MalformedJson( _ ) => "received malformed JSON",
            ReplyError::CommunicationError( _ ) => "communication error"
        }
    }
}

impl fmt::Display for ReplyError {
    fn fmt( &self, fmt: &mut fmt::Formatter ) -> fmt::Result {
        match *self {
            ReplyError::Timeout => write!( fmt, "{}", self.description() ),
            ReplyError::MalformedMessage( ref error ) => write!( fmt, "{}: {}", self.description(), error ),
            ReplyError::MalformedJson( ref error ) => write!( fmt, "{}: {}", self.description(), error ),
            ReplyError::CommunicationError( ref error ) => write!( fmt, "{}: {}", self.description(), error )
        }
    }
}

impl From< CommunicationError > for ReplyError {
    fn from( error: CommunicationError ) -> Self {
        ReplyError::CommunicationError( error )
    }
}

impl From< JsonError > for ReplyError {
    fn from( error: JsonError ) -> Self {
        ReplyError::MalformedJson( error )
    }
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct RequestId( u64 );

#[derive(Clone, Debug)]
pub enum Reply {
    Event {
        method: String,
        body: Value
    },
    Result {
        id: RequestId,
        body: Value
    },
    Error {
        id: RequestId,
        code: i64,
        message: String
    }
}

pub struct Connection {
    tx: mpsc::Sender< OwnedMessage >,
    rx: mpsc::Receiver< Result< OwnedMessage, CommunicationError > >,
    last_id: u64
}

fn owned_message_to_json( message: Result< OwnedMessage, CommunicationError > ) -> Result< Value, ReplyError > {
    match message? {
        OwnedMessage::Text( text ) => {
            match serde_json::from_str( &text ) {
                Ok( value ) => return Ok( value ),
                Err( error ) => return Err( error.into() )
            }
        },
        _ => return Err( ReplyError::MalformedMessage( "non text message received" ) )
    }
}

impl Connection {
    pub fn connect( json_url: &str ) -> Result< Self , ConnectionError > {
        let mut response = reqwest::get( json_url )?;
        let text = response.text()?;
        let json: Value = serde_json::from_str( &text ).unwrap();

        debug!( "Got initial response: {:?}", json );

        let url = json.get( 0 ).expect( "can't find first element" )
            .get( "webSocketDebuggerUrl" ).expect( "no webSocketDebuggerUrl found" )
            .as_str().expect( "webSocketDebuggerUrl is not a string" );

        debug!( "Got websocket debugger URL {}", url );

        let client = ClientBuilder::new( &url ).unwrap().connect_insecure()?;
        debug!( "Connected to: {}", url );

        let (mut receiver, mut sender) = client.split().unwrap();

        let (output_tx, output_rx) = channel();
        let (input_tx, input_rx) = channel();

        let input_tx_clone = input_tx.clone();
        thread::spawn( move || {
            loop {
                let message = match output_rx.recv() {
                    Ok( message ) => message,
                    Err( _ ) => break
                };

                debug!( "Sending: {:?}", message );
                if let Err( error ) = sender.send_message( &message ) {
                    let _ = input_tx_clone.send( Err( CommunicationError::Send( error ) ) );
                    let _ = sender.send_message( &Message::close() );
                    break;
                }

                if let OwnedMessage::Close( _ ) = message {
                    break;
                }
            }
        });

        let output_tx_clone = output_tx.clone();
        thread::spawn( move || {
            for message in receiver.incoming_messages() {
                trace!( "Received: {:?}", message );
                let message = match message {
                    Ok( message ) => message,
                    Err( error ) => {
                        let _ = input_tx.send( Err( CommunicationError::Recv( error ) ) );
                        let _ = output_tx_clone.send( OwnedMessage::Close( None ) );
                        break;
                    }
                };

                match message {
                    message @ OwnedMessage::Close( _ ) => {
                        let _ = output_tx_clone.send( message.clone() );
                        let _ = input_tx.send( Ok( message ) );
                        break;
                    }
                    message @ OwnedMessage::Ping( _ ) => {
                        match output_tx_clone.send( message ) {
                            Ok(()) => {},
                            Err( _ ) => break
                        }
                    }
                    message => {
                        match input_tx.send( Ok( message ) ) {
                            Ok(()) => {},
                            Err( _ ) => break
                        }
                    },
                }
            }
        });

        Ok( Connection {
            tx: output_tx,
            rx: input_rx,
            last_id: 0
        })
    }

    fn raw_send( &mut self, message: OwnedMessage ) {
        let _ = self.tx.send( message );
    }

    pub fn send_cmd< T: Serialize >( &mut self, method: &str, params: T ) -> RequestId {
        #[derive(Serialize)]
        struct Command< T: Serialize > {
            method: String,
            params: T,
            id: u64
        }

        let id = self.last_id;
        let command = Command {
            method: method.to_owned(),
            params,
            id
        };

        self.last_id += 1;
        let message = serde_json::to_string( &command ).unwrap();
        self.raw_send( OwnedMessage::Text( message ) );

        RequestId( id )
    }

    fn raw_try_recv( &mut self, wait_for: Option< Duration > ) -> Option< Result< OwnedMessage, CommunicationError > > {
        if let Some( wait_for ) = wait_for {
            match self.rx.recv_timeout( wait_for ) {
                Ok( message ) => Some( message ),
                Err( _ ) => None
            }
        } else {
            match self.rx.try_recv() {
                Ok( message ) => Some( message ),
                Err( _ ) => None
            }
        }
    }

    fn json_try_recv( &mut self, wait_for: Option< Duration > ) -> Result< Value, ReplyError > {
        let message = self.raw_try_recv( wait_for );
        match message {
            Some( message ) => return owned_message_to_json( message ),
            None => return Err( ReplyError::Timeout )
        }
    }

    pub fn try_recv( &mut self, wait_for: Option< Duration > ) -> Result< Reply, ReplyError > {
        let json = self.json_try_recv( wait_for )?;
        if let Some( error ) = json.get( "error" ) {
            let id = json.get( "id" )
                .ok_or( ReplyError::MalformedMessage( "'id' field not found" ) )?
                .as_u64()
                .ok_or( ReplyError::MalformedMessage( "'id' field is not an integer" ) )?;
            let id = RequestId( id );
            let code = error.get( "code" )
                .ok_or( ReplyError::MalformedMessage( "'error.code' field not found" ) )?
                .as_i64()
                .ok_or( ReplyError::MalformedMessage( "'error.code' field is not an integer" ) )?;
            let message = error.get( "message" )
                .ok_or( ReplyError::MalformedMessage( "'error.message' field not found" ) )?
                .as_str()
                .ok_or( ReplyError::MalformedMessage( "'error.message' field is not an integer" ) )?
                .to_owned();
            Ok( Reply::Error { id, code, message } )
        } else if let Some( id ) = json.get( "id" ) {
            let id = id.as_u64().ok_or( ReplyError::MalformedMessage( "'id' field is not an integer" ) )?;
            let id = RequestId( id );
            let body = json.get( "result" ).ok_or( ReplyError::MalformedMessage( "'body' field not found" ) )?.clone();
            Ok( Reply::Result { id, body } )
        } else {
            let method = json.get( "method" )
                .ok_or( ReplyError::MalformedMessage( "'method' field not found" ) )?
                .as_str()
                .ok_or( ReplyError::MalformedMessage( "'method' field is not a string" ) )?
                .to_owned();
            let body = json.get( "params" ).ok_or( ReplyError::MalformedMessage( "'params' field not found" ) )?.clone();
            Ok( Reply::Event { method, body } )
        }
    }
}

// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-RemoteObject
#[derive(Clone, Deserialize, Debug)]
pub struct RemoteObject {
    #[serde(rename = "type")]
    pub kind: String,
    pub value: Option< Value >,
    #[serde(rename = "className")]
    pub class_name: Option< String >,
    pub description: Option< String >
}

// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#event-consoleAPICalled
#[derive(Clone, Deserialize, Debug)]
pub struct ConsoleApiCalledBody {
    #[serde(rename = "type")]
    pub kind: String,
    pub args: Vec< RemoteObject >
}

// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#event-exceptionThrown
#[derive(Clone, Deserialize, Debug)]
pub struct ExceptionThrownBody {
    #[serde(rename = "exceptionDetails")]
    pub exception_details: ExceptionDetails
}

// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-ExceptionDetails
#[derive(Clone, Deserialize, Debug)]
pub struct ExceptionDetails {
    pub text: String,
    pub exception: Option< RemoteObject >,
    #[serde(rename = "lineNumber")]
    pub line_number: u32,
    #[serde(rename = "columnNumber")]
    pub column_number: u32,
    #[serde(rename = "scriptId")]
    pub script_id: Option< String >,
    pub url: Option< String >
}
<|endoftext|>


<commit_before>use ::screen;
use ::screen::Screen;

use piston_window;

pub struct Game {
    window: piston_window::PistonWindow,
    screens: Vec<Box<screen::Screen>>,
}

impl Game {
    pub fn new() -> Game {
        let window: piston_window::PistonWindow = piston_window::WindowSettings::new("rrthozopsi", [600, 600]).exit_on_esc(true).build().unwrap();
        let screens: Vec<Box<screen::Screen>> = vec![Box::new(screen::MainMenuScreen::new())];
        Game {
            window: window,
            screens: screens,
        }
    }

    pub fn run(&mut self) {
        use piston_window::Event;

        // TODO: Remove clone?
        for window in &mut self.window {
            match window.event {
                Some(Event::Update(ref args)) => { self.screens.last_mut().unwrap().on_update(&args); }
                Some(Event::Render(ref args)) => { self.screens.last_mut().unwrap().on_draw(&args, &window); }
                Some(Event::Input(ref input)) => {
                    for action in self.screens.last_mut().unwrap().on_input(&input, &window) {
                        match action {
                            screen::InputResult::PushScreen(new_screen) => {
                                self.screens.push(new_screen);
                            }
            		        screen::InputResult::PopScreen => {
            			        self.screens.pop();
            		        }
                        }
                    }
            	}
                _ => {}
            }
        }
    }
}
<commit_msg>last function<commit_after>use ::screen;
use ::screen::Screen;

use piston_window;

pub struct Game {
    window: piston_window::PistonWindow,
    screens: Vec<Box<screen::Screen>>,
}

impl Game {
    pub fn new() -> Game {
        let window: piston_window::PistonWindow = piston_window::WindowSettings::new("rrthozopsi", [600, 600]).exit_on_esc(true).build().unwrap();
        let screens: Vec<Box<screen::Screen>> = vec![Box::new(screen::MainMenuScreen::new())];
        Game {
            window: window,
            screens: screens,
        }
    }

    pub fn run(&mut self) {
        use piston_window::Event;

        // TODO: Remove clone?
        for window in &mut self.window {
            match window.event {
                Some(Event::Update(ref args)) => { self.screens.last_mut().unwrap().on_update(&args); }
                Some(Event::Render(ref args)) => { self.screens.last_mut().unwrap().on_draw(&args, &window); }
                Some(Event::Input(ref input)) => {
                    for action in self.screens.last_mut().unwrap().on_input(&input, &window) {
                        match action {
                            screen::InputResult::PushScreen(new_screen) => {
                                self.screens.push(new_screen);
                            }
            		        screen::InputResult::PopScreen => {
            			        self.screens.pop();
            		        }
                        }
                    }
            	}
                _ => {}
            }
        }
    }
}

fn last<'a>(vec: &'a mut Vec<Box<screen::Screen>>) -> &'a mut Box<screen::Screen> {
    vec.last_mut().unwrap()
}<|endoftext|>


<commit_before>extern crate find_folder;

use screen::{self, Screen, MainMenu};
use context::{Context, GameState};

use piston_window::{self, PistonWindow, WindowSettings};

type Screens = Vec<Box<Screen>>;

pub struct Game {
    window: PistonWindow,
    context: Context,
    screens: Screens,
}

impl Game {
    pub fn new() -> Self {
        let window: PistonWindow = WindowSettings::new("rrthozopsi", [600, 600])
                                       .build()
                                       .unwrap();
        let mut context = Context {
            assets_path: find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap(),
            game_state: GameState::NotStarted,
        };
        let screens: Screens = vec![Box::new(MainMenu::new(&window, &mut context))];
        Game {
            window: window,
            screens: screens,
            context: context,
        }
    }

    pub fn run(&mut self) {
        use piston_window::Event;

        let screens = &mut self.screens;

        for window in &mut self.window {
            match window.event {
                Some(Event::Update(ref args)) => {
                    last(screens).on_update(&args);
                }
                Some(Event::Render(ref args)) => {
                    last(screens).on_draw(&args, &window);
                }
                Some(Event::Input(ref input)) => {
                    if handle_input(screens, &input, &window, &mut self.context) {
                        // Exit game.
                        return;
                    }
                }
                _ => {}
            }
        }
    }
}

fn last<'a>(vec: &'a mut Screens) -> &'a mut Box<Screen> {
    vec.last_mut().unwrap()
}

fn handle_input(screens: &mut Screens, input: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> bool {
    use screen::InputResult;

    for action in last(screens).on_input(&input, &window, context) {
        match action {
            InputResult::PushScreen(new_screen) => {
                screens.push(new_screen);
            }
            InputResult::PopScreen => {
                screens.pop();
            }
            // TODO: Handle event correctly.
            // TODO: Use screen::InputResult.
            InputResult::Exit => { return true }
        }
    }

    false
}
<commit_msg>Comments have been removed<commit_after>extern crate find_folder;

use screen::{self, Screen, MainMenu};
use context::{Context, GameState};

use piston_window::{self, PistonWindow, WindowSettings};

type Screens = Vec<Box<Screen>>;

pub struct Game {
    window: PistonWindow,
    context: Context,
    screens: Screens,
}

impl Game {
    pub fn new() -> Self {
        let window: PistonWindow = WindowSettings::new("rrthozopsi", [600, 600])
                                       .build()
                                       .unwrap();
        let mut context = Context {
            assets_path: find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap(),
            game_state: GameState::NotStarted,
        };
        let screens: Screens = vec![Box::new(MainMenu::new(&window, &mut context))];
        Game {
            window: window,
            screens: screens,
            context: context,
        }
    }

    pub fn run(&mut self) {
        use piston_window::Event;

        let screens = &mut self.screens;

        for window in &mut self.window {
            match window.event {
                Some(Event::Update(ref args)) => {
                    last(screens).on_update(&args);
                }
                Some(Event::Render(ref args)) => {
                    last(screens).on_draw(&args, &window);
                }
                Some(Event::Input(ref input)) => {
                    if handle_input(screens, &input, &window, &mut self.context) {
                        // Exit game.
                        return;
                    }
                }
                _ => {}
            }
        }
    }
}

fn last<'a>(vec: &'a mut Screens) -> &'a mut Box<Screen> {
    vec.last_mut().unwrap()
}

fn handle_input(screens: &mut Screens, input: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> bool {
    use screen::InputResult;

    for action in last(screens).on_input(&input, &window, context) {
        match action {
            InputResult::PushScreen(new_screen) => {
                screens.push(new_screen);
            }
            InputResult::PopScreen => {
                screens.pop();
            }
            InputResult::Exit => { return true }
        }
    }

    false
}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(generators, nll)]

// Test for issue #47189. Here, both `s` and `t` are live for the
// generator's lifetime, but within the generator they have distinct
// lifetimes.
//
// Currently, we accept this code (with NLL enabled) since `x` is only
// borrowed once at a time -- though whether we should is not entirely
// obvious to me (the borrows are live over a yield, but then they are
// re-borrowing borrowed content, etc). Maybe I just haven't had
// enough coffee today, but I'm not entirely sure at this moment what
// effect a `suspend` should have on existing borrows. -nmatsakis

fn foo(x: &mut u32) {
    move || {
        let s = &mut *x;
        yield;
        *s += 1;

        let t = &mut *x;
        yield;
        *t += 1;
    };
}

fn main() {
    foo(&mut 0);
}
<commit_msg>update test case<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(generators, nll)]

// Test for issue #47189. Here, both `s` and `t` are live for the
// generator's lifetime, but within the generator they have distinct
// lifetimes. We accept this code -- even though the borrow extends
// over a yield -- because the data that is borrowed (`*x`) is not
// stored on the stack.

// must-compile-successfully

fn foo(x: &mut u32) {
    move || {
        let s = &mut *x;
        yield;
        *s += 1;

        let t = &mut *x;
        yield;
        *t += 1;
    };
}

fn main() {
    foo(&mut 0);
}
<|endoftext|>


<commit_before>//! Directory module for managing Algorithmia Data Directories
//!
//! # Examples
//!
//! ```no_run
//! use algorithmia::Algorithmia;
//! use algorithmia::data::DataAcl;
//! use std::fs::File;
//!
//! let client = Algorithmia::client("111112222233333444445555566");
//! let my_dir = client.dir(".my/my_dir");
//!
//! my_dir.create(DataAcl::default());
//! my_dir.put_file("/path/to/file");
//! ```

use client::HttpClient;
use error::{self, Error};
use data::*;
use super::parse_data_uri;
use super::header::XDataType;

use std::io::Read;
use std::fs::File;
use std::path::Path;
use std::vec::IntoIter;

use serde_json;
use chrono::{DateTime, UTC};
use hyper::header::ContentType;
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::Url;

/// Algorithmia Data Directory
pub struct DataDir {
    path: String,
    client: HttpClient,
}

#[derive(Deserialize, Debug)]
pub struct DirectoryUpdated {
    pub acl: Option<DataAcl>,
}

/// Response when deleting a new Directory
#[derive(Deserialize, Debug)]
pub struct DirectoryDeleted {
    // Omitting deleted.number and error.number for now
    pub result: DeletedResult,
}

#[derive(Deserialize, Serialize, Debug)]
struct FolderItem {
    pub name: String,
    pub acl: Option<DataAcl>,
}

#[derive(Deserialize, Debug)]
struct FileItem {
    pub filename: String,
    pub size: u64,
    pub last_modified: DateTime<UTC>,
}

/// ACL that indicates permissions for a `DataDirectory`
/// See also: [`ReadAcl`](enum.ReadAcl.html) enum to construct a `DataACL`
#[derive(Deserialize, Serialize, Debug)]
pub struct DataAcl {
    pub read: Vec<String>,
}

pub enum ReadAcl {
    /// Readable only by owner
    Private,
    /// Readable by owner's algorithms (regardless of caller)
    MyAlgorithms,
    /// Readable by any user
    Public,
}

impl Default for DataAcl {
    fn default() -> Self {
        ReadAcl::MyAlgorithms.into()
    }
}

impl From<ReadAcl> for DataAcl {
    fn from(acl: ReadAcl) -> Self {
        match acl {
            ReadAcl::Private => DataAcl { read: vec![] },
            ReadAcl::MyAlgorithms => DataAcl { read: vec!["algo://.my/*".into()] },
            ReadAcl::Public => DataAcl { read: vec!["user://*".into()] },
        }
    }
}

/// Response when querying an existing Directory
#[derive(Deserialize, Debug)]
struct DirectoryShow {
    pub acl: Option<DataAcl>,
    pub folders: Option<Vec<FolderItem>>,
    pub files: Option<Vec<FileItem>>,
    pub marker: Option<String>,
}

pub struct DirectoryListing<'a> {
    pub acl: Option<DataAcl>,
    dir: &'a DataDir,
    folders: IntoIter<FolderItem>,
    files: IntoIter<FileItem>,
    marker: Option<String>,
    query_count: u32,
}

impl<'a> DirectoryListing<'a> {
    fn new(dir: &'a DataDir) -> DirectoryListing<'a> {
        DirectoryListing {
            acl: None,
            dir: dir,
            folders: Vec::new().into_iter(),
            files: Vec::new().into_iter(),
            marker: None,
            query_count: 0,
        }
    }
}

impl<'a> Iterator for DirectoryListing<'a> {
    type Item = Result<DataItem, Error>;

    fn next(&mut self) -> Option<Self::Item> {
        match self.folders.next() {
            // Return folders first
            Some(d) => Some(Ok(DataItem::Dir(DataDirItem { dir: self.dir.child(&d.name) }))),
            None => {
                match self.files.next() {
                    // Return files second
                    Some(f) => {
                        Some(Ok(DataItem::File(DataFileItem {
                            size: f.size,
                            last_modified: f.last_modified,
                            file: self.dir.child(&f.filename),
                        })))
                    }
                    None => {
                        // Query if there is another page of files/folders
                        if self.query_count == 0 || self.marker.is_some() {
                            self.query_count += 1;
                            match get_directory(self.dir, self.marker.clone()) {
                                Ok(ds) => {
                                    self.folders = ds.folders.unwrap_or_else(Vec::new).into_iter();
                                    self.files = ds.files.unwrap_or_else(Vec::new).into_iter();
                                    self.marker = ds.marker;
                                    self.next()
                                }
                                Err(err) => Some(Err(err)),
                            }
                        } else {
                            None
                        }
                    }
                }
            }
        }
    }
}

fn get_directory(dir: &DataDir, marker: Option<String>) -> Result<DirectoryShow, Error> {
    let url = match marker {
        Some(m) => Url::parse(&format!("{}?marker={}", dir.to_url(), m)).unwrap(),
        None => dir.to_url(),
    };

    let req = dir.client.get(url);
    let mut res = try!(req.send());

    if res.status.is_success() {
        if let Some(data_type) = res.headers.get::<XDataType>() {
            if "directory" != data_type.as_str() {
                return Err(Error::UnexpectedDataType("directory", data_type.to_string()));
            }
        }
    }

    let mut res_json = String::new();
    try!(res.read_to_string(&mut res_json));

    if res.status.is_success() {
        serde_json::from_str(&res_json).map_err(|err| err.into())
    } else {
        Err(error::decode(&res_json))
    }
}

impl HasDataPath for DataDir {
    fn new(client: HttpClient, path: &str) -> Self {
        DataDir {
            client: client,
            path: parse_data_uri(path).to_string(),
        }
    }
    fn path(&self) -> &str {
        &self.path
    }
    fn client(&self) -> &HttpClient {
        &self.client
    }
}

impl DataDir {
    /// Display Directory details if it exists
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Algorithmia;
    /// # use algorithmia::data::{DataItem, HasDataPath};
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let my_dir = client.dir(".my/my_dir");
    /// let dir_list = my_dir.list();
    /// for entry in dir_list {
    ///     match entry {
    ///         Ok(DataItem::File(f)) => println!("File: {}", f.to_data_uri()),
    ///         Ok(DataItem::Dir(d)) => println!("Dir: {}", d.to_data_uri()),
    ///         Err(err) => { println!("Error: {}", err); break; },
    ///     }
    /// };
    /// ```
    pub fn list(&self) -> DirectoryListing {
        DirectoryListing::new(self)
    }

    /// Create a Directory
    ///
    /// Use `DataAcl::default()` or the `ReadAcl` enum to set the ACL
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Algorithmia;
    /// # use algorithmia::data::DataAcl;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let my_dir = client.dir(".my/my_dir");
    /// match my_dir.create(DataAcl::default()) {
    ///   Ok(_) => println!("Successfully created Directory"),
    ///   Err(e) => println!("Error created directory: {}", e),
    /// };
    /// ```
    pub fn create<Acl: Into<DataAcl>>(&self, acl: Acl) -> Result<(), Error> {
        let parent = try!(self.parent().ok_or_else(|| Error::InvalidDataPath(self.path.clone())));
        let url = parent.to_url();

        // TODO: address complete abuse of this structure
        let input_data = FolderItem {
            name: try!(self.basename().ok_or_else(|| Error::InvalidDataPath(self.path.clone())))
                .into(),
            acl: Some(acl.into()),
        };
        let raw_input = try!(serde_json::to_string(&input_data));

        // POST request
        let req = self.client
            .post(url)
            .header(ContentType(Mime(TopLevel::Application, SubLevel::Json, vec![])))
            .body(&raw_input);

        // Parse response
        let mut res = try!(req.send());

        if res.status.is_success() {
            Ok(())
        } else {
            let mut res_json = String::new();
            try!(res.read_to_string(&mut res_json));
            Err(error::decode(&res_json))
        }
    }

    /// Delete a Directory
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let my_dir = client.dir(".my/my_dir");
    /// match my_dir.delete(false) {
    ///   Ok(_) => println!("Successfully deleted Directory"),
    ///   Err(err) => println!("Error deleting directory: {}", err),
    /// };
    /// ```
    pub fn delete(&self, force: bool) -> Result<DirectoryDeleted, Error> {
        // DELETE request
        let url_string = format!("{}?force={}", self.to_url(), force.to_string());
        let url = Url::parse(&url_string).unwrap();
        let req = self.client.delete(url);

        // Parse response
        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        if res.status.is_success() {
            serde_json::from_str(&res_json).map_err(|err| err.into())
        } else {
            Err(error::decode(&res_json))
        }
    }

    /// Upload a file to an existing Directory
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let my_dir = client.dir(".my/my_dir");
    ///
    /// match my_dir.put_file("/path/to/file") {
    ///   Ok(response) => println!("Successfully uploaded to: {}", response.result),
    ///   Err(err) => println!("Error uploading file: {}", err),
    /// };
    /// ```
    pub fn put_file<P: AsRef<Path>>(&self, file_path: P) -> Result<FileAdded, Error> {
        // FIXME: A whole lot of unwrap going on here...
        let path_ref = file_path.as_ref();
        let url_string = format!("{}/{}",
                                 self.to_url(),
                                 path_ref.file_name().unwrap().to_str().unwrap());
        let url = Url::parse(&url_string).unwrap();

        let mut file = File::open(path_ref).unwrap();
        let req = self.client.put(url).body(&mut file);

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        if res.status.is_success() {
            serde_json::from_str(&res_json).map_err(|err| err.into())
        } else {
            Err(error::decode(&res_json))
        }
    }

    pub fn child<T: HasDataPath>(&self, filename: &str) -> T {
        let new_uri = match self.to_data_uri() {
            ref uri if uri.ends_with('/') => format!("{}{}", uri, filename),
            uri => format!("{}/{}", uri, filename),
        };
        T::new(self.client.clone(), &new_uri)
    }
}

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

    fn mock_client() -> Algorithmia {
        Algorithmia::client("")
    }

    #[test]
    fn test_to_url() {
        let dir = mock_client().dir("data://anowell/foo");
        assert_eq!(dir.to_url().path(), "/v1/connector/data/anowell/foo");
    }

    #[test]
    fn test_to_data_uri() {
        let dir = mock_client().dir("/anowell/foo");
        assert_eq!(dir.to_data_uri(), "data://anowell/foo".to_string());
    }

    #[test]
    fn test_parent() {
        let dir = mock_client().dir("data://anowell/foo");
        let expected = mock_client().dir("data://anowell");
        assert_eq!(dir.parent().unwrap().path, expected.path);

        let dir = mock_client().dir("dropbox://anowell/foo");
        let expected = mock_client().dir("dropbox://anowell");
        assert_eq!(dir.parent().unwrap().path, expected.path);

        let dir = mock_client().dir("data://anowell");
        let expected = mock_client().dir("data://");
        assert_eq!(dir.parent().unwrap().path, expected.path);

        let dir = mock_client().dir("data://");
        assert!(dir.parent().is_none());
    }

    #[test]
    fn test_default_acl() {
        let acl: DataAcl = DataAcl::default();
        assert_eq!(acl.read, vec!["algo://.my/*".to_string()]);
    }

    #[test]
    fn test_private_acl() {
        let acl: DataAcl = ReadAcl::Private.into();
        assert!(acl.read.is_empty());
    }

    #[test]
    fn test_public_acl() {
        let acl: DataAcl = ReadAcl::Public.into();
        assert_eq!(acl.read, vec!["user://*".to_string()]);
    }

    #[test]
    fn test_myalgos_acl() {
        let acl: DataAcl = ReadAcl::MyAlgorithms.into();
        assert_eq!(acl.read, vec!["algo://.my/*".to_string()]);
    }

}
<commit_msg>Fix #3: don't panic on put_file with bad path<commit_after>//! Directory module for managing Algorithmia Data Directories
//!
//! # Examples
//!
//! ```no_run
//! use algorithmia::Algorithmia;
//! use algorithmia::data::DataAcl;
//! use std::fs::File;
//!
//! let client = Algorithmia::client("111112222233333444445555566");
//! let my_dir = client.dir(".my/my_dir");
//!
//! my_dir.create(DataAcl::default());
//! my_dir.put_file("/path/to/file");
//! ```

use client::HttpClient;
use error::{self, Error};
use data::*;
use super::parse_data_uri;
use super::header::XDataType;

use std::io::Read;
use std::fs::File;
use std::path::Path;
use std::vec::IntoIter;

use serde_json;
use chrono::{DateTime, UTC};
use hyper::header::ContentType;
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::Url;

/// Algorithmia Data Directory
pub struct DataDir {
    path: String,
    client: HttpClient,
}

#[derive(Deserialize, Debug)]
pub struct DirectoryUpdated {
    pub acl: Option<DataAcl>,
}

/// Response when deleting a new Directory
#[derive(Deserialize, Debug)]
pub struct DirectoryDeleted {
    // Omitting deleted.number and error.number for now
    pub result: DeletedResult,
}

#[derive(Deserialize, Serialize, Debug)]
struct FolderItem {
    pub name: String,
    pub acl: Option<DataAcl>,
}

#[derive(Deserialize, Debug)]
struct FileItem {
    pub filename: String,
    pub size: u64,
    pub last_modified: DateTime<UTC>,
}

/// ACL that indicates permissions for a `DataDirectory`
/// See also: [`ReadAcl`](enum.ReadAcl.html) enum to construct a `DataACL`
#[derive(Deserialize, Serialize, Debug)]
pub struct DataAcl {
    pub read: Vec<String>,
}

pub enum ReadAcl {
    /// Readable only by owner
    Private,
    /// Readable by owner's algorithms (regardless of caller)
    MyAlgorithms,
    /// Readable by any user
    Public,
}

impl Default for DataAcl {
    fn default() -> Self {
        ReadAcl::MyAlgorithms.into()
    }
}

impl From<ReadAcl> for DataAcl {
    fn from(acl: ReadAcl) -> Self {
        match acl {
            ReadAcl::Private => DataAcl { read: vec![] },
            ReadAcl::MyAlgorithms => DataAcl { read: vec!["algo://.my/*".into()] },
            ReadAcl::Public => DataAcl { read: vec!["user://*".into()] },
        }
    }
}

/// Response when querying an existing Directory
#[derive(Deserialize, Debug)]
struct DirectoryShow {
    pub acl: Option<DataAcl>,
    pub folders: Option<Vec<FolderItem>>,
    pub files: Option<Vec<FileItem>>,
    pub marker: Option<String>,
}

pub struct DirectoryListing<'a> {
    pub acl: Option<DataAcl>,
    dir: &'a DataDir,
    folders: IntoIter<FolderItem>,
    files: IntoIter<FileItem>,
    marker: Option<String>,
    query_count: u32,
}

impl<'a> DirectoryListing<'a> {
    fn new(dir: &'a DataDir) -> DirectoryListing<'a> {
        DirectoryListing {
            acl: None,
            dir: dir,
            folders: Vec::new().into_iter(),
            files: Vec::new().into_iter(),
            marker: None,
            query_count: 0,
        }
    }
}

impl<'a> Iterator for DirectoryListing<'a> {
    type Item = Result<DataItem, Error>;

    fn next(&mut self) -> Option<Self::Item> {
        match self.folders.next() {
            // Return folders first
            Some(d) => Some(Ok(DataItem::Dir(DataDirItem { dir: self.dir.child(&d.name) }))),
            None => {
                match self.files.next() {
                    // Return files second
                    Some(f) => {
                        Some(Ok(DataItem::File(DataFileItem {
                            size: f.size,
                            last_modified: f.last_modified,
                            file: self.dir.child(&f.filename),
                        })))
                    }
                    None => {
                        // Query if there is another page of files/folders
                        if self.query_count == 0 || self.marker.is_some() {
                            self.query_count += 1;
                            match get_directory(self.dir, self.marker.clone()) {
                                Ok(ds) => {
                                    self.folders = ds.folders.unwrap_or_else(Vec::new).into_iter();
                                    self.files = ds.files.unwrap_or_else(Vec::new).into_iter();
                                    self.marker = ds.marker;
                                    self.next()
                                }
                                Err(err) => Some(Err(err)),
                            }
                        } else {
                            None
                        }
                    }
                }
            }
        }
    }
}

fn get_directory(dir: &DataDir, marker: Option<String>) -> Result<DirectoryShow, Error> {
    let url = match marker {
        Some(m) => Url::parse(&format!("{}?marker={}", dir.to_url(), m)).unwrap(),
        None => dir.to_url(),
    };

    let req = dir.client.get(url);
    let mut res = try!(req.send());

    if res.status.is_success() {
        if let Some(data_type) = res.headers.get::<XDataType>() {
            if "directory" != data_type.as_str() {
                return Err(Error::UnexpectedDataType("directory", data_type.to_string()));
            }
        }
    }

    let mut res_json = String::new();
    try!(res.read_to_string(&mut res_json));

    if res.status.is_success() {
        serde_json::from_str(&res_json).map_err(|err| err.into())
    } else {
        Err(error::decode(&res_json))
    }
}

impl HasDataPath for DataDir {
    fn new(client: HttpClient, path: &str) -> Self {
        DataDir {
            client: client,
            path: parse_data_uri(path).to_string(),
        }
    }
    fn path(&self) -> &str {
        &self.path
    }
    fn client(&self) -> &HttpClient {
        &self.client
    }
}

impl DataDir {
    /// Display Directory details if it exists
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Algorithmia;
    /// # use algorithmia::data::{DataItem, HasDataPath};
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let my_dir = client.dir(".my/my_dir");
    /// let dir_list = my_dir.list();
    /// for entry in dir_list {
    ///     match entry {
    ///         Ok(DataItem::File(f)) => println!("File: {}", f.to_data_uri()),
    ///         Ok(DataItem::Dir(d)) => println!("Dir: {}", d.to_data_uri()),
    ///         Err(err) => { println!("Error: {}", err); break; },
    ///     }
    /// };
    /// ```
    pub fn list(&self) -> DirectoryListing {
        DirectoryListing::new(self)
    }

    /// Create a Directory
    ///
    /// Use `DataAcl::default()` or the `ReadAcl` enum to set the ACL
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Algorithmia;
    /// # use algorithmia::data::DataAcl;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let my_dir = client.dir(".my/my_dir");
    /// match my_dir.create(DataAcl::default()) {
    ///   Ok(_) => println!("Successfully created Directory"),
    ///   Err(e) => println!("Error created directory: {}", e),
    /// };
    /// ```
    pub fn create<Acl: Into<DataAcl>>(&self, acl: Acl) -> Result<(), Error> {
        let parent = try!(self.parent().ok_or_else(|| Error::InvalidDataPath(self.path.clone())));
        let url = parent.to_url();

        // TODO: address complete abuse of this structure
        let input_data = FolderItem {
            name: try!(self.basename().ok_or_else(|| Error::InvalidDataPath(self.path.clone())))
                .into(),
            acl: Some(acl.into()),
        };
        let raw_input = try!(serde_json::to_string(&input_data));

        // POST request
        let req = self.client
            .post(url)
            .header(ContentType(Mime(TopLevel::Application, SubLevel::Json, vec![])))
            .body(&raw_input);

        // Parse response
        let mut res = try!(req.send());

        if res.status.is_success() {
            Ok(())
        } else {
            let mut res_json = String::new();
            try!(res.read_to_string(&mut res_json));
            Err(error::decode(&res_json))
        }
    }

    /// Delete a Directory
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let my_dir = client.dir(".my/my_dir");
    /// match my_dir.delete(false) {
    ///   Ok(_) => println!("Successfully deleted Directory"),
    ///   Err(err) => println!("Error deleting directory: {}", err),
    /// };
    /// ```
    pub fn delete(&self, force: bool) -> Result<DirectoryDeleted, Error> {
        // DELETE request
        let url_string = format!("{}?force={}", self.to_url(), force.to_string());
        let url = Url::parse(&url_string).unwrap();
        let req = self.client.delete(url);

        // Parse response
        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        if res.status.is_success() {
            serde_json::from_str(&res_json).map_err(|err| err.into())
        } else {
            Err(error::decode(&res_json))
        }
    }

    /// Upload a file to an existing Directory
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let my_dir = client.dir(".my/my_dir");
    ///
    /// match my_dir.put_file("/path/to/file") {
    ///   Ok(response) => println!("Successfully uploaded to: {}", response.result),
    ///   Err(err) => println!("Error uploading file: {}", err),
    /// };
    /// ```
    pub fn put_file<P: AsRef<Path>>(&self, file_path: P) -> Result<FileAdded, Error> {
        // FIXME: A whole lot of unwrap going on here...
        let path_ref = file_path.as_ref();
        let url_string = format!("{}/{}",
                                 self.to_url(),
                                 path_ref.file_name().unwrap().to_str().unwrap());
        let url = Url::parse(&url_string).unwrap();

        let mut file = try!(File::open(path_ref));
        let req = self.client.put(url).body(&mut file);

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        if res.status.is_success() {
            serde_json::from_str(&res_json).map_err(|err| err.into())
        } else {
            Err(error::decode(&res_json))
        }
    }

    pub fn child<T: HasDataPath>(&self, filename: &str) -> T {
        let new_uri = match self.to_data_uri() {
            ref uri if uri.ends_with('/') => format!("{}{}", uri, filename),
            uri => format!("{}/{}", uri, filename),
        };
        T::new(self.client.clone(), &new_uri)
    }
}

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

    fn mock_client() -> Algorithmia {
        Algorithmia::client("")
    }

    #[test]
    fn test_to_url() {
        let dir = mock_client().dir("data://anowell/foo");
        assert_eq!(dir.to_url().path(), "/v1/connector/data/anowell/foo");
    }

    #[test]
    fn test_to_data_uri() {
        let dir = mock_client().dir("/anowell/foo");
        assert_eq!(dir.to_data_uri(), "data://anowell/foo".to_string());
    }

    #[test]
    fn test_parent() {
        let dir = mock_client().dir("data://anowell/foo");
        let expected = mock_client().dir("data://anowell");
        assert_eq!(dir.parent().unwrap().path, expected.path);

        let dir = mock_client().dir("dropbox://anowell/foo");
        let expected = mock_client().dir("dropbox://anowell");
        assert_eq!(dir.parent().unwrap().path, expected.path);

        let dir = mock_client().dir("data://anowell");
        let expected = mock_client().dir("data://");
        assert_eq!(dir.parent().unwrap().path, expected.path);

        let dir = mock_client().dir("data://");
        assert!(dir.parent().is_none());
    }

    #[test]
    fn test_default_acl() {
        let acl: DataAcl = DataAcl::default();
        assert_eq!(acl.read, vec!["algo://.my/*".to_string()]);
    }

    #[test]
    fn test_private_acl() {
        let acl: DataAcl = ReadAcl::Private.into();
        assert!(acl.read.is_empty());
    }

    #[test]
    fn test_public_acl() {
        let acl: DataAcl = ReadAcl::Public.into();
        assert_eq!(acl.read, vec!["user://*".to_string()]);
    }

    #[test]
    fn test_myalgos_acl() {
        let acl: DataAcl = ReadAcl::MyAlgorithms.into();
        assert_eq!(acl.read, vec!["algo://.my/*".to_string()]);
    }

}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate cc;
extern crate gl_generator;

use gl_generator::{Api, Fallbacks, Profile, Registry};
use std::env;
use std::fs::File;
use std::path::Path;

fn main() {
    let target = env::var("TARGET").unwrap();
    if target.contains("android") {
        android_main()
    }
    generate_gl_bindings(&target);
}

fn android_main() {
    // Get the NDK path from NDK_HOME env.
    let ndk_path = env::var_os("ANDROID_NDK").expect("Please set the ANDROID_NDK environment variable");
    let ndk_path = Path::new(&ndk_path);

    let target = env::var("TARGET").unwrap();
    let arch = if target.contains("arm") {
        "arch-arm"
    } else if target.contains("aarch64") {
        "arch-arm64"
    } else if target.contains("x86") || target.contains("i686") {
        "arch-x86"
    } else if target.contains("mips") {
        "arch-mips"
    } else {
        panic!("Invalid target architecture {}", target);
    };

    let platform = if target.contains("aarch64") {
        "android-21"
    } else {
        "android-18"
    };

    // compiling android_native_app_glue.c
    let c_file = ndk_path.join("sources").join("android").join("native_app_glue").join("android_native_app_glue.c");
    let sysroot = ndk_path.join("platforms").join(platform).join(arch);
    cc::Build::new()
        .file(c_file)
        .flag("--sysroot")
        .flag(sysroot.to_str().unwrap())
        .warnings(false)
        .compile("android_native_app_glue");

    // Get the output directory.
    let out_dir = env::var("OUT_DIR").expect("Cargo should have set the OUT_DIR environment variable");

    println!("cargo:rustc-link-lib=static=android_native_app_glue");
    println!("cargo:rustc-link-search=native={}", out_dir);
    println!("cargo:rustc-link-lib=log");
    println!("cargo:rustc-link-lib=android");

}

fn generate_gl_bindings(target: &str) {
    // For now, we only support EGL, and only on Windows and Android.
    if target.contains("android") || target.contains("windows") {
        let dest = env::var("OUT_DIR").unwrap();
        let mut file = File::create(&Path::new(&dest).join("egl_bindings.rs")).unwrap();
        if target.contains("android") {
            Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
                .write_bindings(gl_generator::StaticStructGenerator, &mut file)
                .unwrap();
        }
        if target.contains("windows") {
            Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
                .write_bindings(gl_generator::StructGenerator, &mut file)
                .unwrap();
        };
    }
}
<commit_msg>Auto merge of #21675 - chansuke:format_libsimpleservo, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate cc;
extern crate gl_generator;

use gl_generator::{Api, Fallbacks, Profile, Registry};
use std::env;
use std::fs::File;
use std::path::Path;

fn main() {
    let target = env::var("TARGET").unwrap();
    if target.contains("android") {
        android_main()
    }
    generate_gl_bindings(&target);
}

fn android_main() {
    // Get the NDK path from NDK_HOME env.
    let ndk_path =
        env::var_os("ANDROID_NDK").expect("Please set the ANDROID_NDK environment variable");
    let ndk_path = Path::new(&ndk_path);

    let target = env::var("TARGET").unwrap();
    let arch = if target.contains("arm") {
        "arch-arm"
    } else if target.contains("aarch64") {
        "arch-arm64"
    } else if target.contains("x86") || target.contains("i686") {
        "arch-x86"
    } else if target.contains("mips") {
        "arch-mips"
    } else {
        panic!("Invalid target architecture {}", target);
    };

    let platform = if target.contains("aarch64") {
        "android-21"
    } else {
        "android-18"
    };

    // compiling android_native_app_glue.c
    let c_file = ndk_path
        .join("sources")
        .join("android")
        .join("native_app_glue")
        .join("android_native_app_glue.c");
    let sysroot = ndk_path.join("platforms").join(platform).join(arch);
    cc::Build::new()
        .file(c_file)
        .flag("--sysroot")
        .flag(sysroot.to_str().unwrap())
        .warnings(false)
        .compile("android_native_app_glue");

    // Get the output directory.
    let out_dir =
        env::var("OUT_DIR").expect("Cargo should have set the OUT_DIR environment variable");

    println!("cargo:rustc-link-lib=static=android_native_app_glue");
    println!("cargo:rustc-link-search=native={}", out_dir);
    println!("cargo:rustc-link-lib=log");
    println!("cargo:rustc-link-lib=android");
}

fn generate_gl_bindings(target: &str) {
    // For now, we only support EGL, and only on Windows and Android.
    if target.contains("android") || target.contains("windows") {
        let dest = env::var("OUT_DIR").unwrap();
        let mut file = File::create(&Path::new(&dest).join("egl_bindings.rs")).unwrap();
        if target.contains("android") {
            Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
                .write_bindings(gl_generator::StaticStructGenerator, &mut file)
                .unwrap();
        }
        if target.contains("windows") {
            Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
                .write_bindings(gl_generator::StructGenerator, &mut file)
                .unwrap();
        };
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
use std::vec::Vec;

use engine::Dev;
use engine::EngineError;
use engine::EngineResult;
use engine::ErrorEnum;
use engine::Filesystem;
use engine::Pool;
use engine::RenameAction;

use super::blockdev::SimDev;
use super::filesystem::SimFilesystem;
use super::randomization::Randomizer;

use uuid::Uuid;

#[derive(Debug)]
pub struct SimPool {
    pub block_devs: BTreeMap<PathBuf, SimDev>,
    pub cache_devs: BTreeMap<PathBuf, SimDev>,
    pub filesystems: BTreeMap<String, SimFilesystem>,
    pub raid_level: u16,
    rdm: Rc<RefCell<Randomizer>>,
}

impl SimPool {
    pub fn new(rdm: Rc<RefCell<Randomizer>>, paths: &[&Path], raid_level: u16) -> SimPool {

        let devices = BTreeSet::from_iter(paths);
        let device_pairs = devices.iter()
            .map(|p| (p.to_path_buf(), SimDev::new(rdm.clone(), p)));
        let new_pool = SimPool {
            block_devs: BTreeMap::from_iter(device_pairs),
            filesystems: BTreeMap::new(),
            cache_devs: BTreeMap::new(),
            raid_level: raid_level,
            rdm: rdm.clone(),
        };

        new_pool
    }
}

impl Pool for SimPool {
    fn add_blockdevs(&mut self, paths: &[&Path], _force: bool) -> EngineResult<Vec<PathBuf>> {
        let rdm = self.rdm.clone();
        let devices = BTreeSet::from_iter(paths);
        let device_pairs = devices.iter()
            .map(|p| (p.to_path_buf(), SimDev::new(rdm.clone(), p)));
        self.block_devs.extend(device_pairs);
        Ok(devices.iter().map(|d| d.to_path_buf()).collect())
    }

    fn add_cachedevs(&mut self, paths: &[&Path], _force: bool) -> EngineResult<Vec<PathBuf>> {
        let rdm = self.rdm.clone();
        let devices = BTreeSet::from_iter(paths);
        let device_pairs = devices.iter()
            .map(|p| (p.to_path_buf(), SimDev::new(rdm.clone(), p)));
        self.cache_devs.extend(device_pairs);
        Ok(devices.iter().map(|d| d.to_path_buf()).collect())
    }

    fn destroy_filesystems<'a, 'b>(&'a mut self,
                                   fs_names: &[&'b str])
                                   -> EngineResult<Vec<&'b str>> {
        destroy_filesystems!{self; fs_names}
    }

    fn create_filesystems<'a, 'b, 'c>(&'a mut self,
                                      specs: &[(&'b str, &'c str, Option<u64>)])
                                      -> EngineResult<Vec<&'b str>> {
        let mut temp = Vec::new();
        for spec in specs {
            temp.push(spec);
        }
        temp.sort();
        temp.dedup();

        let names = BTreeSet::from_iter(temp.iter().map(|x| x.0));
        if names.len() < temp.len() {
            let error_message = "duplicate_names in filesystem spec";
            return Err(EngineError::Stratis(ErrorEnum::Error(error_message.into())));
        }

        for spec in temp.iter() {
            let name = spec.0;
            if self.filesystems.contains_key(name) {
                return Err(EngineError::Stratis(ErrorEnum::AlreadyExists(name.into())));
            }
        }

        let mut names = Vec::new();
        for spec in temp.iter() {
            let (name, mountpoint, quota) = **spec;
            let new_filesystem = SimFilesystem::new_filesystem(Uuid::new_v4(), mountpoint, quota);
            self.filesystems.insert(name.into(), new_filesystem);
            names.push(name);
        }

        Ok(names)
    }

    fn create_snapshot<'a, 'b, 'c>(&'a mut self,
                                   snapshot_name: &'b str,
                                   source: &'c str)
                                   -> EngineResult<&'b str> {

        let parent_id = try!(self.filesystems
                .get(source)
                .ok_or(EngineError::Stratis(ErrorEnum::NotFound(String::from(source)))))
            .fs_id;

        let names = try!(self.create_filesystems(&[(snapshot_name, "", None)]));

        let new_snapshot = try!(self.filesystems
            .get_mut(snapshot_name)
            .ok_or(EngineError::Stratis(ErrorEnum::NotFound(String::from(snapshot_name)))));

        new_snapshot.nearest_ancestor = Some(parent_id);

        Ok(names[0])
    }

    fn filesystems(&mut self) -> BTreeMap<&str, &mut Filesystem> {
        BTreeMap::from_iter(self.filesystems
            .iter_mut()
            .map(|x| (x.0 as &str, x.1 as &mut Filesystem)))
    }

    fn blockdevs(&mut self) -> Vec<&mut Dev> {
        Vec::from_iter(self.block_devs.values_mut().map(|x| x as &mut Dev))
    }

    fn cachedevs(&mut self) -> Vec<&mut Dev> {
        Vec::from_iter(self.cache_devs.values_mut().map(|x| x as &mut Dev))
    }

    // Should verify that block devices are not required by pool, but does not.
    fn remove_blockdevs(&mut self, paths: &[&Path]) -> EngineResult<Vec<PathBuf>> {
        let devices = BTreeSet::from_iter(paths);

        let mut removed = vec![];
        for dev in devices {
            let pathbuf = dev.to_path_buf();
            match self.block_devs.remove(&pathbuf) {
                Some(_) => removed.push(pathbuf),
                _ => {}
            }
        }
        Ok(removed)
    }

    // Should verify that block devices are not required by pool, but does not.
    fn remove_cachedevs(&mut self, paths: &[&Path]) -> EngineResult<Vec<PathBuf>> {
        let devices = BTreeSet::from_iter(paths);

        let mut removed = vec![];
        for dev in devices {
            let pathbuf = dev.to_path_buf();
            match self.cache_devs.remove(&pathbuf) {
                Some(_) => removed.push(pathbuf),
                _ => {}
            }
        }
        Ok(removed)
    }

    fn rename_filesystem(&mut self, old_name: &str, new_name: &str) -> EngineResult<RenameAction> {
        rename_filesystem!{self; old_name; new_name}
    }
}

#[cfg(test)]
mod tests {

    use engine::Engine;
    use engine::ErrorEnum;
    use engine::EngineError;
    use engine::RenameAction;

    use super::super::SimEngine;

    #[test]
    /// Renaming a filesystem on an empty pool always works
    fn rename_empty() {
        let pool_name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.rename_filesystem("old_name", "new_name") {
            Ok(RenameAction::NoSource) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a filesystem to itself on an empty pool always works.
    fn rename_empty_identity() {
        let pool_name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.rename_filesystem("old_name", "old_name") {
            Ok(RenameAction::Identity) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a filesystem to itself always works
    fn rename_identity() {
        let name = "name";
        let pool_name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.rename_filesystem(name, name) {
            Ok(RenameAction::Identity) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a filesystem to another filesystem should work if new name not taken
    fn rename_happens() {
        let old_name = "old_name";
        let pool_name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let pool = engine.get_pool(pool_name).unwrap();
        pool.create_filesystems(&[(old_name, "", None)]).unwrap();
        assert!(match pool.rename_filesystem(old_name, "new_name") {
            Ok(RenameAction::Renamed) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a filesystem to another filesystem should fail if new name taken
    fn rename_fails() {
        let old_name = "old_name";
        let new_name = "new_name";
        let pool_name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let pool = engine.get_pool(pool_name).unwrap();
        pool.create_filesystems(&[(old_name, "", None), (new_name, "", None)]).unwrap();
        assert!(match pool.rename_filesystem(old_name, new_name) {
            Err(EngineError::Stratis(ErrorEnum::AlreadyExists(_))) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming should succeed if old_name absent, new present
    fn rename_no_op() {
        let old_name = "old_name";
        let new_name = "new_name";
        let pool_name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let pool = engine.get_pool(pool_name).unwrap();
        pool.create_filesystems(&[(new_name, "", None)]).unwrap();
        assert!(match pool.rename_filesystem(old_name, new_name) {
            Ok(RenameAction::NoSource) => true,
            _ => false,
        });
    }

    #[test]
    /// Removing an empty list of filesystems should always succeed
    fn destroy_fs_empty() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(name).unwrap();
        assert!(match pool.destroy_filesystems(&[]) {
            Ok(names) => names.is_empty(),
            _ => false,
        });
    }

    #[test]
    /// Removing a non-empty list of filesystems should succeed on empty pool
    fn destroy_fs_some() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(name).unwrap();
        assert!(pool.destroy_filesystems(&["fs"]).is_ok());
    }

    #[test]
    /// Removing a non-empty list of filesystems should succeed on any pool
    fn destroy_fs_any() {
        let pool_name = "name";
        let fs_name = "fs_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        pool.create_filesystems(&[(fs_name, "", None)]).unwrap();
        assert!(match pool.destroy_filesystems(&[fs_name, "other"]) {
            Ok(names) => names == vec![fs_name],
            _ => false,
        });
    }

    #[test]
    /// Creating an empty list of filesystems should succeed, always
    fn create_fs_none() {
        let pool_name = "pool_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.create_filesystems(&[]) {
            Ok(names) => names.is_empty(),
            _ => false,
        });
    }

    #[test]
    /// Creating a non-empty list of filesystems always succeeds.
    fn create_fs_some() {
        let pool_name = "pool_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.create_filesystems(&[("name", "", None)]) {
            Ok(names) => (names.len() == 1) & (names[0] == "name"),
            _ => false,
        });
    }

    #[test]
    /// Creating a an already existing filesystem fails.
    fn create_fs_conflict() {
        let pool_name = "pool_name";
        let fs_name = "fs_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        pool.create_filesystems(&[(fs_name, "", None)]).unwrap();
        assert!(match pool.create_filesystems(&[(fs_name, "", None)]) {
            Err(EngineError::Stratis(ErrorEnum::AlreadyExists(_))) => true,
            _ => false,
        });
    }

    #[test]
    /// Requesting identical filesystems succeeds.
    fn create_fs_dups() {
        let fs_name = "fs_name";
        let pool_name = "pool_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.create_filesystems(&[(fs_name, "", None), (fs_name, "", None)]) {
            Ok(names) => (names.len() == 1) & (names[0] == fs_name),
            _ => false,
        });
    }

    #[test]
    /// Requesting filesystems with same name but different specs fails.
    fn create_fs_conflicts() {
        let fs_name = "fs_name";
        let pool_name = "pool_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.create_filesystems(&[(fs_name, "", None), (fs_name, "/", None)]) {
            Err(EngineError::Stratis(ErrorEnum::Error(_))) => true,
            _ => false,
        });
    }
}
<commit_msg>Add some tests for removed_ and add_ devices.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
use std::vec::Vec;

use engine::Dev;
use engine::EngineError;
use engine::EngineResult;
use engine::ErrorEnum;
use engine::Filesystem;
use engine::Pool;
use engine::RenameAction;

use super::blockdev::SimDev;
use super::filesystem::SimFilesystem;
use super::randomization::Randomizer;

use uuid::Uuid;

#[derive(Debug)]
pub struct SimPool {
    pub block_devs: BTreeMap<PathBuf, SimDev>,
    pub cache_devs: BTreeMap<PathBuf, SimDev>,
    pub filesystems: BTreeMap<String, SimFilesystem>,
    pub raid_level: u16,
    rdm: Rc<RefCell<Randomizer>>,
}

impl SimPool {
    pub fn new(rdm: Rc<RefCell<Randomizer>>, paths: &[&Path], raid_level: u16) -> SimPool {

        let devices = BTreeSet::from_iter(paths);
        let device_pairs = devices.iter()
            .map(|p| (p.to_path_buf(), SimDev::new(rdm.clone(), p)));
        let new_pool = SimPool {
            block_devs: BTreeMap::from_iter(device_pairs),
            filesystems: BTreeMap::new(),
            cache_devs: BTreeMap::new(),
            raid_level: raid_level,
            rdm: rdm.clone(),
        };

        new_pool
    }
}

impl Pool for SimPool {
    fn add_blockdevs(&mut self, paths: &[&Path], _force: bool) -> EngineResult<Vec<PathBuf>> {
        let rdm = self.rdm.clone();
        let devices = BTreeSet::from_iter(paths);
        let device_pairs = devices.iter()
            .map(|p| (p.to_path_buf(), SimDev::new(rdm.clone(), p)));
        self.block_devs.extend(device_pairs);
        Ok(devices.iter().map(|d| d.to_path_buf()).collect())
    }

    fn add_cachedevs(&mut self, paths: &[&Path], _force: bool) -> EngineResult<Vec<PathBuf>> {
        let rdm = self.rdm.clone();
        let devices = BTreeSet::from_iter(paths);
        let device_pairs = devices.iter()
            .map(|p| (p.to_path_buf(), SimDev::new(rdm.clone(), p)));
        self.cache_devs.extend(device_pairs);
        Ok(devices.iter().map(|d| d.to_path_buf()).collect())
    }

    fn destroy_filesystems<'a, 'b>(&'a mut self,
                                   fs_names: &[&'b str])
                                   -> EngineResult<Vec<&'b str>> {
        destroy_filesystems!{self; fs_names}
    }

    fn create_filesystems<'a, 'b, 'c>(&'a mut self,
                                      specs: &[(&'b str, &'c str, Option<u64>)])
                                      -> EngineResult<Vec<&'b str>> {
        let mut temp = Vec::new();
        for spec in specs {
            temp.push(spec);
        }
        temp.sort();
        temp.dedup();

        let names = BTreeSet::from_iter(temp.iter().map(|x| x.0));
        if names.len() < temp.len() {
            let error_message = "duplicate_names in filesystem spec";
            return Err(EngineError::Stratis(ErrorEnum::Error(error_message.into())));
        }

        for spec in temp.iter() {
            let name = spec.0;
            if self.filesystems.contains_key(name) {
                return Err(EngineError::Stratis(ErrorEnum::AlreadyExists(name.into())));
            }
        }

        let mut names = Vec::new();
        for spec in temp.iter() {
            let (name, mountpoint, quota) = **spec;
            let new_filesystem = SimFilesystem::new_filesystem(Uuid::new_v4(), mountpoint, quota);
            self.filesystems.insert(name.into(), new_filesystem);
            names.push(name);
        }

        Ok(names)
    }

    fn create_snapshot<'a, 'b, 'c>(&'a mut self,
                                   snapshot_name: &'b str,
                                   source: &'c str)
                                   -> EngineResult<&'b str> {

        let parent_id = try!(self.filesystems
                .get(source)
                .ok_or(EngineError::Stratis(ErrorEnum::NotFound(String::from(source)))))
            .fs_id;

        let names = try!(self.create_filesystems(&[(snapshot_name, "", None)]));

        let new_snapshot = try!(self.filesystems
            .get_mut(snapshot_name)
            .ok_or(EngineError::Stratis(ErrorEnum::NotFound(String::from(snapshot_name)))));

        new_snapshot.nearest_ancestor = Some(parent_id);

        Ok(names[0])
    }

    fn filesystems(&mut self) -> BTreeMap<&str, &mut Filesystem> {
        BTreeMap::from_iter(self.filesystems
            .iter_mut()
            .map(|x| (x.0 as &str, x.1 as &mut Filesystem)))
    }

    fn blockdevs(&mut self) -> Vec<&mut Dev> {
        Vec::from_iter(self.block_devs.values_mut().map(|x| x as &mut Dev))
    }

    fn cachedevs(&mut self) -> Vec<&mut Dev> {
        Vec::from_iter(self.cache_devs.values_mut().map(|x| x as &mut Dev))
    }

    // Should verify that block devices are not required by pool, but does not.
    fn remove_blockdevs(&mut self, paths: &[&Path]) -> EngineResult<Vec<PathBuf>> {
        let devices = BTreeSet::from_iter(paths);

        let mut removed = vec![];
        for dev in devices {
            let pathbuf = dev.to_path_buf();
            match self.block_devs.remove(&pathbuf) {
                Some(_) => removed.push(pathbuf),
                _ => {}
            }
        }
        Ok(removed)
    }

    // Should verify that block devices are not required by pool, but does not.
    fn remove_cachedevs(&mut self, paths: &[&Path]) -> EngineResult<Vec<PathBuf>> {
        let devices = BTreeSet::from_iter(paths);

        let mut removed = vec![];
        for dev in devices {
            let pathbuf = dev.to_path_buf();
            match self.cache_devs.remove(&pathbuf) {
                Some(_) => removed.push(pathbuf),
                _ => {}
            }
        }
        Ok(removed)
    }

    fn rename_filesystem(&mut self, old_name: &str, new_name: &str) -> EngineResult<RenameAction> {
        rename_filesystem!{self; old_name; new_name}
    }
}

#[cfg(test)]
mod tests {

    use std::path::Path;

    use engine::Engine;
    use engine::ErrorEnum;
    use engine::EngineError;
    use engine::RenameAction;

    use super::super::SimEngine;

    #[test]
    /// Renaming a filesystem on an empty pool always works
    fn rename_empty() {
        let pool_name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.rename_filesystem("old_name", "new_name") {
            Ok(RenameAction::NoSource) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a filesystem to itself on an empty pool always works.
    fn rename_empty_identity() {
        let pool_name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.rename_filesystem("old_name", "old_name") {
            Ok(RenameAction::Identity) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a filesystem to itself always works
    fn rename_identity() {
        let name = "name";
        let pool_name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.rename_filesystem(name, name) {
            Ok(RenameAction::Identity) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a filesystem to another filesystem should work if new name not taken
    fn rename_happens() {
        let old_name = "old_name";
        let pool_name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let pool = engine.get_pool(pool_name).unwrap();
        pool.create_filesystems(&[(old_name, "", None)]).unwrap();
        assert!(match pool.rename_filesystem(old_name, "new_name") {
            Ok(RenameAction::Renamed) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a filesystem to another filesystem should fail if new name taken
    fn rename_fails() {
        let old_name = "old_name";
        let new_name = "new_name";
        let pool_name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let pool = engine.get_pool(pool_name).unwrap();
        pool.create_filesystems(&[(old_name, "", None), (new_name, "", None)]).unwrap();
        assert!(match pool.rename_filesystem(old_name, new_name) {
            Err(EngineError::Stratis(ErrorEnum::AlreadyExists(_))) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming should succeed if old_name absent, new present
    fn rename_no_op() {
        let old_name = "old_name";
        let new_name = "new_name";
        let pool_name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let pool = engine.get_pool(pool_name).unwrap();
        pool.create_filesystems(&[(new_name, "", None)]).unwrap();
        assert!(match pool.rename_filesystem(old_name, new_name) {
            Ok(RenameAction::NoSource) => true,
            _ => false,
        });
    }

    #[test]
    /// Removing an empty list of filesystems should always succeed
    fn destroy_fs_empty() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(name).unwrap();
        assert!(match pool.destroy_filesystems(&[]) {
            Ok(names) => names.is_empty(),
            _ => false,
        });
    }

    #[test]
    /// Removing a non-empty list of filesystems should succeed on empty pool
    fn destroy_fs_some() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(name).unwrap();
        assert!(pool.destroy_filesystems(&["fs"]).is_ok());
    }

    #[test]
    /// Removing a non-empty list of filesystems should succeed on any pool
    fn destroy_fs_any() {
        let pool_name = "name";
        let fs_name = "fs_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        pool.create_filesystems(&[(fs_name, "", None)]).unwrap();
        assert!(match pool.destroy_filesystems(&[fs_name, "other"]) {
            Ok(names) => names == vec![fs_name],
            _ => false,
        });
    }

    #[test]
    /// Creating an empty list of filesystems should succeed, always
    fn create_fs_none() {
        let pool_name = "pool_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.create_filesystems(&[]) {
            Ok(names) => names.is_empty(),
            _ => false,
        });
    }

    #[test]
    /// Creating a non-empty list of filesystems always succeeds.
    fn create_fs_some() {
        let pool_name = "pool_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.create_filesystems(&[("name", "", None)]) {
            Ok(names) => (names.len() == 1) & (names[0] == "name"),
            _ => false,
        });
    }

    #[test]
    /// Creating a an already existing filesystem fails.
    fn create_fs_conflict() {
        let pool_name = "pool_name";
        let fs_name = "fs_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        pool.create_filesystems(&[(fs_name, "", None)]).unwrap();
        assert!(match pool.create_filesystems(&[(fs_name, "", None)]) {
            Err(EngineError::Stratis(ErrorEnum::AlreadyExists(_))) => true,
            _ => false,
        });
    }

    #[test]
    /// Requesting identical filesystems succeeds.
    fn create_fs_dups() {
        let fs_name = "fs_name";
        let pool_name = "pool_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.create_filesystems(&[(fs_name, "", None), (fs_name, "", None)]) {
            Ok(names) => (names.len() == 1) & (names[0] == fs_name),
            _ => false,
        });
    }

    #[test]
    /// Requesting filesystems with same name but different specs fails.
    fn create_fs_conflicts() {
        let fs_name = "fs_name";
        let pool_name = "pool_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.create_filesystems(&[(fs_name, "", None), (fs_name, "/", None)]) {
            Err(EngineError::Stratis(ErrorEnum::Error(_))) => true,
            _ => false,
        });
    }

    #[test]
    /// Removing an empty list of devices from an empty pool yields empty list.
    fn remove_device_empty() {
        let pool_name = "pool_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.remove_blockdevs(&[]) {
            Ok(devs) => devs.is_empty(),
            _ => false,
        });
    }

    #[test]
    /// Removing a non-empyt list of devices from empty pool yields empty list.
    fn remove_device_empty_2() {
        let pool_name = "pool_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        assert!(match pool.remove_blockdevs(&[Path::new("/s/b")]) {
            Ok(devs) => devs.is_empty(),
            _ => false,
        });
    }

    #[test]
    /// Removing a list of devices from non-empty pool yields intersection.
    fn remove_device_intersection() {
        let pool_name = "pool_name";
        let mut engine = SimEngine::new();
        let devices = [Path::new("/s/a"), Path::new("/s/b")];
        engine.create_pool(pool_name, &devices, 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        let remove_devices = [Path::new("/s/a"), Path::new("/s/c")];
        assert!(match pool.remove_blockdevs(&remove_devices) {
            Ok(devs) => devs == [Path::new("/s/a")],
            _ => false,
        });
    }

    #[test]
    /// Adding a list of devices to an empty pool should yield list.
    fn add_device_empty() {
        let pool_name = "pool_name";
        let mut engine = SimEngine::new();
        engine.create_pool(pool_name, &[], 0, false).unwrap();
        let mut pool = engine.get_pool(pool_name).unwrap();
        let devices = [Path::new("/s/a"), Path::new("/s/b")];
        assert!(match pool.add_blockdevs(&devices, false) {
            Ok(devs) => devs == devices,
            _ => false,
        });
    }
}
<|endoftext|>


<commit_before>fn main() {
    let n = 5i;

    if n < 0 {
        print!("{} is negative", n);
    } else if n > 0 {
        print!("{} is positive", n);
    } else {
        print!("{} is zero", n);
    }

    let big_n =
        if n < 10 && n > -10 {
            println!(", and is a small number, increase ten-fold");

            // This expression returns an `int`
            10 * n
        } else {
            println!(", and is a big number, reduce by two");

            // This expression must return an `int` as well
            n / 2
            // TODO ^ Try suppressing this expression with a semicolon
        };

    println!("{} -> {}", n, big_n);
}
<commit_msg>if-else: remark on a semicolon after a long if-else.<commit_after>fn main() {
    let n = 5i;

    if n < 0 {
        print!("{} is negative", n);
    } else if n > 0 {
        print!("{} is positive", n);
    } else {
        print!("{} is zero", n);
    }

    let big_n =
        if n < 10 && n > -10 {
            println!(", and is a small number, increase ten-fold");

            // This expression returns an `int`
            10 * n
        } else {
            println!(", and is a big number, reduce by two");

            // This expression must return an `int` as well
            n / 2
            // TODO ^ Try suppressing this expression with a semicolon
        }; // don't forget to put a semicolon here;  `let` requires it

    println!("{} -> {}", n, big_n);
}
<|endoftext|>