<commit_before>use std::io::net::ip::{Port, IpAddr};

use router::Router;
use middleware::{ MiddlewareStack, Middleware, Action };
use into_middleware::IntoMiddleware;
use into_error_handler::IntoErrorHandler;
use nickel_error::{ NickelError, ErrorWithStatusCode };
use server::Server;

use http::method::{ Method, Get, Post, Put, Delete };
use http::status::NotFound;
use request::Request;
use response::Response;

//pre defined middleware
use json_body_parser::JsonBodyParser;
use query_string::QueryStringParser;
use default_error_handler::DefaultErrorHandler;

/// Nickel is the application object. It's the surface that
/// holds all public APIs.

pub struct Nickel{
    middleware_stack: MiddlewareStack,
    server: Option<Server>,
}

impl Nickel {

    /// In order to use Nickels API one first has to create an instance.
    ///
    /// # Example
    /// ```{rust,ignore}
    /// let mut server = Nickel::new();
    /// ```
    pub fn new() -> Nickel {
        let mut middleware_stack = MiddlewareStack::new();

        // Hook up the default error handler by default. Users are
        // free to cancel it out from their custom error handler if
        // they don't like the default behaviour.
        middleware_stack.add_error_handler(DefaultErrorHandler);

        Nickel {
            middleware_stack: middleware_stack,
            server: None
        }
    }

    /// Registers a middleware handler which will be invoked among other middleware
    /// handlers before each request. Middleware can be stacked and is invoked in the
    /// same order it was registered.
    ///
    /// A middleware handler is nearly identical to a regular route handler with the only
    /// difference that it expects a result of either Action or NickelError.
    /// That is to indicate whether other middleware handlers (if any) further
    /// down the stack should continue or if the middleware invocation should
    /// be stopped after the current handler.
    ///
    /// # Example
    ///
    /// ```{rust}
    /// use nickel::IntoMiddleware; // This is *hopefully* temporary
    /// use nickel::{Nickel, Request, Response, Action, Continue, NickelError};
    /// fn logger(req: &Request, res: &mut Response) -> Result<Action, NickelError>{
    ///     println!("logging request: {}", req.origin.request_uri);
    ///     Ok(Continue)
    /// }
    ///
    /// let mut server = Nickel::new();
    /// server.utilize(IntoMiddleware::from_fn(logger));
    /// ```
    pub fn utilize<T: Middleware>(&mut self, handler: T){
        self.middleware_stack.add_middleware(handler);
    }

    /// Registers a handler to be used for a specific GET request.
    /// Handlers are assigned to paths and paths are allowed to contain
    /// variables and wildcards.
    ///
    /// A handler added through this API will
    /// be attached to the default router. Consider creating the router
    /// middleware manually for advanced functionality.
    ///
    /// # Example
    ///
    /// ```{rust}
    /// use nickel::{Nickel, Request, Response};
    /// let mut server = Nickel::new();
    ///
    /// //  without variables or wildcards
    /// fn bare_handler(request: &Request, response: &mut Response) {
    ///     response.send("This matches /user");
    /// };
    /// server.get("/user", bare_handler);
    ///
    /// // with variables
    /// fn var_handler(request: &Request, response: &mut Response) {
    ///     let text = format!("This is user: {}", request.param("userid"));
    ///     response.send(text.as_slice());
    /// };
    /// server.get("/user/:userid", var_handler);
    ///
    /// // with simple wildcard
    /// fn wild_handler(request: &Request, response: &mut Response) {
    ///     response.send("This matches /user/list/4711 but not /user/extended/list/4711");
    /// };
    /// server.get("/user/*/:userid", wild_handler);
    ///
    /// // with double wildcard
    /// fn very_wild_handler(request: &Request, response: &mut Response) {
    ///     response.send("This matches /user/list/4711 and also /user/extended/list/4711");
    /// };
    /// server.get("/user/**/:userid", very_wild_handler);
    /// ```
    pub fn get(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.register_route_with_new_router(Get, uri, handler);
    }

    /// Registers a handler to be used for a specific POST request.
    /// A handler added through this API will be attached to the default router.
    /// Consider creating the router middleware manually for advanced functionality.
    ///
    /// Take a look at `get(...)` for a more detailed description.
    /// # Example
    ///
    /// ```{rust}
    /// use nickel::{Nickel, Request, Response};
    /// fn handler(request: &Request, response: &mut Response) {
    ///     response.send("This matches a POST request to /a/post/request");
    /// };
    ///
    /// let mut server = Nickel::new();
    /// server.post("/a/post/request", handler);
    /// ```
    pub fn post(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.register_route_with_new_router(Post, uri, handler);
    }

    /// Registers a handler to be used for a specific PUT request.
    /// A handler added through this API will be attached to the default router.
    /// Consider creating the router middleware manually for advanced functionality.
    ///
    /// Take a look at `get(...)` for a more detailed description.
    /// # Example
    ///
    /// ```{rust}
    /// use nickel::{Nickel, Request, Response};
    /// fn handler(request: &Request, response: &mut Response) {
    ///     response.send("This matches a POST request to /a/put/request");
    /// };
    ///
    /// let mut server = Nickel::new();
    /// server.put("/a/put/request", handler);
    /// ```
    pub fn put(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.register_route_with_new_router(Put, uri, handler);
    }

    /// Registers a handler to be used for a specific DELETE request.
    /// A handler added through this API will be attached to the default router.
    /// Consider creating the router middleware manually for advanced functionality.
    ///
    /// Take a look at `get(...)` for a more detailed description.
    /// # Example
    ///
    /// ```{rust}
    /// use nickel::{Nickel, Request, Response};
    /// fn handler(request: &Request, response: &mut Response) {
    ///     response.send("This matches a DELETE request to /a/delete/request");
    /// };
    ///
    /// let mut server = Nickel::new();
    /// server.delete("/a/delete/request", handler);
    /// ```
    pub fn delete(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.register_route_with_new_router(Delete, uri, handler);
    }

    fn register_route_with_new_router(&mut self, method: Method, uri: &str, handler: fn(request: &Request, response: &mut Response)) {
        let mut router = Router::new();
        router.add_route(method, String::from_str(uri), handler);
        self.utilize(router);
    }

    /// Registers an error handler which will be invoked among other error handler
    /// as soon as any regular handler returned an error
    ///
    /// A error handler is nearly identical to a regular middleware handler with the only
    /// difference that it takes an additional error parameter or type `NickelError.
    ///
    /// # Example
    ///
    /// ```{rust}
    /// # extern crate http;
    /// # extern crate nickel;
    /// # fn main() {
    /// use nickel::{Nickel, Request, Response, Action, Continue, Halt};
    /// use nickel::{NickelError, ErrorWithStatusCode, get_media_type};
    /// use http::status::NotFound;
    ///
    /// fn error_handler(err: &NickelError, req: &Request, response: &mut Response)
    ///                  -> Result<Action, NickelError>{
    ///    match err.kind {
    ///        ErrorWithStatusCode(NotFound) => {
    ///            response.origin.headers.content_type = get_media_type("html");
    ///            response.origin.status = NotFound;
    ///            response.send("<h1>Call the police!<h1>");
    ///            Ok(Halt)
    ///        },
    ///        _ => Ok(Continue)
    ///    }
    /// }
    ///
    /// let mut server = Nickel::new();
    /// server.handle_error(error_handler)
    /// # }
    /// ```
    pub fn handle_error(&mut self, handler: fn(err: &NickelError,
                                               req: &Request,
                                               res: &mut Response)
                                            -> Result<Action, NickelError>){
        let handler = IntoErrorHandler::from_fn(handler);
        self.middleware_stack.add_error_handler(handler);
    }

    /// Create a new middleware to serve as a router.
    ///
    ///
    /// # Example
    /// ```{rust}
    /// use nickel::{Nickel, Request, Response};
    ///
    /// let mut server = Nickel::new();
    /// let mut router = Nickel::router();
    ///
    /// fn foo_handler(request: &Request, response: &mut Response) {
    ///     response.send("Hi from /foo");
    /// };
    ///
    /// router.get("/foo", foo_handler);
    /// server.utilize(router);
    /// ```
    pub fn router() -> Router {
        Router::new()
    }

    /// Create a new middleware to parse JSON bodies.
    ///
    ///
    /// # Example
    /// ```{rust}
    /// # #![feature(phase)]
    /// # #[phase(plugin)] extern crate nickel_macros;
    /// # extern crate nickel;
    /// # extern crate serialize;
    /// # use nickel::{Nickel, Request, Response};
    /// use nickel::JsonBody;
    ///
    /// # fn main() {
    /// #[deriving(Decodable, Encodable)]
    /// struct Person {
    ///     first_name: String,
    ///     last_name:  String,
    /// }
    ///
    /// let router = router! {
    ///     post "/a/post/request" => |request, response| {
    ///         let person = request.json_as::<Person>().unwrap();
    ///         let text = format!("Hello {} {}", person.first_name, person.last_name);
    ///         response.send(text);
    ///     }
    /// };
    ///
    /// let mut server = Nickel::new();
    /// // It is currently a requirement that the json_body_parser middleware
    /// // is added before any routes that require it.
    /// server.utilize(Nickel::json_body_parser());
    /// server.utilize(router);
    /// # }
    /// ```
    pub fn json_body_parser() -> JsonBodyParser {
        JsonBodyParser
    }

