<commit_before>use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::sync::Arc;

use iron::{Request, Response, Handler, IronResult, IronError};
use iron::{status, method, headers};
use iron::typemap::Key;
use iron::modifiers::Redirect;

use recognizer::Router as Recognizer;
use recognizer::{Match, Params};

pub struct RouterInner {
    // The routers, specialized by method.
    pub routers: HashMap<method::Method, Recognizer<Box<Handler>>>,
    // Routes that accept any method.
    pub wildcard: Recognizer<Box<Handler>>,
    // Used in URL generation.
    pub route_ids: HashMap<String, String>
}

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
pub struct Router {
    inner: Arc<RouterInner>
}

impl Router {
    /// Construct a new, empty `Router`.
    ///
    /// ```
    /// # use router::Router;
    /// let router = Router::new();
    /// ```
    pub fn new() -> Router {
        Router {
            inner: Arc::new(RouterInner {
                routers: HashMap::new(),
                wildcard: Recognizer::new(),
                route_ids: HashMap::new()
            })
        }
    }

    fn mut_inner(&mut self) -> &mut RouterInner {
        Arc::get_mut(&mut self.inner).expect("Cannot modify router at this point.")
    }

    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports glob patterns: `*` for a single wildcard segment and
    /// `:param` for matching storing that segment of the request url in the `Params`
    /// object, which is stored in the request `extensions`.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```ignore
    /// let mut router = Router::new();
    /// router.route(method::Get, "/users/:userid/:friendid", controller, "user_friend");
    /// ```
    ///
    /// `route_id` is a unique name for your route, and is used when generating an URL with
    /// `url_for`.
    ///
    /// The controller provided to route can be any `Handler`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Handler`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, method: method::Method, glob: S, handler: H, route_id: I) -> &mut Router {
        self.mut_inner().routers
            .entry(method)
            .or_insert(Recognizer::new())
            .add(glob.as_ref(), Box::new(handler));
        self.route_id(route_id.as_ref(), glob.as_ref());
        self
    }

    fn route_id(&mut self, id: &str, glob: &str) {
        let mut mut_inner = self.mut_inner();
        let ref mut route_ids = mut_inner.route_ids;

        match route_ids.get(id) {
            Some(other_glob) if glob != other_glob => panic!("Duplicate route_id: {}", id),
            _ => ()
        };

        route_ids.insert(id.to_owned(), glob.to_owned());
    }

    /// Like route, but specialized to the `Get` method.
    pub fn get<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Get, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Post` method.
    pub fn post<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Post, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Put` method.
    pub fn put<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Put, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Delete` method.
    pub fn delete<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Delete, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Head` method.
    pub fn head<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Head, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Patch` method.
    pub fn patch<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Patch, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Options` method.
    pub fn options<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Options, glob, handler, route_id)
    }

    /// Route will match any method, including gibberish.
    /// In case of ambiguity, handlers specific to methods will be preferred.
    pub fn any<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.mut_inner().wildcard.add(glob.as_ref(), Box::new(handler));
        self.route_id(route_id.as_ref(), glob.as_ref());
        self
    }

    fn recognize(&self, method: &method::Method, path: &str)
                     -> Option<Match<&Box<Handler>>> {
        self.inner.routers.get(method).and_then(|router| router.recognize(path).ok())
            .or(self.inner.wildcard.recognize(path).ok())
    }

    fn handle_options(&self, path: &str) -> Response {
        static METHODS: &'static [method::Method] =
            &[method::Get, method::Post, method::Put,
              method::Delete, method::Head, method::Patch];

        // Get all the available methods and return them.
        let mut options = vec![];

        for method in METHODS.iter() {
            self.inner.routers.get(method).map(|router| {
                if let Some(_) = router.recognize(path).ok() {
                    options.push(method.clone());
                }
            });
        }
        // If GET is there, HEAD is also there.
        if options.contains(&method::Get) && !options.contains(&method::Head) {
            options.push(method::Head);
        }

        let mut res = Response::with(status::Ok);
        res.headers.set(headers::Allow(options));
        res
    }

    // Tests for a match by adding or removing a trailing slash.
    fn redirect_slash(&self, req : &Request) -> Option<IronError> {
        let mut url = req.url.clone();
        let mut path = url.path().join("/");

        if let Some(last_char) = path.chars().last() {
            {
                let mut path_segments = url.as_mut().path_segments_mut().unwrap();
                if last_char == '/' {
                    // We didn't recognize anything without a trailing slash; try again with one appended.
                    path.pop();
                    path_segments.pop();
                } else {
                    // We didn't recognize anything with a trailing slash; try again without it.
                    path.push('/');
                    path_segments.push("");
                }
            }
        }

        self.recognize(&req.method, &path).and(
            Some(IronError::new(TrailingSlash,
                                (status::MovedPermanently, Redirect(url))))
        )
    }

    fn handle_method(&self, req: &mut Request, path: &str) -> Option<IronResult<Response>> {
        if let Some(matched) = self.recognize(&req.method, path) {
            req.extensions.insert::<Router>(matched.params);
            req.extensions.insert::<RouterInner>(self.inner.clone());
            Some(matched.handler.handle(req))
        } else { self.redirect_slash(req).and_then(|redirect| Some(Err(redirect))) }
    }
}

impl Key for Router { type Value = Params; }

impl Key for RouterInner { type Value = Arc<RouterInner>; }

impl Handler for Router {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path().join("/");

        self.handle_method(req, &path).unwrap_or_else(||
            match req.method {
                method::Options => Ok(self.handle_options(&path)),
                // For HEAD, fall back to GET. Hyper ensures no response body is written.
                method::Head => {
                    req.method = method::Get;
                    self.handle_method(req, &path).unwrap_or(
                        Err(IronError::new(NoRoute, status::NotFound))
                    )
                }
                _ => Err(IronError::new(NoRoute, status::NotFound))
            }
        )
    }
}

/// The error thrown by router if there is no matching route,
/// it is always accompanied by a NotFound response.
#[derive(Debug, PartialEq, Eq)]
pub struct NoRoute;

impl fmt::Display for NoRoute {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("No matching route found.")
    }
}

impl Error for NoRoute {
    fn description(&self) -> &str { "No Route" }
}

/// The error thrown by router if a request was redirected
/// by adding or removing a trailing slash.
#[derive(Debug, PartialEq, Eq)]
pub struct TrailingSlash;

impl fmt::Display for TrailingSlash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("The request had a trailing slash.")
    }
}

impl Error for TrailingSlash {
    fn description(&self) -> &str { "Trailing Slash" }
}

#[cfg(test)]
mod test {
    use super::Router;
    use iron::{headers, method, status, Request, Response};

