<commit_before>// This module implements the central application object.

use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use std::path::PathBuf;

use hyper;
use hyper::server::Request as HTTPRequest;
use hyper::server::Response as HTTPResponse;

use types::{
    PencilValue,
        PenResponse,

    PencilError,
        PenHTTPError,
        PenUserError,

    UserError,
    PencilResult,
    ViewFunc,
    HTTPErrorHandler,
    UserErrorHandler,
    BeforeRequestFunc,
    AfterRequestFunc,
    TeardownRequestFunc,
};
use wrappers::{
    Request,
    Response,
};
use helpers::{PathBound, send_static_file};
use helpers;
use config;
use logging;
use serving::run_server;
use routing::{Map, Rule};
use testing::PencilClient;
use errors::{HTTPError, NotFound, InternalServerError};

/// The pencil type.  It acts as the central application object.  Once it is created it
/// will act as a central registry for the view functions, the URL rules and much more.
pub struct Pencil {
    pub root_path: String,
    pub static_folder: String,
    pub static_url_path: String,
    pub config: config::Config,
    pub url_map: Map,
    // A dictionary of all view functions registered.
    pub view_functions: HashMap<String, ViewFunc>,
    pub before_request_funcs: Vec<BeforeRequestFunc>,
    pub after_request_funcs: Vec<AfterRequestFunc>,
    pub teardown_request_funcs: Vec<TeardownRequestFunc>,
    pub http_error_handlers: HashMap<isize, HTTPErrorHandler>,
    pub user_error_handlers: HashMap<&'static str, UserErrorHandler>,
}

impl Pencil {
    /// Create a new pencil object.  It is passed the root path of your application.
    /// The root path is used to resolve resources from inside it, for more information
    /// about resource loading, see method `open_resource`.
    ///
    /// Usually you create a pencil object in your main function like this:
    ///
    /// ```rust,no_run
    /// use pencil::Pencil;
    ///
    /// fn main() {
    ///     let mut app = Pencil::new("/web/myapp");
    /// }
    /// ```
    pub fn new(root_path: &str) -> Pencil {
        Pencil {
            root_path: root_path.to_string(),
            static_folder: String::from("static"),
            static_url_path: String::from("/static"),
            config: config::Config::new(),
            url_map: Map::new(),
            view_functions: HashMap::new(),
            before_request_funcs: vec![],
            after_request_funcs: vec![],
            teardown_request_funcs: vec![],
            http_error_handlers: HashMap::new(),
            user_error_handlers: HashMap::new(),
        }
    }

    /// Set global log level based on the application's debug flag.
    pub fn set_log_level(&self) {
        logging::set_log_level(self);
    }

    /// A shortcut that is used to register a view function for a given
    /// URL rule.
    pub fn route(&mut self, rule: &str, methods: &[&str], endpoint: &str, view_func: ViewFunc) {
        self.add_url_rule(rule, methods, endpoint, view_func);
    }

    /// Connects a URL rule.
    fn add_url_rule(&mut self, rule: &str, methods: &[&str], endpoint: &str, view_func: ViewFunc) {
        let url_rule = Rule::new(rule, methods, endpoint);
        self.url_map.add(url_rule);
        self.view_functions.insert(endpoint.to_string(), view_func);
    }

    /// Enables static file handling.
    pub fn enable_static_file_handle(&mut self) {
        let mut rule = self.static_url_path.clone();
        rule = rule + "/([^/].*?)";
        self.add_url_rule(&rule, &["GET"], "static", send_static_file);
    }

    /// Registers a function to run before each request.
    pub fn before_request(&mut self, f: BeforeRequestFunc) {
        self.before_request_funcs.push(f);
    }

    /// Registers a function to run after each request.  Your function
    /// must take a response object and modify it.
    pub fn after_request(&mut self, f: AfterRequestFunc) {
        self.after_request_funcs.push(f);
    }

    /// Registers a function to run at the end of each request,
    /// regardless of whether there was an error or not.
    pub fn teardown_request(&mut self, f: TeardownRequestFunc) {
        self.teardown_request_funcs.push(f);
    }

    /// Registers a function as one http error handler.
    fn register_http_error_handler(&mut self, status_code: isize, f: HTTPErrorHandler) {
        self.http_error_handlers.insert(status_code, f);
    }

    /// Registers a function as one user error handler.
    fn register_user_error_handler(&mut self, error_desc: &'static str, f: UserErrorHandler) {
        self.user_error_handlers.insert(error_desc, f);
    }

    /// Registers a function as one http error handler.  Example:
    ///
    /// ```rust,no_run
    /// use pencil::{Pencil, PencilResult, Response, PenResponse};
    /// use pencil::HTTPError;
    ///
    ///
    /// fn page_not_found(error: HTTPError) -> PencilResult {
    ///     let mut response = Response::new(String::from("The page does not exist"));
    ///     response.status_code = 404;
    ///     return Ok(PenResponse(response));
    /// }
    ///
    ///
    /// fn main() {
    ///     let mut app = Pencil::new("/web/demo");
    ///     app.httperrorhandler(404, page_not_found);
    /// }
    /// ```
    pub fn httperrorhandler(&mut self, status_code: isize, f: HTTPErrorHandler) {
        self.register_http_error_handler(status_code, f);
    }

    /// Registers a function as one user error handler.  There are two ways to handle
    /// user errors currently, you can do it in your own view like this:
    ///
    /// ```rust,no_run
    /// use pencil::Request;
    /// use pencil::{PencilResult, PenString};
    ///
    ///
    /// #[derive(Clone, Copy)]
    /// struct MyErr(isize);
    ///
    ///
    /// fn some_operation() -> Result<isize, MyErr> {
    ///     return Err(MyErr(10));
    /// }
    ///
    ///
    /// fn my_err_handler(_: MyErr) -> PencilResult {
    ///     Ok(PenString(String::from("My err occurred!")))
    /// }
    ///
    ///
    /// fn hello(_: Request) -> PencilResult {
    ///     match some_operation() {
    ///         Ok(_) => Ok(PenString(String::from("Hello!"))),
    ///         Err(e) => my_err_handler(e),
    ///     }
    /// }
    /// ```
    ///
    /// The problem with this is that you have to do it in all of your views, it brings
    /// a lot of redundance, so pencil provides another solution, currently I still
    /// haven't got any better idea on how to store user error handlers, this feature is
    /// really just experimental, if you have any good idea, please wake me up.  Here is
    /// one simple example:
    ///
    /// ```rust,no_run
    /// use std::convert;
    ///
    /// use pencil::Request;
    /// use pencil::{Pencil, PencilResult, PenString};
    /// use pencil::{PencilError, PenUserError, UserError};
    ///
    ///
    /// #[derive(Clone, Copy)]
    /// pub struct MyErr(isize);
    ///
    /// impl convert::From<MyErr> for PencilError {
    ///     fn from(err: MyErr) -> PencilError {
    ///         let user_error = UserError::new("MyErr");
    ///         return PenUserError(user_error);
    ///     }
    /// }
    ///
    ///
    /// fn my_err_handler(_: UserError) -> PencilResult {
    ///     Ok(PenString(String::from("My err occurred!")))
    /// }
    ///
    ///
    /// fn some_operation() -> Result<String, MyErr> {
    ///     return Err(MyErr(10));
    /// }
    ///
    ///
    /// fn hello(_: Request) -> PencilResult {
    ///     let rv = try!(some_operation());
    ///     return Ok(PenString(rv));
    /// }
    ///
    ///
    /// fn main() {
    ///     let mut app = Pencil::new("/web/demo");
    ///     // Use error description as key to store handlers, really ugly...
    ///     app.usererrorhandler("MyErr", my_err_handler);
    /// }
    /// ```
    pub fn usererrorhandler(&mut self, error_desc: &'static str, f: UserErrorHandler) {
        self.register_user_error_handler(error_desc, f);
    }

    /// Creates a test client for this application, you can use it
    /// like this:
    ///
    /// ```ignore
    /// let client = app.test_client();
    /// let response = client.get('/');
    /// assert!(response.code, 200);
    /// ```
    pub fn test_client(&self) -> PencilClient {
        PencilClient::new(self)
    }

    /// Called before the actual request dispatching, you can return value
    /// from here and stop the further request handling.
    fn preprocess_request(&self, request: &Request) -> Option<PencilResult> {
        let mut result: Option<PencilResult>;
        for &func in self.before_request_funcs.iter() {
            result = func(request);
            if result.is_some() {
                return result;
            }
        }
        return None;
    }

    /// Does the request dispatching.  Matches the URL and returns the return
    /// value of the view.
    fn dispatch_request(&self, request: Request) -> PencilResult {
        if request.routing_error.is_some() {
            return Err(PenHTTPError(request.routing_error.unwrap()));
        }
        match self.view_functions.get(&request.endpoint().unwrap()) {
            Some(&view_func) => {
                return view_func(request);
            },
            None => {
                return Err(PenHTTPError(NotFound));
            }
        }
    }

    /// Converts the return value from a view function to a real
    /// response object.
    fn make_response(&self, rv: PencilValue) -> Response {
        return helpers::make_response(rv);
    }

    /// Modify the response object before it's sent to the HTTP server.
    fn process_response(&self, response: &mut Response) {
        // TODO: reverse order
        for &func in self.after_request_funcs.iter() {
            func(response);
        }
    }

    /// Called after the actual request dispatching.
    fn do_teardown_request(&self, e: Option<&PencilError>) {
        // TODO: reverse order
        for &func in self.teardown_request_funcs.iter() {
            func(e);
        }
    }

    /// This method is called whenever an error occurs that should be handled.
    fn handle_all_error(&self, e: PencilError) -> PencilResult {
        match e {
            PenHTTPError(e) => self.handle_http_error(e),
            PenUserError(e) => self.handle_user_error(e),
        }
    }

    /// Handles an User error.
    fn handle_user_error(&self, e: UserError) -> PencilResult {
        match self.user_error_handlers.get(e.description()) {
            Some(&handler) => handler(e),
            None => Err(PenUserError(e)),
        }
    }

    /// Handles an HTTP error.
    fn handle_http_error(&self, e: HTTPError) -> PencilResult {
        match self.http_error_handlers.get(&e.code()) {
            Some(&handler) => handler(e),
            None => Ok(PenResponse(e.to_response())),
        }
    }