    /// Create a new middleware to parse the query string.
    ///
    ///
    /// # Example
    /// ```{rust}
    /// # #![feature(phase)]
    /// # #[phase(plugin)] extern crate nickel_macros;
    /// # extern crate nickel;
    /// # use nickel::{Nickel, Request, Response};
    /// use nickel::QueryString;
    /// # fn main() {
    /// let router = router! {
    ///     get "/a/get/request" => |request, response| {
    ///         let foo = request.query("foo", "this is the default value, if foo is not present!");
    ///         response.send(foo[0].as_slice());
    ///     }
    /// };
    ///
    /// let mut server = Nickel::new();
    /// // It is currently a requirement that the query_string middleware
    /// // is added before any routes that require it.
    /// server.utilize(Nickel::query_string());
    /// server.utilize(router);
    /// # }
    /// ```
    pub fn query_string() -> QueryStringParser {
        QueryStringParser
    }

    /// Bind and listen for connections on the given host and port
    ///
    /// # Example
    /// ```{rust,ignore}
    /// let mut server = Nickel::new();
    /// server.listen(Ipv4Addr(127, 0, 0, 1), 6767);
    /// ```
    pub fn listen(mut self, ip: IpAddr, port: Port) {
        fn not_found_handler(_request: &Request, _response: &mut Response) -> Result<Action, NickelError> {
            Err(NickelError::new("File Not Found", ErrorWithStatusCode(NotFound)))
        }

        self.middleware_stack.add_middleware(IntoMiddleware::from_fn(not_found_handler));
        self.server = Some(Server::new(self.middleware_stack, ip, port));
        self.server.unwrap().serve();
    }
}
<commit_msg>docs(nickel): fix docs for new<commit_after>use std::io::net::ip::{Port, IpAddr};

use router::Router;
use middleware::{ MiddlewareStack, Middleware, Action };
use into_middleware::IntoMiddleware;
use into_error_handler::IntoErrorHandler;
use nickel_error::{ NickelError, ErrorWithStatusCode };
use server::Server;

use http::method::{ Method, Get, Post, Put, Delete };
use http::status::NotFound;
use request::Request;
use response::Response;

//pre defined middleware
use json_body_parser::JsonBodyParser;
use query_string::QueryStringParser;
use default_error_handler::DefaultErrorHandler;

/// Nickel is the application object. It's the surface that
/// holds all public APIs.

pub struct Nickel{
    middleware_stack: MiddlewareStack,
    server: Option<Server>,
}

impl Nickel {
    /// Creates an instance of Nickel with default error handling.
    pub fn new() -> Nickel {
        let mut middleware_stack = MiddlewareStack::new();

        // Hook up the default error handler by default. Users are
        // free to cancel it out from their custom error handler if
        // they don't like the default behaviour.
        middleware_stack.add_error_handler(DefaultErrorHandler);

        Nickel {
            middleware_stack: middleware_stack,
            server: None
        }
    }

    /// Registers a middleware handler which will be invoked among other middleware
    /// handlers before each request. Middleware can be stacked and is invoked in the
    /// same order it was registered.
    ///
    /// A middleware handler is nearly identical to a regular route handler with the only
    /// difference that it expects a result of either Action or NickelError.
    /// That is to indicate whether other middleware handlers (if any) further
    /// down the stack should continue or if the middleware invocation should
    /// be stopped after the current handler.
    ///
    /// # Example
    ///
    /// ```{rust}
    /// use nickel::IntoMiddleware; // This is *hopefully* temporary
    /// use nickel::{Nickel, Request, Response, Action, Continue, NickelError};
    /// fn logger(req: &Request, res: &mut Response) -> Result<Action, NickelError>{
    ///     println!("logging request: {}", req.origin.request_uri);
    ///     Ok(Continue)
    /// }
    ///
    /// let mut server = Nickel::new();
    /// server.utilize(IntoMiddleware::from_fn(logger));
    /// ```
    pub fn utilize<T: Middleware>(&mut self, handler: T){
        self.middleware_stack.add_middleware(handler);
    }

    /// Registers a handler to be used for a specific GET request.
    /// Handlers are assigned to paths and paths are allowed to contain
    /// variables and wildcards.
    ///
    /// A handler added through this API will
    /// be attached to the default router. Consider creating the router
    /// middleware manually for advanced functionality.
    ///
    /// # Example
    ///
    /// ```{rust}
    /// use nickel::{Nickel, Request, Response};
    /// let mut server = Nickel::new();
    ///
    /// //  without variables or wildcards
    /// fn bare_handler(request: &Request, response: &mut Response) {
    ///     response.send("This matches /user");
    /// };
    /// server.get("/user", bare_handler);
    ///
    /// // with variables
    /// fn var_handler(request: &Request, response: &mut Response) {
    ///     let text = format!("This is user: {}", request.param("userid"));
    ///     response.send(text.as_slice());
    /// };
    /// server.get("/user/:userid", var_handler);
    ///
    /// // with simple wildcard
    /// fn wild_handler(request: &Request, response: &mut Response) {
    ///     response.send("This matches /user/list/4711 but not /user/extended/list/4711");
    /// };
    /// server.get("/user/*/:userid", wild_handler);
    ///
    /// // with double wildcard
    /// fn very_wild_handler(request: &Request, response: &mut Response) {
    ///     response.send("This matches /user/list/4711 and also /user/extended/list/4711");
    /// };
    /// server.get("/user/**/:userid", very_wild_handler);
    /// ```
    pub fn get(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.register_route_with_new_router(Get, uri, handler);
    }

    /// Registers a handler to be used for a specific POST request.
    /// A handler added through this API will be attached to the default router.
    /// Consider creating the router middleware manually for advanced functionality.
    ///
    /// Take a look at `get(...)` for a more detailed description.
    /// # Example
    ///
    /// ```{rust}
    /// use nickel::{Nickel, Request, Response};
    /// fn handler(request: &Request, response: &mut Response) {
    ///     response.send("This matches a POST request to /a/post/request");
    /// };
    ///
    /// let mut server = Nickel::new();
    /// server.post("/a/post/request", handler);
    /// ```
    pub fn post(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.register_route_with_new_router(Post, uri, handler);
    }

    /// Registers a handler to be used for a specific PUT request.
    /// A handler added through this API will be attached to the default router.
    /// Consider creating the router middleware manually for advanced functionality.
    ///
    /// Take a look at `get(...)` for a more detailed description.
    /// # Example
    ///
    /// ```{rust}
    /// use nickel::{Nickel, Request, Response};
    /// fn handler(request: &Request, response: &mut Response) {
    ///     response.send("This matches a POST request to /a/put/request");
    /// };
    ///
    /// let mut server = Nickel::new();
    /// server.put("/a/put/request", handler);
    /// ```
    pub fn put(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.register_route_with_new_router(Put, uri, handler);
    }

    /// Registers a handler to be used for a specific DELETE request.
    /// A handler added through this API will be attached to the default router.
    /// Consider creating the router middleware manually for advanced functionality.
    ///
    /// Take a look at `get(...)` for a more detailed description.
    /// # Example
    ///
    /// ```{rust}
    /// use nickel::{Nickel, Request, Response};
    /// fn handler(request: &Request, response: &mut Response) {
    ///     response.send("This matches a DELETE request to /a/delete/request");
    /// };
    ///
    /// let mut server = Nickel::new();
    /// server.delete("/a/delete/request", handler);
    /// ```
    pub fn delete(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.register_route_with_new_router(Delete, uri, handler);
    }

    fn register_route_with_new_router(&mut self, method: Method, uri: &str, handler: fn(request: &Request, response: &mut Response)) {
        let mut router = Router::new();
        router.add_route(method, String::from_str(uri), handler);
        self.utilize(router);
    }