    #[test]
    fn test_handle_options_post() {
        let mut router = Router::new();
        router.post("/", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        let resp = router.handle_options("/");
        let headers = resp.headers.get::<headers::Allow>().unwrap();
        let expected = headers::Allow(vec![method::Method::Post]);
        assert_eq!(&expected, headers);
    }

    #[test]
    fn test_handle_options_get_head() {
        let mut router = Router::new();
        router.get("/", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        let resp = router.handle_options("/");
        let headers = resp.headers.get::<headers::Allow>().unwrap();
        let expected = headers::Allow(vec![method::Method::Get, method::Method::Head]);
        assert_eq!(&expected, headers);
    }

    #[test]
    fn test_handle_any_ok() {
        let mut router = Router::new();
        router.post("/post", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        router.any("/post", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        router.put("/post", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        router.any("/get", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "any");

        assert!(router.recognize(&method::Get, "/post").is_ok());
        assert!(router.recognize(&method::Get, "/get").is_ok());
    }

    #[test]
    fn test_request() {
        let mut router = Router::new();
        router.post("/post", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        router.get("/post", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");

        assert!(router.recognize(&method::Post, "/post").is_ok());
        assert!(router.recognize(&method::Get, "/post").is_ok());
        assert!(router.recognize(&method::Put, "/post").is_err());
        assert!(router.recognize(&method::Get, "/post/").is_err());
    }

    #[test]
    fn test_not_found() {
        let mut router = Router::new();
        router.put("/put", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        match router.recognize(&method::Patch, "/patch") {
            Ok(_) => {
                panic!();
            },
            Err(e) => {
                assert_eq!(RouterError::NotFound, e);
            }
        }
    }

    #[test]
    #[should_panic]
    fn test_same_route_id() {
        let mut router = Router::new();
        router.put("/put", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "my_route_id");
        router.get("/get", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "my_route_id");
    }

    #[test]
    fn test_wildcard_regression() {
        let mut router = Router::new();
        router.options("*", |_: &mut Request| Ok(Response::with((status::Ok, ""))), "id1");
        router.put("/upload/*filename", |_: &mut Request| Ok(Response::with((status::Ok, ""))), "id2");
        assert!(router.recognize(&method::Options, "/foo").is_ok());
        assert!(router.recognize(&method::Put, "/foo").is_err());
        assert!(router.recognize(&method::Put, "/upload/foo").is_ok());
    }
}
<commit_msg>Fix compilation<commit_after>use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::sync::Arc;

use iron::{Request, Response, Handler, IronResult, IronError};
use iron::{status, method, headers};
use iron::typemap::Key;
use iron::modifiers::Redirect;

use recognizer::Router as Recognizer;
use recognizer::{Match, Params};

pub struct RouterInner {
    // The routers, specialized by method.
    pub routers: HashMap<method::Method, Recognizer<Box<Handler>>>,
    // Routes that accept any method.
    pub wildcard: Recognizer<Box<Handler>>,
    // Used in URL generation.
    pub route_ids: HashMap<String, String>
}

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
pub struct Router {
    inner: Arc<RouterInner>
}

impl Router {
    /// Construct a new, empty `Router`.
    ///
    /// ```
    /// # use router::Router;
    /// let router = Router::new();
    /// ```
    pub fn new() -> Router {
        Router {
            inner: Arc::new(RouterInner {
                routers: HashMap::new(),
                wildcard: Recognizer::new(),
                route_ids: HashMap::new()
            })
        }
    }

    fn mut_inner(&mut self) -> &mut RouterInner {
        Arc::get_mut(&mut self.inner).expect("Cannot modify router at this point.")
    }

    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports glob patterns: `*` for a single wildcard segment and
    /// `:param` for matching storing that segment of the request url in the `Params`
    /// object, which is stored in the request `extensions`.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```ignore
    /// let mut router = Router::new();
    /// router.route(method::Get, "/users/:userid/:friendid", controller, "user_friend");
    /// ```
    ///
    /// `route_id` is a unique name for your route, and is used when generating an URL with
    /// `url_for`.
    ///
    /// The controller provided to route can be any `Handler`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Handler`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, method: method::Method, glob: S, handler: H, route_id: I) -> &mut Router {
        self.mut_inner().routers
            .entry(method)
            .or_insert(Recognizer::new())
            .add(glob.as_ref(), Box::new(handler));
        self.route_id(route_id.as_ref(), glob.as_ref());
        self
    }

    fn route_id(&mut self, id: &str, glob: &str) {
        let mut mut_inner = self.mut_inner();
        let ref mut route_ids = mut_inner.route_ids;

        match route_ids.get(id) {
            Some(other_glob) if glob != other_glob => panic!("Duplicate route_id: {}", id),
            _ => ()
        };

        route_ids.insert(id.to_owned(), glob.to_owned());
    }

    /// Like route, but specialized to the `Get` method.
    pub fn get<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Get, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Post` method.
    pub fn post<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Post, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Put` method.
    pub fn put<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Put, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Delete` method.
    pub fn delete<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Delete, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Head` method.
    pub fn head<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Head, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Patch` method.
    pub fn patch<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Patch, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Options` method.
    pub fn options<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Options, glob, handler, route_id)
    }

    /// Route will match any method, including gibberish.
    /// In case of ambiguity, handlers specific to methods will be preferred.
    pub fn any<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.mut_inner().wildcard.add(glob.as_ref(), Box::new(handler));
        self.route_id(route_id.as_ref(), glob.as_ref());
        self
    }

    fn recognize(&self, method: &method::Method, path: &str)
                     -> Option<Match<&Box<Handler>>> {
        self.inner.routers.get(method).and_then(|router| router.recognize(path).ok())
            .or(self.inner.wildcard.recognize(path).ok())
    }

    fn handle_options(&self, path: &str) -> Response {
        static METHODS: &'static [method::Method] =
            &[method::Get, method::Post, method::Put,
              method::Delete, method::Head, method::Patch];

        // Get all the available methods and return them.
        let mut options = vec![];

        for method in METHODS.iter() {
            self.inner.routers.get(method).map(|router| {
                if let Some(_) = router.recognize(path).ok() {
                    options.push(method.clone());
                }
            });
        }
        // If GET is there, HEAD is also there.
        if options.contains(&method::Get) && !options.contains(&method::Head) {
            options.push(method::Head);
        }

        let mut res = Response::with(status::Ok);
        res.headers.set(headers::Allow(options));
        res
    }

    // Tests for a match by adding or removing a trailing slash.
    fn redirect_slash(&self, req : &Request) -> Option<IronError> {
        let mut url = req.url.clone();
        let mut path = url.path().join("/");

        if let Some(last_char) = path.chars().last() {
            {
                let mut path_segments = url.as_mut().path_segments_mut().unwrap();
                if last_char == '/' {
                    // We didn't recognize anything without a trailing slash; try again with one appended.
                    path.pop();
                    path_segments.pop();
                } else {
                    // We didn't recognize anything with a trailing slash; try again without it.
                    path.push('/');
                    path_segments.push("");
                }
            }
        }

        self.recognize(&req.method, &path).and(
            Some(IronError::new(TrailingSlash,
                                (status::MovedPermanently, Redirect(url))))
        )
    }

    fn handle_method(&self, req: &mut Request, path: &str) -> Option<IronResult<Response>> {
        if let Some(matched) = self.recognize(&req.method, path) {
            req.extensions.insert::<Router>(matched.params);
            req.extensions.insert::<RouterInner>(self.inner.clone());
            Some(matched.handler.handle(req))
        } else { self.redirect_slash(req).and_then(|redirect| Some(Err(redirect))) }
    }
}

impl Key for Router { type Value = Params; }

impl Key for RouterInner { type Value = Arc<RouterInner>; }

impl Handler for Router {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path().join("/");

        self.handle_method(req, &path).unwrap_or_else(||
            match req.method {
                method::Options => Ok(self.handle_options(&path)),
                // For HEAD, fall back to GET. Hyper ensures no response body is written.
                method::Head => {
                    req.method = method::Get;
                    self.handle_method(req, &path).unwrap_or(
                        Err(IronError::new(NoRoute, status::NotFound))
                    )
                }
                _ => Err(IronError::new(NoRoute, status::NotFound))
            }
        )
    }
}

/// The error thrown by router if there is no matching route,
/// it is always accompanied by a NotFound response.
#[derive(Debug, PartialEq, Eq)]
pub struct NoRoute;

impl fmt::Display for NoRoute {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("No matching route found.")
    }
}

impl Error for NoRoute {
    fn description(&self) -> &str { "No Route" }
}

/// The error thrown by router if a request was redirected
/// by adding or removing a trailing slash.
#[derive(Debug, PartialEq, Eq)]
pub struct TrailingSlash;

impl fmt::Display for TrailingSlash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("The request had a trailing slash.")
    }
}

impl Error for TrailingSlash {
    fn description(&self) -> &str { "Trailing Slash" }
}

#[cfg(test)]
mod test {
    use super::Router;
    use iron::{headers, method, status, Request, Response};