    /// Default error handing that kicks in when an error occurs that is not
    /// handled.
    fn handle_error(&self, e: &PencilError) -> PencilValue {
        self.log_error(e);
        let internal_server_error = InternalServerError;
        match self.http_error_handlers.get(&500) {
            Some(&handler) => {
                match handler(internal_server_error) {
                    Ok(value) => value,
                    Err(_) => {
                        let e = InternalServerError;
                        PenResponse(e.to_response())
                    }
                }
            },
            None => {
                let e = InternalServerError;
                PenResponse(e.to_response())
            }
        }
    }

    /// Logs an error.
    fn log_error(&self, e: &PencilError) {
        error!("Error: {}", e.description());
    }

    /// Dispatches the request and performs request pre and postprocessing
    /// as well as HTTP error handling.
    fn full_dispatch_request(&self, request: Request) -> Result<Response, PencilError> {
        let result = match self.preprocess_request(&request) {
            Some(result) => result,
            None => self.dispatch_request(request),
        };
        let rv = match result {
            Ok(value) => Ok(value),
            Err(e) => self.handle_all_error(e),
        };
        match rv {
            Ok(value) => {
                let mut response = self.make_response(value);
                self.process_response(&mut response);
                Ok(response)
            },
            Err(e) => Err(e),
        }
    }

    /// The actual application handler.
    pub fn handle_request(&self, mut request: Request) -> Response {
        request.match_request();
        match self.full_dispatch_request(request) {
            Ok(response) => {
                self.do_teardown_request(None);
                return response;
            },
            Err(e) => {
                let response = self.make_response(self.handle_error(&e));
                self.do_teardown_request(Some(&e));
                return response;
            }
        };
    }

    /// Runs the application on a local development server.
    pub fn run(self) {
        run_server(self);
    }
}

impl hyper::server::Handler for Pencil {
    fn handle(&self, req: HTTPRequest, res: HTTPResponse) {
        let request = Request::new(self, req);
        let request_method = request.method();
        let response = self.handle_request(request);
        response.write(request_method, res);
    }
}

impl PathBound for Pencil {
    fn open_resource(&self, resource: &str) -> File {
        let mut pathbuf = PathBuf::from(&self.root_path);
        pathbuf.push(resource);
        return File::open(&pathbuf.as_path()).unwrap();
    }
}
<commit_msg>Added template_folder attribute<commit_after>// This module implements the central application object.

use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use std::path::PathBuf;

use hyper;
use hyper::server::Request as HTTPRequest;
use hyper::server::Response as HTTPResponse;

use types::{
    PencilValue,
        PenResponse,

    PencilError,
        PenHTTPError,
        PenUserError,

    UserError,
    PencilResult,
    ViewFunc,
    HTTPErrorHandler,
    UserErrorHandler,
    BeforeRequestFunc,
    AfterRequestFunc,
    TeardownRequestFunc,
};
use wrappers::{
    Request,
    Response,
};
use helpers::{PathBound, send_static_file};
use helpers;
use config;
use logging;
use serving::run_server;
use routing::{Map, Rule};
use testing::PencilClient;
use errors::{HTTPError, NotFound, InternalServerError};

/// The pencil type.  It acts as the central application object.  Once it is created it
/// will act as a central registry for the view functions, the URL rules and much more.
pub struct Pencil {
    /// The path where your application locates.
    pub root_path: String,
    /// The folder with static files that should be served at `static_url_path`.
    /// Defaults to the `"static"` folder in the root path of the application.
    pub static_folder: String,
    /// The url path for the static files on the web, defaults to be `"/static"`.
    pub static_url_path: String,
    /// The folder that contains the templates that should be used for the application.
    /// Defaults to `''templates''` folder in the root path of the application.
    pub template_folder: String,
    pub config: config::Config,
    pub url_map: Map,
    /// A dictionary of all view functions registered.
    pub view_functions: HashMap<String, ViewFunc>,
    pub before_request_funcs: Vec<BeforeRequestFunc>,
    pub after_request_funcs: Vec<AfterRequestFunc>,
    pub teardown_request_funcs: Vec<TeardownRequestFunc>,
    pub http_error_handlers: HashMap<isize, HTTPErrorHandler>,
    pub user_error_handlers: HashMap<&'static str, UserErrorHandler>,
}

impl Pencil {
    /// Create a new pencil object.  It is passed the root path of your application.
    /// The root path is used to resolve resources from inside it, for more information
    /// about resource loading, see method `open_resource`.
    ///
    /// Usually you create a pencil object in your main function like this:
    ///
    /// ```rust,no_run
    /// use pencil::Pencil;
    ///
    /// fn main() {
    ///     let mut app = Pencil::new("/web/myapp");
    /// }
    /// ```
    pub fn new(root_path: &str) -> Pencil {
        Pencil {
            root_path: root_path.to_string(),
            static_folder: String::from("static"),
            static_url_path: String::from("/static"),
            template_folder: String::from("templates"),
            config: config::Config::new(),
            url_map: Map::new(),
            view_functions: HashMap::new(),
            before_request_funcs: vec![],
            after_request_funcs: vec![],
            teardown_request_funcs: vec![],
            http_error_handlers: HashMap::new(),
            user_error_handlers: HashMap::new(),
        }
    }

    /// Set global log level based on the application's debug flag.
    pub fn set_log_level(&self) {
        logging::set_log_level(self);
    }

    /// A shortcut that is used to register a view function for a given
    /// URL rule.
    pub fn route(&mut self, rule: &str, methods: &[&str], endpoint: &str, view_func: ViewFunc) {
        self.add_url_rule(rule, methods, endpoint, view_func);
    }

    /// Connects a URL rule.
    fn add_url_rule(&mut self, rule: &str, methods: &[&str], endpoint: &str, view_func: ViewFunc) {
        let url_rule = Rule::new(rule, methods, endpoint);
        self.url_map.add(url_rule);
        self.view_functions.insert(endpoint.to_string(), view_func);
    }

    /// Enables static file handling.
    pub fn enable_static_file_handle(&mut self) {
        let mut rule = self.static_url_path.clone();
        rule = rule + "/([^/].*?)";
        self.add_url_rule(&rule, &["GET"], "static", send_static_file);
    }

    /// Registers a function to run before each request.
    pub fn before_request(&mut self, f: BeforeRequestFunc) {
        self.before_request_funcs.push(f);
    }

    /// Registers a function to run after each request.  Your function
    /// must take a response object and modify it.
    pub fn after_request(&mut self, f: AfterRequestFunc) {
        self.after_request_funcs.push(f);
    }

    /// Registers a function to run at the end of each request,
    /// regardless of whether there was an error or not.
    pub fn teardown_request(&mut self, f: TeardownRequestFunc) {
        self.teardown_request_funcs.push(f);
    }

    /// Registers a function as one http error handler.
    fn register_http_error_handler(&mut self, status_code: isize, f: HTTPErrorHandler) {
        self.http_error_handlers.insert(status_code, f);
    }

    /// Registers a function as one user error handler.
    fn register_user_error_handler(&mut self, error_desc: &'static str, f: UserErrorHandler) {
        self.user_error_handlers.insert(error_desc, f);
    }

    /// Registers a function as one http error handler.  Example:
    ///
    /// ```rust,no_run
    /// use pencil::{Pencil, PencilResult, Response, PenResponse};
    /// use pencil::HTTPError;
    ///
    ///
    /// fn page_not_found(error: HTTPError) -> PencilResult {
    ///     let mut response = Response::new(String::from("The page does not exist"));
    ///     response.status_code = 404;
    ///     return Ok(PenResponse(response));
    /// }
    ///
    ///
    /// fn main() {
    ///     let mut app = Pencil::new("/web/demo");
    ///     app.httperrorhandler(404, page_not_found);
    /// }
    /// ```
    pub fn httperrorhandler(&mut self, status_code: isize, f: HTTPErrorHandler) {
        self.register_http_error_handler(status_code, f);
    }

    /// Registers a function as one user error handler.  There are two ways to handle
    /// user errors currently, you can do it in your own view like this:
    ///
    /// ```rust,no_run
    /// use pencil::Request;
    /// use pencil::{PencilResult, PenString};
    ///
    ///
    /// #[derive(Clone, Copy)]
    /// struct MyErr(isize);
    ///
    ///
    /// fn some_operation() -> Result<isize, MyErr> {
    ///     return Err(MyErr(10));
    /// }
    ///
    ///
    /// fn my_err_handler(_: MyErr) -> PencilResult {
    ///     Ok(PenString(String::from("My err occurred!")))
    /// }
    ///
    ///
    /// fn hello(_: Request) -> PencilResult {
    ///     match some_operation() {
    ///         Ok(_) => Ok(PenString(String::from("Hello!"))),
    ///         Err(e) => my_err_handler(e),
    ///     }
    /// }
    /// ```
    ///
    /// The problem with this is that you have to do it in all of your views, it brings
    /// a lot of redundance, so pencil provides another solution, currently I still
    /// haven't got any better idea on how to store user error handlers, this feature is
    /// really just experimental, if you have any good idea, please wake me up.  Here is
    /// one simple example:
    ///
    /// ```rust,no_run
    /// use std::convert;
    ///
    /// use pencil::Request;
    /// use pencil::{Pencil, PencilResult, PenString};
    /// use pencil::{PencilError, PenUserError, UserError};
    ///
    ///
    /// #[derive(Clone, Copy)]
    /// pub struct MyErr(isize);
    ///
    /// impl convert::From<MyErr> for PencilError {
    ///     fn from(err: MyErr) -> PencilError {
    ///         let user_error = UserError::new("MyErr");
    ///         return PenUserError(user_error);
    ///     }
    /// }
    ///
    ///
    /// fn my_err_handler(_: UserError) -> PencilResult {
    ///     Ok(PenString(String::from("My err occurred!")))
    /// }
    ///
    ///
    /// fn some_operation() -> Result<String, MyErr> {
    ///     return Err(MyErr(10));
    /// }
    ///
    ///
    /// fn hello(_: Request) -> PencilResult {
    ///     let rv = try!(some_operation());
    ///     return Ok(PenString(rv));
    /// }
    ///
    ///
    /// fn main() {
    ///     let mut app = Pencil::new("/web/demo");
    ///     // Use error description as key to store handlers, really ugly...
    ///     app.usererrorhandler("MyErr", my_err_handler);
    /// }
    /// ```
    pub fn usererrorhandler(&mut self, error_desc: &'static str, f: UserErrorHandler) {
        self.register_user_error_handler(error_desc, f);
    }