    /// Registers an error handler which will be invoked among other error handler
    /// as soon as any regular handler returned an error
    ///
    /// A error handler is nearly identical to a regular middleware handler with the only
    /// difference that it takes an additional error parameter or type `NickelError.
    ///
    /// # Example
    ///
    /// ```{rust}
    /// # extern crate http;
    /// # extern crate nickel;
    /// # fn main() {
    /// use nickel::{Nickel, Request, Response, Action, Continue, Halt};
    /// use nickel::{NickelError, ErrorWithStatusCode, get_media_type};
    /// use http::status::NotFound;
    ///
    /// fn error_handler(err: &NickelError, req: &Request, response: &mut Response)
    ///                  -> Result<Action, NickelError>{
    ///    match err.kind {
    ///        ErrorWithStatusCode(NotFound) => {
    ///            response.origin.headers.content_type = get_media_type("html");
    ///            response.origin.status = NotFound;
    ///            response.send("<h1>Call the police!<h1>");
    ///            Ok(Halt)
    ///        },
    ///        _ => Ok(Continue)
    ///    }
    /// }
    ///
    /// let mut server = Nickel::new();
    /// server.handle_error(error_handler)
    /// # }
    /// ```
    pub fn handle_error(&mut self, handler: fn(err: &NickelError,
                                               req: &Request,
                                               res: &mut Response)
                                            -> Result<Action, NickelError>){
        let handler = IntoErrorHandler::from_fn(handler);
        self.middleware_stack.add_error_handler(handler);
    }

    /// Create a new middleware to serve as a router.
    ///
    ///
    /// # Example
    /// ```{rust}
    /// use nickel::{Nickel, Request, Response};
    ///
    /// let mut server = Nickel::new();
    /// let mut router = Nickel::router();
    ///
    /// fn foo_handler(request: &Request, response: &mut Response) {
    ///     response.send("Hi from /foo");
    /// };
    ///
    /// router.get("/foo", foo_handler);
    /// server.utilize(router);
    /// ```
    pub fn router() -> Router {
        Router::new()
    }

    /// Create a new middleware to parse JSON bodies.
    ///
    ///
    /// # Example
    /// ```{rust}
    /// # #![feature(phase)]
    /// # #[phase(plugin)] extern crate nickel_macros;
    /// # extern crate nickel;
    /// # extern crate serialize;
    /// # use nickel::{Nickel, Request, Response};
    /// use nickel::JsonBody;
    ///
    /// # fn main() {
    /// #[deriving(Decodable, Encodable)]
    /// struct Person {
    ///     first_name: String,
    ///     last_name:  String,
    /// }
    ///
    /// let router = router! {
    ///     post "/a/post/request" => |request, response| {
    ///         let person = request.json_as::<Person>().unwrap();
    ///         let text = format!("Hello {} {}", person.first_name, person.last_name);
    ///         response.send(text);
    ///     }
    /// };
    ///
    /// let mut server = Nickel::new();
    /// // It is currently a requirement that the json_body_parser middleware
    /// // is added before any routes that require it.
    /// server.utilize(Nickel::json_body_parser());
    /// server.utilize(router);
    /// # }
    /// ```
    pub fn json_body_parser() -> JsonBodyParser {
        JsonBodyParser
    }

    /// Create a new middleware to parse the query string.
    ///
    ///
    /// # Example
    /// ```{rust}
    /// # #![feature(phase)]
    /// # #[phase(plugin)] extern crate nickel_macros;
    /// # extern crate nickel;
    /// # use nickel::{Nickel, Request, Response};
    /// use nickel::QueryString;
    /// # fn main() {
    /// let router = router! {
    ///     get "/a/get/request" => |request, response| {
    ///         let foo = request.query("foo", "this is the default value, if foo is not present!");
    ///         response.send(foo[0].as_slice());
    ///     }
    /// };
    ///
    /// let mut server = Nickel::new();
    /// // It is currently a requirement that the query_string middleware
    /// // is added before any routes that require it.
    /// server.utilize(Nickel::query_string());
    /// server.utilize(router);
    /// # }
    /// ```
    pub fn query_string() -> QueryStringParser {
        QueryStringParser
    }

    /// Bind and listen for connections on the given host and port
    ///
    /// # Example
    /// ```{rust,ignore}
    /// let mut server = Nickel::new();
    /// server.listen(Ipv4Addr(127, 0, 0, 1), 6767);
    /// ```
    pub fn listen(mut self, ip: IpAddr, port: Port) {
        fn not_found_handler(_request: &Request, _response: &mut Response) -> Result<Action, NickelError> {
            Err(NickelError::new("File Not Found", ErrorWithStatusCode(NotFound)))
        }

        self.middleware_stack.add_middleware(IntoMiddleware::from_fn(not_found_handler));
        self.server = Some(Server::new(self.middleware_stack, ip, port));
        self.server.unwrap().serve();
    }
}
<|endoftext|>


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

use std::ascii::AsciiExt;
use std::cmp;

#[deriving(Show, Clone)]
pub struct LogDirective {
    pub name: Option<String>,
    pub level: u32,
}

pub static LOG_LEVEL_NAMES: [&'static str, ..4] = ["ERROR", "WARN", "INFO",
                                               "DEBUG"];

/// Parse an individual log level that is either a number or a symbolic log level
fn parse_log_level(level: &str) -> Option<u32> {
    from_str::<u32>(level).or_else(|| {
        let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
        pos.map(|p| p as u32 + 1)
    }).map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
}

/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1")
/// and return a vector with log directives.
///
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in
/// std::).  Also supports string log levels of error, warn, info, and debug
pub fn parse_logging_spec(spec: &str) -> Vec<LogDirective> {
    let mut dirs = Vec::new();
    for s in spec.split(',') {
        if s.len() == 0 { continue }
        let mut parts = s.split('=');
        let (log_level, name) = match (parts.next(), parts.next(), parts.next()) {
            (Some(part0), None, None) => {
                // if the single argument is a log-level string or number,
                // treat that as a global fallback
                match parse_log_level(part0) {
                    Some(num) => (num, None),
                    None => (::MAX_LOG_LEVEL, Some(part0)),
                }
            }
            (Some(part0), Some(part1), None) => {
                match parse_log_level(part1) {
                    Some(num) => (num, Some(part0)),
                    _ => {
                        println!("warning: invalid logging spec '{}', \
                                 ignoring it", part1);
                        continue
                    }
                }
            },
            _ => {
                println!("warning: invalid logging spec '{}', \
                         ignoring it", s);
                continue
            }
        };
        dirs.push(LogDirective {
            name: name.map(|s| s.to_string()),
            level: log_level,
        });
    }
    return dirs;
}

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

    #[test]
    fn parse_logging_spec_valid() {
        let dirs = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_string()));
        assert_eq!(dirs[2].level, 4);
    }

    #[test]
    fn parse_logging_spec_invalid_crate() {
        // test parse_logging_spec with multiple = in specification
        let dirs = parse_logging_spec("crate1::mod1=1=2,crate2=4");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
    }

    #[test]
    fn parse_logging_spec_invalid_log_level() {
        // test parse_logging_spec with 'noNumber' as log level
        let dirs = parse_logging_spec("crate1::mod1=noNumber,crate2=4");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
    }

    #[test]
    fn parse_logging_spec_string_log_level() {
        // test parse_logging_spec with 'warn' as log level
        let dirs = parse_logging_spec("crate1::mod1=wrong,crate2=warn");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, ::WARN);
    }

    #[test]
    fn parse_logging_spec_global() {
        // test parse_logging_spec with no crate
        let dirs = parse_logging_spec("warn,crate2=4");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 2);
        assert_eq!(dirs[0].name, None);
        assert_eq!(dirs[0].level, 2);
        assert_eq!(dirs[1].name, Some("crate2".to_string()));
        assert_eq!(dirs[1].level, 4);
    }
}
<commit_msg>Accept empty log level<commit_after>// Copyright 2014 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.

use std::ascii::AsciiExt;
use std::cmp;

#[deriving(Show, Clone)]
pub struct LogDirective {
    pub name: Option<String>,
    pub level: u32,
}

pub static LOG_LEVEL_NAMES: [&'static str, ..4] = ["ERROR", "WARN", "INFO",
                                               "DEBUG"];

/// Parse an individual log level that is either a number or a symbolic log level
fn parse_log_level(level: &str) -> Option<u32> {
    from_str::<u32>(level).or_else(|| {
        let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
        pos.map(|p| p as u32 + 1)
    }).map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
}