    #[test]
    fn test_handle_options_post() {
        let mut router = Router::new();
        router.post("/", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        let resp = router.handle_options("/");
        let headers = resp.headers.get::<headers::Allow>().unwrap();
        let expected = headers::Allow(vec![method::Method::Post]);
        assert_eq!(&expected, headers);
    }

    #[test]
    fn test_handle_options_get_head() {
        let mut router = Router::new();
        router.get("/", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        let resp = router.handle_options("/");
        let headers = resp.headers.get::<headers::Allow>().unwrap();
        let expected = headers::Allow(vec![method::Method::Get, method::Method::Head]);
        assert_eq!(&expected, headers);
    }

    #[test]
    fn test_handle_any_ok() {
        let mut router = Router::new();
        router.post("/post", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        router.any("/post", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        router.put("/post", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        router.any("/get", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "any");

        assert!(router.recognize(&method::Get, "/post").is_some());
        assert!(router.recognize(&method::Get, "/get").is_some());
    }

    #[test]
    fn test_request() {
        let mut router = Router::new();
        router.post("/post", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        router.get("/post", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");

        assert!(router.recognize(&method::Post, "/post").is_some());
        assert!(router.recognize(&method::Get, "/post").is_some());
        assert!(router.recognize(&method::Put, "/post").is_none());
        assert!(router.recognize(&method::Get, "/post/").is_none());
    }

    #[test]
    fn test_not_found() {
        let mut router = Router::new();
        router.put("/put", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        assert!(router.recognize(&method::Patch, "/patch").is_none());
    }

    #[test]
    #[should_panic]
    fn test_same_route_id() {
        let mut router = Router::new();
        router.put("/put", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "my_route_id");
        router.get("/get", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "my_route_id");
    }

    #[test]
    fn test_wildcard_regression() {
        let mut router = Router::new();
        router.options("*", |_: &mut Request| Ok(Response::with((status::Ok, ""))), "id1");
        router.put("/upload/*filename", |_: &mut Request| Ok(Response::with((status::Ok, ""))), "id2");
        assert!(router.recognize(&method::Options, "/foo").is_some());
        assert!(router.recognize(&method::Put, "/foo").is_none());
        assert!(router.recognize(&method::Put, "/upload/foo").is_some());
    }
}
<|endoftext|>


<commit_before>//! Functions for deserializing datatypes used by the protocol
use errors::Result;
use u128;

use std::io::Read;
use std::string;

use byteorder::{BigEndian, ReadBytesExt};

/// Read a single bool from the Reader
pub fn read_bool<R: Read>(reader: &mut R) -> Result<bool> {
    let byte = read_u8(reader)?;
    match byte {
        0 => Ok(false),
        1 => Ok(true),
        _ => bail!("Bool had invalid value {}", byte),
    }
}

/* Many of these functions obviously just duplicate functions from byteorder.
 * I keep them here to keep everything nicely organized, and also to make
 * things easier in the clientbound packet event macros.
 *
 * Also it ensures that if the MC modern protocol is changed, we can simply
 * change these functions without breaking anything. */

/// Read a single i8 from the Reader
pub fn read_i8<R: Read>(reader: &mut R) -> Result<i8> {
    Ok(reader.read_i8()?)
}

/// Read a single u8 from the Reader
pub fn read_u8<R: Read>(reader: &mut R) -> Result<u8> {
    Ok(reader.read_u8()?)
}

/// Read a single i16 from the Reader
pub fn read_i16<R: Read>(reader: &mut R) -> Result<i16> {
    Ok(reader.read_i16::<BigEndian>()?)
}

/// Read a single u16 from the Reader
pub fn read_u16<R: Read>(reader: &mut R) -> Result<u16> {
    Ok(reader.read_u16::<BigEndian>()?)
}

/// Read a single i32 from the Reader
pub fn read_i32<R: Read>(reader: &mut R) -> Result<i32> {
    Ok(reader.read_i32::<BigEndian>()?)
}

/// Read a single i64 from the Reader
pub fn read_i64<R: Read>(reader: &mut R) -> Result<i64> {
    Ok(reader.read_i64::<BigEndian>()?)
}

/// Read a single u64 from the Reader
pub fn read_u64<R: Read>(reader: &mut R) -> Result<u64> {
    Ok(reader.read_u64::<BigEndian>()?)
}

/// Read a single f32 from the Reader
pub fn read_f32<R: Read>(reader: &mut R) -> Result<f32> {
    Ok(reader.read_f32::<BigEndian>()?)
}

/// Read a single f64 from the Reader
pub fn read_f64<R: Read>(reader: &mut R) -> Result<f64> {
    Ok(reader.read_f64::<BigEndian>()?)
}

/// Read a length-prefixed utf-8 String from the Reader
#[allow(non_snake_case)]
pub fn read_String<R: Read>(reader: &mut R) -> Result<String> {
    let length = read_varint(reader)? as usize;

    if length > (1 << 16) {
        bail!("read_string refusing to read string due to its length");
    }

    /* FIXME can we do this without a double copy? */
    let mut buf = vec![0; length];
    reader.read_exact(&mut buf)?;

    Ok(string::String::from_utf8_lossy(&buf).into_owned())
}

/// Read a Minecraft-style varint, which currently fits into a i32
pub fn read_varint<R: Read>(reader: &mut R) -> Result<i32> {
    let mut radix: u64 = 128;
    let msb: u8 = 0b10000000; /* Only the MSB set */

    /* First we read the varint as an unsigned int */
    let mut buf = reader.read_u8()?;
    let mut res = (buf & (!msb)) as u64;

    let mut i: usize = 0;
    while (buf & msb) != 0 {
        if i >= 5 {
            bail!("VarInt is too long");
        }

        i += 1;
        buf = reader.read_u8()?;
        res += ((buf & (!msb)) as u64) * radix;
        radix <<= 7;
    }

    /* Now we convert it to signed */
    if res >= 4294967296 {
        bail!("Received too large varint");
    }

    if res > 2147483647 {
        return Ok((4294967296 - res) as i32 * -1);
    } else {
        return Ok(res as i32);
    }
}

/// Read length-prefixed bytearray where the length is given as a varint
pub fn read_prefixed_bytearray<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
    let length = read_varint(reader)?;
    let mut tmp = vec![0; length as usize];
    reader.read_exact(&mut tmp)?;
    Ok(tmp)
}

/// Read length-prefixed varint array where the length is given as a varint
pub fn read_prefixed_varintarray<R: Read>(reader: &mut R) -> Result<Vec<i32>> {
    let length = read_varint(reader)?;
    let mut tmp = Vec::with_capacity(length as usize);
    for _ in 0..length {
        tmp.push(read_varint(reader)?);
    }
    Ok(tmp)
}

/// Read a uuid encoded as 16 bytes
pub fn read_uuid<R: Read>(reader: &mut R) -> Result<u128> {
    let a = read_u64(reader)?;
    let b = read_u64(reader)?;
    Ok(u128(a, b))
}

/// Read a uuid encoded as a string
///
/// Either with or without dashes.
pub fn read_uuid_str<R: Read>(reader: &mut R) -> Result<u128> {
    /* If it's without dashes, then it'll be 32 characters long, else it'll
     * be 36 characters long, so we read 32 characters first and see if it
     * contains any dahes */

    let tmp = read_String(reader)?.replace("-", "");

    let a = match u64::from_str_radix(&tmp[..16], 16) {
        Ok(x) => x,
        Err(_) => bail!("Invalid hex in first half of uuid_str"),
    };
    let b = match u64::from_str_radix(&tmp[16..], 16) {
        Ok(x) => x,
        Err(_) => bail!("Invalid hex in second half of uuid_str"),
    };
    Ok(u128(a, b))
}

/// Read a bytearray to the end of the reader
pub fn read_bytearray_to_end<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
    let mut tmp = Vec::new();
    reader.read_to_end(&mut tmp)?;
    Ok(tmp)
}

/// Alias for read_bytearray_to_end
pub fn read_bytearray<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
    read_bytearray_to_end(reader)
}

/// Read a position as described on wiki.vg, i.e. x/y/z given as an u64
pub fn read_position<R: Read>(reader: &mut R) -> Result<(i32, i32, i32)> {
    let val = read_u64(reader)?;
    let mut x = (val >> 38) as i32;
    let mut y = ((val >> 26) & 0xfff) as i32;
    let mut z = (val & 0x3ffffff) as i32;
    if x >= 1 << 25 {
        x -= 1 << 26;
    }
    if y >= 1 << 11 {
        y -= 1 << 12;
    }
    if z >= 2 << 25 {
        z -= 1 << 26;
    }
    Ok((x, y, z))
}
<commit_msg>Avoid double copy in read_String<commit_after>//! Functions for deserializing datatypes used by the protocol
use errors::Result;
use u128;

use std::io::Read;

use byteorder::{BigEndian, ReadBytesExt};

/// Read a single bool from the Reader
pub fn read_bool<R: Read>(reader: &mut R) -> Result<bool> {
    let byte = read_u8(reader)?;
    match byte {
        0 => Ok(false),
        1 => Ok(true),
        _ => bail!("Bool had invalid value {}", byte),
    }
}

/* Many of these functions obviously just duplicate functions from byteorder.
 * I keep them here to keep everything nicely organized, and also to make
 * things easier in the clientbound packet event macros.
 *
 * Also it ensures that if the MC modern protocol is changed, we can simply
 * change these functions without breaking anything. */

/// Read a single i8 from the Reader
pub fn read_i8<R: Read>(reader: &mut R) -> Result<i8> {
    Ok(reader.read_i8()?)
}

/// Read a single u8 from the Reader
pub fn read_u8<R: Read>(reader: &mut R) -> Result<u8> {
    Ok(reader.read_u8()?)
}

/// Read a single i16 from the Reader
pub fn read_i16<R: Read>(reader: &mut R) -> Result<i16> {
    Ok(reader.read_i16::<BigEndian>()?)
}

/// Read a single u16 from the Reader
pub fn read_u16<R: Read>(reader: &mut R) -> Result<u16> {
    Ok(reader.read_u16::<BigEndian>()?)
}

/// Read a single i32 from the Reader
pub fn read_i32<R: Read>(reader: &mut R) -> Result<i32> {
    Ok(reader.read_i32::<BigEndian>()?)
}

/// Read a single i64 from the Reader
pub fn read_i64<R: Read>(reader: &mut R) -> Result<i64> {
    Ok(reader.read_i64::<BigEndian>()?)
}

/// Read a single u64 from the Reader
pub fn read_u64<R: Read>(reader: &mut R) -> Result<u64> {
    Ok(reader.read_u64::<BigEndian>()?)
}

/// Read a single f32 from the Reader
pub fn read_f32<R: Read>(reader: &mut R) -> Result<f32> {
    Ok(reader.read_f32::<BigEndian>()?)
}

/// Read a single f64 from the Reader
pub fn read_f64<R: Read>(reader: &mut R) -> Result<f64> {
    Ok(reader.read_f64::<BigEndian>()?)
}

/// Read a length-prefixed utf-8 String from the Reader
#[allow(non_snake_case)]
pub fn read_String<R: Read>(reader: &mut R) -> Result<String> {
    let length = read_varint(reader)? as usize;

    if length > (1 << 16) {
        bail!("read_string refusing to read string due to its length");
    }

    let mut ret = String::with_capacity(length);
    let read = reader.take(length as u64).read_to_string(&mut ret)?;

    if read != length {
        bail!("read_String expected a string with length {} but was only able to read {} bytes", length, read);
    }

    Ok(ret)
}

/// Read a Minecraft-style varint, which currently fits into a i32
pub fn read_varint<R: Read>(reader: &mut R) -> Result<i32> {
    let mut radix: u64 = 128;
    let msb: u8 = 0b10000000; /* Only the MSB set */

    /* First we read the varint as an unsigned int */
    let mut buf = reader.read_u8()?;
    let mut res = (buf & (!msb)) as u64;

    let mut i: usize = 0;
    while (buf & msb) != 0 {
        if i >= 5 {
            bail!("VarInt is too long");
        }

        i += 1;
        buf = reader.read_u8()?;
        res += ((buf & (!msb)) as u64) * radix;
        radix <<= 7;
    }

    /* Now we convert it to signed */
    if res >= 4294967296 {
        bail!("Received too large varint");
    }

    if res > 2147483647 {
        return Ok((4294967296 - res) as i32 * -1);
    } else {
        return Ok(res as i32);
    }
}

/// Read length-prefixed bytearray where the length is given as a varint
pub fn read_prefixed_bytearray<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
    let length = read_varint(reader)?;
    let mut tmp = vec![0; length as usize];
    reader.read_exact(&mut tmp)?;
    Ok(tmp)
}

/// Read length-prefixed varint array where the length is given as a varint
pub fn read_prefixed_varintarray<R: Read>(reader: &mut R) -> Result<Vec<i32>> {
    let length = read_varint(reader)?;
    let mut tmp = Vec::with_capacity(length as usize);
    for _ in 0..length {
        tmp.push(read_varint(reader)?);
    }
    Ok(tmp)
}

/// Read a uuid encoded as 16 bytes
pub fn read_uuid<R: Read>(reader: &mut R) -> Result<u128> {
    let a = read_u64(reader)?;
    let b = read_u64(reader)?;
    Ok(u128(a, b))
}

/// Read a uuid encoded as a string
///
/// Either with or without dashes.
pub fn read_uuid_str<R: Read>(reader: &mut R) -> Result<u128> {
    /* If it's without dashes, then it'll be 32 characters long, else it'll
     * be 36 characters long, so we read 32 characters first and see if it
     * contains any dahes */

    let tmp = read_String(reader)?.replace("-", "");

    let a = match u64::from_str_radix(&tmp[..16], 16) {
        Ok(x) => x,
        Err(_) => bail!("Invalid hex in first half of uuid_str"),
    };
    let b = match u64::from_str_radix(&tmp[16..], 16) {
        Ok(x) => x,
        Err(_) => bail!("Invalid hex in second half of uuid_str"),
    };
    Ok(u128(a, b))
}

/// Read a bytearray to the end of the reader
pub fn read_bytearray_to_end<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
    let mut tmp = Vec::new();
    reader.read_to_end(&mut tmp)?;
    Ok(tmp)
}

/// Alias for read_bytearray_to_end
pub fn read_bytearray<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
    read_bytearray_to_end(reader)
}

/// Read a position as described on wiki.vg, i.e. x/y/z given as an u64
pub fn read_position<R: Read>(reader: &mut R) -> Result<(i32, i32, i32)> {
    let val = read_u64(reader)?;
    let mut x = (val >> 38) as i32;
    let mut y = ((val >> 26) & 0xfff) as i32;
    let mut z = (val & 0x3ffffff) as i32;
    if x >= 1 << 25 {
        x -= 1 << 26;
    }
    if y >= 1 << 11 {
        y -= 1 << 12;
    }
    if z >= 2 << 25 {
        z -= 1 << 26;
    }
    Ok((x, y, z))
}
<|endoftext|>


<commit_before>use combustion::board::Board;
use combustion::moves::Move;
use combustion::piece::Color;

use std::env;
use std::process::exit;

fn main() {
    let args: Vec<String> = env::args().collect();

    if args.len() < 2 {
        println!("Error: at least one argument required. Exiting...");
        exit(1);
    }

    let mut board = if args[1] == "startpos" {
        Board::initial()
    } else {
        Board::from_fen(&args[1]).unwrap()
    };

    let mut to_move = Color::White;

    for mv_str in args.iter().skip(2) {
        // should be UCI format
        let mv = Move::from_xboard_format(mv_str, &board).unwrap();
        board = board.make_move(&mv).unwrap();
    }

    for mv in &board.legal_moves().unwrap() {
        println!("{}", mv);
    }
}
<commit_msg>lazy automatic commit message<commit_after>use combustion::board::Board;
use combustion::moves::Move;
use combustion::piece::Color;

use std::env;
use std::process::exit;

fn main() {
    let args: Vec<String> = env::args().collect();

    if args.len() < 2 {
        println!("Error: at least one argument required. Exiting...");
        exit(1);
    }

    let mut board = if args[1] == "startpos" {
        Board::initial()
    } else {
        Board::from_fen(&args[1]).unwrap()
    };

    let mut to_move = Color::White;

    for mv_str in args.iter().skip(2) {
        // should be UCI format
        let mv = Move::from_xboard_format(mv_str, &board).unwrap();
        board = board.make_move(&mv).unwrap();
    }

    for mv in &board.legal_moves().unwrap() {
        println!("{}", mv.to_xboard_format(board.color_to_move));
    }
}
<|endoftext|>


<commit_before>use {Col, ColVec, Cols, Mat, MutCol, MutRow, MutView, Row, RowVec, Rows, Scaled, Trans, View};
use traits::{Matrix, MatrixCol, MatrixRow};

impl<'a, T, M> Iterator<Scaled<T, Row<'a, T>>> for Scaled<T, Rows<'a, M>> where
    T: Clone,
    M: MatrixRow<T>,
{
    fn next(&mut self) -> Option<Scaled<T, Row<'a, T>>> {
        self.1.next().map(|r| Scaled(self.0.clone(), r))
    }
}

impl<'a, T, M> Iterator<Scaled<T, Col<'a, T>>> for Scaled<T, Cols<'a, M>> where
    T: Clone,
    M: MatrixCol<T>,
{
    fn next(&mut self) -> Option<Scaled<T, Col<'a, T>>> {
        self.1.next().map(|r| Scaled(self.0.clone(), r))
    }
}