    /// Creates a test client for this application, you can use it
    /// like this:
    ///
    /// ```ignore
    /// let client = app.test_client();
    /// let response = client.get('/');
    /// assert!(response.code, 200);
    /// ```
    pub fn test_client(&self) -> PencilClient {
        PencilClient::new(self)
    }

    /// Called before the actual request dispatching, you can return value
    /// from here and stop the further request handling.
    fn preprocess_request(&self, request: &Request) -> Option<PencilResult> {
        let mut result: Option<PencilResult>;
        for &func in self.before_request_funcs.iter() {
            result = func(request);
            if result.is_some() {
                return result;
            }
        }
        return None;
    }

    /// Does the request dispatching.  Matches the URL and returns the return
    /// value of the view.
    fn dispatch_request(&self, request: Request) -> PencilResult {
        if request.routing_error.is_some() {
            return Err(PenHTTPError(request.routing_error.unwrap()));
        }
        match self.view_functions.get(&request.endpoint().unwrap()) {
            Some(&view_func) => {
                return view_func(request);
            },
            None => {
                return Err(PenHTTPError(NotFound));
            }
        }
    }

    /// Converts the return value from a view function to a real
    /// response object.
    fn make_response(&self, rv: PencilValue) -> Response {
        return helpers::make_response(rv);
    }

    /// Modify the response object before it's sent to the HTTP server.
    fn process_response(&self, response: &mut Response) {
        // TODO: reverse order
        for &func in self.after_request_funcs.iter() {
            func(response);
        }
    }

    /// Called after the actual request dispatching.
    fn do_teardown_request(&self, e: Option<&PencilError>) {
        // TODO: reverse order
        for &func in self.teardown_request_funcs.iter() {
            func(e);
        }
    }

    /// This method is called whenever an error occurs that should be handled.
    fn handle_all_error(&self, e: PencilError) -> PencilResult {
        match e {
            PenHTTPError(e) => self.handle_http_error(e),
            PenUserError(e) => self.handle_user_error(e),
        }
    }

    /// Handles an User error.
    fn handle_user_error(&self, e: UserError) -> PencilResult {
        match self.user_error_handlers.get(e.description()) {
            Some(&handler) => handler(e),
            None => Err(PenUserError(e)),
        }
    }

    /// Handles an HTTP error.
    fn handle_http_error(&self, e: HTTPError) -> PencilResult {
        match self.http_error_handlers.get(&e.code()) {
            Some(&handler) => handler(e),
            None => Ok(PenResponse(e.to_response())),
        }
    }

    /// Default error handing that kicks in when an error occurs that is not
    /// handled.
    fn handle_error(&self, e: &PencilError) -> PencilValue {
        self.log_error(e);
        let internal_server_error = InternalServerError;
        match self.http_error_handlers.get(&500) {
            Some(&handler) => {
                match handler(internal_server_error) {
                    Ok(value) => value,
                    Err(_) => {
                        let e = InternalServerError;
                        PenResponse(e.to_response())
                    }
                }
            },
            None => {
                let e = InternalServerError;
                PenResponse(e.to_response())
            }
        }
    }

    /// Logs an error.
    fn log_error(&self, e: &PencilError) {
        error!("Error: {}", e.description());
    }

    /// Dispatches the request and performs request pre and postprocessing
    /// as well as HTTP error handling.
    fn full_dispatch_request(&self, request: Request) -> Result<Response, PencilError> {
        let result = match self.preprocess_request(&request) {
            Some(result) => result,
            None => self.dispatch_request(request),
        };
        let rv = match result {
            Ok(value) => Ok(value),
            Err(e) => self.handle_all_error(e),
        };
        match rv {
            Ok(value) => {
                let mut response = self.make_response(value);
                self.process_response(&mut response);
                Ok(response)
            },
            Err(e) => Err(e),
        }
    }

    /// The actual application handler.
    pub fn handle_request(&self, mut request: Request) -> Response {
        request.match_request();
        match self.full_dispatch_request(request) {
            Ok(response) => {
                self.do_teardown_request(None);
                return response;
            },
            Err(e) => {
                let response = self.make_response(self.handle_error(&e));
                self.do_teardown_request(Some(&e));
                return response;
            }
        };
    }

    /// Runs the application on a local development server.
    pub fn run(self) {
        run_server(self);
    }
}

impl hyper::server::Handler for Pencil {
    fn handle(&self, req: HTTPRequest, res: HTTPResponse) {
        let request = Request::new(self, req);
        let request_method = request.method();
        let response = self.handle_request(request);
        response.write(request_method, res);
    }
}

impl PathBound for Pencil {
    fn open_resource(&self, resource: &str) -> File {
        let mut pathbuf = PathBuf::from(&self.root_path);
        pathbuf.push(resource);
        return File::open(&pathbuf.as_path()).unwrap();
    }
}
<|endoftext|>


<commit_before>

/*

*/

use machine;

#[derive(Debug)]
pub struct Grammar {
    rules : Vec<Pattern>,
    main : u32
}

#[derive(Debug)]
pub enum Pattern {
    CharClass(Vec<(u8, Option<u8>)>),
    CharSequence(Vec<u8>),
    CharAny,
    Variable(i32),
    Choice(Box<Pattern>, Box<Pattern>),
    ZeroOrMore(Box<Pattern>),
    OneOrMore(Box<Pattern>),
    Sequence(Vec<Box<Pattern>>),
    Optional(Box<Pattern>),
    Lookahead(bool, Box<Pattern>)
}

impl Grammar {
    pub fn compile(&self) -> Vec<machine::Instruction> {
        let mut rules = Vec::new();
        let mut lookup = vec![];

        for p in &self.rules {
            rules.push(Grammar::compile_pattern(p));
        }

        let mut result = vec![
            machine::Instruction::Call(self.main as isize),
            machine::Instruction::Stop
        ];

        let mut k = 2;
        for mut rule in rules {
            lookup.push(k);
            k += 3 + rule.len();
            result.push(machine::Instruction::PushPos);
            result.append(&mut rule);
            result.push(machine::Instruction::SavePos);
            result.push(machine::Instruction::Return);
        }

        for i in 0..result.len() {
            if let machine::Instruction::Call(r) = result[i] {
                let dist = lookup[r as usize] - i;
                result[i] = machine::Instruction::Call(dist as isize);
            }
        }
        result
    }

    pub fn compile_pattern(p : &Pattern) -> Vec<machine::Instruction> {
        match p {
            &Pattern::CharClass(ref data) => Grammar::compile_char_class(data),
            &Pattern::CharSequence(ref data) => Grammar::compile_char_sequence(data),
            &Pattern::CharAny => Grammar::compile_char_any(),
            &Pattern::Variable(id) => Grammar::compile_variable(id),
            &Pattern::Choice(ref le, ref ri) => Grammar::compile_choice(le, ri),
            &Pattern::ZeroOrMore(ref data) => Grammar::compile_zero_or_more(data),
            &Pattern::OneOrMore(ref data) => Grammar::compile_one_or_more(data),
            &Pattern::Sequence(ref data) => Grammar::compile_sequence(data),
            &Pattern::Optional(ref data) => Grammar::compile_optional(data),
            &Pattern::Lookahead(flag, ref data) => Grammar::compile_lookahead(flag, data)
        }
    }

    fn compile_char_class(data : &Vec<(u8, Option<u8>)>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        let mut jump = data.len();
        for range in data.iter().take(data.len() - 1) {
            let left = (*range).0;
            let right = (*range).1.unwrap_or(left);
            result.push(machine::Instruction::CharRangeLink(left, right, jump as isize));
            jump -= 1;
        }

        if let Some(last) = data.iter().last() {
            let left = (*last).0;
            let right = (*last).1.unwrap_or(left);
            result.push(machine::Instruction::CharRange(left, right));
        }
        result
    }

    fn compile_char_sequence(data : &Vec<u8>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        for c in data {
            result.push(machine::Instruction::Char(*c));
        }
        result
    }

    fn compile_char_any() -> Vec<machine::Instruction> {
        vec![machine::Instruction::Any]
    }

    fn compile_variable(id : i32) -> Vec<machine::Instruction> {
        vec![machine::Instruction::Call(id as isize)]
    }

    fn compile_choice(left : &Box<Pattern>, right : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut inner_left = Grammar::compile_pattern(left);
        let mut inner_right = Grammar::compile_pattern(right);
        let mut result = vec![];
        result.push(machine::Instruction::Choice(inner_left.len() as isize + 2));
        result.append(&mut inner_left);
        result.push(machine::Instruction::Commit(inner_right.len() as isize + 1));
        result.append(&mut inner_right);
        result
    }

    fn compile_zero_or_more(data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut inner = Grammar::compile_pattern(data);
        let instr_count = inner.len() as isize;
        let mut result = vec![];
        result.push(machine::Instruction::Choice(instr_count + 2));
        result.append(&mut inner);
        result.push(machine::Instruction::PartialCommit(-instr_count));
        result
    }

    fn compile_one_or_more(data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut inner = Grammar::compile_pattern(data);
        let mut inner_clone = inner.clone();
        let instr_count = inner.len() as isize;
        let mut result = vec![];
        result.append(&mut inner_clone);
        result.push(machine::Instruction::Choice(instr_count + 2));
        result.append(&mut inner);
        result.push(machine::Instruction::PartialCommit(-instr_count));
        result
    }

    fn compile_sequence(data : &Vec<Box<Pattern>>) -> Vec<machine::Instruction> {
        let mut result = vec![];

        for p in data {
            let mut inner = Grammar::compile_pattern(p);
            result.append(&mut inner);
        }
        result
    }

    fn compile_optional(data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        let mut inner = Grammar::compile_pattern(data);

        result.push(machine::Instruction::Choice(inner.len() as isize + 2));
        result.append(&mut inner);
        result.push(machine::Instruction::Commit(1));
        result
    }

