<commit_before>#![feature(globs)]

extern crate conduit;

use std::fmt::Show;

use conduit::{Request, Response, Handler};

pub trait Middleware {
    fn before(&self, _: &mut Request) -> Result<(), Box<Show>> {
        Ok(())
    }

    fn after(&self, _: &mut Request, res: Result<Response, Box<Show>>)
             -> Result<Response, Box<Show>>
    {
        res
    }
}

pub trait AroundMiddleware : Handler {
    fn with_handler(&mut self, handler: Box<Handler + 'static + Share>);
}

pub struct MiddlewareBuilder {
    middlewares: Vec<Box<Middleware + 'static + Share>>,
    handler: Option<Box<Handler + 'static + Share>>
}

impl MiddlewareBuilder {
    pub fn new<H: Handler + 'static + Share>(handler: H) -> MiddlewareBuilder {
        MiddlewareBuilder {
            middlewares: vec!(),
            handler: Some(box handler as Box<Handler + 'static + Share>)
        }
    }

    pub fn add<M: Middleware + 'static + Share>(&mut self, middleware: M) {
        self.middlewares.push(box middleware as Box<Middleware + 'static + Share>);
    }

    pub fn around<M: AroundMiddleware + 'static + Share>(&mut self,
                                                         mut middleware: M) {
        let handler = self.handler.take_unwrap();
        middleware.with_handler(handler);
        self.handler = Some(box middleware as Box<Handler + 'static + Share>);
    }
}

impl Handler for MiddlewareBuilder {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Show>> {
        let mut error = None;

        for (i, middleware) in self.middlewares.iter().enumerate() {
            match middleware.before(req) {
                Ok(_) => (),
                Err(err) => {
                    error = Some((err, i));
                    break;
                }
            }
        }

        match error {
            Some((err, i)) => {
                let middlewares = self.middlewares.slice_to(i);
                run_afters(middlewares, req, Err(err))
            },
            None => {
                let res = { self.handler.get_ref().call(req) };
                let middlewares = self.middlewares.as_slice();

                run_afters(middlewares, req, res)
            }
        }
    }
}

fn run_afters(middleware: &[Box<Middleware>],
                  req: &mut Request,
                  res: Result<Response, Box<Show>>)
                  -> Result<Response, Box<Show>>
{
    middleware.iter().rev().fold(res, |res, m| m.after(req, res))
}

#[cfg(test)]
mod tests {
    extern crate semver;

    use super::*;

    use std::any::{Any, AnyRefExt};
    use std::io::net::ip::IpAddr;
    use std::io::MemReader;
    use std::fmt;
    use std::fmt::{Show, Formatter};
    use std::collections::HashMap;

    use conduit;
    use conduit::{Request, Response, Host, Headers, Method, Scheme, Extensions, Handler};

    struct RequestSentinel {
        path: String,
        extensions: HashMap<&'static str, Box<Any>>,
        method: Method
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_str(),
                extensions: HashMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    struct MyMiddleware;

    impl Middleware for MyMiddleware {
        fn before<'a>(&self, req: &'a mut Request) -> Result<(), Box<Show>> {
            req.mut_extensions().insert("test.middleware", box "hello".to_str() as Box<Any>);
            Ok(())
        }
    }

    struct ErrorRecovery;

    impl Middleware for ErrorRecovery {
        fn after(&self, _: &mut Request, res: Result<Response, Box<Show>>)
                     -> Result<Response, Box<Show>>
        {
            res.or_else(|e| {
                Ok(Response {
                    status: (500, "Internal Server Error"),
                    headers: HashMap::new(),
                    body: box MemReader::new(show(e).to_str().into_bytes())
                })
            })
        }
    }

    struct ProducesError;

    impl Middleware for ProducesError {
        fn before(&self, _: &mut Request) -> Result<(), Box<Show>> {
            Err(box "Nope".to_str() as Box<Show>)
        }
    }

    struct NotReached;

    impl Middleware for NotReached {
        fn after(&self, _: &mut Request, _: Result<Response, Box<Show>>)
                     -> Result<Response, Box<Show>>
        {
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(vec!())
            })
        }
    }

    struct MyAroundMiddleware {
        handler: Option<Box<Handler + 'static + Share>>
    }

    impl MyAroundMiddleware {
        fn new() -> MyAroundMiddleware {
            MyAroundMiddleware { handler: None }
        }
    }

    impl Middleware for MyAroundMiddleware {}

    impl AroundMiddleware for MyAroundMiddleware {
        fn with_handler(&mut self, handler: Box<Handler + 'static + Share>) {
            self.handler = Some(handler)
        }
    }

    impl Handler for MyAroundMiddleware {
        fn call(&self, req: &mut Request) -> Result<Response, Box<Show>> {
            req.mut_extensions().insert("test.round-and-round", box "hello".to_str() as Box<Any>);
            self.handler.get_ref().call(req)
        }
    }

    struct Shower<'a> {
        inner: &'a Show
    }

    impl<'a> Show for Shower<'a> {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
            self.inner.fmt(f)
        }
    }

    fn show<'a>(s: &'a Show) -> Shower<'a> {
        Shower { inner: s }
    }

    fn get_extension<'a, T: 'static>(req: &'a Request, key: &'static str) -> &'a T {
        req.extensions().find(&key).and_then(|s| s.as_ref::<T>())
            .expect(format!("No {} key found in extensions", key).as_slice())
    }

    fn response(string: String) -> Response {
        Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(string.into_bytes())
        }
    }

    fn handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req, "test.middleware");
        Ok(response(hello.clone()))
    }

    fn error_handler(_: &mut Request) -> Result<Response, String> {
        Err("Error in handler".to_str())
    }

    fn middle_handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req, "test.middleware");
        let middle = get_extension::<String>(req, "test.round-and-round");

        Ok(response(format!("{} {}", hello, middle)))
    }

    #[test]
    fn test_simple_middleware() {
        let mut builder = MiddlewareBuilder::new(box handler);
        builder.add(MyMiddleware);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_str().ok().expect("No body"), "hello".to_str());
    }

    #[test]
    fn test_error_recovery() {
        let mut builder = MiddlewareBuilder::new(box handler);
        builder.add(ErrorRecovery);
        builder.add(ProducesError);
        // the error bubbles up from ProducesError and shouldn't reach here
        builder.add(NotReached);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
    }

    #[test]
    fn test_error_recovery_in_handlers() {
        let mut builder = MiddlewareBuilder::new(box error_handler);
        builder.add(ErrorRecovery);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
        assert_eq!(res.body.read_to_str().ok().expect("No body"), "Error in handler".to_str());
    }

    #[test]
    fn test_around_middleware() {
        let mut builder = MiddlewareBuilder::new(middle_handler);
        builder.add(MyMiddleware);
        builder.around(MyAroundMiddleware::new());

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_str().ok().expect("No body"), "hello hello".to_str());
    }
}
<commit_msg>Fixed tests<commit_after>#![feature(globs)]

extern crate conduit;

use std::fmt::Show;

use conduit::{Request, Response, Handler};

pub trait Middleware {
    fn before(&self, _: &mut Request) -> Result<(), Box<Show>> {
        Ok(())
    }

    fn after(&self, _: &mut Request, res: Result<Response, Box<Show>>)
             -> Result<Response, Box<Show>>
    {
        res
    }
}

pub trait AroundMiddleware : Handler {
    fn with_handler(&mut self, handler: Box<Handler + 'static + Share>);
}

pub struct MiddlewareBuilder {
    middlewares: Vec<Box<Middleware + 'static + Share>>,
    handler: Option<Box<Handler + 'static + Share>>
}

impl MiddlewareBuilder {
    pub fn new<H: Handler + 'static + Share>(handler: H) -> MiddlewareBuilder {
        MiddlewareBuilder {
            middlewares: vec!(),
            handler: Some(box handler as Box<Handler + 'static + Share>)
        }
    }

    pub fn add<M: Middleware + 'static + Share>(&mut self, middleware: M) {
        self.middlewares.push(box middleware as Box<Middleware + 'static + Share>);
    }

    pub fn around<M: AroundMiddleware + 'static + Share>(&mut self,
                                                         mut middleware: M) {
        let handler = self.handler.take_unwrap();
        middleware.with_handler(handler);
        self.handler = Some(box middleware as Box<Handler + 'static + Share>);
    }
}

impl Handler for MiddlewareBuilder {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Show>> {
        let mut error = None;

        for (i, middleware) in self.middlewares.iter().enumerate() {
            match middleware.before(req) {
                Ok(_) => (),
                Err(err) => {
                    error = Some((err, i));
                    break;
                }
            }
        }

        match error {
            Some((err, i)) => {
                let middlewares = self.middlewares.slice_to(i);
                run_afters(middlewares, req, Err(err))
            },
            None => {
                let res = { self.handler.get_ref().call(req) };
                let middlewares = self.middlewares.as_slice();

                run_afters(middlewares, req, res)
            }
        }
    }
}

fn run_afters(middleware: &[Box<Middleware>],
                  req: &mut Request,
                  res: Result<Response, Box<Show>>)
                  -> Result<Response, Box<Show>>
{
    middleware.iter().rev().fold(res, |res, m| m.after(req, res))
}

#[cfg(test)]
mod tests {
    extern crate semver;

    use super::*;

    use std::any::{Any, AnyRefExt};
    use std::io::net::ip::IpAddr;
    use std::io::MemReader;
    use std::fmt;
    use std::fmt::{Show, Formatter};
    use std::collections::HashMap;

    use conduit;
    use conduit::{Request, Response, Host, Headers, Method, Scheme, Extensions, Handler};

    struct RequestSentinel {
        path: String,
        extensions: HashMap<&'static str, Box<Any>>,
        method: Method
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_str(),
                extensions: HashMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    struct MyMiddleware;

    impl Middleware for MyMiddleware {
        fn before<'a>(&self, req: &'a mut Request) -> Result<(), Box<Show>> {
            req.mut_extensions().insert("test.middleware", box "hello".to_str() as Box<Any>);
            Ok(())
        }
    }

    struct ErrorRecovery;

    impl Middleware for ErrorRecovery {
        fn after(&self, _: &mut Request, res: Result<Response, Box<Show>>)
                     -> Result<Response, Box<Show>>
        {
            res.or_else(|e| {
                Ok(Response {
                    status: (500, "Internal Server Error"),
                    headers: HashMap::new(),
                    body: box MemReader::new(show(e).to_str().into_bytes())
                })
            })
        }
    }