impl<T, M> Matrix for Scaled<T, M> where M: Matrix {
    fn ncols(&self) -> uint {
        self.1.ncols()
    }

    fn nrows(&self) -> uint {
        self.1.nrows()
    }

    fn size(&self) -> (uint, uint) {
        self.1.size()
    }
}

// col
impl<'a, T> Mul<T, Scaled<T, Col<'a, T>>> for Col<'a, T> {
    fn mul(self, rhs: T) -> Scaled<T, Col<'a, T>> {
        Scaled(rhs, self)
    }
}

impl<'a, T> Mul<Col<'a, T>, Scaled<T, Col<'a, T>>> for T {
    fn mul(self, rhs: Col<'a, T>) -> Scaled<T, Col<'a, T>> {
        rhs * self
    }
}

impl<'a, T> Mul<T, Scaled<T, Col<'a, T>>> for &'a ColVec<T> {
    fn mul(self, rhs: T) -> Scaled<T, Col<'a, T>> {
        Scaled(rhs, self.as_col())
    }
}

impl<'a, T> Mul<&'a ColVec<T>, Scaled<T, Col<'a, T>>> for T {
    fn mul(self, rhs: &'a ColVec<T>) -> Scaled<T, Col<'a, T>> {
        rhs * self
    }
}

impl<'a, 'b, T> Mul<T, Scaled<T, Col<'a, T>>> for &'a MutCol<'b, T> {
    fn mul(self, rhs: T) -> Scaled<T, Col<'a, T>> {
        Scaled(rhs, self.as_col())
    }
}

impl<'a, 'b, T> Mul<&'a MutCol<'b, T>, Scaled<T, Col<'a, T>>> for T {
    fn mul(self, rhs: &'a MutCol<'b, T>) -> Scaled<T, Col<'a, T>> {
        rhs * self
    }
}

// mat
impl<'a, T> Mul<T, Scaled<T, View<'a, T>>> for &'a Mat<T> {
    fn mul(self, rhs: T) -> Scaled<T, View<'a, T>> {
        Scaled(rhs, self.as_view())
    }
}

impl<'a, T> Mul<&'a Mat<T>, Scaled<T, View<'a, T>>> for T {
    fn mul(self, rhs: &'a Mat<T>) -> Scaled<T, View<'a, T>> {
        rhs * self
    }
}

impl<'a, 'b, T> Mul<T, Scaled<T, View<'a, T>>> for &'a MutView<'b, T> {
    fn mul(self, rhs: T) -> Scaled<T, View<'a, T>> {
        Scaled(rhs, self.as_view())
    }
}

impl<'a, 'b, T> Mul<&'a MutView<'b, T>, Scaled<T, View<'a, T>>> for T {
    fn mul(self, rhs: &'a MutView<'b, T>) -> Scaled<T, View<'a, T>> {
        rhs * self
    }
}

impl<'a, T> Mul<T, Scaled<T, Trans<View<'a, T>>>> for &'a Trans<Mat<T>> {
    fn mul(self, rhs: T) -> Scaled<T, Trans<View<'a, T>>> {
        Scaled(rhs, Trans(self.0.as_view()))
    }
}

impl<'a, T> Mul<&'a Trans<Mat<T>>, Scaled<T, Trans<View<'a, T>>>> for T {
    fn mul(self, rhs: &'a Trans<Mat<T>>) -> Scaled<T, Trans<View<'a, T>>> {
        rhs * self
    }
}

impl<'a, 'b, T> Mul<T, Scaled<T, Trans<View<'a, T>>>> for &'a Trans<MutView<'b, T>> {
    fn mul(self, rhs: T) -> Scaled<T, Trans<View<'a, T>>> {
        Scaled(rhs, Trans(self.0.as_view()))
    }
}

impl<'a, 'b, T> Mul<&'a Trans<MutView<'b, T>>, Scaled<T, Trans<View<'a, T>>>> for T {
    fn mul(self, rhs: &'a Trans<MutView<'b, T>>) -> Scaled<T, Trans<View<'a, T>>> {
        rhs * self
    }
}

impl<'a, T> Mul<T, Scaled<T, Trans<View<'a, T>>>> for Trans<View<'a, T>> {
    fn mul(self, rhs: T) -> Scaled<T, Trans<View<'a, T>>> {
        Scaled(rhs, self)
    }
}

impl<'a, T> Mul<Trans<View<'a, T>>, Scaled<T, Trans<View<'a, T>>>> for T {
    fn mul(self, rhs: Trans<View<'a, T>>) -> Scaled<T, Trans<View<'a, T>>> {
        rhs * self
    }
}
impl<'a, T> Mul<T, Scaled<T, View<'a, T>>> for View<'a, T> {
    fn mul(self, rhs: T) -> Scaled<T, View<'a, T>> {
        Scaled(rhs, self)
    }
}

impl<'a, T> Mul<View<'a, T>, Scaled<T, View<'a, T>>> for T {
    fn mul(self, rhs: View<'a, T>) -> Scaled<T, View<'a, T>> {
        rhs * self
    }
}

// row
impl<'a, T> Mul<T, Scaled<T, Row<'a, T>>> for Row<'a, T> {
    fn mul(self, rhs: T) -> Scaled<T, Row<'a, T>> {
        Scaled(rhs, self)
    }
}

impl<'a, T> Mul<Row<'a, T>, Scaled<T, Row<'a, T>>> for T {
    fn mul(self, rhs: Row<'a, T>) -> Scaled<T, Row<'a, T>> {
        rhs * self
    }
}