/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1")
/// and return a vector with log directives.
///
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in
/// std::).  Also supports string log levels of error, warn, info, and debug
pub fn parse_logging_spec(spec: &str) -> Vec<LogDirective> {
    let mut dirs = Vec::new();
    for s in spec.split(',') {
        if s.len() == 0 { continue }
        let mut parts = s.split('=');
        let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
            (Some(part0), None, None) => {
                // if the single argument is a log-level string or number,
                // treat that as a global fallback
                match parse_log_level(part0) {
                    Some(num) => (num, None),
                    None => (::MAX_LOG_LEVEL, Some(part0)),
                }
            }
            (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
            (Some(part0), Some(part1), None) => {
                match parse_log_level(part1) {
                    Some(num) => (num, Some(part0)),
                    _ => {
                        println!("warning: invalid logging spec '{}', \
                                 ignoring it", part1);
                        continue
                    }
                }
            },
            _ => {
                println!("warning: invalid logging spec '{}', \
                         ignoring it", s);
                continue
            }
        };
        dirs.push(LogDirective {
            name: name.map(|s| s.to_string()),
            level: log_level,
        });
    }
    return dirs;
}

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

    #[test]
    fn parse_logging_spec_valid() {
        let dirs = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_string()));
        assert_eq!(dirs[2].level, 4);
    }

    #[test]
    fn parse_logging_spec_invalid_crate() {
        // test parse_logging_spec with multiple = in specification
        let dirs = parse_logging_spec("crate1::mod1=1=2,crate2=4");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
    }

    #[test]
    fn parse_logging_spec_invalid_log_level() {
        // test parse_logging_spec with 'noNumber' as log level
        let dirs = parse_logging_spec("crate1::mod1=noNumber,crate2=4");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
    }

    #[test]
    fn parse_logging_spec_string_log_level() {
        // test parse_logging_spec with 'warn' as log level
        let dirs = parse_logging_spec("crate1::mod1=wrong,crate2=warn");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, ::WARN);
    }

    #[test]
    fn parse_logging_spec_empty_log_level() {
        // test parse_logging_spec with '' as log level
        let dirs = parse_logging_spec("crate1::mod1=wrong,crate2=");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
    }

    #[test]
    fn parse_logging_spec_global() {
        // test parse_logging_spec with no crate
        let dirs = parse_logging_spec("warn,crate2=4");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 2);
        assert_eq!(dirs[0].name, None);
        assert_eq!(dirs[0].level, 2);
        assert_eq!(dirs[1].name, Some("crate2".to_string()));
        assert_eq!(dirs[1].level, 4);
    }
}
<|endoftext|>


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

use std::ascii::AsciiExt;
use std::cmp;

#[derive(Debug, Clone)]
pub struct LogDirective {
    pub name: Option<String>,
    pub level: u32,
}

pub const LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO", "DEBUG"];

/// Parse an individual log level that is either a number or a symbolic log level
fn parse_log_level(level: &str) -> Option<u32> {
    level.parse::<u32>()
         .ok()
         .or_else(|| {
             let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
             pos.map(|p| p as u32 + 1)
         })
         .map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
}

/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo")
/// and return a vector with log directives.
///
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in
/// std::).  Also supports string log levels of error, warn, info, and debug
pub fn parse_logging_spec(spec: &str) -> (Vec<LogDirective>, Option<String>) {
    let mut dirs = Vec::new();

    let mut parts = spec.split('/');
    let mods = parts.next();
    let filter = parts.next();
    if parts.next().is_some() {
        println!("warning: invalid logging spec '{}', ignoring it (too many '/'s)",
                 spec);
        return (dirs, None);
    }
    mods.map(|m| {
        for s in m.split(',') {
            if s.is_empty() {
                continue
            }
            let mut parts = s.split('=');
            let (log_level, name) = match (parts.next(),
                                           parts.next().map(|s| s.trim()),
                                           parts.next()) {
                (Some(part0), None, None) => {
                    // if the single argument is a log-level string or number,
                    // treat that as a global fallback
                    match parse_log_level(part0) {
                        Some(num) => (num, None),
                        None => (::MAX_LOG_LEVEL, Some(part0)),
                    }
                }
                (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
                (Some(part0), Some(part1), None) => {
                    match parse_log_level(part1) {
                        Some(num) => (num, Some(part0)),
                        _ => {
                            println!("warning: invalid logging spec '{}', ignoring it", part1);
                            continue
                        }
                    }
                }
                _ => {
                    println!("warning: invalid logging spec '{}', ignoring it", s);
                    continue
                }
            };
            dirs.push(LogDirective {
                name: name.map(str::to_owned),
                level: log_level,
            });
        }
    });

    (dirs, filter.map(str::to_owned))
}

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

    #[test]
    fn parse_logging_spec_valid() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4");
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_owned()));
        assert_eq!(dirs[2].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_invalid_crate() {
        // test parse_logging_spec with multiple = in specification
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_owned()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_invalid_log_level() {
        // test parse_logging_spec with 'noNumber' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=4");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_owned()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_string_log_level() {
        // test parse_logging_spec with 'warn' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_owned()));
        assert_eq!(dirs[0].level, ::WARN);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_empty_log_level() {
        // test parse_logging_spec with '' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_owned()));
        assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_global() {
        // test parse_logging_spec with no crate
        let (dirs, filter) = parse_logging_spec("warn,crate2=4");
        assert_eq!(dirs.len(), 2);
        assert_eq!(dirs[0].name, None);
        assert_eq!(dirs[0].level, 2);
        assert_eq!(dirs[1].name, Some("crate2".to_owned()));
        assert_eq!(dirs[1].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_valid_filter() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4/abc");
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_owned()));
        assert_eq!(dirs[2].level, 4);
        assert!(filter.is_some() && filter.unwrap().to_owned() == "abc");
    }

    #[test]
    fn parse_logging_spec_invalid_crate_filter() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4/a.c");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_owned()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_some() && filter.unwrap().to_owned() == "a.c");
    }

    #[test]
    fn parse_logging_spec_empty_with_filter() {
        let (dirs, filter) = parse_logging_spec("crate1/a*c");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate1".to_owned()));
        assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
        assert!(filter.is_some() && filter.unwrap().to_owned() == "a*c");
    }
}
<commit_msg>Use if-let rather than map() in parse_logging_spec.<commit_after>// Copyright 2014 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.

use std::ascii::AsciiExt;
use std::cmp;

#[derive(Debug, Clone)]
pub struct LogDirective {
    pub name: Option<String>,
    pub level: u32,
}

pub const LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO", "DEBUG"];

/// Parse an individual log level that is either a number or a symbolic log level
fn parse_log_level(level: &str) -> Option<u32> {
    level.parse::<u32>()
         .ok()
         .or_else(|| {
             let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
             pos.map(|p| p as u32 + 1)
         })
         .map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
}

/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo")
/// and return a vector with log directives.
///
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in
/// std::).  Also supports string log levels of error, warn, info, and debug
pub fn parse_logging_spec(spec: &str) -> (Vec<LogDirective>, Option<String>) {
    let mut dirs = Vec::new();

    let mut parts = spec.split('/');
    let mods = parts.next();
    let filter = parts.next();
    if parts.next().is_some() {
        println!("warning: invalid logging spec '{}', ignoring it (too many '/'s)",
                 spec);
        return (dirs, None);
    }
    if let Some(m) = mods {
        for s in m.split(',') {
            if s.is_empty() {
                continue
            }
            let mut parts = s.split('=');
            let (log_level, name) = match (parts.next(),
                                           parts.next().map(|s| s.trim()),
                                           parts.next()) {
                (Some(part0), None, None) => {
                    // if the single argument is a log-level string or number,
                    // treat that as a global fallback
                    match parse_log_level(part0) {
                        Some(num) => (num, None),
                        None => (::MAX_LOG_LEVEL, Some(part0)),
                    }
                }
                (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
                (Some(part0), Some(part1), None) => {
                    match parse_log_level(part1) {
                        Some(num) => (num, Some(part0)),
                        _ => {
                            println!("warning: invalid logging spec '{}', ignoring it", part1);
                            continue
                        }
                    }
                }
                _ => {
                    println!("warning: invalid logging spec '{}', ignoring it", s);
                    continue
                }
            };
            dirs.push(LogDirective {
                name: name.map(str::to_owned),
                level: log_level,
            });
        }
    }

    (dirs, filter.map(str::to_owned))
}

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

    #[test]
    fn parse_logging_spec_valid() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4");
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_owned()));
        assert_eq!(dirs[2].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_invalid_crate() {
        // test parse_logging_spec with multiple = in specification
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_owned()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_invalid_log_level() {
        // test parse_logging_spec with 'noNumber' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=4");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_owned()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_string_log_level() {
        // test parse_logging_spec with 'warn' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_owned()));
        assert_eq!(dirs[0].level, ::WARN);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_empty_log_level() {
        // test parse_logging_spec with '' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_owned()));
        assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_global() {
        // test parse_logging_spec with no crate
        let (dirs, filter) = parse_logging_spec("warn,crate2=4");
        assert_eq!(dirs.len(), 2);
        assert_eq!(dirs[0].name, None);
        assert_eq!(dirs[0].level, 2);
        assert_eq!(dirs[1].name, Some("crate2".to_owned()));
        assert_eq!(dirs[1].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_valid_filter() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4/abc");
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_owned()));
        assert_eq!(dirs[2].level, 4);
        assert!(filter.is_some() && filter.unwrap().to_owned() == "abc");
    }

    #[test]
    fn parse_logging_spec_invalid_crate_filter() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4/a.c");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_owned()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_some() && filter.unwrap().to_owned() == "a.c");
    }

    #[test]
    fn parse_logging_spec_empty_with_filter() {
        let (dirs, filter) = parse_logging_spec("crate1/a*c");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate1".to_owned()));
        assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
        assert!(filter.is_some() && filter.unwrap().to_owned() == "a*c");
    }
}
<|endoftext|>


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

/*!

Rust MIR: a lowered representation of Rust. Also: an experiment!

*/

#![crate_name = "rustc_mir"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![cfg_attr(not(stage0), deny(warnings))]

#![feature(rustc_private)]

#[macro_use] extern crate log;
extern crate graphviz as dot;
extern crate rustc;
extern crate rustc_data_structures;
extern crate rustc_front;
extern crate rustc_back;
extern crate syntax;

pub mod build;
pub mod graphviz;
mod hair;
pub mod mir_map;
pub mod pretty;
pub mod transform;
<commit_msg>rustc_mir: Mark the crate as unstable<commit_after>// Copyright 2014 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.

/*!

Rust MIR: a lowered representation of Rust. Also: an experiment!

*/

#![crate_name = "rustc_mir"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![cfg_attr(not(stage0), deny(warnings))]
#![unstable(feature = "rustc_private", issue = "27812")]

#![feature(rustc_private)]
#![feature(staged_api)]

#[macro_use] extern crate log;
extern crate graphviz as dot;
extern crate rustc;
extern crate rustc_data_structures;
extern crate rustc_front;
extern crate rustc_back;
extern crate syntax;

pub mod build;
pub mod graphviz;
mod hair;
pub mod mir_map;
pub mod pretty;
pub mod transform;
<|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.

//! Operations on ASCII strings and characters.

use to_str::{ToStr,ToStrConsume};
use str;
use str::StrSlice;
use cast;
use old_iter::BaseIter;
use iterator::IteratorUtil;
use vec::{CopyableVector, ImmutableVector, OwnedVector};

/// Datatype to hold one ascii character. It is 8 bit long.
#[deriving(Clone, Eq)]
pub struct Ascii { priv chr: u8 }

impl Ascii {
    /// Converts a ascii character into a `u8`.
    #[inline(always)]
    pub fn to_byte(self) -> u8 {
        self.chr
    }

    /// Converts a ascii character into a `char`.
    #[inline(always)]
    pub fn to_char(self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline(always)]
    pub fn to_lower(self) -> Ascii {
        if self.chr >= 65 && self.chr <= 90 {
            Ascii{chr: self.chr | 0x20 }
        } else {
            self
        }
    }

    /// Convert to uppercase.
    #[inline(always)]
    pub fn to_upper(self) -> Ascii {
        if self.chr >= 97 && self.chr <= 122 {
            Ascii{chr: self.chr & !0x20 }
        } else {
            self
        }
    }

    /// Compares two ascii characters of equality, ignoring case.
    #[inline(always)]
    pub fn eq_ignore_case(self, other: Ascii) -> bool {
        self.to_lower().chr == other.to_lower().chr
    }
}

impl ToStr for Ascii {
    #[inline(always)]
    fn to_str(&self) -> ~str { str::from_bytes(['\'' as u8, self.chr, '\'' as u8]) }
}

/// Trait for converting into an ascii type.
pub trait AsciiCast<T> {
    /// Convert to an ascii type
    fn to_ascii(&self) -> T;

    /// Check if convertible to ascii
    fn is_ascii(&self) -> bool;
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        unsafe{ cast::transmute(*self) }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self str {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        let (p,len): (*u8, uint) = unsafe{ cast::transmute(*self) };
        unsafe{ cast::transmute((p, len - 1))}
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        self.bytes_iter().all(|b| b.is_ascii())
    }
}

impl AsciiCast<Ascii> for u8 {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self & 128 == 0u8
    }
}