    fn compile_lookahead(success : bool, data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        let mut inner = Grammar::compile_pattern(data);
        let mut instr_count = inner.len() as isize;
        if success {
            result.push(machine::Instruction::Choice(instr_count + 4));
            result.push(machine::Instruction::Choice(instr_count + 2));
            result.append(&mut inner);
            result.push(machine::Instruction::FailTwice);
            result.push(machine::Instruction::FailTwice);
        } else {
            result.push(machine::Instruction::Choice(instr_count + 2));
            result.append(&mut inner);
            result.push(machine::Instruction::FailTwice);
        }
        result
    }
}

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

    fn execute_test(grammar : &Grammar, subjects : &Vec<&str>, expected : &Vec<bool>) {
        let program = grammar.compile();
        let mut machine = machine::Machine::new(program);
        assert!(subjects.len() == expected.len());
        for i in 0..expected.len() {
            let result = machine.execute(subjects[i].to_string().into_bytes());
            let fail = result.is_err();
            println!("{:?}", machine.program);
            println!("{}", subjects[i]);
            assert!(!fail == expected[i]);
        }
    }

    #[test]
    fn simple_char_grammar_rules() {
        /*
            main { .;char_class;char_seq }
            char_class { ['a'..'z''A'..'A'] }
            char_seq { 'a';'b';'c' }
        */
        let char_class = Pattern::CharClass(vec![
            ('a' as u8, Some('z' as u8)),
            ('A' as u8, Some('A' as u8))
        ]);
        let char_seq = Pattern::CharSequence(vec![
            'a' as u8,
            'b' as u8,
            'c' as u8
        ]);
        let main = Pattern::Sequence(vec![
            Box::new(Pattern::Variable(1)),
            Box::new(Pattern::Variable(2)),
            Box::new(Pattern::Variable(3)),
        ]);

        let grammar = Grammar {
            rules: vec![
                main,
                Pattern::CharAny,
                char_class,
                char_seq
            ],
            main: 0
        };
        let subjects = vec!["azabc", "Bkabc", "AAabc", "aqd", "xyz"];
        let expected = vec![true, true, true, false, false];
        execute_test(&grammar, &subjects, &expected);
    }

    #[test]
    fn simple_lookahead_grammar() {
        /*
            main { !a;. / &a;. }
        */
        let ambersand = Pattern::Lookahead(true,
            Box::new(Pattern::CharSequence(vec!['a' as u8])));
        let not = Pattern::Lookahead(false,
            Box::new(Pattern::CharSequence(vec!['a' as u8])));
        let main = Pattern::Choice(
            Box::new(Pattern::Sequence(vec![
                Box::new(not),
                Box::new(Pattern::CharAny)
            ])),
            Box::new(Pattern::Sequence(vec![
                Box::new(ambersand),
                Box::new(Pattern::CharAny)
            ])),
        );

        let grammar = Grammar {
            rules: vec![
                main
            ],
            main: 0
        };
        let subjects = vec!["b", "a", "z", "aa", ""];
        let expected = vec![true, true, true, false, false];
        execute_test(&grammar, &subjects, &expected);
    }

}<commit_msg>Add unit tests<commit_after>use machine;

#[derive(Debug)]
pub struct Grammar {
    rules : Vec<Pattern>,
    main : u32
}

#[derive(Debug)]
pub enum Pattern {
    CharClass(Vec<(u8, Option<u8>)>),
    CharSequence(Vec<u8>),
    CharAny,
    Variable(i32),
    Choice(Box<Pattern>, Box<Pattern>),
    ZeroOrMore(Box<Pattern>),
    OneOrMore(Box<Pattern>),
    Sequence(Vec<Box<Pattern>>),
    Optional(Box<Pattern>),
    Lookahead(bool, Box<Pattern>)
}

impl Grammar {
    pub fn compile(&self) -> Vec<machine::Instruction> {
        let mut rules = Vec::new();
        let mut lookup = vec![];

        for p in &self.rules {
            rules.push(Grammar::compile_pattern(p));
        }

        let mut result = vec![
            machine::Instruction::Call(self.main as isize),
            machine::Instruction::Stop
        ];

        let mut k = 2;
        for mut rule in rules {
            lookup.push(k);
            k += 3 + rule.len();
            result.push(machine::Instruction::PushPos);
            result.append(&mut rule);
            result.push(machine::Instruction::SavePos);
            result.push(machine::Instruction::Return);
        }

        for i in 0..result.len() {
            if let machine::Instruction::Call(r) = result[i] {
                let dist = lookup[r as usize] - i;
                result[i] = machine::Instruction::Call(dist as isize);
            }
        }
        result
    }

    pub fn compile_pattern(p : &Pattern) -> Vec<machine::Instruction> {
        match p {
            &Pattern::CharClass(ref data) => Grammar::compile_char_class(data),
            &Pattern::CharSequence(ref data) => Grammar::compile_char_sequence(data),
            &Pattern::CharAny => Grammar::compile_char_any(),
            &Pattern::Variable(id) => Grammar::compile_variable(id),
            &Pattern::Choice(ref le, ref ri) => Grammar::compile_choice(le, ri),
            &Pattern::ZeroOrMore(ref data) => Grammar::compile_zero_or_more(data),
            &Pattern::OneOrMore(ref data) => Grammar::compile_one_or_more(data),
            &Pattern::Sequence(ref data) => Grammar::compile_sequence(data),
            &Pattern::Optional(ref data) => Grammar::compile_optional(data),
            &Pattern::Lookahead(flag, ref data) => Grammar::compile_lookahead(flag, data)
        }
    }

    fn compile_char_class(data : &Vec<(u8, Option<u8>)>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        let mut jump = data.len();
        for range in data.iter().take(data.len() - 1) {
            let left = (*range).0;
            let right = (*range).1.unwrap_or(left);
            result.push(machine::Instruction::CharRangeLink(left, right, jump as isize));
            jump -= 1;
        }

        if let Some(last) = data.iter().last() {
            let left = (*last).0;
            let right = (*last).1.unwrap_or(left);
            result.push(machine::Instruction::CharRange(left, right));
        }
        result
    }

    fn compile_char_sequence(data : &Vec<u8>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        for c in data {
            result.push(machine::Instruction::Char(*c));
        }
        result
    }

    fn compile_char_any() -> Vec<machine::Instruction> {
        vec![machine::Instruction::Any]
    }

    fn compile_variable(id : i32) -> Vec<machine::Instruction> {
        vec![machine::Instruction::Call(id as isize)]
    }

    fn compile_choice(left : &Box<Pattern>, right : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut inner_left = Grammar::compile_pattern(left);
        let mut inner_right = Grammar::compile_pattern(right);
        let mut result = vec![];
        result.push(machine::Instruction::Choice(inner_left.len() as isize + 2));
        result.append(&mut inner_left);
        result.push(machine::Instruction::Commit(inner_right.len() as isize + 1));
        result.append(&mut inner_right);
        result
    }

    fn compile_zero_or_more(data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut inner = Grammar::compile_pattern(data);
        let instr_count = inner.len() as isize;
        let mut result = vec![];
        result.push(machine::Instruction::Choice(instr_count + 2));
        result.append(&mut inner);
        result.push(machine::Instruction::PartialCommit(-instr_count));
        result
    }

    fn compile_one_or_more(data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut inner = Grammar::compile_pattern(data);
        let mut inner_clone = inner.clone();
        let instr_count = inner.len() as isize;
        let mut result = vec![];
        result.append(&mut inner_clone);
        result.push(machine::Instruction::Choice(instr_count + 2));
        result.append(&mut inner);
        result.push(machine::Instruction::PartialCommit(-instr_count));
        result
    }

    fn compile_sequence(data : &Vec<Box<Pattern>>) -> Vec<machine::Instruction> {
        let mut result = vec![];

        for p in data {
            let mut inner = Grammar::compile_pattern(p);
            result.append(&mut inner);
        }
        result
    }

    fn compile_optional(data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        let mut inner = Grammar::compile_pattern(data);

        result.push(machine::Instruction::Choice(inner.len() as isize + 2));
        result.append(&mut inner);
        result.push(machine::Instruction::Commit(1));
        result
    }

    fn compile_lookahead(success : bool, data : &Box<Pattern>) -> Vec<machine::Instruction> {
        let mut result = vec![];
        let mut inner = Grammar::compile_pattern(data);
        let mut instr_count = inner.len() as isize;
        if success {
            result.push(machine::Instruction::Choice(instr_count + 4));
            result.push(machine::Instruction::Choice(instr_count + 2));
            result.append(&mut inner);
            result.push(machine::Instruction::FailTwice);
            result.push(machine::Instruction::FailTwice);
        } else {
            result.push(machine::Instruction::Choice(instr_count + 2));
            result.append(&mut inner);
            result.push(machine::Instruction::FailTwice);
        }
        result
    }
}

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

    fn execute_test(grammar : &Grammar, subjects : &Vec<&str>, expected : &Vec<bool>) {
        let program = grammar.compile();
        let mut machine = machine::Machine::new(program);
        assert!(subjects.len() == expected.len());
        for i in 0..expected.len() {
            let result = machine.execute(subjects[i].to_string().into_bytes());
            let fail = result.is_err();
            println!("{:?}", machine.program);
            println!("{}", subjects[i]);
            assert!(!fail == expected[i]);
        }
    }

    #[test]
    fn simple_char_grammar_rules() {
        /*
            main { .;char_class;char_seq }
            char_class { ['a'..'z''A'..'A'] }
            char_seq { 'a';'b';'c' }
        */
        let char_class = Pattern::CharClass(vec![
            ('a' as u8, Some('z' as u8)),
            ('A' as u8, Some('A' as u8))
        ]);
        let char_seq = Pattern::CharSequence(vec![
            'a' as u8,
            'b' as u8,
            'c' as u8
        ]);
        let main = Pattern::Sequence(vec![
            Box::new(Pattern::Variable(1)),
            Box::new(Pattern::Variable(2)),
            Box::new(Pattern::Variable(3)),
        ]);

        let grammar = Grammar {
            rules: vec![
                main,
                Pattern::CharAny,
                char_class,
                char_seq
            ],
            main: 0
        };
        let subjects = vec!["azabc", "Bkabc", "AAabc", "aqd", "xyz"];
        let expected = vec![true, true, true, false, false];
        execute_test(&grammar, &subjects, &expected);
    }

    #[test]
    fn simple_lookahead_grammar() { // main { !a;. / &a;. }
        let ambersand = Pattern::Lookahead(true,
            Box::new(Pattern::CharSequence(vec!['a' as u8])));
        let not = Pattern::Lookahead(false,
            Box::new(Pattern::CharSequence(vec!['a' as u8])));
        let main = Pattern::Choice(
            Box::new(Pattern::Sequence(vec![
                Box::new(not),
                Box::new(Pattern::CharAny)
            ])),
            Box::new(Pattern::Sequence(vec![
                Box::new(ambersand),
                Box::new(Pattern::CharAny)
            ])),
        );

        let grammar = Grammar {
            rules: vec![
                main
            ],
            main: 0
        };
        let subjects = vec!["b", "a", "z", "aa", ""];
        let expected = vec![true, true, true, false, false];
        execute_test(&grammar, &subjects, &expected);
    }

    #[test]
    fn simple_iteration_grammar() { // main { a+ / b* }
        let main = Pattern::Choice(
            Box::new(Pattern::OneOrMore(
                Box::new(Pattern::CharSequence(vec!['a' as u8]))
            )),
            Box::new(Pattern::ZeroOrMore(
                Box::new(Pattern::CharSequence(vec!['b' as u8]))
            ))
        );

        let grammar = Grammar {
            rules: vec![
                main
            ],
            main: 0
        };
        let subjects = vec!["a", "aaaa", "", "b", "bbbbb", "c"];
        let expected = vec![true, true, true, true, true, false];
        execute_test(&grammar, &subjects, &expected);
    }

    #[test]
    fn simple_optional_subparser() {
        /*
            main { a? 'b' }
            a { a+ }
        */
        let a = Pattern::OneOrMore(
            Box::new(Pattern::CharSequence(vec!['a' as u8])));
        let main = Pattern::Sequence(vec![
            Box::new(Pattern::Optional(Box::new(Pattern::Variable(1)))),
            Box::new(Pattern::CharSequence(vec!['b' as u8]))
        ]);

        let grammar = Grammar {
            rules: vec![
                main,
                a
            ],
            main: 0
        };
        let subjects = vec!["b", "ab", "aaaaab", "", "bb"];
        let expected = vec![true, true, true, false, false];
        execute_test(&grammar, &subjects, &expected);
    }
}<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