impl<'a, T> Mul<T, Scaled<T, Row<'a, T>>> for &'a RowVec<T> {
    fn mul(self, rhs: T) -> Scaled<T, Row<'a, T>> {
        Scaled(rhs, self.as_row())
    }
}

impl<'a, T> Mul<&'a RowVec<T>, Scaled<T, Row<'a, T>>> for T {
    fn mul(self, rhs: &'a RowVec<T>) -> Scaled<T, Row<'a, T>> {
        rhs * self
    }
}

impl<'a, 'b, T> Mul<T, Scaled<T, Row<'a, T>>> for &'a MutRow<'b, T> {
    fn mul(self, rhs: T) -> Scaled<T, Row<'a, T>> {
        Scaled(rhs, self.as_row())
    }
}

impl<'a, 'b, T> Mul<&'a MutRow<'b, T>, Scaled<T, Row<'a, T>>> for T {
    fn mul(self, rhs: &'a MutRow<'b, T>) -> Scaled<T, Row<'a, T>> {
        rhs * self
    }
}
<commit_msg>feat(scaled): allow further (lazy) scaling<commit_after>use {Col, ColVec, Cols, Mat, MutCol, MutRow, MutView, Row, RowVec, Rows, Scaled, Trans, View};
use traits::{Matrix, MatrixCol, MatrixRow};

impl<'a, T, M> Iterator<Scaled<T, Row<'a, T>>> for Scaled<T, Rows<'a, M>> where
    T: Clone,
    M: MatrixRow<T>,
{
    fn next(&mut self) -> Option<Scaled<T, Row<'a, T>>> {
        self.1.next().map(|r| Scaled(self.0.clone(), r))
    }
}

impl<'a, T, M> Iterator<Scaled<T, Col<'a, T>>> for Scaled<T, Cols<'a, M>> where
    T: Clone,
    M: MatrixCol<T>,
{
    fn next(&mut self) -> Option<Scaled<T, Col<'a, T>>> {
        self.1.next().map(|r| Scaled(self.0.clone(), r))
    }
}

impl<T, M> Matrix for Scaled<T, M> where M: Matrix {
    fn ncols(&self) -> uint {
        self.1.ncols()
    }

    fn nrows(&self) -> uint {
        self.1.nrows()
    }

    fn size(&self) -> (uint, uint) {
        self.1.size()
    }
}

// col
impl<'a, T> Mul<T, Scaled<T, Col<'a, T>>> for Col<'a, T> {
    fn mul(self, rhs: T) -> Scaled<T, Col<'a, T>> {
        Scaled(rhs, self)
    }
}

impl<'a, T> Mul<Col<'a, T>, Scaled<T, Col<'a, T>>> for T {
    fn mul(self, rhs: Col<'a, T>) -> Scaled<T, Col<'a, T>> {
        rhs * self
    }
}

impl<'a, T> Mul<T, Scaled<T, Col<'a, T>>> for &'a ColVec<T> {
    fn mul(self, rhs: T) -> Scaled<T, Col<'a, T>> {
        Scaled(rhs, self.as_col())
    }
}

impl<'a, T> Mul<&'a ColVec<T>, Scaled<T, Col<'a, T>>> for T {
    fn mul(self, rhs: &'a ColVec<T>) -> Scaled<T, Col<'a, T>> {
        rhs * self
    }
}

impl<'a, 'b, T> Mul<T, Scaled<T, Col<'a, T>>> for &'a MutCol<'b, T> {
    fn mul(self, rhs: T) -> Scaled<T, Col<'a, T>> {
        Scaled(rhs, self.as_col())
    }
}

impl<'a, 'b, T> Mul<&'a MutCol<'b, T>, Scaled<T, Col<'a, T>>> for T {
    fn mul(self, rhs: &'a MutCol<'b, T>) -> Scaled<T, Col<'a, T>> {
        rhs * self
    }
}

// mat
impl<'a, T> Mul<T, Scaled<T, View<'a, T>>> for &'a Mat<T> {
    fn mul(self, rhs: T) -> Scaled<T, View<'a, T>> {
        Scaled(rhs, self.as_view())
    }
}

impl<'a, T> Mul<&'a Mat<T>, Scaled<T, View<'a, T>>> for T {
    fn mul(self, rhs: &'a Mat<T>) -> Scaled<T, View<'a, T>> {
        rhs * self
    }
}

impl<'a, 'b, T> Mul<T, Scaled<T, View<'a, T>>> for &'a MutView<'b, T> {
    fn mul(self, rhs: T) -> Scaled<T, View<'a, T>> {
        Scaled(rhs, self.as_view())
    }
}

impl<'a, 'b, T> Mul<&'a MutView<'b, T>, Scaled<T, View<'a, T>>> for T {
    fn mul(self, rhs: &'a MutView<'b, T>) -> Scaled<T, View<'a, T>> {
        rhs * self
    }
}

impl<'a, T> Mul<T, Scaled<T, Trans<View<'a, T>>>> for &'a Trans<Mat<T>> {
    fn mul(self, rhs: T) -> Scaled<T, Trans<View<'a, T>>> {
        Scaled(rhs, Trans(self.0.as_view()))
    }
}

impl<'a, T> Mul<&'a Trans<Mat<T>>, Scaled<T, Trans<View<'a, T>>>> for T {
    fn mul(self, rhs: &'a Trans<Mat<T>>) -> Scaled<T, Trans<View<'a, T>>> {
        rhs * self
    }
}

impl<'a, 'b, T> Mul<T, Scaled<T, Trans<View<'a, T>>>> for &'a Trans<MutView<'b, T>> {
    fn mul(self, rhs: T) -> Scaled<T, Trans<View<'a, T>>> {
        Scaled(rhs, Trans(self.0.as_view()))
    }
}

impl<'a, 'b, T> Mul<&'a Trans<MutView<'b, T>>, Scaled<T, Trans<View<'a, T>>>> for T {
    fn mul(self, rhs: &'a Trans<MutView<'b, T>>) -> Scaled<T, Trans<View<'a, T>>> {
        rhs * self
    }
}

impl<'a, T> Mul<T, Scaled<T, Trans<View<'a, T>>>> for Trans<View<'a, T>> {
    fn mul(self, rhs: T) -> Scaled<T, Trans<View<'a, T>>> {
        Scaled(rhs, self)
    }
}

impl<'a, T> Mul<Trans<View<'a, T>>, Scaled<T, Trans<View<'a, T>>>> for T {
    fn mul(self, rhs: Trans<View<'a, T>>) -> Scaled<T, Trans<View<'a, T>>> {
        rhs * self
    }
}
impl<'a, T> Mul<T, Scaled<T, View<'a, T>>> for View<'a, T> {
    fn mul(self, rhs: T) -> Scaled<T, View<'a, T>> {
        Scaled(rhs, self)
    }
}

impl<'a, T> Mul<View<'a, T>, Scaled<T, View<'a, T>>> for T {
    fn mul(self, rhs: View<'a, T>) -> Scaled<T, View<'a, T>> {
        rhs * self
    }
}

// row
impl<'a, T> Mul<T, Scaled<T, Row<'a, T>>> for Row<'a, T> {
    fn mul(self, rhs: T) -> Scaled<T, Row<'a, T>> {
        Scaled(rhs, self)
    }
}

impl<'a, T> Mul<Row<'a, T>, Scaled<T, Row<'a, T>>> for T {
    fn mul(self, rhs: Row<'a, T>) -> Scaled<T, Row<'a, T>> {
        rhs * self
    }
}

impl<'a, T> Mul<T, Scaled<T, Row<'a, T>>> for &'a RowVec<T> {
    fn mul(self, rhs: T) -> Scaled<T, Row<'a, T>> {
        Scaled(rhs, self.as_row())
    }
}

impl<'a, T> Mul<&'a RowVec<T>, Scaled<T, Row<'a, T>>> for T {
    fn mul(self, rhs: &'a RowVec<T>) -> Scaled<T, Row<'a, T>> {
        rhs * self
    }
}

impl<'a, 'b, T> Mul<T, Scaled<T, Row<'a, T>>> for &'a MutRow<'b, T> {
    fn mul(self, rhs: T) -> Scaled<T, Row<'a, T>> {
        Scaled(rhs, self.as_row())
    }
}

impl<'a, 'b, T> Mul<&'a MutRow<'b, T>, Scaled<T, Row<'a, T>>> for T {
    fn mul(self, rhs: &'a MutRow<'b, T>) -> Scaled<T, Row<'a, T>> {
        rhs * self
    }
}

// scaled
impl<T, M> Mul<T, Scaled<T, M>> for Scaled<T, M> where T: Mul<T, T> {
    fn mul(self, rhs: T) -> Scaled<T, M> {
        Scaled(self.0 * rhs, self.1)
    }
}

impl<T, M> Mul<Scaled<T, M>, Scaled<T, M>> for T where T: Mul<T, T> {
    fn mul(self, rhs: Scaled<T, M>) -> Scaled<T, M> {
        rhs * self
    }
}
<|endoftext|>


<commit_before>// (c) 2016 Productize SPRL <joost@productize.be>

use std::fmt;
use std::result;
use std::str::FromStr;

use str_error;
use Result;

// like Into trait but works from a ref avoiding consumption or expensive clone
pub trait IntoSexp {
    fn into_sexp(&self) -> Sexp;
}

#[derive(Debug, Clone)]
pub enum Sexp {
    String(String),
    List(Vec<Sexp>),
    Empty,
}