    struct ProducesError;

    impl Middleware for ProducesError {
        fn before(&self, _: &mut Request) -> Result<(), Box<Show>> {
            Err(box "Nope".to_str() as Box<Show>)
        }
    }

    struct NotReached;

    impl Middleware for NotReached {
        fn after(&self, _: &mut Request, _: Result<Response, Box<Show>>)
                     -> Result<Response, Box<Show>>
        {
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(vec!())
            })
        }
    }

    struct MyAroundMiddleware {
        handler: Option<Box<Handler + 'static + Share>>
    }

    impl MyAroundMiddleware {
        fn new() -> MyAroundMiddleware {
            MyAroundMiddleware { handler: None }
        }
    }

    impl Middleware for MyAroundMiddleware {}

    impl AroundMiddleware for MyAroundMiddleware {
        fn with_handler(&mut self, handler: Box<Handler + 'static + Share>) {
            self.handler = Some(handler)
        }
    }

    impl Handler for MyAroundMiddleware {
        fn call(&self, req: &mut Request) -> Result<Response, Box<Show>> {
            req.mut_extensions().insert("test.round-and-round", box "hello".to_str() as Box<Any>);
            self.handler.get_ref().call(req)
        }
    }

    struct Shower<'a> {
        inner: &'a Show
    }

    impl<'a> Show for Shower<'a> {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
            self.inner.fmt(f)
        }
    }

    fn show<'a>(s: &'a Show) -> Shower<'a> {
        Shower { inner: s }
    }

    fn get_extension<'a, T: 'static>(req: &'a Request, key: &'static str) -> &'a T {
        req.extensions().find(&key).and_then(|s| s.as_ref::<T>())
            .expect(format!("No {} key found in extensions", key).as_slice())
    }

    fn response(string: String) -> Response {
        Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(string.into_bytes())
        }
    }

    fn handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req, "test.middleware");
        Ok(response(hello.clone()))
    }

    fn error_handler(_: &mut Request) -> Result<Response, String> {
        Err("Error in handler".to_str())
    }

    fn middle_handler(req: &mut Request) -> Result<Response, ()> {
        let hello = get_extension::<String>(req, "test.middleware");
        let middle = get_extension::<String>(req, "test.round-and-round");

        Ok(response(format!("{} {}", hello, middle)))
    }

    #[test]
    fn test_simple_middleware() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(MyMiddleware);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_str().ok().expect("No body"), "hello".to_str());
    }

    #[test]
    fn test_error_recovery() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(ErrorRecovery);
        builder.add(ProducesError);
        // the error bubbles up from ProducesError and shouldn't reach here
        builder.add(NotReached);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
    }

    #[test]
    fn test_error_recovery_in_handlers() {
        let mut builder = MiddlewareBuilder::new(error_handler);
        builder.add(ErrorRecovery);

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
        assert_eq!(res.body.read_to_str().ok().expect("No body"), "Error in handler".to_str());
    }

    #[test]
    fn test_around_middleware() {
        let mut builder = MiddlewareBuilder::new(middle_handler);
        builder.add(MyMiddleware);
        builder.around(MyAroundMiddleware::new());

        let mut req = RequestSentinel::new(conduit::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_str().ok().expect("No body"), "hello hello".to_str());
    }
}
<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::error::Error;

use mio::Token;

use {Response, Time};

#[derive(Debug)]
pub enum ResponseImpl<M, N> {
    Normal(M),
    Deadline(M, Time),
    Spawn(M, N),
    Error(Box<Error>),
    Done,
}

impl<M: Sized, N:Sized> Response<M, N> {
    pub fn ok(machine: M) -> Response<M, N> {
        Response(ResponseImpl::Normal(machine))
    }
    pub fn spawn(machine: M, result: N) -> Response<M, N> {
        Response(ResponseImpl::Spawn(machine, result))
    }
    pub fn done() -> Response<M, N> {
        Response::<M, N>(ResponseImpl::Done)
    }
    pub fn error(e: Box<Error>) -> Response<M, N> {
        Response::<M, N>(ResponseImpl::Error(e))
    }
    pub fn deadline(self, time: Time) -> Response<M, N> {
        let imp = match self.0 {
            ResponseImpl::Normal(x) => ResponseImpl::Deadline(x, time),
            ResponseImpl::Deadline(x, _) => ResponseImpl::Deadline(x, time),
            ResponseImpl::Spawn(..) => {
                panic!("You can't attach a deadline/timeout to the \
                    Response::spawn(). The `spawn` action is synchronous \
                    you must set a deadline in the `spawned` handler."); }
            ResponseImpl::Done => {
                panic!("You can't attach a deadline/timeout to \
                    Response::done() as it's useless. \
                    Timeout will never happen");
            }
            ResponseImpl::Error(_) => {
                panic!("You can't attach a deadline/timeout to \
                    Response::error(_) as it's useless. \
                    Timeout will never happen");
            }
        };
        Response(imp)
    }
    /// Maps state machine and/or spawned result with a function
    ///
    /// Usually it's okay to use constructor of wrapper state machine
    /// here as a mapper
    pub fn map<T, U,  S, R>(self, self_mapper: S, result_mapper: R)
        -> Response<T, U>
        where S: FnOnce(M) -> T,
              R: FnOnce(N) -> U,
    {
        use self::ResponseImpl::*;
        let imp = match self.0 {
            Normal(m) => Normal(self_mapper(m)),
            Deadline(m, time) => Deadline(self_mapper(m), time),
            Spawn(m, n) => Spawn(self_mapper(m), result_mapper(n)),
            Done => Done,
            Error(e) => Error(e),
        };
        Response(imp)
    }
    /// Similar to `map` but only maps state machine
    ///
    /// This is especially useful in state machine constructors, which
    /// have a Void child type.
    pub fn wrap<T, S>(self, self_mapper: S) -> Response<T, N>
        where S: FnOnce(M) -> T
    {
        use self::ResponseImpl::*;
        let imp = match self.0 {
            Normal(m) => Normal(self_mapper(m)),
            Deadline(m, time) => Deadline(self_mapper(m), time),
            Spawn(m, n) => Spawn(self_mapper(m), n),
            Done => Done,
            Error(e) => Error(e),
        };
        Response(imp)
    }

    /// Returns true if state machine is stopped
    ///
    /// I.e. the method returns true if the `Response` was created either with
    /// `Response::done` or `Response::error`
    pub fn is_stopped(&self) -> bool {
        use self::ResponseImpl::*;
        match self.0 {
            Normal(..) => false,
            Deadline(..) => false,
            Spawn(..) => false,
            Done => true,
            Error(..) => true,
        }
    }

    /// Return a reference to an error passed to `Response::error`
    ///
    /// Returns None if any other constructor was used.
    ///
    /// This is mostly useful for printing the error.
    pub fn cause(&self) -> Option<&Error> {
        use self::ResponseImpl::*;
        match self.0 {
            Normal(..) => None,
            Deadline(..) => None,
            Spawn(..) => None,
            Done => None,
            Error(ref e) => Some(&**e),
        }
    }
}

impl<M: Sized + Debug, N: Sized + Debug> Response<M, N> {
    /// Return state machine if response created with `Response::ok(..)`
    ///
    /// *Use only for unit tests*
    ///
    /// If the response is not okay, the function panics.
    pub fn expect_machine(self) -> M {
        match self.0 {
            ResponseImpl::Normal(x) => x,
            me => panic!("expected machine (`Response::ok(x)`), \
                got {:?} instead", me),
        }
    }
    /// Return a tuple if response created with `Response::spawn(..)`
    ///
    /// *Use only for unit tests*
    ///
    /// If the response is not `spawn`, the function panics.
    pub fn expect_spawn(self) -> (M, N) {
        match self.0 {
            ResponseImpl::Spawn(x, y) => (x, y),
            me => panic!("expected spawn (`Response::spawn(x)`), \
                got {:?} instead", me),
        }
    }
    /// Returns if response created with `Response::done()`
    ///
    /// *Use only for unit tests*
    ///
    /// If the response is not done, the function panics.
    pub fn expect_done(self) {
        match self.0 {
            ResponseImpl::Done => {}
            me => panic!("expected done (`Response::done()`), \
                got {:?} instead", me),
        }
    }
    /// Returns an error if response created with `Response::error(..)`
    ///
    /// *Use only for unit tests*
    ///
    /// If the response does not contain error, the function panics.
    pub fn expect_error(self) -> Box<Error> {
        match self.0 {
            ResponseImpl::Error(e) => e,
            me => panic!("expected error (`Response::error(e)`), \
                got {:?} instead", me),
        }
    }
}

pub fn decompose<M, N>(token: Token, res: Response<M, N>)
    -> (Result<M, Option<Box<Error>>>, Option<N>, Option<Time>)
{
    match res.0 {
        ResponseImpl::Normal(m) => (Ok(m), None, None),
        ResponseImpl::Deadline(m, time) => (Ok(m), None, Some(time)),
        ResponseImpl::Spawn(m, n) => (Ok(m), Some(n), None),
        ResponseImpl::Done => (Err(None), None, None),
        ResponseImpl::Error(e) => {
            if cfg!(log_errors) {
                warn!("State machine {:?} exited with error: {}", token, e);
            }
            (Err(Some(e)), None, None)
        }
    }
}

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

    #[test]
    fn size_of_response() {
        assert_eq!(::std::mem::size_of::<Response<u64, u64>>(), 24)
    }
}
<commit_msg>Allow `Result::ok().deadline()` to succeed for `expect_machine`<commit_after>use std::fmt::Debug;
use std::error::Error;

use mio::Token;

use {Response, Time};

#[derive(Debug)]
pub enum ResponseImpl<M, N> {
    Normal(M),
    Deadline(M, Time),
    Spawn(M, N),
    Error(Box<Error>),
    Done,
}