use cabot;

use std::collections::HashMap;
use std::iter::FromIterator;
use std::net::{AddrParseError, SocketAddr};
use std::pin::Pin;

use async_std;
use async_std::fs::OpenOptions;
use async_std::io::{self, Write};
use async_std::prelude::*;
use async_std::task::Context;
use async_std::task::Poll;
use clap::{App, Arg};
use log::Level::Info;

use cabot::constants;
use cabot::http;
use cabot::request::RequestBuilder;
use cabot::results::CabotResult;

macro_rules! parse_int {
    ($name:expr, $typ:ty, $matches:ident) => {
        <$typ>::from_str_radix($matches.value_of($name).unwrap(), 10)
            .expect(format!("{} must be an integer", $name).as_str())
    };
}

pub async fn run() -> CabotResult<()> {
    let user_agent: String = constants::user_agent();

    let dns_lookup_timeout = format!("{}", constants::DNS_LOOKUP_TIMEOUT);
    let connect_timeout = format!("{}", constants::CONNECT_TIMEOUT);
    let request_timeout = format!("{}", constants::REQUEST_TIMEOUT);
    let read_timeout = format!("{}", constants::READ_TIMEOUT);

    let number_of_redirect = format!("{}", constants::NUMBER_OF_REDIRECT);

    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(constants::VERSION)
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .arg(
            Arg::with_name("URL")
                .index(1)
                .required(true)
                .help("URL to request"),
        )
        .arg(
            Arg::with_name("REQUEST")
                .short("X")
                .long("request")
                .default_value("GET")
                .help("Specify request command to use"),
        )
        .arg(
            Arg::with_name("HEADER")
                .short("H")
                .long("header")
                .takes_value(true)
                .multiple(true)
                .help("Pass custom header to server"),
        )
        .arg(
            Arg::with_name("FILE")
                .short("o")
                .long("output")
                .takes_value(true)
                .help("Write to FILE instead of stdout"),
        )
        .arg(
            Arg::with_name("VERBOSE")
                .short("v")
                .long("verbose")
                .help("Make the operation more talkative"),
        )
        .arg(
            Arg::with_name("BODY")
                .short("d")
                .long("data")
                .takes_value(true)
                .help("Post Data (Using utf-8 encoding)"),
        )
        .arg(
            Arg::with_name("IPv4")
                .short("4")
                .long("ipv4")
                .help("Resolve host names to IPv4 addresses"),
        )
        .arg(
            Arg::with_name("IPv6")
                .short("6")
                .long("ipv6")
                .help("Resolve host names to IPv6 addresses"),
        )
        .arg(
            Arg::with_name("UA")
                .short("A")
                .long("user-agent")
                .default_value(user_agent.as_str())
                .help("The user-agent HTTP header to use"),
        )
        .arg(
            Arg::with_name("DNS_LOOKUP_TIMEOUT")
                .long("dns-timeout")
                .takes_value(true)
                .default_value(dns_lookup_timeout.as_str())
                .help("timeout for the dns lookup resolution in seconds"),
        )
        .arg(
            Arg::with_name("CONNECT_TIMEOUT")
                .long("connect-timeout")
                .takes_value(true)
                .default_value(connect_timeout.as_str())
                .help("timeout for the tcp connection"),
        )
        .arg(
            Arg::with_name("READ_TIMEOUT")
                .long("read-timeout")
                .takes_value(true)
                .default_value(read_timeout.as_str())
                .help("timeout for the tcp read in seconds"),
        )
        .arg(
            Arg::with_name("REQUEST_TIMEOUT")
                .long("max-time")
                .takes_value(true)
                .default_value(request_timeout.as_str())
                .help("timeout for the whole http request in seconds (0 means no timeout)"),
        )
        .arg(
            Arg::with_name("NUMBER_OF_REDIRECT")
                .long("max-redirs")
                .takes_value(true)
                .default_value(number_of_redirect.as_str())
                .help("max number of redirection before returning a response"),
        )
        .arg(
            Arg::with_name("RESOLVE")
                .long("resolve")
                .takes_value(true)
                .multiple(true)
                .help("<host:port:address> Resolve the host+port to this address"),
        )
        .get_matches();

    let url = matches.value_of("URL").unwrap();
    let http_method = matches.value_of("REQUEST").unwrap();
    let verbose = matches.is_present("VERBOSE");
    let body = matches.value_of("BODY");
    let ua = matches.value_of("UA").unwrap();

    let mut ipv4 = matches.is_present("IPv4");
    let mut ipv6 = matches.is_present("IPv6");

    if !ipv4 && !ipv6 {
        ipv4 = true;
        ipv6 = true;
    }

    let headers: Vec<&str> = match matches.values_of("HEADER") {
        Some(headers) => headers.collect(),
        None => Vec::new(),
    };

    let resolved: HashMap<String, SocketAddr> = match matches.values_of("RESOLVE") {
        Some(headers) => HashMap::from_iter(
            headers
                .map(|resolv| resolv.splitn(3, ':'))
                .map(|resolv| {
                    let count = resolv.clone().count();
                    if count != 3 {
                        let resolv: Vec<&str> = resolv.collect();
                        let _ =
                            eprintln!("Invalid format in resolve argument: {}", resolv.join(":"));
                        std::process::exit(1);
                    }
                    resolv
                })
                .map(|mut resolv| {
                    (
                        resolv.next().unwrap(),
                        resolv.next().unwrap(),
                        resolv.next().unwrap(),
                    )
                })
                .map(|(host, port, addr)| {
                    let parsed_port = port.parse::<usize>();
                    if parsed_port.is_err() {
                        let _ = eprintln!(
                            "Invalid port in resolve argument: {}:{}:{}",
                            host, port, addr
                        );
                        std::process::exit(1);
                    }
                    let sockaddr: Result<SocketAddr, AddrParseError> =
                        format!("{}:{}", addr, port).parse();
                    if sockaddr.is_err() {
                        let _ = eprintln!(
                            "Invalid address in resolve argument: {}:{}:{}",
                            host, port, addr
                        );
                        std::process::exit(1);
                    }
                    let sockaddr = sockaddr.unwrap();
                    (format!("{}:{}", host, port), sockaddr)
                }),
        ),
        None => HashMap::new(),
    };

    let dns_timeout = parse_int!("DNS_LOOKUP_TIMEOUT", u64, matches) * 1_000;
    let connect_timeout = parse_int!("CONNECT_TIMEOUT", u64, matches) * 1_000;
    let read_timeout = parse_int!("READ_TIMEOUT", u64, matches) * 1_000;
    let request_timeout = parse_int!("REQUEST_TIMEOUT", u64, matches) * 1_000;
    let number_of_redirect = parse_int!("NUMBER_OF_REDIRECT", u8, matches);

    let mut builder = RequestBuilder::new(url)
        .set_http_method(http_method)
        .set_user_agent(ua)
        .add_headers(&headers.as_slice());

    if body.is_some() {
        builder = builder.set_body_as_str(body.unwrap());
    }

    let request = builder.build()?;

    if let Some(path) = matches.value_of("FILE") {
        let mut f = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(path)
            .await
            .unwrap();
        http::http_query(
            &request,
            &mut CabotBinWrite::new(&mut f, verbose),
            &resolved,
            verbose,
            ipv4,
            ipv6,
            dns_timeout,
            connect_timeout,
            read_timeout,
            request_timeout,
            number_of_redirect,
        )
        .await?
    } else {
        http::http_query(
            &request,
            &mut CabotBinWrite::new(&mut io::stdout(), verbose),
            &resolved,
            verbose,
            ipv4,
            ipv6,
            dns_timeout,
            connect_timeout,
            read_timeout,
            request_timeout,
            number_of_redirect,
        )
        .await?
    };
    Ok(())
}

#[async_std::main]
async fn main() {
    #[cfg(feature = "pretty_log")]
    pretty_env_logger::init();
    debug!("Starting cabot");

    run()
        .await
        .map(|ok| {
            debug!("Command cabot ended succesfully");
            ok
        })
        .map_err(|err| {
            eprintln!("{}", err);
            std::process::exit(1);
        })
        .unwrap();
}

// Internal Of the Binary

struct CabotBinWrite<'a> {
    out: &'a mut (dyn Write + Unpin),
    header_read: bool,
    verbose: bool,
}

impl<'a> CabotBinWrite<'a> {
    pub fn new(out: &'a mut (dyn Write + Unpin), verbose: bool) -> Self {
        CabotBinWrite {
            out,
            verbose,
            header_read: false,
        }
    }
    fn display_headers(&self, buf: &[u8]) {
        let headers = String::from_utf8_lossy(buf);
        let split: Vec<&str> = constants::SPLIT_HEADER_RE.split(&headers).collect();
        if log_enabled!(Info) {
            for part in split {
                info!("< {}", part);
            }
        } else if self.verbose {
            for part in split {
                eprintln!("< {}", part);
            }
        }
    }
}