/*

Following the KiCad file formats specification chapter 4.4 - Identifiers and Strings:
A string may not contain an actual newline or carriage return, but it may use an escape sequence to encode a
newline, such as \n.
If a string has any of the following conditions, then it must be quoted with a leading and trailing double quote
character, otherwise it is acceptable to not quote the string:
1. has one or more of the following 4 separator bytes: ASCII space, tab, '(', or ')'.
2. has one or more of the following bytes: '%', '{', or '}'.
3. has a length of zero bytes, and you need a place holder for the field, then use "".
4. includes a byte of '-', and this byte is not in the first position of the string.
*/

pub fn encode_string(s:&str) -> String {
    fn rule_4(s:&str) -> bool {
        s.contains('-') && s.len() > 1 && s.as_bytes()[0] != 45
    }
    if s.contains('(') || s.contains(' ') || s.contains(')') || s.contains('\t') || s.contains('{') || s.contains('}') || s.contains('}') || s.contains('%') || s.is_empty() || rule_4(s) {
        format!("\"{}\"", s)
    } else {
        String::from(s)
    }
}

impl Sexp {

    pub fn new_empty() -> Sexp {
        Sexp::Empty
    }

    pub fn new_string<T>(s:T) -> Sexp where T:fmt::Display {
        Sexp::String(format!("{}", s))
    }

    pub fn new_list(v:Vec<Sexp>) -> Sexp {
        Sexp::List(v)
    }

    pub fn new_named<T>(name:&str, value:T) -> Sexp where T:fmt::Display {
        let mut v = vec![];
        v.push(Sexp::new_string(name));
        v.push(Sexp::new_string(value));
        Sexp::List(v)
    }

    pub fn new_named_sexp<T>(name:&str, value:&T) -> Sexp where T:IntoSexp {
        let mut v = vec![];
        v.push(Sexp::new_string(name));
        v.push(value.into_sexp());
        Sexp::List(v)
    }

    pub fn from<T:IntoSexp>(t:&T) -> Sexp {
        t.into_sexp()
    }

    pub fn list(&self) -> Result<&Vec<Sexp> > {
        match *self {
            Sexp::List(ref v) => Ok(v),
            _ => str_error(format!("not a list: {}", self))
        }
    }

    pub fn string(&self) -> Result<&String> {
        match *self {
            Sexp::String(ref s) => Ok(s),
            _ => str_error(format!("not a string: {}", self))
        }
    }

    pub fn f(&self) -> Result<f64> {
        let s = try!(self.string());
        match f64::from_str(s) {
            Ok(f) => Ok(f),
            _ => str_error("Error parsing float".to_string())
        }
    }

    pub fn i(&self) -> Result<i64> {
        let s = try!(self.string());
        match i64::from_str(s) {
            Ok(f) => Ok(f),
            _ => str_error("Error parsing int".to_string())
        }
    }

    pub fn list_name(&self) -> Result<&String> {
        let l = try!(self.list());
        let l = &l[..];
        let a = try!(l[0].string());
        Ok(a)
    }

    pub fn slice_atom(&self, s:&str) -> Result<&[Sexp]> {
        let v = try!(self.list());
        let v2 =&v[..];
        let st = try!(v2[0].string());
        if st != s {
            return str_error(format!("list {} doesn't start with {}, but with {}", self, s, st))
        };
        Ok(&v[1..])
    }

    pub fn named_value(&self, s:&str) -> Result<&Sexp> {
        let v = try!(self.list());
        if v.len() != 2 {
            return str_error(format!("list {} is not a named_value", s))
        }
        let l = try!(self.slice_atom(s));
        Ok(&l[0])
    }

    pub fn named_value_i(&self, s:&str) -> Result<i64> {
        try!(self.named_value(s)).i()
    }

    pub fn named_value_f(&self, s:&str) -> Result<f64> {
        try!(self.named_value(s)).f()
    }

    pub fn named_value_string(&self, s:&str) -> Result<&String> {
        try!(self.named_value(s)).string()
    }

    pub fn slice_atom_num(&self, s:&str, num:usize) -> Result<&[Sexp]> {
        let v = try!(self.list());
        let v2 =&v[..];
        let st = try!(v2[0].string());
        if st != s {
            return str_error(format!("list doesn't start with {}, but with {}", s, st))
        };
        if v.len() != (num+1) {
            return str_error(format!("list ({}) doesn't have {} elements but {}", s, num, v.len()-1))
        }
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        match *self {
            Sexp::String(ref s) => {
                write!(f, "{}", encode_string(s))
            },
            Sexp::List(ref v) => {
                try!(write!(f, "("));
                let l = v.len();
                for (i,x) in v.iter().enumerate() {
                    if i < l-1 {
                        try!(write!(f, "{} ", x));
                    } else {
                        try!(write!(f, "{}", x));
                    }
                }
                write!(f, ")")
            },
            Sexp::Empty => Ok(())
        }
    }
}
<commit_msg>new_named_list<commit_after>// (c) 2016 Productize SPRL <joost@productize.be>

use std::fmt;
use std::result;
use std::str::FromStr;

use str_error;
use Result;

// like Into trait but works from a ref avoiding consumption or expensive clone
pub trait IntoSexp {
    fn into_sexp(&self) -> Sexp;
}

#[derive(Debug, Clone)]
pub enum Sexp {
    String(String),
    List(Vec<Sexp>),
    Empty,
}

/*

Following the KiCad file formats specification chapter 4.4 - Identifiers and Strings:
A string may not contain an actual newline or carriage return, but it may use an escape sequence to encode a
newline, such as \n.
If a string has any of the following conditions, then it must be quoted with a leading and trailing double quote
character, otherwise it is acceptable to not quote the string:
1. has one or more of the following 4 separator bytes: ASCII space, tab, '(', or ')'.
2. has one or more of the following bytes: '%', '{', or '}'.
3. has a length of zero bytes, and you need a place holder for the field, then use "".
4. includes a byte of '-', and this byte is not in the first position of the string.
*/

pub fn encode_string(s:&str) -> String {
    fn rule_4(s:&str) -> bool {
        s.contains('-') && s.len() > 1 && s.as_bytes()[0] != 45
    }
    if s.contains('(') || s.contains(' ') || s.contains(')') || s.contains('\t') || s.contains('{') || s.contains('}') || s.contains('}') || s.contains('%') || s.is_empty() || rule_4(s) {
        format!("\"{}\"", s)
    } else {
        String::from(s)
    }
}

impl Sexp {

    pub fn new_empty() -> Sexp {
        Sexp::Empty
    }

    pub fn new_string<T>(s:T) -> Sexp where T:fmt::Display {
        Sexp::String(format!("{}", s))
    }

    pub fn new_list(v:Vec<Sexp>) -> Sexp {
        Sexp::List(v)
    }

    pub fn new_named_list<F>(name:&str, fill:F) -> Sexp
        where F:Fn(&mut Vec<Sexp>)
    {
        let mut v = vec![];
        v.push(Sexp::new_string(name));
        fill(&mut v);
        Sexp::List(v)
    }

    pub fn new_named<T>(name:&str, value:T) -> Sexp where T:fmt::Display {
        let mut v = vec![];
        v.push(Sexp::new_string(name));
        v.push(Sexp::new_string(value));
        Sexp::List(v)
    }

    pub fn new_named_sexp<T>(name:&str, value:&T) -> Sexp where T:IntoSexp {
        let mut v = vec![];
        v.push(Sexp::new_string(name));
        v.push(value.into_sexp());
        Sexp::List(v)
    }

    pub fn from<T:IntoSexp>(t:&T) -> Sexp {
        t.into_sexp()
    }

    pub fn list(&self) -> Result<&Vec<Sexp> > {
        match *self {
            Sexp::List(ref v) => Ok(v),
            _ => str_error(format!("not a list: {}", self))
        }
    }

    pub fn string(&self) -> Result<&String> {
        match *self {
            Sexp::String(ref s) => Ok(s),
            _ => str_error(format!("not a string: {}", self))
        }
    }

    pub fn f(&self) -> Result<f64> {
        let s = try!(self.string());
        match f64::from_str(s) {
            Ok(f) => Ok(f),
            _ => str_error("Error parsing float".to_string())
        }
    }

    pub fn i(&self) -> Result<i64> {
        let s = try!(self.string());
        match i64::from_str(s) {
            Ok(f) => Ok(f),
            _ => str_error("Error parsing int".to_string())
        }
    }

    pub fn list_name(&self) -> Result<&String> {
        let l = try!(self.list());
        let l = &l[..];
        let a = try!(l[0].string());
        Ok(a)
    }

    pub fn slice_atom(&self, s:&str) -> Result<&[Sexp]> {
        let v = try!(self.list());
        let v2 =&v[..];
        let st = try!(v2[0].string());
        if st != s {
            return str_error(format!("list {} doesn't start with {}, but with {}", self, s, st))
        };
        Ok(&v[1..])
    }

    pub fn named_value(&self, s:&str) -> Result<&Sexp> {
        let v = try!(self.list());
        if v.len() != 2 {
            return str_error(format!("list {} is not a named_value", s))
        }
        let l = try!(self.slice_atom(s));
        Ok(&l[0])
    }

    pub fn named_value_i(&self, s:&str) -> Result<i64> {
        try!(self.named_value(s)).i()
    }

    pub fn named_value_f(&self, s:&str) -> Result<f64> {
        try!(self.named_value(s)).f()
    }

    pub fn named_value_string(&self, s:&str) -> Result<&String> {
        try!(self.named_value(s)).string()
    }