impl<M: Sized, N:Sized> Response<M, N> {
    pub fn ok(machine: M) -> Response<M, N> {
        Response(ResponseImpl::Normal(machine))
    }
    pub fn spawn(machine: M, result: N) -> Response<M, N> {
        Response(ResponseImpl::Spawn(machine, result))
    }
    pub fn done() -> Response<M, N> {
        Response::<M, N>(ResponseImpl::Done)
    }
    pub fn error(e: Box<Error>) -> Response<M, N> {
        Response::<M, N>(ResponseImpl::Error(e))
    }
    pub fn deadline(self, time: Time) -> Response<M, N> {
        let imp = match self.0 {
            ResponseImpl::Normal(x) => ResponseImpl::Deadline(x, time),
            ResponseImpl::Deadline(x, _) => ResponseImpl::Deadline(x, time),
            ResponseImpl::Spawn(..) => {
                panic!("You can't attach a deadline/timeout to the \
                    Response::spawn(). The `spawn` action is synchronous \
                    you must set a deadline in the `spawned` handler."); }
            ResponseImpl::Done => {
                panic!("You can't attach a deadline/timeout to \
                    Response::done() as it's useless. \
                    Timeout will never happen");
            }
            ResponseImpl::Error(_) => {
                panic!("You can't attach a deadline/timeout to \
                    Response::error(_) as it's useless. \
                    Timeout will never happen");
            }
        };
        Response(imp)
    }
    /// Maps state machine and/or spawned result with a function
    ///
    /// Usually it's okay to use constructor of wrapper state machine
    /// here as a mapper
    pub fn map<T, U,  S, R>(self, self_mapper: S, result_mapper: R)
        -> Response<T, U>
        where S: FnOnce(M) -> T,
              R: FnOnce(N) -> U,
    {
        use self::ResponseImpl::*;
        let imp = match self.0 {
            Normal(m) => Normal(self_mapper(m)),
            Deadline(m, time) => Deadline(self_mapper(m), time),
            Spawn(m, n) => Spawn(self_mapper(m), result_mapper(n)),
            Done => Done,
            Error(e) => Error(e),
        };
        Response(imp)
    }
    /// Similar to `map` but only maps state machine
    ///
    /// This is especially useful in state machine constructors, which
    /// have a Void child type.
    pub fn wrap<T, S>(self, self_mapper: S) -> Response<T, N>
        where S: FnOnce(M) -> T
    {
        use self::ResponseImpl::*;
        let imp = match self.0 {
            Normal(m) => Normal(self_mapper(m)),
            Deadline(m, time) => Deadline(self_mapper(m), time),
            Spawn(m, n) => Spawn(self_mapper(m), n),
            Done => Done,
            Error(e) => Error(e),
        };
        Response(imp)
    }

    /// Returns true if state machine is stopped
    ///
    /// I.e. the method returns true if the `Response` was created either with
    /// `Response::done` or `Response::error`
    pub fn is_stopped(&self) -> bool {
        use self::ResponseImpl::*;
        match self.0 {
            Normal(..) => false,
            Deadline(..) => false,
            Spawn(..) => false,
            Done => true,
            Error(..) => true,
        }
    }

    /// Return a reference to an error passed to `Response::error`
    ///
    /// Returns None if any other constructor was used.
    ///
    /// This is mostly useful for printing the error.
    pub fn cause(&self) -> Option<&Error> {
        use self::ResponseImpl::*;
        match self.0 {
            Normal(..) => None,
            Deadline(..) => None,
            Spawn(..) => None,
            Done => None,
            Error(ref e) => Some(&**e),
        }
    }
}

impl<M: Sized + Debug, N: Sized + Debug> Response<M, N> {
    /// Return state machine if response created with `Response::ok(..)`
    ///
    /// *Use only for unit tests*
    ///
    /// If the response is not okay, the function panics.
    pub fn expect_machine(self) -> M {
        match self.0 {
            ResponseImpl::Normal(x) => x,
            ResponseImpl::Deadline(x, _) => x,
            me => panic!("expected machine (`Response::ok(x)`), \
                got {:?} instead", me),
        }
    }
    /// Return a tuple if response created with `Response::spawn(..)`
    ///
    /// *Use only for unit tests*
    ///
    /// If the response is not `spawn`, the function panics.
    pub fn expect_spawn(self) -> (M, N) {
        match self.0 {
            ResponseImpl::Spawn(x, y) => (x, y),
            me => panic!("expected spawn (`Response::spawn(x)`), \
                got {:?} instead", me),
        }
    }
    /// Returns if response created with `Response::done()`
    ///
    /// *Use only for unit tests*
    ///
    /// If the response is not done, the function panics.
    pub fn expect_done(self) {
        match self.0 {
            ResponseImpl::Done => {}
            me => panic!("expected done (`Response::done()`), \
                got {:?} instead", me),
        }
    }
    /// Returns an error if response created with `Response::error(..)`
    ///
    /// *Use only for unit tests*
    ///
    /// If the response does not contain error, the function panics.
    pub fn expect_error(self) -> Box<Error> {
        match self.0 {
            ResponseImpl::Error(e) => e,
            me => panic!("expected error (`Response::error(e)`), \
                got {:?} instead", me),
        }
    }
}

pub fn decompose<M, N>(token: Token, res: Response<M, N>)
    -> (Result<M, Option<Box<Error>>>, Option<N>, Option<Time>)
{
    match res.0 {
        ResponseImpl::Normal(m) => (Ok(m), None, None),
        ResponseImpl::Deadline(m, time) => (Ok(m), None, Some(time)),
        ResponseImpl::Spawn(m, n) => (Ok(m), Some(n), None),
        ResponseImpl::Done => (Err(None), None, None),
        ResponseImpl::Error(e) => {
            if cfg!(log_errors) {
                warn!("State machine {:?} exited with error: {}", token, e);
            }
            (Err(Some(e)), None, None)
        }
    }
}

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

    #[test]
    fn size_of_response() {
        assert_eq!(::std::mem::size_of::<Response<u64, u64>>(), 24)
    }
}
<|endoftext|>


<commit_before>use encoding::types::EncodingRef;

use error::Error;
use history::{Cursor, History};
use buffer::Buffer;
use parser::{parse, ParseError, ParseSuccess};
use instr;

#[derive(Copy,Clone)]
pub enum EditMode {
    Emacs,
    Vi,
}

#[derive(Copy, Clone, PartialEq)]
pub enum ViMode {
    Insert,
    Normal,
    Replace,
}

pub struct EditCtx<'a> {
    buf: Buffer,
    history_cursor: Cursor<'a>,
    prompt: &'a str,
    seq: Vec<u8>,
    enc: EncodingRef,
    mode: EditMode,
    vi_mode: ViMode,
    vi_count: u32,
}

impl<'a> EditCtx<'a> {

    pub fn new(prompt: &'a str, history: &'a History, enc: EncodingRef, mode: EditMode) -> Self {
        EditCtx {
            buf: Buffer::new(),
            history_cursor: Cursor::new(history),
            prompt: prompt,
            seq: Vec::new(),
            enc: enc,
            mode: mode,
            // always start in insert mode
            vi_mode: ViMode::Insert,
            vi_count: 0,
        }
    }

    pub fn fill(&mut self, byte: u8) {
        self.seq.push(byte)
    }

}

pub enum EditResult<C> {
    Cont(C),
    Halt(Result<String, Error>)
}

pub fn edit<'a>(ctx: &mut EditCtx<'a>) -> EditResult<Vec<u8>> {
    use self::EditResult::*;

    let res = match parse(&ctx.seq, ctx.enc) {
        Err(ParseError::Error(len)) => {
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            Cont(false)
        },
        Err(ParseError::Incomplete) => Cont(false),
        Ok(ParseSuccess(token, len)) => {
            let res = match instr::interpret_token(token, ctx.mode, ctx.vi_mode) {
                instr::Instr::Done => {
                    Halt(Ok(ctx.buf.drain()))
                },
                instr::Instr::DeleteCharLeftOfCursor => {
                    ctx.buf.delete_char_left_of_cursor();
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursor => {
                    ctx.buf.delete_char_right_of_cursor();
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursorOrEOF => {
                    if !ctx.buf.delete_char_right_of_cursor() {
                        Halt(Err(Error::EndOfFile))
                    } else {
                        Cont(false)
                    }
                },
                instr::Instr::MoveCursorLeft => {
                    ctx.buf.move_left();
                    Cont(false)
                },
                instr::Instr::MoveCursorRight => {
                    ctx.buf.move_right();
                    Cont(false)
                },
                instr::Instr::MoveCursorStart => {
                    ctx.buf.move_start();
                    Cont(false)
                },
                instr::Instr::MoveCursorEnd => {
                    ctx.buf.move_end();
                    Cont(false)
                },
                instr::Instr::HistoryPrev => {
                    if ctx.history_cursor.incr() {
                        ctx.buf.swap()
                    }
                    ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    Cont(false)
                },
                instr::Instr::HistoryNext => {
                    if ctx.history_cursor.decr() {
                        ctx.buf.swap()
                    }
                    ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    Cont(false)
                },
                instr::Instr::NormalMode => {
                    if ctx.vi_mode == ViMode::Insert {
                        // cursor moves left when leaving insert mode
                        ctx.buf.move_left();
                    }
                    ctx.vi_mode = ViMode::Normal;
                    ctx.vi_count = 0;
                    Cont(false)
                }
                instr::Instr::ReplaceMode => {
                    ctx.vi_mode = ViMode::Replace;
                    Cont(false)
                }
                instr::Instr::Insert => {
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::InsertStart => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_start();
                    Cont(false)
                }
                instr::Instr::Append => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_right();
                    Cont(false)
                }
                instr::Instr::AppendEnd => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_end();
                    Cont(false)
                }
                instr::Instr::Digit(i) => {
                    match (ctx.vi_count, i) {
                        // if count is 0, then 0 moves to the start of a line
                        (0, 0) => ctx.buf.move_start(),
                        // otherwise add a digit to the count
                        (_, i) => ctx.vi_count = ctx.vi_count * 10 + i,
                    }
                    Cont(false)
                }
                instr::Instr::MoveEndOfWordRight => {
                    ctx.buf.move_to_end_of_word();
                    Cont(false)
                }
                instr::Instr::Substitute => {
                    ctx.buf.delete_char_right_of_cursor();
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::Noop => {
                    Cont(false)
                },
                instr::Instr::Cancel => Halt(Err(Error::Cancel)),
                instr::Instr::Clear => {
                    Cont(true)
                },
                instr::Instr::InsertAtCursor(text) => {
                    ctx.buf.insert_chars_at_cursor(text);
                    Cont(false)
                }
                instr::Instr::ReplaceAtCursor(text) => {
                    ctx.buf.replace_chars_at_cursor(text);
                    ctx.vi_mode = ViMode::Normal;
                    Cont(false)
                }
            };
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            res
        }
    };
    match res {
        Cont(clear) => EditResult::Cont(ctx.buf.get_line(ctx.prompt, clear)),
        Halt(res) => EditResult::Halt(res)
    }
}
<commit_msg>implement a macro to assist with repeated vi commands<commit_after>use encoding::types::EncodingRef;

use error::Error;
use history::{Cursor, History};
use buffer::Buffer;
use parser::{parse, ParseError, ParseSuccess};
use instr;

#[derive(Copy,Clone)]
pub enum EditMode {
    Emacs,
    Vi,
}

#[derive(Copy, Clone, PartialEq)]
pub enum ViMode {
    Insert,
    Normal,
    Replace,
}

pub struct EditCtx<'a> {
    buf: Buffer,
    history_cursor: Cursor<'a>,
    prompt: &'a str,
    seq: Vec<u8>,
    enc: EncodingRef,
    mode: EditMode,
    vi_mode: ViMode,
    vi_count: u32,
}