impl AsciiCast<Ascii> for char {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self as u8 }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self - ('\x7F' & *self) == '\x00'
    }
}

/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast {
    /// Take ownership and cast to an ascii vector without trailing zero element.
    fn to_ascii_consume(self) -> ~[Ascii];
}

impl OwnedAsciiCast for ~[u8] {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        unsafe {cast::transmute(self)}
    }
}

impl OwnedAsciiCast for ~str {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        let mut s = self;
        unsafe {
            str::raw::pop_byte(&mut s);
            cast::transmute(s)
        }
    }
}

/// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str`
pub trait AsciiStr {
    /// Convert to a string.
    fn to_str_ascii(&self) -> ~str;

    /// Convert to vector representing a lower cased ascii string.
    fn to_lower(&self) -> ~[Ascii];

    /// Convert to vector representing a upper cased ascii string.
    fn to_upper(&self) -> ~[Ascii];

}

impl<'self> AsciiStr for &'self [Ascii] {
    #[inline(always)]
    fn to_str_ascii(&self) -> ~str {
        let mut cpy = self.to_owned();
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }

    #[inline(always)]
    fn to_lower(&self) -> ~[Ascii] {
        self.map(|a| a.to_lower())
    }

    #[inline(always)]
    fn to_upper(&self) -> ~[Ascii] {
        self.map(|a| a.to_upper())
    }
}

impl ToStrConsume for ~[Ascii] {
    #[inline(always)]
    fn to_str_consume(self) -> ~str {
        let mut cpy = self;
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }
}

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

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
        (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
    )

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().to_byte(), 65u8);
        assert_eq!(65u8.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_byte(), 65u8);

        assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
        assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
        assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
        assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');

        assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
        assert_eq!('['.to_ascii().to_lower().to_char(), '[');
        assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
        assert_eq!('{'.to_ascii().to_upper().to_char(), '{');

        assert!("banana".iter().all(|c| c.is_ascii()));
        assert!(!"ประเทศไทย中华Việt Nam".iter().all(|c| c.is_ascii()));
    }

    #[test]
    fn test_ascii_vec() {
        assert_eq!((&[40u8, 32u8, 59u8]).to_ascii(), v2ascii!([40, 32, 59]));
        assert_eq!("( ;".to_ascii(),                 v2ascii!([40, 32, 59]));
        // FIXME: #5475 borrowchk error, owned vectors do not live long enough
        // if chained-from directly
        let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
        let v = ~"( ;";              assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));

        assert_eq!("abCDef&?#".to_ascii().to_lower().to_str_ascii(), ~"abcdef&?#");
        assert_eq!("abCDef&?#".to_ascii().to_upper().to_str_ascii(), ~"ABCDEF&?#");

        assert_eq!("".to_ascii().to_lower().to_str_ascii(), ~"");
        assert_eq!("YMCA".to_ascii().to_lower().to_str_ascii(), ~"ymca");
        assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().to_str_ascii(), ~"ABCDEFXYZ:.;");

        assert!("".is_ascii());
        assert!("a".is_ascii());
        assert!(!"\u2009".is_ascii());

    }

    #[test]
    fn test_owned_ascii_vec() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(~"( ;".to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~"( ;".to_ascii_consume_with_null(), v2ascii!(~[40, 32, 59, 0]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume_with_null(),
        //           v2ascii!(~[40, 32, 59, 0]));
    }

    #[test]
    fn test_ascii_to_str() { assert_eq!(v2ascii!([40, 32, 59]).to_str_ascii(), ~"( ;"); }

    #[test]
    fn test_ascii_to_str_consume() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(v2ascii!(~[40, 32, 59]).to_str_consume(), ~"( ;");
    }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
}
<commit_msg>fix tests, remove some warnings<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.

//! Operations on ASCII strings and characters.

use to_str::{ToStr,ToStrConsume};
use str;
use str::StrSlice;
use cast;
use old_iter::BaseIter;
use iterator::IteratorUtil;
use vec::{CopyableVector, ImmutableVector, OwnedVector};

/// Datatype to hold one ascii character. It is 8 bit long.
#[deriving(Clone, Eq)]
pub struct Ascii { priv chr: u8 }

impl Ascii {
    /// Converts a ascii character into a `u8`.
    #[inline(always)]
    pub fn to_byte(self) -> u8 {
        self.chr
    }

    /// Converts a ascii character into a `char`.
    #[inline(always)]
    pub fn to_char(self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline(always)]
    pub fn to_lower(self) -> Ascii {
        if self.chr >= 65 && self.chr <= 90 {
            Ascii{chr: self.chr | 0x20 }
        } else {
            self
        }
    }

    /// Convert to uppercase.
    #[inline(always)]
    pub fn to_upper(self) -> Ascii {
        if self.chr >= 97 && self.chr <= 122 {
            Ascii{chr: self.chr & !0x20 }
        } else {
            self
        }
    }