    pub fn slice_atom_num(&self, s:&str, num:usize) -> Result<&[Sexp]> {
        let v = try!(self.list());
        let v2 =&v[..];
        let st = try!(v2[0].string());
        if st != s {
            return str_error(format!("list doesn't start with {}, but with {}", s, st))
        };
        if v.len() != (num+1) {
            return str_error(format!("list ({}) doesn't have {} elements but {}", s, num, v.len()-1))
        }
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        match *self {
            Sexp::String(ref s) => {
                write!(f, "{}", encode_string(s))
            },
            Sexp::List(ref v) => {
                try!(write!(f, "("));
                let l = v.len();
                for (i,x) in v.iter().enumerate() {
                    if i < l-1 {
                        try!(write!(f, "{} ", x));
                    } else {
                        try!(write!(f, "{}", x));
                    }
                }
                write!(f, ")")
            },
            Sexp::Empty => Ok(())
        }
    }
}
<|endoftext|>


<commit_before>use sha1::Sha1;

use aio::ConnectionLike as AsyncConnectionLike;
use cmd::cmd;
use connection::ConnectionLike;
use futures::{
    future::{err, Either},
    Future,
};
use std::sync::{
    atomic::{AtomicBool, Ordering},
    Arc,
};
use types::{ErrorKind, FromRedisValue, RedisFuture, RedisResult, ToRedisArgs};

/// Represents a lua script.
#[derive(Clone)]
pub struct Script {
    inner: Arc<ScriptInner>,
    // This stores whether the script has already been loaded into Redis
    // by this instance. It is possible that the script could have been loaded
    // by another instance before even if this value is false.
    already_loaded: Arc<AtomicBool>,
}

struct ScriptInner {
    code: String,
    hash: String,
}

/// The script object represents a lua script that can be executed on the
/// redis server.  The object itself takes care of automatic uploading and
/// execution.  The script object itself can be shared and is immutable.
///
/// Example:
///
/// ```rust,no_run
/// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// # let mut con = client.get_connection().unwrap();
/// let script = redis::Script::new(r"
///     return tonumber(ARGV[1]) + tonumber(ARGV[2]);
/// ");
/// let result = script.arg(1).arg(2).invoke(&mut con);
/// assert_eq!(result, Ok(3));
/// ```
impl Script {
    /// Creates a new script object.
    pub fn new(code: &str) -> Script {
        let mut hash = Sha1::new();
        hash.update(code.as_bytes());
        Script {
            inner: Arc::new(ScriptInner {
                code: code.to_string(),
                hash: hash.digest().to_string(),
            }),
            already_loaded: Arc::new(AtomicBool::new(false)),
        }
    }

    /// Returns the script's SHA1 hash in hexadecimal format.
    pub fn get_hash(&self) -> &str {
        &self.inner.hash
    }

    /// Creates a script invocation object with a key filled in.
    #[inline]
    pub fn key<T: ToRedisArgs>(&self, key: T) -> ScriptInvocation {
        ScriptInvocation {
            script: self.clone(),
            args: vec![],
            keys: key.to_redis_args(),
        }
    }

    /// Creates a script invocation object with an argument filled in.
    #[inline]
    pub fn arg<T: ToRedisArgs>(&self, arg: T) -> ScriptInvocation {
        ScriptInvocation {
            script: self.clone(),
            args: arg.to_redis_args(),
            keys: vec![],
        }
    }

    /// Returns an empty script invocation object.  This is primarily useful
    /// for programmatically adding arguments and keys because the type will
    /// not change.  Normally you can use `arg` and `key` directly.
    #[inline]
    pub fn prepare_invoke(&self) -> ScriptInvocation {
        ScriptInvocation {
            script: self.clone(),
            args: vec![],
            keys: vec![],
        }
    }

    /// Invokes the script directly without arguments.
    #[inline]
    pub fn invoke<T: FromRedisValue>(&self, con: &mut ConnectionLike) -> RedisResult<T> {
        ScriptInvocation {
            script: self.clone(),
            args: vec![],
            keys: vec![],
        }
        .invoke(con)
    }

    #[inline]
    pub fn invoke_async<T, C>(&self, con: C) -> RedisFuture<(C, T)>
    where
        T: FromRedisValue + Send + 'static,
        C: AsyncConnectionLike + Send + Clone + 'static,
    {
        ScriptInvocation {
            script: self.clone(),
            args: vec![],
            keys: vec![],
        }
        .invoke_async(con)
    }
}

/// Represents a prepared script call.
#[derive(Clone)]
pub struct ScriptInvocation {
    script: Script,
    args: Vec<Vec<u8>>,
    keys: Vec<Vec<u8>>,
}

/// This type collects keys and other arguments for the script so that it
/// can be then invoked.  While the `Script` type itself holds the script,
/// the `ScriptInvocation` holds the arguments that should be invoked until
/// it's sent to the server.
impl ScriptInvocation {
    /// Adds a regular argument to the invocation.  This ends up as `ARGV[i]`
    /// in the script.
    #[inline]
    pub fn arg<T: ToRedisArgs>(&mut self, arg: T) -> &mut ScriptInvocation {
        arg.write_redis_args(&mut self.args);
        self
    }

    /// Adds a key argument to the invocation.  This ends up as `KEYS[i]`
    /// in the script.
    #[inline]
    pub fn key<T: ToRedisArgs>(&mut self, key: T) -> &mut ScriptInvocation {
        key.write_redis_args(&mut self.keys);
        self
    }

    /// Invokes the script and returns the result.
    #[inline]
    pub fn invoke<T: FromRedisValue>(&self, con: &mut ConnectionLike) -> RedisResult<T> {
        loop {
            match cmd("EVALSHA")
                .arg(self.script.inner.hash.as_bytes())
                .arg(self.keys.len())
                .arg(&*self.keys)
                .arg(&*self.args)
                .query(con)
            {
                Ok(val) => {
                    return Ok(val);
                }
                Err(err) => {
                    if err.kind() == ErrorKind::NoScriptError {
                        let _: () = cmd("SCRIPT")
                            .arg("LOAD")
                            .arg(self.script.inner.code.as_bytes())
                            .query(con)?;
                    } else {
                        fail!(err);
                    }
                }
            }
        }
    }

    /// Invokes the script and returns the result.
    #[inline]
    pub fn invoke_async<T, C>(&self, con: C) -> RedisFuture<(C, T)>
    where
        T: FromRedisValue + Send + 'static,
        C: AsyncConnectionLike + Send + Clone + 'static,
    {
        let code = self.script.inner.code.to_string();

        // Check if the script has already been loaded into Redis by this instance
        // Note that storing this boolean makes it so that we do not need to clone
        // the ScriptInvocation in the normal case when we know that the script has
        // already been loaded.
        let already_loaded = self
            .script
            .already_loaded
            .fetch_and(true, Ordering::Relaxed);
        if already_loaded {
            Box::new(
                cmd("EVALSHA")
                    .arg(self.script.inner.hash.as_bytes())
                    .arg(self.keys.len())
                    .arg(&*self.keys)
                    .arg(&*self.args)
                    .query_async(con.clone()),
            )
        } else {
            let self_clone = self.clone();
            let already_loaded_ref = self.script.already_loaded.clone();
            Box::new(
                cmd("EVALSHA")
                    .arg(self.script.inner.hash.as_bytes())
                    .arg(self.keys.len())
                    .arg(&*self.keys)
                    .arg(&*self.args)
                    .query_async(con.clone())
                    .or_else(move |error| {
                        if error.kind() == ErrorKind::NoScriptError {
                            Either::A(
                                cmd("SCRIPT")
                                    .arg("LOAD")
                                    .arg(code.as_bytes())
                                    .query_async(con)
                                    .and_then(move |(con, _result): (C, String)| {
                                        already_loaded_ref.store(true, Ordering::Relaxed);
                                        self_clone.invoke_async(con)
                                    }),
                            )
                        } else {
                            Either::B(err(error))
                        }
                    })
                    .then(|result| result),
            )
        }
    }
}
<commit_msg>refactor: invoke_async without changing sync Script<commit_after>use sha1::Sha1;

use aio::SharedConnection;
use cmd::{cmd, Cmd};
use connection::ConnectionLike;
use futures::{Async, Future, Poll};
use types::{ErrorKind, FromRedisValue, RedisError, RedisFuture, RedisResult, ToRedisArgs};

/// Represents a lua script.
#[derive(Clone)]
pub struct Script {
    code: String,
    hash: String,
}

/// The script object represents a lua script that can be executed on the
/// redis server.  The object itself takes care of automatic uploading and
/// execution.  The script object itself can be shared and is immutable.
///
/// Example:
///
/// ```rust,no_run
/// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// # let mut con = client.get_connection().unwrap();
/// let script = redis::Script::new(r"
///     return tonumber(ARGV[1]) + tonumber(ARGV[2]);
/// ");
/// let result = script.arg(1).arg(2).invoke(&mut con);
/// assert_eq!(result, Ok(3));
/// ```
impl Script {
    /// Creates a new script object.
    pub fn new(code: &str) -> Script {
        let mut hash = Sha1::new();
        hash.update(code.as_bytes());
        Script {
            code: code.to_string(),
            hash: hash.digest().to_string(),
        }
    }

    /// Returns the script's SHA1 hash in hexadecimal format.
    pub fn get_hash(&self) -> &str {
        &self.hash
    }

    /// Creates a script invocation object with a key filled in.
    #[inline]
    pub fn key<T: ToRedisArgs>(&self, key: T) -> ScriptInvocation {
        ScriptInvocation {
            script: self,
            args: vec![],
            keys: key.to_redis_args(),
        }
    }

    /// Creates a script invocation object with an argument filled in.
    #[inline]
    pub fn arg<T: ToRedisArgs>(&self, arg: T) -> ScriptInvocation {
        ScriptInvocation {
            script: self,
            args: arg.to_redis_args(),
            keys: vec![],
        }
    }