impl<'a> EditCtx<'a> {

    pub fn new(prompt: &'a str, history: &'a History, enc: EncodingRef, mode: EditMode) -> Self {
        EditCtx {
            buf: Buffer::new(),
            history_cursor: Cursor::new(history),
            prompt: prompt,
            seq: Vec::new(),
            enc: enc,
            mode: mode,
            // always start in insert mode
            vi_mode: ViMode::Insert,
            vi_count: 0,
        }
    }

    pub fn fill(&mut self, byte: u8) {
        self.seq.push(byte)
    }

}

pub enum EditResult<C> {
    Cont(C),
    Halt(Result<String, Error>)
}

macro_rules! vi_repeat {
    ( $ctx:ident, $x:expr ) => {
        match $ctx.vi_count {
            0 => { $x; }
            _ => for _ in 0..$ctx.vi_count { $x; }
        }
        $ctx.vi_count = 0;
    };
}

pub fn edit<'a>(ctx: &mut EditCtx<'a>) -> EditResult<Vec<u8>> {
    use self::EditResult::*;

    let res = match parse(&ctx.seq, ctx.enc) {
        Err(ParseError::Error(len)) => {
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            Cont(false)
        },
        Err(ParseError::Incomplete) => Cont(false),
        Ok(ParseSuccess(token, len)) => {
            let res = match instr::interpret_token(token, ctx.mode, ctx.vi_mode) {
                instr::Instr::Done => {
                    Halt(Ok(ctx.buf.drain()))
                },
                instr::Instr::DeleteCharLeftOfCursor => {
                    ctx.buf.delete_char_left_of_cursor();
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursor => {
                    ctx.buf.delete_char_right_of_cursor();
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursorOrEOF => {
                    if !ctx.buf.delete_char_right_of_cursor() {
                        Halt(Err(Error::EndOfFile))
                    } else {
                        Cont(false)
                    }
                },
                instr::Instr::MoveCursorLeft => {
                    ctx.buf.move_left();
                    Cont(false)
                },
                instr::Instr::MoveCursorRight => {
                    ctx.buf.move_right();
                    Cont(false)
                },
                instr::Instr::MoveCursorStart => {
                    ctx.buf.move_start();
                    Cont(false)
                },
                instr::Instr::MoveCursorEnd => {
                    ctx.buf.move_end();
                    Cont(false)
                },
                instr::Instr::HistoryPrev => {
                    if ctx.history_cursor.incr() {
                        ctx.buf.swap()
                    }
                    ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    Cont(false)
                },
                instr::Instr::HistoryNext => {
                    if ctx.history_cursor.decr() {
                        ctx.buf.swap()
                    }
                    ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    Cont(false)
                },
                instr::Instr::NormalMode => {
                    if ctx.vi_mode == ViMode::Insert {
                        // cursor moves left when leaving insert mode
                        ctx.buf.move_left();
                    }
                    ctx.vi_mode = ViMode::Normal;
                    ctx.vi_count = 0;
                    Cont(false)
                }
                instr::Instr::ReplaceMode => {
                    ctx.vi_mode = ViMode::Replace;
                    Cont(false)
                }
                instr::Instr::Insert => {
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::InsertStart => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_start();
                    Cont(false)
                }
                instr::Instr::Append => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_right();
                    Cont(false)
                }
                instr::Instr::AppendEnd => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_end();
                    Cont(false)
                }
                instr::Instr::Digit(i) => {
                    match (ctx.vi_count, i) {
                        // if count is 0, then 0 moves to the start of a line
                        (0, 0) => ctx.buf.move_start(),
                        // otherwise add a digit to the count
                        (_, i) => ctx.vi_count = ctx.vi_count * 10 + i,
                    }
                    Cont(false)
                }
                instr::Instr::MoveEndOfWordRight => {
                    ctx.buf.move_to_end_of_word();
                    Cont(false)
                }
                instr::Instr::Substitute => {
                    ctx.buf.delete_char_right_of_cursor();
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::Noop => {
                    Cont(false)
                },
                instr::Instr::Cancel => Halt(Err(Error::Cancel)),
                instr::Instr::Clear => {
                    Cont(true)
                },
                instr::Instr::InsertAtCursor(text) => {
                    ctx.buf.insert_chars_at_cursor(text);
                    Cont(false)
                }
                instr::Instr::ReplaceAtCursor(text) => {
                    ctx.buf.replace_chars_at_cursor(text);
                    ctx.vi_mode = ViMode::Normal;
                    Cont(false)
                }
            };
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            res
        }
    };
    match res {
        Cont(clear) => EditResult::Cont(ctx.buf.get_line(ctx.prompt, clear)),
        Halt(res) => EditResult::Halt(res)
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

extern crate regex;

use crate::common::util::*;

extern crate stat;
pub use self::stat::*;

#[test]
fn test_scanners() {
    assert_eq!(Some((-5, 2)), "-5zxc".scan_num::<i32>());
    assert_eq!(Some((51, 2)), "51zxc".scan_num::<u32>());
    assert_eq!(Some((192, 4)), "+192zxc".scan_num::<i32>());
    assert_eq!(None, "z192zxc".scan_num::<i32>());

    assert_eq!(Some(('a', 3)), "141zxc".scan_char(8));
    assert_eq!(Some(('\n', 2)), "12qzxc".scan_char(8)); // spell-checker:disable-line
    assert_eq!(Some(('\r', 1)), "dqzxc".scan_char(16)); // spell-checker:disable-line
    assert_eq!(None, "z2qzxc".scan_char(8)); // spell-checker:disable-line
}

#[test]
fn test_group_num() {
    assert_eq!("12,379,821,234", group_num("12379821234"));
    assert_eq!("21,234", group_num("21234"));
    assert_eq!("821,234", group_num("821234"));
    assert_eq!("1,821,234", group_num("1821234"));
    assert_eq!("1,234", group_num("1234"));
    assert_eq!("234", group_num("234"));
    assert_eq!("24", group_num("24"));
    assert_eq!("4", group_num("4"));
    assert_eq!("", group_num(""));
    assert_eq!("-5", group_num("-5"));
    assert_eq!("-1,234", group_num("-1234"));
}

#[test]
#[should_panic]
fn test_group_num_panic_if_invalid_numeric_characters() {
    group_num("³³³³³");
}

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

    #[test]
    fn normal_format() {
        let s = "%'010.2ac%-#5.w\n";
        let expected = vec![
            Token::Directive {
                flag: F_GROUP | F_ZERO,
                width: 10,
                precision: 2,
                format: 'a',
            },
            Token::Char('c'),
            Token::Directive {
                flag: F_LEFT | F_ALTER,
                width: 5,
                precision: 0,
                format: 'w',
            },
            Token::Char('\n'),
        ];
        assert_eq!(&expected, &Stater::generate_tokens(s, false).unwrap());
    }

    #[test]
    fn printf_format() {
        let s = "%-# 15a\\t\\r\\\"\\\\\\a\\b\\e\\f\\v%+020.-23w\\x12\\167\\132\\112\\n";
        let expected = vec![
            Token::Directive {
                flag: F_LEFT | F_ALTER | F_SPACE,
                width: 15,
                precision: -1,
                format: 'a',
            },
            Token::Char('\t'),
            Token::Char('\r'),
            Token::Char('"'),
            Token::Char('\\'),
            Token::Char('\x07'),
            Token::Char('\x08'),
            Token::Char('\x1B'),
            Token::Char('\x0C'),
            Token::Char('\x0B'),
            Token::Directive {
                flag: F_SIGN | F_ZERO,
                width: 20,
                precision: -1,
                format: 'w',
            },
            Token::Char('\x12'),
            Token::Char('w'),
            Token::Char('Z'),
            Token::Char('J'),
            Token::Char('\n'),
        ];
        assert_eq!(&expected, &Stater::generate_tokens(s, true).unwrap());
    }
}

#[test]
fn test_invalid_option() {
    new_ucmd!().arg("-w").arg("-q").arg("/").fails();
}

#[cfg(unix)]
const NORMAL_FORMAT_STR: &str =
    "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s %u %U %x %X %y %Y %z %Z"; // avoid "%w %W" (birth/creation) due to `stat` limitations and linux kernel & rust version capability variations
#[cfg(any(target_os = "linux", target_os = "android"))]
const DEV_FORMAT_STR: &str =
    "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s (%t/%T) %u %U %w %W %x %X %y %Y %z %Z";
#[cfg(target_os = "linux")]
const FS_FORMAT_STR: &str = "%b %c %i %l %n %s %S %t %T"; // avoid "%a %d %f" which can cause test failure due to race conditions

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_terse_fs_format() {
    let args = ["-f", "-t", "/proc"];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).run().stdout_is(expected_stdout);
}

#[test]
#[cfg(target_os = "linux")]
fn test_fs_format() {
    let args = ["-f", "-c", FS_FORMAT_STR, "/dev/shm"];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).run().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_terse_normal_format() {
    // note: contains birth/creation date which increases test fragility
    // * results may vary due to built-in `stat` limitations as well as linux kernel and rust version capability variations
    let args = ["-t", "/"];
    let ts = TestScenario::new(util_name!());
    let actual = ts.ucmd().args(&args).succeeds().stdout_move_str();
    let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    let v_actual: Vec<&str> = actual.trim().split(' ').collect();
    let mut v_expect: Vec<&str> = expect.trim().split(' ').collect();
    assert!(!v_expect.is_empty());

    // uu_stat does not support selinux
    if v_actual.len() == v_expect.len() - 1 && v_expect[v_expect.len() - 1].contains(':') {
        // assume last element contains: `SELinux security context string`
        v_expect.pop();
    }

    // * allow for inequality if `stat` (aka, expect) returns "0" (unknown value)
    assert!(
        expect == "0"
            || expect == "0\n"
            || v_actual
                .iter()
                .zip(v_expect.iter())
                .all(|(a, e)| a == e || *e == "0" || *e == "0\n")
    );
}

#[cfg(unix)]
#[test]
fn test_format_created_time() {
    let args = ["-c", "%w", "/bin"];
    let ts = TestScenario::new(util_name!());
    let actual = ts.ucmd().args(&args).succeeds().stdout_move_str();
    let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences
    let re = regex::Regex::new(r"\s").unwrap();
    let v_actual: Vec<&str> = re.split(&actual).collect();
    let v_expect: Vec<&str> = re.split(&expect).collect();
    assert!(!v_expect.is_empty());
    // * allow for inequality if `stat` (aka, expect) returns "-" (unknown value)
    assert!(
        expect == "-"
            || expect == "-\n"
            || v_actual
                .iter()
                .zip(v_expect.iter())
                .all(|(a, e)| a == e || *e == "-" || *e == "-\n")
    );
}

#[cfg(unix)]
#[test]
fn test_format_created_seconds() {
    let args = ["-c", "%W", "/bin"];
    let ts = TestScenario::new(util_name!());
    let actual = ts.ucmd().args(&args).succeeds().stdout_move_str();
    let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences
    let re = regex::Regex::new(r"\s").unwrap();
    let v_actual: Vec<&str> = re.split(&actual).collect();
    let v_expect: Vec<&str> = re.split(&expect).collect();
    assert!(!v_expect.is_empty());
    // * allow for inequality if `stat` (aka, expect) returns "0" (unknown value)
    assert!(
        expect == "0"
            || expect == "0\n"
            || v_actual
                .iter()
                .zip(v_expect.iter())
                .all(|(a, e)| a == e || *e == "0" || *e == "0\n")
    );
}

#[cfg(unix)]
#[test]
fn test_normal_format() {
    let args = ["-c", NORMAL_FORMAT_STR, "/bin"];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_symlinks() {
    let ts = TestScenario::new(util_name!());
    let at = &ts.fixtures;

    let mut tested: bool = false;
    // arbitrarily chosen symlinks with hope that the CI environment provides at least one of them
    for file in [
        "/bin/sh",
        "/data/data/com.termux/files/usr/bin/sh", // spell-checker:disable-line
        "/bin/sudoedit",
        "/usr/bin/ex",
        "/etc/localtime",
        "/etc/aliases",
    ] {
        if at.file_exists(file) && at.is_symlink(file) {
            tested = true;
            let args = ["-c", NORMAL_FORMAT_STR, file];
            let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
            ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
            // -L, --dereference    follow links
            let args = ["-L", "-c", NORMAL_FORMAT_STR, file];
            let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
            ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
        }
    }
    if !tested {
        panic!("No symlink found to test in this environment");
    }
}

#[cfg(any(target_os = "linux", target_os = "android", target_vendor = "apple"))]
#[test]
fn test_char() {
    // TODO: "(%t) (%x) (%w)" deviate from GNU stat for `character special file` on macOS
    // Diff < left / right > :
    // <"(f0000) (2021-05-20 23:08:03.442555000 +0200) (1970-01-01 01:00:00.000000000 +0100)\n"
    // >"(f) (2021-05-20 23:08:03.455598000 +0200) (-)\n"
    let args = [
        "-c",
        #[cfg(any(target_os = "linux", target_os = "android"))]
        DEV_FORMAT_STR,
        #[cfg(target_os = "linux")]
        "/dev/pts/ptmx",
        #[cfg(any(target_vendor = "apple"))]
        "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s (/%T) %u %U %W %X %y %Y %z %Z",
        #[cfg(any(target_os = "android", target_vendor = "apple"))]
        "/dev/ptmx",
    ];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_multi_files() {
    let args = [
        "-c",
        NORMAL_FORMAT_STR,
        "/dev",
        "/usr/lib",
        #[cfg(target_os = "linux")]
        "/etc/fstab",
        "/var",
    ];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_printf() {
    let args = [
        "--printf=123%-# 15q\\r\\\"\\\\\\a\\b\\e\\f\\v%+020.23m\\x12\\167\\132\\112\\n",
        "/",
    ];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}
<commit_msg>test_stat: add tests for issues with stdin<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

extern crate regex;

use crate::common::util::*;

extern crate stat;
pub use self::stat::*;

#[test]
fn test_scanners() {
    assert_eq!(Some((-5, 2)), "-5zxc".scan_num::<i32>());
    assert_eq!(Some((51, 2)), "51zxc".scan_num::<u32>());
    assert_eq!(Some((192, 4)), "+192zxc".scan_num::<i32>());
    assert_eq!(None, "z192zxc".scan_num::<i32>());

    assert_eq!(Some(('a', 3)), "141zxc".scan_char(8));
    assert_eq!(Some(('\n', 2)), "12qzxc".scan_char(8)); // spell-checker:disable-line
    assert_eq!(Some(('\r', 1)), "dqzxc".scan_char(16)); // spell-checker:disable-line
    assert_eq!(None, "z2qzxc".scan_char(8)); // spell-checker:disable-line
}

#[test]
fn test_group_num() {
    assert_eq!("12,379,821,234", group_num("12379821234"));
    assert_eq!("21,234", group_num("21234"));
    assert_eq!("821,234", group_num("821234"));
    assert_eq!("1,821,234", group_num("1821234"));
    assert_eq!("1,234", group_num("1234"));
    assert_eq!("234", group_num("234"));
    assert_eq!("24", group_num("24"));
    assert_eq!("4", group_num("4"));
    assert_eq!("", group_num(""));
    assert_eq!("-5", group_num("-5"));
    assert_eq!("-1,234", group_num("-1234"));
}

#[test]
#[should_panic]
fn test_group_num_panic_if_invalid_numeric_characters() {
    group_num("³³³³³");
}

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

    #[test]
    fn normal_format() {
        let s = "%'010.2ac%-#5.w\n";
        let expected = vec![
            Token::Directive {
                flag: F_GROUP | F_ZERO,
                width: 10,
                precision: 2,
                format: 'a',
            },
            Token::Char('c'),
            Token::Directive {
                flag: F_LEFT | F_ALTER,
                width: 5,
                precision: 0,
                format: 'w',
            },
            Token::Char('\n'),
        ];
        assert_eq!(&expected, &Stater::generate_tokens(s, false).unwrap());
    }

    #[test]
    fn printf_format() {
        let s = "%-# 15a\\t\\r\\\"\\\\\\a\\b\\e\\f\\v%+020.-23w\\x12\\167\\132\\112\\n";
        let expected = vec![
            Token::Directive {
                flag: F_LEFT | F_ALTER | F_SPACE,
                width: 15,
                precision: -1,
                format: 'a',
            },
            Token::Char('\t'),
            Token::Char('\r'),
            Token::Char('"'),
            Token::Char('\\'),
            Token::Char('\x07'),
            Token::Char('\x08'),
            Token::Char('\x1B'),
            Token::Char('\x0C'),
            Token::Char('\x0B'),
            Token::Directive {
                flag: F_SIGN | F_ZERO,
                width: 20,
                precision: -1,
                format: 'w',
            },
            Token::Char('\x12'),
            Token::Char('w'),
            Token::Char('Z'),
            Token::Char('J'),
            Token::Char('\n'),
        ];
        assert_eq!(&expected, &Stater::generate_tokens(s, true).unwrap());
    }
}

#[test]
fn test_invalid_option() {
    new_ucmd!().arg("-w").arg("-q").arg("/").fails();
}

#[cfg(unix)]
const NORMAL_FORMAT_STR: &str =
    "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s %u %U %x %X %y %Y %z %Z"; // avoid "%w %W" (birth/creation) due to `stat` limitations and linux kernel & rust version capability variations
#[cfg(any(target_os = "linux", target_os = "android"))]
const DEV_FORMAT_STR: &str =
    "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s (%t/%T) %u %U %w %W %x %X %y %Y %z %Z";
#[cfg(target_os = "linux")]
const FS_FORMAT_STR: &str = "%b %c %i %l %n %s %S %t %T"; // avoid "%a %d %f" which can cause test failure due to race conditions

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_terse_fs_format() {
    let args = ["-f", "-t", "/proc"];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).run().stdout_is(expected_stdout);
}

#[test]
#[cfg(target_os = "linux")]
fn test_fs_format() {
    let args = ["-f", "-c", FS_FORMAT_STR, "/dev/shm"];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).run().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_terse_normal_format() {
    // note: contains birth/creation date which increases test fragility
    // * results may vary due to built-in `stat` limitations as well as linux kernel and rust version capability variations
    let args = ["-t", "/"];
    let ts = TestScenario::new(util_name!());
    let actual = ts.ucmd().args(&args).succeeds().stdout_move_str();
    let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    let v_actual: Vec<&str> = actual.trim().split(' ').collect();
    let mut v_expect: Vec<&str> = expect.trim().split(' ').collect();
    assert!(!v_expect.is_empty());

    // uu_stat does not support selinux
    if v_actual.len() == v_expect.len() - 1 && v_expect[v_expect.len() - 1].contains(':') {
        // assume last element contains: `SELinux security context string`
        v_expect.pop();
    }

    // * allow for inequality if `stat` (aka, expect) returns "0" (unknown value)
    assert!(
        expect == "0"
            || expect == "0\n"
            || v_actual
                .iter()
                .zip(v_expect.iter())
                .all(|(a, e)| a == e || *e == "0" || *e == "0\n")
    );
}

#[cfg(unix)]
#[test]
fn test_format_created_time() {
    let args = ["-c", "%w", "/bin"];
    let ts = TestScenario::new(util_name!());
    let actual = ts.ucmd().args(&args).succeeds().stdout_move_str();
    let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences
    let re = regex::Regex::new(r"\s").unwrap();
    let v_actual: Vec<&str> = re.split(&actual).collect();
    let v_expect: Vec<&str> = re.split(&expect).collect();
    assert!(!v_expect.is_empty());
    // * allow for inequality if `stat` (aka, expect) returns "-" (unknown value)
    assert!(
        expect == "-"
            || expect == "-\n"
            || v_actual
                .iter()
                .zip(v_expect.iter())
                .all(|(a, e)| a == e || *e == "-" || *e == "-\n")
    );
}

#[cfg(unix)]
#[test]
fn test_format_created_seconds() {
    let args = ["-c", "%W", "/bin"];
    let ts = TestScenario::new(util_name!());
    let actual = ts.ucmd().args(&args).succeeds().stdout_move_str();
    let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences
    let re = regex::Regex::new(r"\s").unwrap();
    let v_actual: Vec<&str> = re.split(&actual).collect();
    let v_expect: Vec<&str> = re.split(&expect).collect();
    assert!(!v_expect.is_empty());
    // * allow for inequality if `stat` (aka, expect) returns "0" (unknown value)
    assert!(
        expect == "0"
            || expect == "0\n"
            || v_actual
                .iter()
                .zip(v_expect.iter())
                .all(|(a, e)| a == e || *e == "0" || *e == "0\n")
    );
}

#[cfg(unix)]
#[test]
fn test_normal_format() {
    let args = ["-c", NORMAL_FORMAT_STR, "/bin"];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_symlinks() {
    let ts = TestScenario::new(util_name!());
    let at = &ts.fixtures;

    let mut tested: bool = false;
    // arbitrarily chosen symlinks with hope that the CI environment provides at least one of them
    for file in [
        "/bin/sh",
        "/data/data/com.termux/files/usr/bin/sh", // spell-checker:disable-line
        "/bin/sudoedit",
        "/usr/bin/ex",
        "/etc/localtime",
        "/etc/aliases",
    ] {
        if at.file_exists(file) && at.is_symlink(file) {
            tested = true;
            let args = ["-c", NORMAL_FORMAT_STR, file];
            let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
            ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
            // -L, --dereference    follow links
            let args = ["-L", "-c", NORMAL_FORMAT_STR, file];
            let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
            ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
        }
    }
    if !tested {
        panic!("No symlink found to test in this environment");
    }
}

#[cfg(any(target_os = "linux", target_os = "android", target_vendor = "apple"))]
#[test]
fn test_char() {
    // TODO: "(%t) (%x) (%w)" deviate from GNU stat for `character special file` on macOS
    // Diff < left / right > :
    // <"(f0000) (2021-05-20 23:08:03.442555000 +0200) (1970-01-01 01:00:00.000000000 +0100)\n"
    // >"(f) (2021-05-20 23:08:03.455598000 +0200) (-)\n"
    let args = [
        "-c",
        #[cfg(any(target_os = "linux", target_os = "android"))]
        DEV_FORMAT_STR,
        #[cfg(target_os = "linux")]
        "/dev/pts/ptmx",
        #[cfg(any(target_vendor = "apple"))]
        "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s (/%T) %u %U %W %X %y %Y %z %Z",
        #[cfg(any(target_os = "android", target_vendor = "apple"))]
        "/dev/ptmx",
    ];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_multi_files() {
    let args = [
        "-c",
        NORMAL_FORMAT_STR,
        "/dev",
        "/usr/lib",
        #[cfg(target_os = "linux")]
        "/etc/fstab",
        "/var",
    ];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_printf() {
    let args = [
        "--printf=123%-# 15q\\r\\\"\\\\\\a\\b\\e\\f\\v%+020.23m\\x12\\167\\132\\112\\n",
        "/",
    ];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
#[cfg(disable_until_fixed)]
fn test_stdin_pipe_fifo1() {
    // $ echo | stat -
    // File: -
    // Size: 0               Blocks: 0          IO Block: 4096   fifo
    // use std::process::{Command, Stdio};
    new_ucmd!()
        .arg("-")
        .set_stdin(std::process::Stdio::piped())
        .run()
        .no_stderr()
        .stdout_contains("fifo")
        .stdout_contains("File: -")
        .succeeded();
}

#[cfg(unix)]
#[test]
#[cfg(disable_until_fixed)]
fn test_stdin_pipe_fifo2() {
    // $ stat -
    // File: -
    // Size: 0               Blocks: 0          IO Block: 1024   character special file
    new_ucmd!()
        .arg("-")
        .run()
        .no_stderr()
        .stdout_contains("character special file")
        .stdout_contains("File: -")
        .succeeded();
}

#[cfg(unix)]
#[test]
#[cfg(disable_until_fixed)]
fn test_stdin_redirect() {
    // $ touch f && stat - < f
    // File: -
    // Size: 0               Blocks: 0          IO Block: 4096   regular empty file

    let ts = TestScenario::new(util_name!());
    let at = &ts.fixtures;
    at.touch("f");
    new_ucmd!()
        .arg("-")
        .set_stdin(std::fs::File::open("f").unwrap())
        .run()
        .no_stderr()
        .stdout_contains("regular empty file")
        .stdout_contains("File: -")
        .succeeded();
}
<|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::io::{Command, fs, USER_RWX};
use std::os;
use std::path::BytesContainer;
use std::rand::random;

fn main() {
    // If we're the child, make sure we were invoked correctly
    let args = os::args();
    if args.len() > 1 && args[1].as_slice() == "child" {
        return assert_eq!(args[0],
                          format!("mytest{}", os::consts::EXE_SUFFIX));
    }

    test();
}

fn test() {
    // If we're the parent, copy our own binary to a new directory.
    let my_path = os::self_exe_name().unwrap();
    let my_dir  = my_path.dir_path();

    let random_u32: u32 = random();
    let child_dir = Path::new(my_dir.join(format!("issue-15149-child-{}",
                                                  random_u32)));
    fs::mkdir(&child_dir, USER_RWX).unwrap();

    let child_path = child_dir.join(format!("mytest{}",
                                            os::consts::EXE_SUFFIX));
    fs::copy(&my_path, &child_path).unwrap();

    // Append the new directory to our own PATH.
    let mut path = os::split_paths(os::getenv("PATH").unwrap_or(String::new()));
    path.push(child_dir.clone());
    let path = os::join_paths(path.as_slice()).unwrap();

    let child_output = Command::new("mytest").env("PATH", path.as_slice())
                                             .arg("child")
                                             .output().unwrap();

    assert!(child_output.status.success(),
            format!("child assertion failed\n child stdout:\n {}\n child stderr:\n {}",
                    child_output.output.container_as_str().unwrap(),
                    child_output.error.container_as_str().unwrap()));

    fs::rmdir_recursive(&child_dir).unwrap();

}
<commit_msg>assert path ends with executable. On Windows the process executable contains the full path<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::slice::SliceExt;
use std::io::{Command, fs, USER_RWX};
use std::os;
use std::path::BytesContainer;
use std::rand::random;

fn main() {
    // If we're the child, make sure we were invoked correctly
    let args = os::args();
    if args.len() > 1 && args[1].as_slice() == "child" {
        // FIXME: This should check the whole `args[0]` instead of just
        // checking that it ends_with the executable name. This
        // is needed because of Windows, which has a different behavior.
        // See #15149 for more info.
        return assert!(args[0].ends_with(&format!("mytest{}", os::consts::EXE_SUFFIX)[]));
    }

    test();
}

fn test() {
    // If we're the parent, copy our own binary to a new directory.
    let my_path = os::self_exe_name().unwrap();
    let my_dir  = my_path.dir_path();

    let random_u32: u32 = random();
    let child_dir = Path::new(my_dir.join(format!("issue-15149-child-{}",
                                                  random_u32)));
    fs::mkdir(&child_dir, USER_RWX).unwrap();

    let child_path = child_dir.join(format!("mytest{}",
                                            os::consts::EXE_SUFFIX));
    fs::copy(&my_path, &child_path).unwrap();

    // Append the new directory to our own PATH.
    let mut path = os::split_paths(os::getenv("PATH").unwrap_or(String::new()));
    path.push(child_dir.clone());
    let path = os::join_paths(path.as_slice()).unwrap();

    let child_output = Command::new("mytest").env("PATH", path.as_slice())
                                             .arg("child")
                                             .output().unwrap();

    assert!(child_output.status.success(),
            format!("child assertion failed\n child stdout:\n {}\n child stderr:\n {}",
                    child_output.output.container_as_str().unwrap(),
                    child_output.error.container_as_str().unwrap()));

    fs::rmdir_recursive(&child_dir).unwrap();

}
<|endoftext|>


<commit_before>#![feature(generators)]

#![allow(non_camel_case_types)]
#![allow(dead_code)]
#![allow(unreachable_code)]
#![allow(unused_parens)]

#![recursion_limit = "256"]

use std::cell::Cell;
use std::mem::swap;

// Just a grab bag of stuff that you wouldn't want to actually write.

fn strange() -> bool { let _x: bool = return true; }

fn funny() {
    fn f(_x: ()) { }
    f(return);
}

fn what() {
    fn the(x: &Cell<bool>) {
        return while !x.get() { x.set(true); };
    }
    let i = &Cell::new(false);
    let dont = {||the(i)};
    dont();
    assert!((i.get()));
}

fn zombiejesus() {
    loop {
        while (return) {
            if (return) {
                match (return) {
                    1 => {
                        if (return) {
                            return
                        } else {
                            return
                        }
                    }
                    _ => { return }
                };
            } else if (return) {
                return;
            }
        }
        if (return) { break; }
    }
}

fn notsure() {
    let mut _x: isize;
    let mut _y = (_x = 0) == (_x = 0);
    let mut _z = (_x = 0) < (_x = 0);
    let _a = (_x += 0) == (_x = 0);
    let _b = swap(&mut _y, &mut _z) == swap(&mut _y, &mut _z);
}

fn canttouchthis() -> usize {
    fn p() -> bool { true }
    let _a = (assert!((true)) == (assert!(p())));
    let _c = (assert!((p())) == ());
    let _b: bool = (println!("{}", 0) == (return 0));
}

fn angrydome() {
    loop { if break { } }
    let mut i = 0;
    loop { i += 1; if i == 1 { match (continue) { 1 => { }, _ => panic!("wat") } }
      break; }
}

fn evil_lincoln() { let _evil = println!("lincoln"); }

fn dots() {
    assert_eq!(String::from(".................................................."),
               format!("{:?}", .. .. .. .. .. .. .. .. .. .. .. .. ..
                               .. .. .. .. .. .. .. .. .. .. .. ..));
}

fn u8(u8: u8) {
    if u8 != 0u8 {
        assert_eq!(8u8, {
            macro_rules! u8 {
                (u8) => {
                    mod u8 {
                        pub fn u8<'u8: 'u8 + 'u8>(u8: &'u8 u8) -> &'u8 u8 {
                            "u8";
                            u8
                        }
                    }
                };
            }

            u8!(u8);
            let &u8: &u8 = u8::u8(&8u8);
            ::u8(0u8);
            u8
        });
    }
}

fn fishy() {
    assert_eq!(String::from("><>"),
               String::<>::from::<>("><>").chars::<>().rev::<>().collect::<String>());
}

fn union() {
    union union<'union> { union: &'union union<'union>, }
}

fn special_characters() {
    let val = !((|(..):(_,_),__@_|__)((&*"\\",'🤔')/**/,{})=={&[..=..][..];})//
    ;
    assert!(!val);
}

fn punch_card() -> impl std::fmt::Debug {
    ..=..=.. ..    .. .. .. ..    .. .. .. ..    .. ..=.. ..
    ..=.. ..=..    .. .. .. ..    .. .. .. ..    ..=..=..=..
    ..=.. ..=..    ..=.. ..=..    .. ..=..=..    .. ..=.. ..
    ..=..=.. ..    ..=.. ..=..    ..=.. .. ..    .. ..=.. ..
    ..=.. ..=..    ..=.. ..=..    .. ..=.. ..    .. ..=.. ..
    ..=.. ..=..    ..=.. ..=..    .. .. ..=..    .. ..=.. ..
    ..=.. ..=..    .. ..=..=..    ..=..=.. ..    .. ..=.. ..
}

fn r#match() {
    let val = match match match match match () {
        () => ()
    } {
        () => ()
    } {
        () => ()
    } {
        () => ()
    } {
        () => ()
    };
    assert_eq!(val, ());
}

fn i_yield() {
    static || {
        yield yield yield yield yield yield yield yield yield;
    };
}

pub fn main() {
    strange();
    funny();
    what();
    zombiejesus();
    notsure();
    canttouchthis();
    angrydome();
    evil_lincoln();
    dots();
    u8(8u8);
    fishy();
    union();
    special_characters();
    punch_card();
    r#match();
    i_yield();
}
<commit_msg>if if if if<commit_after>#![feature(generators)]

#![allow(non_camel_case_types)]
#![allow(dead_code)]
#![allow(unreachable_code)]
#![allow(unused_parens)]

#![recursion_limit = "256"]

use std::cell::Cell;
use std::mem::swap;

// Just a grab bag of stuff that you wouldn't want to actually write.

fn strange() -> bool { let _x: bool = return true; }

fn funny() {
    fn f(_x: ()) { }
    f(return);
}

fn what() {
    fn the(x: &Cell<bool>) {
        return while !x.get() { x.set(true); };
    }
    let i = &Cell::new(false);
    let dont = {||the(i)};
    dont();
    assert!((i.get()));
}

fn zombiejesus() {
    loop {
        while (return) {
            if (return) {
                match (return) {
                    1 => {
                        if (return) {
                            return
                        } else {
                            return
                        }
                    }
                    _ => { return }
                };
            } else if (return) {
                return;
            }
        }
        if (return) { break; }
    }
}

fn notsure() {
    let mut _x: isize;
    let mut _y = (_x = 0) == (_x = 0);
    let mut _z = (_x = 0) < (_x = 0);
    let _a = (_x += 0) == (_x = 0);
    let _b = swap(&mut _y, &mut _z) == swap(&mut _y, &mut _z);
}

fn canttouchthis() -> usize {
    fn p() -> bool { true }
    let _a = (assert!((true)) == (assert!(p())));
    let _c = (assert!((p())) == ());
    let _b: bool = (println!("{}", 0) == (return 0));
}

fn angrydome() {
    loop { if break { } }
    let mut i = 0;
    loop { i += 1; if i == 1 { match (continue) { 1 => { }, _ => panic!("wat") } }
      break; }
}

fn evil_lincoln() { let _evil = println!("lincoln"); }

fn dots() {
    assert_eq!(String::from(".................................................."),
               format!("{:?}", .. .. .. .. .. .. .. .. .. .. .. .. ..
                               .. .. .. .. .. .. .. .. .. .. .. ..));
}

fn u8(u8: u8) {
    if u8 != 0u8 {
        assert_eq!(8u8, {
            macro_rules! u8 {
                (u8) => {
                    mod u8 {
                        pub fn u8<'u8: 'u8 + 'u8>(u8: &'u8 u8) -> &'u8 u8 {
                            "u8";
                            u8
                        }
                    }
                };
            }

            u8!(u8);
            let &u8: &u8 = u8::u8(&8u8);
            ::u8(0u8);
            u8
        });
    }
}

fn fishy() {
    assert_eq!(String::from("><>"),
               String::<>::from::<>("><>").chars::<>().rev::<>().collect::<String>());
}

fn union() {
    union union<'union> { union: &'union union<'union>, }
}

fn special_characters() {
    let val = !((|(..):(_,_),__@_|__)((&*"\\",'🤔')/**/,{})=={&[..=..][..];})//
    ;
    assert!(!val);
}

fn punch_card() -> impl std::fmt::Debug {
    ..=..=.. ..    .. .. .. ..    .. .. .. ..    .. ..=.. ..
    ..=.. ..=..    .. .. .. ..    .. .. .. ..    ..=..=..=..
    ..=.. ..=..    ..=.. ..=..    .. ..=..=..    .. ..=.. ..
    ..=..=.. ..    ..=.. ..=..    ..=.. .. ..    .. ..=.. ..
    ..=.. ..=..    ..=.. ..=..    .. ..=.. ..    .. ..=.. ..
    ..=.. ..=..    ..=.. ..=..    .. .. ..=..    .. ..=.. ..
    ..=.. ..=..    .. ..=..=..    ..=..=.. ..    .. ..=.. ..
}

fn r#match() {
    let val = match match match match match () {
        () => ()
    } {
        () => ()
    } {
        () => ()
    } {
        () => ()
    } {
        () => ()
    };
    assert_eq!(val, ());
}