    /// Compares two ascii characters of equality, ignoring case.
    #[inline(always)]
    pub fn eq_ignore_case(self, other: Ascii) -> bool {
        self.to_lower().chr == other.to_lower().chr
    }
}

impl ToStr for Ascii {
    #[inline(always)]
    fn to_str(&self) -> ~str { str::from_bytes(['\'' as u8, self.chr, '\'' as u8]) }
}

/// Trait for converting into an ascii type.
pub trait AsciiCast<T> {
    /// Convert to an ascii type
    fn to_ascii(&self) -> T;

    /// Check if convertible to ascii
    fn is_ascii(&self) -> bool;
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        unsafe{ cast::transmute(*self) }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self str {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        let (p,len): (*u8, uint) = unsafe{ cast::transmute(*self) };
        unsafe{ cast::transmute((p, len - 1))}
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        self.bytes_iter().all(|b| b.is_ascii())
    }
}

impl AsciiCast<Ascii> for u8 {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self & 128 == 0u8
    }
}

impl AsciiCast<Ascii> for char {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self as u8 }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self - ('\x7F' & *self) == '\x00'
    }
}

/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast {
    /// Take ownership and cast to an ascii vector without trailing zero element.
    fn to_ascii_consume(self) -> ~[Ascii];
}

impl OwnedAsciiCast for ~[u8] {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        unsafe {cast::transmute(self)}
    }
}

impl OwnedAsciiCast for ~str {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        let mut s = self;
        unsafe {
            str::raw::pop_byte(&mut s);
            cast::transmute(s)
        }
    }
}

/// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str`
pub trait AsciiStr {
    /// Convert to a string.
    fn to_str_ascii(&self) -> ~str;

    /// Convert to vector representing a lower cased ascii string.
    fn to_lower(&self) -> ~[Ascii];

    /// Convert to vector representing a upper cased ascii string.
    fn to_upper(&self) -> ~[Ascii];

}

impl<'self> AsciiStr for &'self [Ascii] {
    #[inline(always)]
    fn to_str_ascii(&self) -> ~str {
        let mut cpy = self.to_owned();
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }

    #[inline(always)]
    fn to_lower(&self) -> ~[Ascii] {
        self.map(|a| a.to_lower())
    }

    #[inline(always)]
    fn to_upper(&self) -> ~[Ascii] {
        self.map(|a| a.to_upper())
    }
}

impl ToStrConsume for ~[Ascii] {
    #[inline(always)]
    fn to_str_consume(self) -> ~str {
        let mut cpy = self;
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }
}

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

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
        (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
    )

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().to_byte(), 65u8);
        assert_eq!(65u8.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_byte(), 65u8);

        assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
        assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
        assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
        assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');

        assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
        assert_eq!('['.to_ascii().to_lower().to_char(), '[');
        assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
        assert_eq!('{'.to_ascii().to_upper().to_char(), '{');

        assert!("banana".iter().all(|c| c.is_ascii()));
        assert!(!"ประเทศไทย中华Việt Nam".iter().all(|c| c.is_ascii()));
    }

    #[test]
    fn test_ascii_vec() {
        assert_eq!((&[40u8, 32u8, 59u8]).to_ascii(), v2ascii!([40, 32, 59]));
        assert_eq!("( ;".to_ascii(),                 v2ascii!([40, 32, 59]));
        // FIXME: #5475 borrowchk error, owned vectors do not live long enough
        // if chained-from directly
        let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
        let v = ~"( ;";              assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));

        assert_eq!("abCDef&?#".to_ascii().to_lower().to_str_ascii(), ~"abcdef&?#");
        assert_eq!("abCDef&?#".to_ascii().to_upper().to_str_ascii(), ~"ABCDEF&?#");

        assert_eq!("".to_ascii().to_lower().to_str_ascii(), ~"");
        assert_eq!("YMCA".to_ascii().to_lower().to_str_ascii(), ~"ymca");
        assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().to_str_ascii(), ~"ABCDEFXYZ:.;");

        assert!("".is_ascii());
        assert!("a".is_ascii());
        assert!(!"\u2009".is_ascii());

    }

    #[test]
    fn test_owned_ascii_vec() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(~"( ;".to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~"( ;".to_ascii_consume_with_null(), v2ascii!(~[40, 32, 59, 0]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume_with_null(),
        //           v2ascii!(~[40, 32, 59, 0]));
    }

    #[test]
    fn test_ascii_to_str() { assert_eq!(v2ascii!([40, 32, 59]).to_str_ascii(), ~"( ;"); }

    #[test]
    fn test_ascii_to_str_consume() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(v2ascii!(~[40, 32, 59]).to_str_consume(), ~"( ;");
    }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
}
<|endoftext|>


<commit_before>use std::hash::{Hash};
use std::slice::{
    Items,
};
use std::fmt;
use test;

// FIXME: These aren't stable, so a public wrapper of node/edge indices
// should be lifetimed just like pointers.
#[deriving(Copy, Clone, Show, PartialEq, PartialOrd, Eq, Hash)]
pub struct NodeIndex(uint);
#[deriving(Copy, Clone, Show, PartialEq, PartialOrd, Eq, Hash)]
pub struct EdgeIndex(uint);

const EdgeEnd: EdgeIndex = EdgeIndex(::std::uint::MAX);
//const InvalidNode: NodeIndex = NodeIndex(::std::uint::MAX);

/// Index into the EdgeIndex arrays
enum Dir {
    Out = 0,
    In = 1
}

#[deriving(Show)]
pub struct Node<N> {
    pub data: N,
    next: [EdgeIndex, ..2],
}

#[deriving(Show, Copy)]
pub struct Edge<E> {
    pub data: E,
    next: [EdgeIndex, ..2],
    a: NodeIndex,
    b: NodeIndex,
}

/// **OGraph\<N, E\>** is a directed graph using an adjacency list representation.
///
/// The graph maintains unique indices for nodes and edges, so both node and edge
/// data may be accessed mutably. Removing nodes or edges from the graph is expensive,
/// while adding is very cheap.
///
/// Based upon the graph implementation in rustc.
//#[deriving(Show)]
pub struct OGraph<N> {
    nodes: Vec<Node<N>>,
    edges: Vec<Edge<()>>,
}

impl<N: fmt::Show> fmt::Show for OGraph<N>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for n in self.nodes.iter() {
            try!(writeln!(f, "{}", n));
        }
        for n in self.edges.iter() {
            try!(writeln!(f, "{}", n));
        }
        Ok(())
    }
}