    /// Returns an empty script invocation object.  This is primarily useful
    /// for programmatically adding arguments and keys because the type will
    /// not change.  Normally you can use `arg` and `key` directly.
    #[inline]
    pub fn prepare_invoke(&self) -> ScriptInvocation {
        ScriptInvocation {
            script: self,
            args: vec![],
            keys: vec![],
        }
    }

    /// Invokes the script directly without arguments.
    #[inline]
    pub fn invoke<T: FromRedisValue>(&self, con: &mut ConnectionLike) -> RedisResult<T> {
        ScriptInvocation {
            script: self,
            args: vec![],
            keys: vec![],
        }
        .invoke(con)
    }
}

/// Represents a prepared script call.
pub struct ScriptInvocation<'a> {
    script: &'a Script,
    args: Vec<Vec<u8>>,
    keys: Vec<Vec<u8>>,
}

/// This type collects keys and other arguments for the script so that it
/// can be then invoked.  While the `Script` type itself holds the script,
/// the `ScriptInvocation` holds the arguments that should be invoked until
/// it's sent to the server.
impl<'a> ScriptInvocation<'a> {
    /// Adds a regular argument to the invocation.  This ends up as `ARGV[i]`
    /// in the script.
    #[inline]
    pub fn arg<'b, T: ToRedisArgs>(&'b mut self, arg: T) -> &'b mut ScriptInvocation<'a>
    where
        'a: 'b,
    {
        arg.write_redis_args(&mut self.args);
        self
    }

    /// Adds a key argument to the invocation.  This ends up as `KEYS[i]`
    /// in the script.
    #[inline]
    pub fn key<'b, T: ToRedisArgs>(&'b mut self, key: T) -> &'b mut ScriptInvocation<'a>
    where
        'a: 'b,
    {
        key.write_redis_args(&mut self.keys);
        self
    }

    /// Invokes the script and returns the result.
    #[inline]
    pub fn invoke<T: FromRedisValue>(&self, con: &mut ConnectionLike) -> RedisResult<T> {
        loop {
            match cmd("EVALSHA")
                .arg(self.script.hash.as_bytes())
                .arg(self.keys.len())
                .arg(&*self.keys)
                .arg(&*self.args)
                .query(con)
            {
                Ok(val) => {
                    return Ok(val);
                }
                Err(err) => {
                    if err.kind() == ErrorKind::NoScriptError {
                        let _: () = cmd("SCRIPT")
                            .arg("LOAD")
                            .arg(self.script.code.as_bytes())
                            .query(con)?;
                    } else {
                        fail!(err);
                    }
                }
            }
        }
    }

    /// Asynchronously invokes the script and returns the result.
    #[inline]
    pub fn invoke_async<T: FromRedisValue + Send + 'static>(
        &self,
        con: SharedConnection,
    ) -> impl Future<Item = (SharedConnection, T), Error = RedisError> {
        let mut eval_cmd = cmd("EVALSHA");
        eval_cmd
            .arg(self.script.hash.as_bytes())
            .arg(self.keys.len())
            .arg(&*self.keys)
            .arg(&*self.args);

        let mut load_cmd = cmd("SCRIPT");
        load_cmd.arg("LOAD").arg(self.script.code.as_bytes());

        let future = eval_cmd.query_async(con.clone());
        InvokeAsyncFuture {
            con: con.clone(),
            eval_cmd,
            load_cmd,
            status: ScriptStatus::NotLoaded,
            future,
        }
    }
}

#[derive(PartialEq)]
enum ScriptStatus {
    NotLoaded,
    Loading,
    Loaded,
}

/// A future that runs the given script and loads it into Redis if
/// it has not already been loaded
struct InvokeAsyncFuture<T> {
    con: SharedConnection,
    eval_cmd: Cmd,
    load_cmd: Cmd,
    status: ScriptStatus,
    future: RedisFuture<(SharedConnection, T)>,
}

impl<T> Future for InvokeAsyncFuture<T>
where
    T: FromRedisValue + Send + 'static,
{
    type Item = (SharedConnection, T);
    type Error = RedisError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            match self.future.poll() {
                Ok(Async::NotReady) => return Ok(Async::NotReady),
                Ok(Async::Ready((con, val))) => {
                    if self.status == ScriptStatus::Loading {
                        self.status = ScriptStatus::Loaded;
                        self.future = self.eval_cmd.query_async(con);
                    } else {
                        return Ok(Async::Ready((con, val)));
                    }
                }
                Err(err) => {
                    if err.kind() == ErrorKind::NoScriptError
                        && self.status == ScriptStatus::NotLoaded
                    {
                        self.status = ScriptStatus::Loading;
                        self.future = self.load_cmd.query_async(self.con.clone())
                    } else {
                        return Err(err);
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(phase)]
#![feature(macro_rules)]
#[phase(syntax, link)]

extern crate log;
extern crate sync;

extern crate time;
extern crate turbine;

#[cfg(test)]
mod test {

	use turbine::{Turbine, Slot, WaitStrategy, BusyWait};

	use std::io::timer;
	use std::fmt;
	use std::task::{TaskBuilder};
	use sync::Future;
	use time::precise_time_ns;

	//use TestSlot;

	struct TestSlot {
		pub value: int
	}

	impl Slot for TestSlot {
		fn new() -> TestSlot {
			TestSlot {
				value: -1	// Negative value here helps catch bugs since counts will be wrong
			}
		}
	}
	impl fmt::Show for TestSlot {
			fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
					write!(f.buf, "{}", self.value)
			}
	}

	#[test]
	fn bench_chan_10m() {

		let (tx_bench, rx_bench) = channel();

		let mut future = Future::spawn(proc() {
			for _ in range(0, 10000000)  {
				tx_bench.send(1);
			}

		});

		let start = precise_time_ns();
		let mut counter = 0;
		for i in range(0, 10000000) {
			counter += rx_bench.recv();
		}
		let end = precise_time_ns();

		future.get();

		debug!("Total time: {}", (end-start) as f32 / 1000000f32);
		debug!("ops/s: {}", 10000000f32 / ((end-start) as f32 / 1000000f32 / 1000f32));
	}

	#[test]
	fn bench_turbine_10m() {
		let mut t: Turbine<TestSlot> = Turbine::new(1048576);
		let e1 = t.ep_new().unwrap();

		let event_processor = t.ep_finalize(e1);
		let (tx, rx) = channel();

		let mut future = Future::spawn(proc() {
			let mut counter = 0;
			event_processor.start::<BusyWait>(|data: &[TestSlot]| -> Result<(),()> {
				for _ in data.iter() {
					counter += data[0].value;
				}

				if counter == 10000000 {
						return Err(());
				} else {
					return Ok(());
				}

			});
			tx.send(1);
		});

		let start = precise_time_ns();
		for i in range(0, 10000000) {
			let mut s: TestSlot = Slot::new();
			s.value = 1;
			t.write(s);

			match rx.try_recv() {
				Ok(v) => break,
				_ => {}
			}
		}

		//rx.recv_opt();
		future.get();
		let end = precise_time_ns();

		debug!("Total time: {}", (end-start) as f32 / 1000000f32);
		debug!("ops/s: {}", 10000000f32 / ((end-start) as f32 / 1000000f32 / 1000f32));
		//
	}
}
<commit_msg>update external test to rust nightly<commit_after>#![feature(phase)]
#![feature(macro_rules)]
#[phase(syntax, link)]

extern crate log;
extern crate sync;

extern crate time;
extern crate turbine;

#[cfg(test)]
mod test {

	use turbine::{Turbine, Slot, WaitStrategy, BusyWait};

	use std::io::timer;
	use std::fmt;
	use std::task::{TaskBuilder};
	use std::sync::Future;
	use time::precise_time_ns;

	//use TestSlot;

	struct TestSlot {
		pub value: int
	}

	impl Slot for TestSlot {
		fn new() -> TestSlot {
			TestSlot {
				value: -1	// Negative value here helps catch bugs since counts will be wrong
			}
		}
	}

	#[test]
	fn bench_chan_10m() {

		let (tx_bench, rx_bench): (Sender<int>, Receiver<int>) = channel();

		let mut future = Future::spawn(proc() {
			for _ in range(0i, 10000000)  {
				tx_bench.send(1);
			}

		});

		let start = precise_time_ns();
		let mut counter = 0;
		for i in range(0i, 10000000) {
			counter += rx_bench.recv();
		}
		let end = precise_time_ns();

		future.get();

		debug!("Total time: {}", (end-start) as f32 / 1000000f32);
		debug!("ops/s: {}", 10000000f32 / ((end-start) as f32 / 1000000f32 / 1000f32));
	}

	#[test]
	fn bench_turbine_10m() {
		let mut t: Turbine<TestSlot> = Turbine::new(1048576);
		let e1 = t.ep_new().unwrap();

		let event_processor = t.ep_finalize(e1);
		let (tx, rx): (Sender<int>, Receiver<int>) = channel();

		let mut future = Future::spawn(proc() {
			let mut counter = 0;
			event_processor.start::<BusyWait>(|data: &[TestSlot]| -> Result<(),()> {
				for _ in data.iter() {
					counter += data[0].value;
				}

				if counter == 10000000 {
						return Err(());
				} else {
					return Ok(());
				}

			});
			tx.send(1);
		});

		let start = precise_time_ns();
		for i in range(0i, 10000000) {
			let mut s: TestSlot = Slot::new();
			s.value = 1;
			t.write(s);

			match rx.try_recv() {
				Ok(v) => break,
				_ => {}
			}
		}

		//rx.recv_opt();
		future.get();
		let end = precise_time_ns();

		debug!("Total time: {}", (end-start) as f32 / 1000000f32);
		debug!("ops/s: {}", 10000000f32 / ((end-start) as f32 / 1000000f32 / 1000f32));
		//
	}
}
<|endoftext|>