fn i_yield() {
    static || {
        yield yield yield yield yield yield yield yield yield;
    };
}

fn match_nested_if() {
    let val = match () {
        () if if if if true {true} else {false} {true} else {false} {true} else {false} => true,
        _ => false,
    };
    assert!(val);
}

pub fn main() {
    strange();
    funny();
    what();
    zombiejesus();
    notsure();
    canttouchthis();
    angrydome();
    evil_lincoln();
    dots();
    u8(8u8);
    fishy();
    union();
    special_characters();
    punch_card();
    r#match();
    i_yield();
    match_nested_if();
}
<|endoftext|>


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

pub trait Foo {
    // @has assoc_consts/trait.Foo.html '//*[@class="rust trait"]' \
    //      'const FOO: usize;'
    // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
    const FOO: usize = 12;
    // @has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool'
    const FOO_NO_DEFAULT: bool;
    // @!has - FOO_HIDDEN
    #[doc(hidden)]
    const FOO_HIDDEN: u8 = 0;
}

pub struct Bar;

impl Foo for Bar {
    // @has assoc_consts/struct.Bar.html '//code' 'impl Foo for Bar'
    // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
    const FOO: usize = 12;
    // @has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool'
    const FOO_NO_DEFAULT: bool = false;
    // @!has - FOO_HIDDEN
    #[doc(hidden)]
    const FOO_HIDDEN: u8 = 0;
}