impl<'a> Write for CabotBinWrite<'a> {
    // may receive headers
    fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<io::Result<usize>> {
        let self_ = Pin::get_mut(self);
        if !self_.header_read {
            // the first time write is called, all headers are sent
            // in the buffer. there is no need to parse it again.
            if log_enabled!(Info) || self_.verbose {
                self_.display_headers(&buf);
            }
            self_.header_read = true;
            Poll::Ready(Ok(0))
        } else {
            let towrite = buf.len();
            let mut written = 0;
            loop {
                let res = Pin::new(&mut self_.out).poll_write(cx, &buf[written..towrite]);
                match res {
                    Poll::Ready(Ok(l)) => written += l,
                    _ => {}
                }
                if written >= towrite {
                    break;
                }
            }
            Poll::Ready(Ok(written))
        }
    }

    /// this function is called when the request is done
    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<io::Result<()>> {
        let self_ = Pin::get_mut(self);
        self_.out.flush();
        Poll::Ready(Ok(()))
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        let self_ = Pin::get_mut(self);
        Pin::new(&mut self_.out).poll_close(cx)
    }
}
<commit_msg>Cleanup to remove duplicate code<commit_after>#[macro_use]
extern crate log;

use cabot;

use std::collections::HashMap;
use std::iter::FromIterator;
use std::net::{AddrParseError, SocketAddr};
use std::pin::Pin;

use async_std;
use async_std::fs::{File, OpenOptions};
use async_std::io::{self, Stdout, Write};
use async_std::prelude::*;
use async_std::task::Context;
use async_std::task::Poll;
use clap::{App, Arg};
use log::Level::Info;

use cabot::constants;
use cabot::http;
use cabot::request::RequestBuilder;
use cabot::results::CabotResult;

macro_rules! parse_int {
    ($name:expr, $typ:ty, $matches:ident) => {
        <$typ>::from_str_radix($matches.value_of($name).unwrap(), 10)
            .expect(format!("{} must be an integer", $name).as_str())
    };
}

pub async fn run() -> CabotResult<()> {
    let user_agent: String = constants::user_agent();

    let dns_lookup_timeout = format!("{}", constants::DNS_LOOKUP_TIMEOUT);
    let connect_timeout = format!("{}", constants::CONNECT_TIMEOUT);
    let request_timeout = format!("{}", constants::REQUEST_TIMEOUT);
    let read_timeout = format!("{}", constants::READ_TIMEOUT);

    let number_of_redirect = format!("{}", constants::NUMBER_OF_REDIRECT);

    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(constants::VERSION)
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .arg(
            Arg::with_name("URL")
                .index(1)
                .required(true)
                .help("URL to request"),
        )
        .arg(
            Arg::with_name("REQUEST")
                .short("X")
                .long("request")
                .default_value("GET")
                .help("Specify request command to use"),
        )
        .arg(
            Arg::with_name("HEADER")
                .short("H")
                .long("header")
                .takes_value(true)
                .multiple(true)
                .help("Pass custom header to server"),
        )
        .arg(
            Arg::with_name("FILE")
                .short("o")
                .long("output")
                .takes_value(true)
                .help("Write to FILE instead of stdout"),
        )
        .arg(
            Arg::with_name("VERBOSE")
                .short("v")
                .long("verbose")
                .help("Make the operation more talkative"),
        )
        .arg(
            Arg::with_name("BODY")
                .short("d")
                .long("data")
                .takes_value(true)
                .help("Post Data (Using utf-8 encoding)"),
        )
        .arg(
            Arg::with_name("IPv4")
                .short("4")
                .long("ipv4")
                .help("Resolve host names to IPv4 addresses"),
        )
        .arg(
            Arg::with_name("IPv6")
                .short("6")
                .long("ipv6")
                .help("Resolve host names to IPv6 addresses"),
        )
        .arg(
            Arg::with_name("UA")
                .short("A")
                .long("user-agent")
                .default_value(user_agent.as_str())
                .help("The user-agent HTTP header to use"),
        )
        .arg(
            Arg::with_name("DNS_LOOKUP_TIMEOUT")
                .long("dns-timeout")
                .takes_value(true)
                .default_value(dns_lookup_timeout.as_str())
                .help("timeout for the dns lookup resolution in seconds"),
        )
        .arg(
            Arg::with_name("CONNECT_TIMEOUT")
                .long("connect-timeout")
                .takes_value(true)
                .default_value(connect_timeout.as_str())
                .help("timeout for the tcp connection"),
        )
        .arg(
            Arg::with_name("READ_TIMEOUT")
                .long("read-timeout")
                .takes_value(true)
                .default_value(read_timeout.as_str())
                .help("timeout for the tcp read in seconds"),
        )
        .arg(
            Arg::with_name("REQUEST_TIMEOUT")
                .long("max-time")
                .takes_value(true)
                .default_value(request_timeout.as_str())
                .help("timeout for the whole http request in seconds (0 means no timeout)"),
        )
        .arg(
            Arg::with_name("NUMBER_OF_REDIRECT")
                .long("max-redirs")
                .takes_value(true)
                .default_value(number_of_redirect.as_str())
                .help("max number of redirection before returning a response"),
        )
        .arg(
            Arg::with_name("RESOLVE")
                .long("resolve")
                .takes_value(true)
                .multiple(true)
                .help("<host:port:address> Resolve the host+port to this address"),
        )
        .get_matches();

    let url = matches.value_of("URL").unwrap();
    let http_method = matches.value_of("REQUEST").unwrap();
    let verbose = matches.is_present("VERBOSE");
    let body = matches.value_of("BODY");
    let ua = matches.value_of("UA").unwrap();

    let mut ipv4 = matches.is_present("IPv4");
    let mut ipv6 = matches.is_present("IPv6");

    if !ipv4 && !ipv6 {
        ipv4 = true;
        ipv6 = true;
    }

    let headers: Vec<&str> = match matches.values_of("HEADER") {
        Some(headers) => headers.collect(),
        None => Vec::new(),
    };

    let resolved: HashMap<String, SocketAddr> = match matches.values_of("RESOLVE") {
        Some(headers) => HashMap::from_iter(
            headers
                .map(|resolv| resolv.splitn(3, ':'))
                .map(|resolv| {
                    let count = resolv.clone().count();
                    if count != 3 {
                        let resolv: Vec<&str> = resolv.collect();
                        let _ =
                            eprintln!("Invalid format in resolve argument: {}", resolv.join(":"));
                        std::process::exit(1);
                    }
                    resolv
                })
                .map(|mut resolv| {
                    (
                        resolv.next().unwrap(),
                        resolv.next().unwrap(),
                        resolv.next().unwrap(),
                    )
                })
                .map(|(host, port, addr)| {
                    let parsed_port = port.parse::<usize>();
                    if parsed_port.is_err() {
                        let _ = eprintln!(
                            "Invalid port in resolve argument: {}:{}:{}",
                            host, port, addr
                        );
                        std::process::exit(1);
                    }
                    let sockaddr: Result<SocketAddr, AddrParseError> =
                        format!("{}:{}", addr, port).parse();
                    if sockaddr.is_err() {
                        let _ = eprintln!(
                            "Invalid address in resolve argument: {}:{}:{}",
                            host, port, addr
                        );
                        std::process::exit(1);
                    }
                    let sockaddr = sockaddr.unwrap();
                    (format!("{}:{}", host, port), sockaddr)
                }),
        ),
        None => HashMap::new(),
    };

    let dns_timeout = parse_int!("DNS_LOOKUP_TIMEOUT", u64, matches) * 1_000;
    let connect_timeout = parse_int!("CONNECT_TIMEOUT", u64, matches) * 1_000;
    let read_timeout = parse_int!("READ_TIMEOUT", u64, matches) * 1_000;
    let request_timeout = parse_int!("REQUEST_TIMEOUT", u64, matches) * 1_000;
    let number_of_redirect = parse_int!("NUMBER_OF_REDIRECT", u8, matches);

    let mut builder = RequestBuilder::new(url)
        .set_http_method(http_method)
        .set_user_agent(ua)
        .add_headers(&headers.as_slice());

    if body.is_some() {
        builder = builder.set_body_as_str(body.unwrap());
    }

    let request = builder.build()?;

    let mut file: Option<File>;
    let mut stdout: Option<Stdout>;

    let mut out = if let Some(path) = matches.value_of("FILE") {
        let f = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(path)
            .await
            .unwrap();
        file = Some(f);
        CabotBinWrite::new(file.as_mut().unwrap(), verbose)
    } else {
        stdout = Some(io::stdout());
        CabotBinWrite::new(stdout.as_mut().unwrap(), verbose)
    };

    http::http_query(
        &request,
        &mut out,
        &resolved,
        verbose,
        ipv4,
        ipv6,
        dns_timeout,
        connect_timeout,
        read_timeout,
        request_timeout,
        number_of_redirect,
    )
    .await?;
    Ok(())
}

#[async_std::main]
async fn main() {
    #[cfg(feature = "pretty_log")]
    pretty_env_logger::init();
    debug!("Starting cabot");

    run()
        .await
        .map(|ok| {
            debug!("Command cabot ended succesfully");
            ok
        })
        .map_err(|err| {
            eprintln!("{}", err);
            std::process::exit(1);
        })
        .unwrap();
}

// Internal Of the Binary

struct CabotBinWrite<'a> {
    out: &'a mut (dyn Write + Unpin),
    header_read: bool,
    verbose: bool,
}

impl<'a> CabotBinWrite<'a> {
    pub fn new(out: &'a mut (dyn Write + Unpin), verbose: bool) -> Self {
        CabotBinWrite {
            out,
            verbose,
            header_read: false,
        }
    }
    fn display_headers(&self, buf: &[u8]) {
        let headers = String::from_utf8_lossy(buf);
        let split: Vec<&str> = constants::SPLIT_HEADER_RE.split(&headers).collect();
        if log_enabled!(Info) {
            for part in split {
                info!("< {}", part);
            }
        } else if self.verbose {
            for part in split {
                eprintln!("< {}", part);
            }
        }
    }
}