pub enum Pair<'a, T: 'a> {
    Both(&'a mut T, &'a mut T),
    One(&'a mut T),
    None,
}

pub fn index_twice<T>(slc: &mut [T], a: uint, b: uint) -> Pair<T>
{
    if a == b {
        slc.get_mut(a).map_or(Pair::None, Pair::One)
    } else {
        if a >= slc.len() || b >= slc.len() {
            Pair::None
        } else {
            // safe because a, b are in bounds and distinct
            unsafe {
                let ar = &mut *(slc.unsafe_mut(a) as *mut _);
                let br = &mut *(slc.unsafe_mut(b) as *mut _);
                Pair::Both(ar, br)
            }
        }
    }
}

impl<N> OGraph<N>
//where N: fmt::Show
{
    pub fn new() -> OGraph<N>
    {
        OGraph{nodes: Vec::new(), edges: Vec::new()}
    }

    pub fn add_node(&mut self, data: N) -> NodeIndex
    {
        let node = Node{data: data, next: [EdgeEnd, EdgeEnd]};
        let node_idx = NodeIndex(self.nodes.len());
        self.nodes.push(node);
        node_idx
    }

    pub fn node(&self, a: NodeIndex) -> Option<&N>
    {
        self.nodes.get(a.0).map(|n| &n.data)
    }

    pub fn node_mut(&mut self, a: NodeIndex) -> Option<&mut N>
    {
        self.nodes.get_mut(a.0).map(|n| &mut n.data)
    }

    pub fn neighbors(&self, a: NodeIndex) -> Neighbors<N>
    {
        Neighbors{
            graph: self,
            next: match self.nodes.get(a.0) {
                None => EdgeEnd,
                Some(n) => n.next[0],
            }
        }
    }

    pub fn add_edge(&mut self, a: NodeIndex, b: NodeIndex) -> EdgeIndex
    {
        let edge_idx = EdgeIndex(self.edges.len());
        match index_twice(self.nodes[mut], a.0, b.0) {
            Pair::None => panic!("NodeIndices out of bounds"),
            Pair::One(an) => {
                let edge = Edge {
                    data: (),
                    a: a,
                    b: b,
                    next: an.next,
                };
                an.next[0] = edge_idx;
                an.next[1] = edge_idx;
                self.edges.push(edge);
            }
            Pair::Both(an, bn) => {
                // a and b are different indices
                let edge = Edge {
                    data: (),
                    a: a,
                    b: b,
                    next: [an.next[0], bn.next[1]],
                };
                an.next[0] = edge_idx;
                bn.next[1] = edge_idx;
                self.edges.push(edge);
            }
        }
        edge_idx
    }

    pub fn remove_node(&mut self, a: NodeIndex) -> Option<N>
    {
        match self.nodes.get(a.0) {
            None => return None,
            _ => {}
        }
        // Remove all edges from and to this node.
        loop {
            let next = self.nodes[a.0].next[0];
            if next == EdgeEnd {
                break
            }
            //println!("Rmove edge {}", next);
            self.remove_edge(next);
        }

        loop {
            let next = self.nodes[a.0].next[1];
            if next == EdgeEnd {
                break
            }
            //println!("Rmove edge {}", next);
            self.remove_edge(next);
        }

        //println!("REMOVED EDGES: {}", self);

        // Adjust all node indices affected
        for edge in self.edges.iter_mut() {
            debug_assert!(edge.a != a);
            debug_assert!(edge.b != a);
            if edge.a > a {
                edge.a.0 -= 1;
            }
            if edge.b > a {
                edge.b.0 -= 1;
            }
        }
        self.nodes.remove(a.0).map(|n|n.data)
    }

    pub fn edge_mut(&mut self, e: EdgeIndex) -> &mut Edge<()>
    {
        &mut self.edges[e.0]
    }

    pub fn remove_edge(&mut self, e: EdgeIndex)
    {
        fn update_edge_list(replace: EdgeIndex, fst: EdgeIndex, edges: &mut [Edge<()>], d: Dir) {
            debug_assert!(fst != replace);
            let k = d as uint;
            let edge_next = edges[replace.0].next[k];
            // walk through edge list
            let mut cur = fst;
            while cur != EdgeEnd {
                let curedge = &mut edges[cur.0];
                if curedge.next[k] == replace {
                    //println!("Have to replace link in {}", curedge);
                    curedge.next[k] = edge_next;
                    break
                } else {
                    cur = curedge.next[k];
                }
            }
        }
        // every edge is part of two lists,
        // outgoing and incoming edges.
        // Remove it from both
        let (edge_a, edge_b, edge_next) = match self.edges.get(e.0) {
            None => return,
            Some(x) => (x.a, x.b, x.next),
        };
        {
            // List out from A
            let node = &mut self.nodes[edge_a.0];
            let fst = node.next[0];
            if fst == e {
                node.next[0] = edge_next[0];
            } else {
                update_edge_list(e, fst, self.edges[mut], Dir::Out);
            }
        }
        {
            // List in to B
            let node = &mut self.nodes[edge_b.0];
            let fst = node.next[1];
            if fst == e {
                node.next[1] = edge_next[1];
            } else {
                update_edge_list(e, fst, self.edges[mut], Dir::In);
            }
        }
        self.remove_edge_adjust_indices(e);
    }

    fn remove_edge_adjust_indices(&mut self, e: EdgeIndex) -> Option<()>
    {
        // swap_remove the edge -- only the removed edge
        // and the edge swapped into place are affected and need updating
        // indices.
        let edge = self.edges.swap_remove(e.0).unwrap();
        let (swap_a, swap_b) = match self.edges.get(e.0) {
            // no elment needed to be swapped.
            None => return Some(edge.data),
            Some(ed) => (ed.a, ed.b),
        };
        let swapped_e = EdgeIndex(self.edges.len());

        fn update_edge_list(replace: EdgeIndex, fst: EdgeIndex, new: EdgeIndex, edges: &mut [Edge<()>], d: Dir) {
            debug_assert!(fst != replace);
            let k = d as uint;
            // walk through edge list
            let mut cur = fst;
            while cur != EdgeEnd {
                let curedge = &mut edges[cur.0];
                if curedge.next[k] == replace {
                    //println!("Have to replace link in {}", curedge);
                    curedge.next[k] = new;
                    break
                } else {
                    cur = curedge.next[k];
                }
            }
        }
        {
            // List out from A
            let node = &mut self.nodes[swap_a.0];
            let fst = node.next[0];
            if fst == swapped_e {
                node.next[0] = e;
            } else {
                update_edge_list(swapped_e, fst, e, self.edges[mut], Dir::Out);
            }
        }
        {
            // List in to B
            let node = &mut self.nodes[swap_b.0];
            let fst = node.next[1];
            if fst == swapped_e {
                node.next[1] = e;
            } else {
                update_edge_list(swapped_e, fst, e, self.edges[mut], Dir::In);
            }
        }
        // All that refer to the swapped edge need to update.
        //
        /*
        // Edge lists are fine, so remove the edge and adjust all edge indices in nodes
        let edge_data = self.edges.remove(e.0).unwrap().data;
        for &k in [0u, 1].iter() {
            for node in self.nodes.iter_mut() {
                debug_assert!(node.next[k] != e);
                if node.next[k] != EdgeEnd && node.next[k] > e {
                    node.next[k].0 -= 1;
                }
            }
            for edge in self.edges.iter_mut() {
                debug_assert!(edge.next[k] != e);
                if edge.next[k] != EdgeEnd && edge.next[k] > e {
                    edge.next[k].0 -= 1;
                }
            }
        }
        */
        let edge_data = edge.data;
        Some(edge_data)
    }
}

pub struct Neighbors<'a, N: 'a> {
    graph: &'a OGraph<N>,
    next: EdgeIndex,
}

impl<'a, N> Iterator<NodeIndex> for Neighbors<'a, N>
{
    fn next(&mut self) -> Option<NodeIndex>
    {
        match self.graph.edges.get(self.next.0) {
            None => None,
            Some(edge) => {
                self.next = edge.next[0];
                Some(edge.b)
            }
        }
    }
}

#[bench]
fn bench_inser(b: &mut test::Bencher) {
    let mut og = OGraph::new();
    let fst = og.add_node(0i);
    for x in range(1, 125) {
        let n = og.add_node(x);
        og.add_edge(fst, n);
    }
    b.iter(|| {
        og.add_node(1)
    })
}

#[bench]
fn bench_remove(b: &mut test::Bencher) {
    // removal is very slow in a big graph.
    // and this one doesn't even have many nodes.
    let mut og = OGraph::new();
    let fst = og.add_node(0i);
    let mut prev = fst;
    for x in range(1, 1250) {
        let n = og.add_node(x);
        og.add_edge(prev, n);
        prev = n;
    }
    //println!("{}", og);
    b.iter(|| {
        for _ in range(0, 100i) {
            og.remove_node(fst);
        }
    })
}
<commit_msg>Extract function for walking edge lists<commit_after>use std::hash::{Hash};
use std::slice::{
    Items,
};
use std::fmt;
use test;

// FIXME: These aren't stable, so a public wrapper of node/edge indices
// should be lifetimed just like pointers.
#[deriving(Copy, Clone, Show, PartialEq, PartialOrd, Eq, Hash)]
pub struct NodeIndex(uint);
#[deriving(Copy, Clone, Show, PartialEq, PartialOrd, Eq, Hash)]
pub struct EdgeIndex(uint);

const EdgeEnd: EdgeIndex = EdgeIndex(::std::uint::MAX);
//const InvalidNode: NodeIndex = NodeIndex(::std::uint::MAX);

/// Index into the EdgeIndex arrays
enum Dir {
    Out = 0,
    In = 1
}

#[deriving(Show)]
pub struct Node<N> {
    pub data: N,
    next: [EdgeIndex, ..2],
}

#[deriving(Show, Copy)]
pub struct Edge<E> {
    pub data: E,
    next: [EdgeIndex, ..2],
    a: NodeIndex,
    b: NodeIndex,
}

/// **OGraph\<N, E\>** is a directed graph using an adjacency list representation.
///
/// The graph maintains unique indices for nodes and edges, so both node and edge
/// data may be accessed mutably. Removing nodes or edges from the graph is expensive,
/// while adding is very cheap.
///
/// Based upon the graph implementation in rustc.
//#[deriving(Show)]
pub struct OGraph<N> {
    nodes: Vec<Node<N>>,
    edges: Vec<Edge<()>>,
}

impl<N: fmt::Show> fmt::Show for OGraph<N>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for n in self.nodes.iter() {
            try!(writeln!(f, "{}", n));
        }
        for n in self.edges.iter() {
            try!(writeln!(f, "{}", n));
        }
        Ok(())
    }
}