impl Bar {
    // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.BAR"]' \
    //      'const BAR: usize'
    pub const BAR: usize = 3;
}

pub struct Baz<'a, U: 'a, T>(T, &'a [U]);

impl Bar {
    // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.BAZ"]' \
    //      "const BAZ: Baz<'static, u8, u32>"
    pub const BAZ: Baz<'static, u8, u32> = Baz(321, &[1, 2, 3]);
}

pub fn f(_: &(ToString + 'static)) {}

impl Bar {
    // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.F"]' \
    //      "const F: fn(_: &(dyn ToString + 'static))"
    pub const F: fn(_: &(ToString + 'static)) = f;
}

impl Bar {
    // @!has assoc_consts/struct.Bar.html 'BAR_PRIVATE'
    const BAR_PRIVATE: char = 'a';
    // @!has assoc_consts/struct.Bar.html 'BAR_HIDDEN'
    #[doc(hidden)]
    pub const BAR_HIDDEN: &'static str = "a";
}

// @has assoc_consts/trait.Qux.html
pub trait Qux {
    // @has - '//*[@id="associatedconstant.QUX0"]' 'const QUX0: u8'
    // @has - '//*[@class="docblock"]' "Docs for QUX0 in trait."
    /// Docs for QUX0 in trait.
    const QUX0: u8;
    // @has - '//*[@id="associatedconstant.QUX1"]' 'const QUX1: i8'
    // @has - '//*[@class="docblock"]' "Docs for QUX1 in trait."
    /// Docs for QUX1 in trait.
    const QUX1: i8;
    // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT0 in trait."
    /// Docs for QUX_DEFAULT0 in trait.
    const QUX_DEFAULT0: u16 = 1;
    // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in trait."
    /// Docs for QUX_DEFAULT1 in trait.
    const QUX_DEFAULT1: i16 = 2;
    // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32'
    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
    /// Docs for QUX_DEFAULT2 in trait.
    const QUX_DEFAULT2: u32 = 3;
}

// @has assoc_consts/struct.Bar.html '//code' 'impl Qux for Bar'
impl Qux for Bar {
    // @has - '//*[@id="associatedconstant.QUX0"]' 'const QUX0: u8'
    // @has - '//*[@class="docblock"]' "Docs for QUX0 in trait."
    /// Docs for QUX0 in trait.
    const QUX0: u8 = 4;
    // @has - '//*[@id="associatedconstant.QUX1"]' 'const QUX1: i8'
    // @has - '//*[@class="docblock"]' "Docs for QUX1 in impl."
    /// Docs for QUX1 in impl.
    const QUX1: i8 = 5;
    // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT0 in trait."
    const QUX_DEFAULT0: u16 = 6;
    // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl."
    /// Docs for QUX_DEFAULT1 in impl.
    const QUX_DEFAULT1: i16 = 7;
    // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32'
    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
}
<commit_msg>Update failing test<commit_after>// Copyright 2015 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.

pub trait Foo {
    // @has assoc_consts/trait.Foo.html '//*[@class="rust trait"]' \
    //      'const FOO: usize;'
    // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
    const FOO: usize = 12;
    // @has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool'
    const FOO_NO_DEFAULT: bool;
    // @!has - FOO_HIDDEN
    #[doc(hidden)]
    const FOO_HIDDEN: u8 = 0;
}

pub struct Bar;

impl Foo for Bar {
    // @has assoc_consts/struct.Bar.html '//code' 'impl Foo for Bar'
    // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
    const FOO: usize = 12;
    // @has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool'
    const FOO_NO_DEFAULT: bool = false;
    // @!has - FOO_HIDDEN
    #[doc(hidden)]
    const FOO_HIDDEN: u8 = 0;
}

impl Bar {
    // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.BAR"]' \
    //      'const BAR: usize'
    pub const BAR: usize = 3;
}

pub struct Baz<'a, U: 'a, T>(T, &'a [U]);

impl Bar {
    // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.BAZ"]' \
    //      "const BAZ: Baz<'static, u8, u32>"
    pub const BAZ: Baz<'static, u8, u32> = Baz(321, &[1, 2, 3]);
}

pub fn f(_: &(ToString + 'static)) {}

impl Bar {
    // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.F"]' \
    //      "const F: fn(_: &(dyn ToString + 'static))"
    pub const F: fn(_: &(ToString + 'static)) = f;
}

impl Bar {
    // @!has assoc_consts/struct.Bar.html 'BAR_PRIVATE'
    const BAR_PRIVATE: char = 'a';
    // @!has assoc_consts/struct.Bar.html 'BAR_HIDDEN'
    #[doc(hidden)]
    pub const BAR_HIDDEN: &'static str = "a";
}

// @has assoc_consts/trait.Qux.html
pub trait Qux {
    // @has - '//*[@id="associatedconstant.QUX0"]' 'const QUX0: u8'
    // @has - '//*[@class="docblock"]' "Docs for QUX0 in trait."
    /// Docs for QUX0 in trait.
    const QUX0: u8;
    // @has - '//*[@id="associatedconstant.QUX1"]' 'const QUX1: i8'
    // @has - '//*[@class="docblock"]' "Docs for QUX1 in trait."
    /// Docs for QUX1 in trait.
    const QUX1: i8;
    // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
    /// Docs for QUX_DEFAULT12 in trait.
    const QUX_DEFAULT0: u16 = 1;
    // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in trait."
    /// Docs for QUX_DEFAULT1 in trait.
    const QUX_DEFAULT1: i16 = 2;
    // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32'
    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
    /// Docs for QUX_DEFAULT2 in trait.
    const QUX_DEFAULT2: u32 = 3;
}

// @has assoc_consts/struct.Bar.html '//code' 'impl Qux for Bar'
impl Qux for Bar {
    // @has - '//*[@id="associatedconstant.QUX0"]' 'const QUX0: u8'
    // @has - '//*[@class="docblock"]' "Docs for QUX0 in trait."
    /// Docs for QUX0 in trait.
    const QUX0: u8 = 4;
    // @has - '//*[@id="associatedconstant.QUX1"]' 'const QUX1: i8'
    // @has - '//*[@class="docblock"]' "Docs for QUX1 in impl."
    /// Docs for QUX1 in impl.
    const QUX1: i8 = 5;
    // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
    // @has - '//*[@class="docblock hidden"]' "Docs for QUX_DEFAULT12 in trait."
    const QUX_DEFAULT0: u16 = 6;
    // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl."
    /// Docs for QUX_DEFAULT1 in impl.
    const QUX_DEFAULT1: i16 = 7;
    // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32'
    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
}
<|endoftext|>


<commit_before>use num::cast::*;
use vec::{Vec2, Vec3, Vec4};

pub trait Mix {
    pure fn mix(other: &self, value: &self) -> self;
}

#[inline(always)] pub pure fn mix<T:Mix>(a: &T, b: &T, value: &T) -> T { a.mix(b, value) }

pub impl f32: Mix {
    #[inline(always)]
    pure fn mix(other: &f32, value: &f32) -> f32 {
        self * (1f32 - (*value)) + (*other) * (*value)
    }
}

pub impl f64: Mix {
    #[inline(always)]
    pure fn mix(other: &f64, value: &f64) -> f64 {
        self * (1f64 - (*value)) + (*other) * (*value)
    }
}

pub impl float: Mix {
    #[inline(always)]
    pure fn mix(other: &float, value: &float) -> float {
        self * (1f - (*value)) + (*other) * (*value)
    }
}

pub impl<T:Copy Mix> Vec2<T>: Mix {
    #[inline(always)]
    pure fn mix(other: &Vec2<T>, values: &Vec2<T>) -> Vec2<T> {
        Vec2::new(self[0].mix(&other[0], &values[0]),
                  self[1].mix(&other[1], &values[1]))
    }
}

pub impl<T:Copy Mix> Vec3<T>: Mix {
    #[inline(always)]
    pure fn mix(other: &Vec3<T>, values: &Vec3<T>) -> Vec3<T> {
        Vec3::new(self[0].mix(&other[0], &values[0]),
                  self[1].mix(&other[1], &values[1]),
                  self[2].mix(&other[2], &values[2]))
    }
}

pub impl<T:Copy Mix> Vec4<T>: Mix {
    #[inline(always)]
    pure fn mix(other: &Vec4<T>, values: &Vec4<T>) -> Vec4<T> {
        Vec4::new(self[0].mix(&other[0], &values[0]),
                  self[1].mix(&other[1], &values[1]),
                  self[2].mix(&other[2], &values[2]),
                  self[3].mix(&other[3], &values[3]))
    }
}<commit_msg>Add smooth and smooth_step methods<commit_after>use num::cast::*;
use vec::{Vec2, Vec3, Vec4};

use extent::{Clamp, clamp};

pub trait Mix {
    pure fn mix(other: &self, value: &self) -> self;
    pure fn smooth_step(edge0: &self, edge1: &self) -> self;
    pure fn step(edge: &self) -> self;
}

#[inline(always)] pub pure fn mix<T:Mix>(a: &T, b: &T, value: &T) -> T { a.mix(b, value) }
#[inline(always)] pub pure fn smooth_step<T:Mix>(x: &T, edge0: &T, edge1: &T) -> T { x.smooth_step(edge0, edge1) }
#[inline(always)] pub pure fn step<T:Mix>(x: &T, edge: &T) -> T { x.step(edge) }

pub impl f32: Mix {
    #[inline(always)]
    pure fn mix(other: &f32, value: &f32) -> f32 {
        self * (1.0 - (*value)) + (*other) * (*value)
    }

    #[inline(always)]
    pure fn smooth_step(edge0: &f32, edge1: &f32) -> f32 {
        let t = clamp(&((self - *edge0) / (*edge1 - *edge0)), &0.0, &1.0);
        return t * t * (3.0 - 2.0 * t);
    }

    #[inline(always)]
    pure fn step(edge: &f32) -> f32 {
        if self < *edge { 0.0 } else { 1.0 }
    }
}

pub impl f64: Mix {
    #[inline(always)]
    pure fn mix(other: &f64, value: &f64) -> f64 {
        self * (1.0 - (*value)) + (*other) * (*value)
    }

    #[inline(always)]
    pure fn smooth_step(edge0: &f64, edge1: &f64) -> f64 {
        let t = clamp(&((self - *edge0) / (*edge1 - *edge0)), &0.0, &1.0);
        return t * t * (3.0 - 2.0 * t);
    }

    #[inline(always)]
    pure fn step(edge: &f64) -> f64 {
        if self < *edge { 0.0 } else { 1.0 }
    }
}

pub impl float: Mix {
    #[inline(always)]
    pure fn mix(other: &float, value: &float) -> float {
        self * (1.0 - (*value)) + (*other) * (*value)
    }

    #[inline(always)]
    pure fn smooth_step(edge0: &float, edge1: &float) -> float {
        let t = clamp(&((self - *edge0) / (*edge1 - *edge0)), &0.0, &1.0);
        return t * t * (3.0 - 2.0 * t);
    }

    #[inline(always)]
    pure fn step(edge: &float) -> float {
        if self < *edge { 0.0 } else { 1.0 }
    }
}

pub impl<T:Copy Mix> Vec2<T>: Mix {
    #[inline(always)]
    pure fn mix(other: &Vec2<T>, value: &Vec2<T>) -> Vec2<T> {
        Vec2::new(self[0].mix(&other[0], &value[0]),
                  self[1].mix(&other[1], &value[1]))
    }

    #[inline(always)]
    pure fn smooth_step(edge0: &Vec2<T>, edge1: &Vec2<T>) -> Vec2<T> {
        Vec2::new(self[0].smooth_step(&edge0[0], &edge1[0]),
                  self[1].smooth_step(&edge0[1], &edge1[1]))
    }

    #[inline(always)]
    pure fn step(edge: &Vec2<T>) -> Vec2<T> {
        Vec2::new(self[0].step(&edge[0]),
                  self[1].step(&edge[1]))
    }
}

pub impl<T:Copy Mix> Vec3<T>: Mix {
    #[inline(always)]
    pure fn mix(other: &Vec3<T>, value: &Vec3<T>) -> Vec3<T> {
        Vec3::new(self[0].mix(&other[0], &value[0]),
                  self[1].mix(&other[1], &value[1]),
                  self[2].mix(&other[2], &value[2]))
    }

    #[inline(always)]
    pure fn smooth_step(edge0: &Vec3<T>, edge1: &Vec3<T>) -> Vec3<T> {
        Vec3::new(self[0].smooth_step(&edge0[0], &edge1[0]),
                  self[1].smooth_step(&edge0[1], &edge1[1]),
                  self[2].smooth_step(&edge0[2], &edge1[2]))
    }

    #[inline(always)]
    pure fn step(edge: &Vec3<T>) -> Vec3<T> {
        Vec3::new(self[0].step(&edge[0]),
                  self[1].step(&edge[1]),
                  self[2].step(&edge[2]))
    }
}

pub impl<T:Copy Mix> Vec4<T>: Mix {
    #[inline(always)]
    pure fn mix(other: &Vec4<T>, value: &Vec4<T>) -> Vec4<T> {
        Vec4::new(self[0].mix(&other[0], &value[0]),
                  self[1].mix(&other[1], &value[1]),
                  self[2].mix(&other[2], &value[2]),
                  self[3].mix(&other[3], &value[3]))
    }

    #[inline(always)]
    pure fn smooth_step(edge0: &Vec4<T>, edge1: &Vec4<T>) -> Vec4<T> {
        Vec4::new(self[0].smooth_step(&edge0[0], &edge1[0]),
                  self[1].smooth_step(&edge0[1], &edge1[1]),
                  self[2].smooth_step(&edge0[2], &edge1[2]),
                  self[3].smooth_step(&edge0[3], &edge1[3]))
    }

    #[inline(always)]
    pure fn step(edge: &Vec4<T>) -> Vec4<T> {
        Vec4::new(self[0].step(&edge[0]),
                  self[1].step(&edge[1]),
                  self[2].step(&edge[2]),
                  self[3].step(&edge[3]))
    }
}<|endoftext|>