impl<'a> Write for CabotBinWrite<'a> {
    // may receive headers
    fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<io::Result<usize>> {
        let self_ = Pin::get_mut(self);
        if !self_.header_read {
            // the first time write is called, all headers are sent
            // in the buffer. there is no need to parse it again.
            if log_enabled!(Info) || self_.verbose {
                self_.display_headers(&buf);
            }
            self_.header_read = true;
            Poll::Ready(Ok(0))
        } else {
            let towrite = buf.len();
            let mut written = 0;
            loop {
                let res = Pin::new(&mut self_.out).poll_write(cx, &buf[written..towrite]);
                match res {
                    Poll::Ready(Ok(l)) => written += l,
                    _ => {}
                }
                if written >= towrite {
                    break;
                }
            }
            Poll::Ready(Ok(written))
        }
    }

    /// this function is called when the request is done
    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<io::Result<()>> {
        let self_ = Pin::get_mut(self);
        self_.out.flush();
        Poll::Ready(Ok(()))
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        let self_ = Pin::get_mut(self);
        Pin::new(&mut self_.out).poll_close(cx)
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 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.

/*! The Clone trait for types that cannot be "implicitly copied"

In Rust, some simple types are "implicitly copyable" and when you
assign them or pass them as arguments, the receiver will get a copy,
leaving the original value in place. These types do not require
allocation to copy and do not have finalizers (i.e. they do not
contain owned boxes or implement `Drop`), so the compiler considers
them cheap and safe to copy and automatically implements the `Copy`
trait for them. For other types copies must be made explicitly,
by convention implementing the `Clone` trait and calling the
`clone` method.

*/

use core::kinds::Const;

pub trait Clone {
    /// Return a deep copy of the owned object tree. Types with shared ownership like managed boxes
    /// are cloned with a shallow copy.
    fn clone(&self) -> Self;
}

impl<T: Clone> Clone for ~T {
    /// Return a deep copy of the owned box.
    #[inline(always)]
    fn clone(&self) -> ~T { ~(**self).clone() }
}

impl<T> Clone for @T {
    /// Return a shallow copy of the managed box.
    #[inline(always)]
    fn clone(&self) -> @T { *self }
}

impl<T> Clone for @mut T {
    /// Return a shallow copy of the managed box.
    #[inline(always)]
    fn clone(&self) -> @mut T { *self }
}

impl<'self, T> Clone for &'self T {
    /// Return a shallow copy of the borrowed pointer.
    #[inline(always)]
    fn clone(&self) -> &'self T { *self }
}

macro_rules! clone_impl(
    ($t:ty) => {
        impl Clone for $t {
            /// Return a deep copy of the value.
            #[inline(always)]
            fn clone(&self) -> $t { *self }
        }
    }
)

clone_impl!(int)
clone_impl!(i8)
clone_impl!(i16)
clone_impl!(i32)
clone_impl!(i64)

clone_impl!(uint)
clone_impl!(u8)
clone_impl!(u16)
clone_impl!(u32)
clone_impl!(u64)

clone_impl!(float)
clone_impl!(f32)
clone_impl!(f64)

clone_impl!(())
clone_impl!(bool)
clone_impl!(char)

pub trait DeepClone {
    /// Return a deep copy of the object tree. Types with shared ownership are also copied via a
    /// deep copy, unlike `Clone`.
    fn deep_clone(&self) -> Self;
}

impl<T: DeepClone> DeepClone for ~T {
    /// Return a deep copy of the owned box.
    #[inline(always)]
    fn deep_clone(&self) -> ~T { ~(**self).deep_clone() }
}

// FIXME: #6525: should also be implemented for `T: Owned + DeepClone`
impl<T: Const + DeepClone> DeepClone for @T {
    /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing
    /// a deep clone of a potentially cyclical type.
    #[inline(always)]
    fn deep_clone(&self) -> @T { @(**self).deep_clone() }
}

// FIXME: #6525: should also be implemented for `T: Owned + DeepClone`
impl<T: Const + DeepClone> DeepClone for @mut T {
    /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing
    /// a deep clone of a potentially cyclical type.
    #[inline(always)]
    fn deep_clone(&self) -> @mut T { @mut (**self).deep_clone() }
}

macro_rules! deep_clone_impl(
    ($t:ty) => {
        impl DeepClone for $t {
            /// Return a deep copy of the value.
            #[inline(always)]
            fn deep_clone(&self) -> $t { *self }
        }
    }
)

deep_clone_impl!(int)
deep_clone_impl!(i8)
deep_clone_impl!(i16)
deep_clone_impl!(i32)
deep_clone_impl!(i64)

deep_clone_impl!(uint)
deep_clone_impl!(u8)
deep_clone_impl!(u16)
deep_clone_impl!(u32)
deep_clone_impl!(u64)

deep_clone_impl!(float)
deep_clone_impl!(f32)
deep_clone_impl!(f64)

deep_clone_impl!(())
deep_clone_impl!(bool)
deep_clone_impl!(char)

#[test]
fn test_owned_clone() {
    let a = ~5i;
    let b: ~int = a.clone();
    assert_eq!(a, b);
}

#[test]
fn test_managed_clone() {
    let a = @5i;
    let b: @int = a.clone();
    assert_eq!(a, b);
}

#[test]
fn test_managed_mut_deep_clone() {
    let x = @mut 5i;
    let y: @mut int = x.deep_clone();
    *x = 20;
    assert_eq!(*y, 5);
}

#[test]
fn test_managed_mut_clone() {
    let a = @mut 5i;
    let b: @mut int = a.clone();
    assert_eq!(a, b);
    *b = 10;
    assert_eq!(a, b);
}

#[test]
fn test_borrowed_clone() {
    let x = 5i;
    let y: &int = &x;
    let z: &int = (&y).clone();
    assert_eq!(*z, 5);
}
<commit_msg>auto merge of #6528 : brson/rust/docs, r=brson<commit_after>// Copyright 2012-2013 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.

/*! The Clone trait for types that cannot be "implicitly copied"

In Rust, some simple types are "implicitly copyable" and when you
assign them or pass them as arguments, the receiver will get a copy,
leaving the original value in place. These types do not require
allocation to copy and do not have finalizers (i.e. they do not
contain owned boxes or implement `Drop`), so the compiler considers
them cheap and safe to copy and automatically implements the `Copy`
trait for them. For other types copies must be made explicitly,
by convention implementing the `Clone` trait and calling the
`clone` method.

*/

use core::kinds::Const;

pub trait Clone {
    /// Returns a copy of the value. The contents of owned pointers
    /// are copied to maintain uniqueness, while the contents of
    /// managed pointers are not copied.
    fn clone(&self) -> Self;
}

impl<T: Clone> Clone for ~T {
    /// Return a deep copy of the owned box.
    #[inline(always)]
    fn clone(&self) -> ~T { ~(**self).clone() }
}

impl<T> Clone for @T {
    /// Return a shallow copy of the managed box.
    #[inline(always)]
    fn clone(&self) -> @T { *self }
}

impl<T> Clone for @mut T {
    /// Return a shallow copy of the managed box.
    #[inline(always)]
    fn clone(&self) -> @mut T { *self }
}

impl<'self, T> Clone for &'self T {
    /// Return a shallow copy of the borrowed pointer.
    #[inline(always)]
    fn clone(&self) -> &'self T { *self }
}

macro_rules! clone_impl(
    ($t:ty) => {
        impl Clone for $t {
            /// Return a deep copy of the value.
            #[inline(always)]
            fn clone(&self) -> $t { *self }
        }
    }
)

clone_impl!(int)
clone_impl!(i8)
clone_impl!(i16)
clone_impl!(i32)
clone_impl!(i64)

clone_impl!(uint)
clone_impl!(u8)
clone_impl!(u16)
clone_impl!(u32)
clone_impl!(u64)

clone_impl!(float)
clone_impl!(f32)
clone_impl!(f64)

clone_impl!(())
clone_impl!(bool)
clone_impl!(char)

pub trait DeepClone {
    /// Return a deep copy of the value. Unlike `Clone`, the contents of shared pointer types
    /// *are* copied. Note that this is currently unimplemented for managed boxes, as
    /// it would need to handle cycles, but it is implemented for other smart-pointer types.
    fn deep_clone(&self) -> Self;
}

impl<T: DeepClone> DeepClone for ~T {
    /// Return a deep copy of the owned box.
    #[inline(always)]
    fn deep_clone(&self) -> ~T { ~(**self).deep_clone() }
}

// FIXME: #6525: should also be implemented for `T: Owned + DeepClone`
impl<T: Const + DeepClone> DeepClone for @T {
    /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing
    /// a deep clone of a potentially cyclical type.
    #[inline(always)]
    fn deep_clone(&self) -> @T { @(**self).deep_clone() }
}

// FIXME: #6525: should also be implemented for `T: Owned + DeepClone`
impl<T: Const + DeepClone> DeepClone for @mut T {
    /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing
    /// a deep clone of a potentially cyclical type.
    #[inline(always)]
    fn deep_clone(&self) -> @mut T { @mut (**self).deep_clone() }
}

macro_rules! deep_clone_impl(
    ($t:ty) => {
        impl DeepClone for $t {
            /// Return a deep copy of the value.
            #[inline(always)]
            fn deep_clone(&self) -> $t { *self }
        }
    }
)

deep_clone_impl!(int)
deep_clone_impl!(i8)
deep_clone_impl!(i16)
deep_clone_impl!(i32)
deep_clone_impl!(i64)

deep_clone_impl!(uint)
deep_clone_impl!(u8)
deep_clone_impl!(u16)
deep_clone_impl!(u32)
deep_clone_impl!(u64)

deep_clone_impl!(float)
deep_clone_impl!(f32)
deep_clone_impl!(f64)

deep_clone_impl!(())
deep_clone_impl!(bool)
deep_clone_impl!(char)

#[test]
fn test_owned_clone() {
    let a = ~5i;
    let b: ~int = a.clone();
    assert_eq!(a, b);
}

#[test]
fn test_managed_clone() {
    let a = @5i;
    let b: @int = a.clone();
    assert_eq!(a, b);
}

#[test]
fn test_managed_mut_deep_clone() {
    let x = @mut 5i;
    let y: @mut int = x.deep_clone();
    *x = 20;
    assert_eq!(*y, 5);
}

#[test]
fn test_managed_mut_clone() {
    let a = @mut 5i;
    let b: @mut int = a.clone();
    assert_eq!(a, b);
    *b = 10;
    assert_eq!(a, b);
}

#[test]
fn test_borrowed_clone() {
    let x = 5i;
    let y: &int = &x;
    let z: &int = (&y).clone();
    assert_eq!(*z, 5);
}
<|endoftext|>


<commit_before>// Copyright 2013 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.

/*!
Weak tasks

Weak tasks are a runtime feature for building global services that
do not keep the runtime alive. Normally the runtime exits when all
tasks exits, but if a task is weak then the runtime may exit while
it is running, sending a notification to the task that the runtime
is trying to shut down.
*/

use option::{Some, None, swap_unwrap};
use private::at_exit::at_exit;
use private::global::global_data_clone_create;
use private::finally::Finally;
use pipes::{Port, Chan, SharedChan, GenericSmartChan, stream};
use task::{Task, task, spawn};
use task::rt::{task_id, get_task_id};
use hashmap::linear::LinearMap;
use ops::Drop;

type ShutdownMsg = ();

// FIXME #4729: This could be a PortOne but I've experienced bugginess
// with oneshot pipes and try_send
pub unsafe fn weaken_task(f: &fn(Port<ShutdownMsg>)) {
    let service = global_data_clone_create(global_data_key,
                                           create_global_service);
    let (shutdown_port, shutdown_chan) = stream::<ShutdownMsg>();
    let shutdown_port = ~mut Some(shutdown_port);
    let task = get_task_id();
    // Expect the weak task service to be alive
    assert service.try_send(RegisterWeakTask(task, shutdown_chan));
    unsafe { rust_inc_kernel_live_count(); }
    do fn&() {
        let shutdown_port = swap_unwrap(&mut *shutdown_port);
        f(shutdown_port)
    }.finally || {
        unsafe { rust_dec_kernel_live_count(); }
        // Service my have already exited
        service.send(UnregisterWeakTask(task));
    }
}

type WeakTaskService = SharedChan<ServiceMsg>;
type TaskHandle = task_id;

fn global_data_key(_v: WeakTaskService) { }

enum ServiceMsg {
    RegisterWeakTask(TaskHandle, Chan<ShutdownMsg>),
    UnregisterWeakTask(TaskHandle),
    Shutdown
}

fn create_global_service() -> ~WeakTaskService {

    debug!("creating global weak task service");
    let (port, chan) = stream::<ServiceMsg>();
    let port = ~mut Some(port);
    let chan = SharedChan(chan);
    let chan_clone = chan.clone();

    do task().unlinked().spawn {
        debug!("running global weak task service");
        let port = swap_unwrap(&mut *port);
        let port = ~mut Some(port);
        do fn&() {
            let port = swap_unwrap(&mut *port);
            // The weak task service is itself a weak task
            debug!("weakening the weak service task");
            unsafe { rust_inc_kernel_live_count(); }
            run_weak_task_service(port);
        }.finally {
            debug!("unweakening the weak service task");
            unsafe { rust_dec_kernel_live_count(); }
        }
    }

    do at_exit {
        debug!("shutting down weak task service");
        chan.send(Shutdown);
    }

    return ~chan_clone;
}

fn run_weak_task_service(port: Port<ServiceMsg>) {

    let mut shutdown_map = LinearMap::new();

    loop {
        match port.recv() {
            RegisterWeakTask(task, shutdown_chan) => {
                let previously_unregistered =
                    shutdown_map.insert(task, shutdown_chan);
                assert previously_unregistered;
            }
            UnregisterWeakTask(task) => {
                match shutdown_map.pop(&task) {
                    Some(shutdown_chan) => {
                        // Oneshot pipes must send, even though
                        // nobody will receive this
                        shutdown_chan.send(());
                    }
                    None => die!()
                }
            }
            Shutdown => break
        }
    }

    do shutdown_map.consume |_, shutdown_chan| {
        // Weak task may have already exited
        shutdown_chan.send(());
    }
}

extern {
    unsafe fn rust_inc_kernel_live_count();
    unsafe fn rust_dec_kernel_live_count();
}

#[test]
fn test_simple() {
    let (port, chan) = stream();
    do spawn {
        unsafe {
            do weaken_task |_signal| {
            }
        }
        chan.send(());
    }
    port.recv();
}

#[test]
fn test_weak_weak() {
    let (port, chan) = stream();
    do spawn {
        unsafe {
            do weaken_task |_signal| {
            }
            do weaken_task |_signal| {
            }
        }
        chan.send(());
    }
    port.recv();
}

#[test]
fn test_wait_for_signal() {
    do spawn {
        unsafe {
            do weaken_task |signal| {
                signal.recv();
            }
        }
    }
}

#[test]
fn test_wait_for_signal_many() {
    use uint;
    for uint::range(0, 100) |_| {
        do spawn {
            unsafe {
                do weaken_task |signal| {
                    signal.recv();
                }
            }
        }
    }
}

#[test]
fn test_select_stream_and_oneshot() {
    use pipes::select2i;
    use either::{Left, Right};

    let (port, chan) = stream();
    let (waitport, waitchan) = stream();
    do spawn {
        unsafe {
            do weaken_task |signal| {
                match select2i(&port, &signal) {
                    Left(*) => (),
                    Right(*) => die!()
                }
            }
        }
        waitchan.send(());
    }
    chan.send(());
    waitport.recv();
}

<commit_msg>core: Fix dec/inc_kernel_live_count mixup<commit_after>// Copyright 2013 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.

/*!
Weak tasks

Weak tasks are a runtime feature for building global services that
do not keep the runtime alive. Normally the runtime exits when all
tasks exits, but if a task is weak then the runtime may exit while
it is running, sending a notification to the task that the runtime
is trying to shut down.
*/

use option::{Some, None, swap_unwrap};
use private::at_exit::at_exit;
use private::global::global_data_clone_create;
use private::finally::Finally;
use pipes::{Port, Chan, SharedChan, GenericSmartChan, stream};
use task::{Task, task, spawn};
use task::rt::{task_id, get_task_id};
use hashmap::linear::LinearMap;
use ops::Drop;

type ShutdownMsg = ();

// FIXME #4729: This could be a PortOne but I've experienced bugginess
// with oneshot pipes and try_send
pub unsafe fn weaken_task(f: &fn(Port<ShutdownMsg>)) {
    let service = global_data_clone_create(global_data_key,
                                           create_global_service);
    let (shutdown_port, shutdown_chan) = stream::<ShutdownMsg>();
    let shutdown_port = ~mut Some(shutdown_port);
    let task = get_task_id();
    // Expect the weak task service to be alive
    assert service.try_send(RegisterWeakTask(task, shutdown_chan));
    unsafe { rust_dec_kernel_live_count(); }
    do fn&() {
        let shutdown_port = swap_unwrap(&mut *shutdown_port);
        f(shutdown_port)
    }.finally || {
        unsafe { rust_inc_kernel_live_count(); }
        // Service my have already exited
        service.send(UnregisterWeakTask(task));
    }
}

type WeakTaskService = SharedChan<ServiceMsg>;
type TaskHandle = task_id;

fn global_data_key(_v: WeakTaskService) { }

enum ServiceMsg {
    RegisterWeakTask(TaskHandle, Chan<ShutdownMsg>),
    UnregisterWeakTask(TaskHandle),
    Shutdown
}

fn create_global_service() -> ~WeakTaskService {

    debug!("creating global weak task service");
    let (port, chan) = stream::<ServiceMsg>();
    let port = ~mut Some(port);
    let chan = SharedChan(chan);
    let chan_clone = chan.clone();

    do task().unlinked().spawn {
        debug!("running global weak task service");
        let port = swap_unwrap(&mut *port);
        let port = ~mut Some(port);
        do fn&() {
            let port = swap_unwrap(&mut *port);
            // The weak task service is itself a weak task
            debug!("weakening the weak service task");
            unsafe { rust_dec_kernel_live_count(); }
            run_weak_task_service(port);
        }.finally {
            debug!("unweakening the weak service task");
            unsafe { rust_inc_kernel_live_count(); }
        }
    }

    do at_exit {
        debug!("shutting down weak task service");
        chan.send(Shutdown);
    }

    return ~chan_clone;
}

fn run_weak_task_service(port: Port<ServiceMsg>) {

    let mut shutdown_map = LinearMap::new();

    loop {
        match port.recv() {
            RegisterWeakTask(task, shutdown_chan) => {
                let previously_unregistered =
                    shutdown_map.insert(task, shutdown_chan);
                assert previously_unregistered;
            }
            UnregisterWeakTask(task) => {
                match shutdown_map.pop(&task) {
                    Some(shutdown_chan) => {
                        // Oneshot pipes must send, even though
                        // nobody will receive this
                        shutdown_chan.send(());
                    }
                    None => die!()
                }
            }
            Shutdown => break
        }
    }

    do shutdown_map.consume |_, shutdown_chan| {
        // Weak task may have already exited
        shutdown_chan.send(());
    }
}

extern {
    unsafe fn rust_inc_kernel_live_count();
    unsafe fn rust_dec_kernel_live_count();
}

#[test]
fn test_simple() {
    let (port, chan) = stream();
    do spawn {
        unsafe {
            do weaken_task |_signal| {
            }
        }
        chan.send(());
    }
    port.recv();
}

#[test]
fn test_weak_weak() {
    let (port, chan) = stream();
    do spawn {
        unsafe {
            do weaken_task |_signal| {
            }
            do weaken_task |_signal| {
            }
        }
        chan.send(());
    }
    port.recv();
}

#[test]
fn test_wait_for_signal() {
    do spawn {
        unsafe {
            do weaken_task |signal| {
                signal.recv();
            }
        }
    }
}

#[test]
fn test_wait_for_signal_many() {
    use uint;
    for uint::range(0, 100) |_| {
        do spawn {
            unsafe {
                do weaken_task |signal| {
                    signal.recv();
                }
            }
        }
    }
}

#[test]
fn test_select_stream_and_oneshot() {
    use pipes::select2i;
    use either::{Left, Right};

    let (port, chan) = stream();
    let (waitport, waitchan) = stream();
    do spawn {
        unsafe {
            do weaken_task |signal| {
                match select2i(&port, &signal) {
                    Left(*) => (),
                    Right(*) => die!()
                }
            }
        }
        waitchan.send(());
    }
    chan.send(());
    waitport.recv();
}

<|endoftext|>


<commit_before>#[derive(Debug, PartialEq)]
pub enum Expression {
    Number(f64),
    Identifier(String),
    Boolean(bool),
    String(String),
}
<commit_msg>Add list to AST<commit_after>#[derive(Debug, PartialEq)]
pub enum Expression {
    Number(f64),
    Identifier(String),
    Boolean(bool),
    String(String),
    List(Vec<Box<Expression>>)
}
<|endoftext|>