pub enum Pair<'a, T: 'a> {
    Both(&'a mut T, &'a mut T),
    One(&'a mut T),
    None,
}

pub fn index_twice<T>(slc: &mut [T], a: uint, b: uint) -> Pair<T>
{
    if a == b {
        slc.get_mut(a).map_or(Pair::None, Pair::One)
    } else {
        if a >= slc.len() || b >= slc.len() {
            Pair::None
        } else {
            // safe because a, b are in bounds and distinct
            unsafe {
                let ar = &mut *(slc.unsafe_mut(a) as *mut _);
                let br = &mut *(slc.unsafe_mut(b) as *mut _);
                Pair::Both(ar, br)
            }
        }
    }
}

/// Iterate over an edge list.
fn walk_edge_list<E, F: FnMut(EdgeIndex, &mut Edge<E>) -> bool>(
    fst: EdgeIndex, edges: &mut [Edge<E>], d: Dir, mut f: F)
{
    let k = d as uint;
    let mut cur = fst;
    loop {
        match edges.get_mut(cur.0) {
            None => {
                debug_assert!(cur == EdgeEnd);
                break;
            }
            Some(curedge) => {
                if !f(cur, curedge) {
                    break;
                }
                cur = curedge.next[k];
            }
        }
    }
}

impl<N> OGraph<N>
//where N: fmt::Show
{
    pub fn new() -> OGraph<N>
    {
        OGraph{nodes: Vec::new(), edges: Vec::new()}
    }

    pub fn add_node(&mut self, data: N) -> NodeIndex
    {
        let node = Node{data: data, next: [EdgeEnd, EdgeEnd]};
        let node_idx = NodeIndex(self.nodes.len());
        self.nodes.push(node);
        node_idx
    }

    pub fn node(&self, a: NodeIndex) -> Option<&N>
    {
        self.nodes.get(a.0).map(|n| &n.data)
    }

    pub fn node_mut(&mut self, a: NodeIndex) -> Option<&mut N>
    {
        self.nodes.get_mut(a.0).map(|n| &mut n.data)
    }

    pub fn neighbors(&self, a: NodeIndex) -> Neighbors<N>
    {
        Neighbors{
            graph: self,
            next: match self.nodes.get(a.0) {
                None => EdgeEnd,
                Some(n) => n.next[0],
            }
        }
    }

    pub fn add_edge(&mut self, a: NodeIndex, b: NodeIndex) -> EdgeIndex
    {
        let edge_idx = EdgeIndex(self.edges.len());
        match index_twice(self.nodes[mut], a.0, b.0) {
            Pair::None => panic!("NodeIndices out of bounds"),
            Pair::One(an) => {
                let edge = Edge {
                    data: (),
                    a: a,
                    b: b,
                    next: an.next,
                };
                an.next[0] = edge_idx;
                an.next[1] = edge_idx;
                self.edges.push(edge);
            }
            Pair::Both(an, bn) => {
                // a and b are different indices
                let edge = Edge {
                    data: (),
                    a: a,
                    b: b,
                    next: [an.next[0], bn.next[1]],
                };
                an.next[0] = edge_idx;
                bn.next[1] = edge_idx;
                self.edges.push(edge);
            }
        }
        edge_idx
    }

    pub fn remove_node(&mut self, a: NodeIndex) -> Option<N>
    {
        match self.nodes.get(a.0) {
            None => return None,
            _ => {}
        }
        // Remove all edges from and to this node.
        loop {
            let next = self.nodes[a.0].next[0];
            if next == EdgeEnd {
                break
            }
            //println!("Rmove edge {}", next);
            self.remove_edge(next);
        }

        loop {
            let next = self.nodes[a.0].next[1];
            if next == EdgeEnd {
                break
            }
            //println!("Rmove edge {}", next);
            self.remove_edge(next);
        }

        //println!("REMOVED EDGES: {}", self);

        // Adjust all node indices affected
        for edge in self.edges.iter_mut() {
            debug_assert!(edge.a != a);
            debug_assert!(edge.b != a);
            if edge.a > a {
                edge.a.0 -= 1;
            }
            if edge.b > a {
                edge.b.0 -= 1;
            }
        }
        self.nodes.remove(a.0).map(|n|n.data)
    }

    pub fn edge_mut(&mut self, e: EdgeIndex) -> &mut Edge<()>
    {
        &mut self.edges[e.0]
    }

    pub fn remove_edge(&mut self, e: EdgeIndex)
    {
        // every edge is part of two lists,
        // outgoing and incoming edges.
        // Remove it from both
        let (edge_a, edge_b, edge_next) = match self.edges.get(e.0) {
            None => return,
            Some(x) => (x.a, x.b, x.next),
        };
        {
            // List out from A
            let node = match self.nodes.get_mut(edge_a.0) {
                Some(r) => r,
                None => { debug_assert!(false, "Edge.A not in nodes"); return }
            };
            let fst = node.next[0];
            if fst == e {
                node.next[0] = edge_next[0];
            } else {
                walk_edge_list(fst, self.edges[mut], Dir::Out, |eidx, curedge| {
                    if curedge.next[0] == e {
                        curedge.next[0] = edge_next[0];
                        false
                    } else { true }
                });
            }
        }
        {
            // List in to B
            let node = match self.nodes.get_mut(edge_b.0) {
                Some(r) => r,
                None => { debug_assert!(false, "Edge.B not in nodes"); return }
            };
            let fst = node.next[1];
            if fst == e {
                node.next[1] = edge_next[1];
            } else {
                walk_edge_list(fst, self.edges[mut], Dir::In, |eidx, curedge| {
                    if curedge.next[1] == e {
                        curedge.next[1] = edge_next[1];
                        false
                    } else { true }
                });
            }
        }
        self.remove_edge_adjust_indices(e);
    }

    fn remove_edge_adjust_indices(&mut self, e: EdgeIndex) -> Option<()>
    {
        // swap_remove the edge -- only the removed edge
        // and the edge swapped into place are affected and need updating
        // indices.
        let edge = self.edges.swap_remove(e.0).unwrap();
        let (swap_a, swap_b) = match self.edges.get(e.0) {
            // no elment needed to be swapped.
            None => return Some(edge.data),
            Some(ed) => (ed.a, ed.b),
        };
        let swapped_e = EdgeIndex(self.edges.len());

        {
            // List out from A
            let node = &mut self.nodes[swap_a.0];
            let fst = node.next[0];
            if fst == swapped_e {
                node.next[0] = e;
            } else {
                walk_edge_list(fst, self.edges[mut], Dir::Out, |eidx, curedge| {
                    if curedge.next[0] == swapped_e {
                        curedge.next[0] = e;
                        false
                    } else { true }
                });
            }
        }
        {
            // List in to B
            let node = &mut self.nodes[swap_b.0];
            let fst = node.next[1];
            if fst == swapped_e {
                node.next[1] = e;
            } else {
                walk_edge_list(fst, self.edges[mut], Dir::In, |eidx, curedge| {
                    if curedge.next[1] == swapped_e {
                        curedge.next[1] = e;
                        false
                    } else { true }
                });
            }
        }
        // All that refer to the swapped edge need to update.
        //
        /*
        // Edge lists are fine, so remove the edge and adjust all edge indices in nodes
        let edge_data = self.edges.remove(e.0).unwrap().data;
        for &k in [0u, 1].iter() {
            for node in self.nodes.iter_mut() {
                debug_assert!(node.next[k] != e);
                if node.next[k] != EdgeEnd && node.next[k] > e {
                    node.next[k].0 -= 1;
                }
            }
            for edge in self.edges.iter_mut() {
                debug_assert!(edge.next[k] != e);
                if edge.next[k] != EdgeEnd && edge.next[k] > e {
                    edge.next[k].0 -= 1;
                }
            }
        }
        */
        let edge_data = edge.data;
        Some(edge_data)
    }
}

pub struct Neighbors<'a, N: 'a> {
    graph: &'a OGraph<N>,
    next: EdgeIndex,
}

impl<'a, N> Iterator<NodeIndex> for Neighbors<'a, N>
{
    fn next(&mut self) -> Option<NodeIndex>
    {
        match self.graph.edges.get(self.next.0) {
            None => None,
            Some(edge) => {
                self.next = edge.next[0];
                Some(edge.b)
            }
        }
    }
}

#[bench]
fn bench_inser(b: &mut test::Bencher) {
    let mut og = OGraph::new();
    let fst = og.add_node(0i);
    for x in range(1, 125) {
        let n = og.add_node(x);
        og.add_edge(fst, n);
    }
    b.iter(|| {
        og.add_node(1)
    })
}

#[bench]
fn bench_remove(b: &mut test::Bencher) {
    // removal is very slow in a big graph.
    // and this one doesn't even have many nodes.
    let mut og = OGraph::new();
    let fst = og.add_node(0i);
    let mut prev = fst;
    for x in range(1, 1250) {
        let n = og.add_node(x);
        og.add_edge(prev, n);
        prev = n;
    }
    //println!("{}", og);
    b.iter(|| {
        for _ in range(0, 100i) {
            og.remove_node(fst);
        }
    })
}
<|endoftext|>