<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

#[doc(hidden)]
#[macro_export]
macro_rules! as_item { ($i:item) => {$i} }

// Required because if-let can't be used with irrefutable patterns, so it needs
// to be special cased.
#[doc(hidden)]
#[macro_export]
macro_rules! client_methods {
    (
        { $(#[$attr:meta])* }
        $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty
    ) => (
        $(#[$attr])*
        pub fn $fn_name(&self, $($arg: $in_),*) -> $crate::Result<$out> {
            let reply = try!((self.0).rpc(request_variant!($fn_name $($arg),*)));
            let __Reply::$fn_name(reply) = reply;
            Ok(reply)
        }
    );
    ($(
            { $(#[$attr:meta])* }
            $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty
    )*) => ( $(
        $(#[$attr])*
        pub fn $fn_name(&self, $($arg: $in_),*) -> $crate::Result<$out> {
            let reply = try!((self.0).rpc(request_variant!($fn_name $($arg),*)));
            if let __Reply::$fn_name(reply) = reply {
                Ok(reply)
            } else {
                panic!("Incorrect reply variant returned from protocol::Clientrpc; expected `{}`, but got {:?}", stringify!($fn_name), reply);
            }
        }
    )*);
}

// Required because if-let can't be used with irrefutable patterns, so it needs
// to be special cased.
#[doc(hidden)]
#[macro_export]
macro_rules! async_client_methods {
    (
        { $(#[$attr:meta])* }
        $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty
    ) => (
        $(#[$attr])*
        pub fn $fn_name(&self, $($arg: $in_),*) -> Future<$out> {
            fn mapper(reply: __Reply) -> $out {
                let __Reply::$fn_name(reply) = reply;
                reply
            }
            let reply = (self.0).rpc_async(request_variant!($fn_name $($arg),*));
            Future {
                future: reply,
                mapper: mapper,
            }
        }
    );
    ($(
            { $(#[$attr:meta])* }
            $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty
    )*) => ( $(
        $(#[$attr])*
        pub fn $fn_name(&self, $($arg: $in_),*) -> Future<$out> {
            fn mapper(reply: __Reply) -> $out {
                if let __Reply::$fn_name(reply) = reply {
                    reply
                } else {
                    panic!("Incorrect reply variant returned from protocol::Clientrpc; expected `{}`, but got {:?}", stringify!($fn_name), reply);
                }
            }
            let reply = (self.0).rpc_async(request_variant!($fn_name $($arg),*));
            Future {
                future: reply,
                mapper: mapper,
            }
        }
    )*);
}

// Required because enum variants with no fields can't be suffixed by parens
#[doc(hidden)]
#[macro_export]
macro_rules! define_request {
    ($(@($($finished:tt)*))* --) => (as_item!(
            #[allow(non_camel_case_types)]
            #[derive(Debug, Serialize, Deserialize)]
            enum __Request { $($($finished)*),* }
    ););
    ($(@$finished:tt)* -- $name:ident() $($req:tt)*) =>
        (define_request!($(@$finished)* @($name) -- $($req)*););
    ($(@$finished:tt)* -- $name:ident $args: tt $($req:tt)*) =>
        (define_request!($(@$finished)* @($name $args) -- $($req)*););
    ($($started:tt)*) => (define_request!(-- $($started)*););
}

// Required because enum variants with no fields can't be suffixed by parens
#[doc(hidden)]
#[macro_export]
macro_rules! request_variant {
    ($x:ident) => (__Request::$x);
    ($x:ident $($y:ident),+) => (__Request::$x($($y),+));
}

/// The main macro that creates RPC services.
///
/// Rpc methods are specified, mirroring trait syntax:
///
/// ```
/// # #![feature(custom_derive, plugin)]
/// # #![plugin(serde_macros)]
/// # #[macro_use] extern crate tarpc;
/// # extern crate serde;
/// # fn main() {}
/// # service! {
/// #[doc="Say hello"]
/// rpc hello(name: String) -> String;
/// # }
/// ```
///
/// Attributes can be attached to each rpc. These attributes
/// will then be attached to the generated `Service` trait's
/// corresponding method, as well as to the `Client` stub's rpcs methods.
///
/// The following items are expanded in the enclosing module:
///
/// * `Service` -- the trait defining the RPC service
/// * `Client` -- a client that makes synchronous requests to the RPC server
/// * `AsyncClient` -- a client that makes asynchronous requests to the RPC server
/// * `Future` -- a handle for asynchronously retrieving the result of an RPC
/// * `serve` -- the function that starts the RPC server
///
/// **Warning**: In addition to the above items, there are a few expanded items that
/// are considered implementation details. As with the above items, shadowing
/// these item names in the enclosing module is likely to break things in confusing
/// ways:
///
/// * `__Server` -- an implementation detail
/// * `__Request` -- an implementation detail
/// * `__Reply` -- an implementation detail
#[macro_export]
macro_rules! service {
    (
        $(
            $(#[$attr:meta])*
            rpc $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;
        )*
    ) => {
        #[doc="Defines the RPC service"]
        pub trait Service: Send + Sync {
            $(
                $(#[$attr])*
                fn $fn_name(&self, $($arg:$in_),*) -> $out;
            )*
        }

        impl<P, S> Service for P
            where P: Send + Sync + ::std::ops::Deref<Target=S>,
                  S: Service
        {
            $(
                $(#[$attr])*
                fn $fn_name(&self, $($arg:$in_),*) -> $out {
                    Service::$fn_name(&**self, $($arg),*)
                }
            )*
        }

        define_request!($($fn_name($($in_),*))*);

        #[allow(non_camel_case_types)]
        #[derive(Debug, Serialize, Deserialize)]
        enum __Reply {
            $(
                $fn_name($out),
            )*
        }

        /// An asynchronous RPC call
        pub struct Future<T> {
            future: $crate::protocol::Future<__Reply>,
            mapper: fn(__Reply) -> T,
        }

        impl<T> Future<T> {
            /// Block until the result of the RPC call is available
            pub fn get(self) -> $crate::Result<T> {
                self.future.get().map(self.mapper)
            }
        }

        #[doc="The client stub that makes RPC calls to the server."]
        pub struct Client($crate::protocol::Client<__Request, __Reply>);

        impl Client {
            #[doc="Create a new client that connects to the given address."]
            pub fn new<A>(addr: A, timeout: ::std::option::Option<::std::time::Duration>)
                -> $crate::Result<Self>
                where A: ::std::net::ToSocketAddrs,
            {
                let inner = try!($crate::protocol::Client::new(addr, timeout));
                Ok(Client(inner))
            }

            client_methods!(
                $(
                    { $(#[$attr])* }
                    $fn_name($($arg: $in_),*) -> $out
                )*
            );
        }

        #[doc="The client stub that makes asynchronous RPC calls to the server."]
        pub struct AsyncClient($crate::protocol::Client<__Request, __Reply>);

        impl AsyncClient {
            #[doc="Create a new asynchronous client that connects to the given address."]
            pub fn new<A>(addr: A, timeout: ::std::option::Option<::std::time::Duration>)
                -> $crate::Result<Self>
                where A: ::std::net::ToSocketAddrs,
            {
                let inner = try!($crate::protocol::Client::new(addr, timeout));
                Ok(AsyncClient(inner))
            }

            async_client_methods!(
                $(
                    { $(#[$attr])* }
                    $fn_name($($arg: $in_),*) -> $out
                )*
            );
        }

        struct __Server<S: 'static + Service>(S);

        impl<S> $crate::protocol::Serve for __Server<S>
            where S: 'static + Service
        {
            type Request = __Request;
            type Reply = __Reply;
            fn serve(&self, request: __Request) -> __Reply {
                match request {
                    $(
                        request_variant!($fn_name $($arg),*) =>
                            __Reply::$fn_name((self.0).$fn_name($($arg),*)),
                     )*
                }
            }
        }

        #[doc="Start a running service."]
        pub fn serve<A, S>(addr: A,
                           service: S,
                           read_timeout: ::std::option::Option<::std::time::Duration>)
            -> $crate::Result<$crate::protocol::ServeHandle>
            where A: ::std::net::ToSocketAddrs,
                  S: 'static + Service
        {
            let server = ::std::sync::Arc::new(__Server(service));
            Ok(try!($crate::protocol::serve_async(addr, server, read_timeout)))
        }
    }
}

#[cfg(test)]
#[allow(dead_code)]
mod test {
    extern crate env_logger;
    use ServeHandle;
    use std::sync::{Arc, Mutex};
    use std::time::Duration;
    use test::Bencher;

    fn test_timeout() -> Option<Duration> {
        Some(Duration::from_secs(5))
    }

    #[derive(PartialEq, Debug, Serialize, Deserialize)]
    pub struct Foo {
        pub message: String
    }

    mod my_server {
        use super::Foo;

        service! {
            rpc hello(foo: Foo) -> Foo;
            rpc add(x: i32, y: i32) -> i32;
        }
    }

    struct Server;

    impl my_server::Service for Server {
        fn hello(&self, s: Foo) -> Foo {
            Foo { message: format!("Hello, {}", &s.message) }
        }

        fn add(&self, x: i32, y: i32) -> i32 {
            x + y
        }
    }

    #[test]
    fn serve_arc_server() {
        my_server::serve("localhost:0", ::std::sync::Arc::new(Server), None)
            .unwrap()
            .shutdown();
    }

    #[test]
    fn simple() {
        let handle = my_server::serve( "localhost:0", Server, test_timeout()).unwrap();
        let client = my_server::Client::new(handle.local_addr(), None).unwrap();
        assert_eq!(3, client.add(1, 2).unwrap());
        let foo = Foo { message: "Adam".into() };
        let want = Foo { message: format!("Hello, {}", &foo.message) };
        assert_eq!(want, client.hello(Foo { message: "Adam".into() }).unwrap());
        drop(client);
        handle.shutdown();
    }

    #[test]
    fn simple_async() {
        let handle = my_server::serve("localhost:0", Server, test_timeout()).unwrap();
        let client = my_server::AsyncClient::new(handle.local_addr(), None).unwrap();
        assert_eq!(3, client.add(1, 2).get().unwrap());
        let foo = Foo { message: "Adam".into() };
        let want = Foo { message: format!("Hello, {}", &foo.message) };
        assert_eq!(want, client.hello(Foo { message: "Adam".into() }).get().unwrap());
        drop(client);
        handle.shutdown();
    }

    /// Tests a service definition with a fn that takes no args
    mod qux {
        service! {
            rpc hello() -> String;
        }
    }

    /// Tests a service definition with an import
    mod foo {
        use std::collections::HashMap;

        service! {
            #[doc="Hello bob"]
            #[inline(always)]
            rpc baz(s: String) -> HashMap<String, String>;
        }
    }

    /// Tests a service definition with an attribute but no doc comment
    #[deny(missing_docs)]
    mod bar {
        use std::collections::HashMap;

        service! {
            #[inline(always)]
            rpc baz(s: String) -> HashMap<String, String>;
        }
    }

    /// Tests a service definition with an attribute and a doc comment
    #[deny(missing_docs)]
    #[allow(unused)]
    mod baz {
        use std::collections::HashMap;

        #[derive(Debug)]
        pub struct Debuggable;

        service! {
            #[doc="Hello bob"]
            #[inline(always)]
            rpc baz(s: String) -> HashMap<String, String>;
        }
    }

    #[test]
    fn debug() {
        println!("{:?}", baz::Debuggable);
    }

    mod hi {
        service! {
            rpc hello(s: String) -> String;
        }
    }

    struct HelloServer;

    impl hi::Service for HelloServer {
        fn hello(&self, s: String) -> String {
            format!("Hello, {}!", s)
        }
    }

    // Prevents resource exhaustion when benching
    lazy_static! {
        static ref HANDLE: Arc<Mutex<ServeHandle>> = {
            let handle = hi::serve("localhost:0", HelloServer, None).unwrap();
            Arc::new(Mutex::new(handle))
        };
        static ref CLIENT: Arc<Mutex<hi::AsyncClient>> = {
            let addr = HANDLE.lock().unwrap().local_addr().clone();
            let client = hi::AsyncClient::new(addr, None).unwrap();
            Arc::new(Mutex::new(client))
        };
    }

    #[bench]
    fn hello(bencher: &mut Bencher) {
        let _ = env_logger::init();
        let client = CLIENT.lock().unwrap();
        let concurrency = 100;
        let mut futures = Vec::with_capacity(concurrency);
        let mut count = 0;
        bencher.iter(|| {
            futures.push(client.hello("Bob".into()));
            count += 1;
            if count % concurrency == 0 {
                // We can't block on each rpc call, otherwise we'd be
                // benchmarking latency instead of throughput. It's also
                // not ideal to call more than one rpc per iteration, because
                // it makes the output of the bencher harder to parse (you have
                // to mentally divide the number by `concurrency` to get
                // the ns / iter for one rpc
                for f in futures.drain(..) {
                    f.get().unwrap();
                }
            }
        });
    }
}
<commit_msg>Allow rpc methods with an implicit unit return type<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

#[doc(hidden)]
#[macro_export]
macro_rules! as_item { ($i:item) => {$i} }

// Required because if-let can't be used with irrefutable patterns, so it needs
// to be special cased.
#[doc(hidden)]
#[macro_export]
macro_rules! client_methods {
    (
        { $(#[$attr:meta])* }
        $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty
    ) => (
        $(#[$attr])*
        pub fn $fn_name(&self, $($arg: $in_),*) -> $crate::Result<$out> {
            let reply = try!((self.0).rpc(request_variant!($fn_name $($arg),*)));
            let __Reply::$fn_name(reply) = reply;
            Ok(reply)
        }
    );
    ($(
            { $(#[$attr:meta])* }
            $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty
    )*) => ( $(
        $(#[$attr])*
        pub fn $fn_name(&self, $($arg: $in_),*) -> $crate::Result<$out> {
            let reply = try!((self.0).rpc(request_variant!($fn_name $($arg),*)));
            if let __Reply::$fn_name(reply) = reply {
                Ok(reply)
            } else {
                panic!("Incorrect reply variant returned from protocol::Clientrpc; expected `{}`, but got {:?}", stringify!($fn_name), reply);
            }
        }
    )*);
}

// Required because if-let can't be used with irrefutable patterns, so it needs
// to be special cased.
#[doc(hidden)]
#[macro_export]
macro_rules! async_client_methods {
    (
        { $(#[$attr:meta])* }
        $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty
    ) => (
        $(#[$attr])*
        pub fn $fn_name(&self, $($arg: $in_),*) -> Future<$out> {
            fn mapper(reply: __Reply) -> $out {
                let __Reply::$fn_name(reply) = reply;
                reply
            }
            let reply = (self.0).rpc_async(request_variant!($fn_name $($arg),*));
            Future {
                future: reply,
                mapper: mapper,
            }
        }
    );
    ($(
            { $(#[$attr:meta])* }
            $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty
    )*) => ( $(
        $(#[$attr])*
        pub fn $fn_name(&self, $($arg: $in_),*) -> Future<$out> {
            fn mapper(reply: __Reply) -> $out {
                if let __Reply::$fn_name(reply) = reply {
                    reply
                } else {
                    panic!("Incorrect reply variant returned from protocol::Clientrpc; expected `{}`, but got {:?}", stringify!($fn_name), reply);
                }
            }
            let reply = (self.0).rpc_async(request_variant!($fn_name $($arg),*));
            Future {
                future: reply,
                mapper: mapper,
            }
        }
    )*);
}

// Required because enum variants with no fields can't be suffixed by parens
#[doc(hidden)]
#[macro_export]
macro_rules! define_request {
    ($(@($($finished:tt)*))* --) => (as_item!(
            #[allow(non_camel_case_types)]
            #[derive(Debug, Serialize, Deserialize)]
            enum __Request { $($($finished)*),* }
    ););
    ($(@$finished:tt)* -- $name:ident() $($req:tt)*) =>
        (define_request!($(@$finished)* @($name) -- $($req)*););
    ($(@$finished:tt)* -- $name:ident $args: tt $($req:tt)*) =>
        (define_request!($(@$finished)* @($name $args) -- $($req)*););
    ($($started:tt)*) => (define_request!(-- $($started)*););
}

// Required because enum variants with no fields can't be suffixed by parens
#[doc(hidden)]
#[macro_export]
macro_rules! request_variant {
    ($x:ident) => (__Request::$x);
    ($x:ident $($y:ident),+) => (__Request::$x($($y),+));
}

/// The main macro that creates RPC services.
///
/// Rpc methods are specified, mirroring trait syntax:
///
/// ```
/// # #![feature(custom_derive, plugin)]
/// # #![plugin(serde_macros)]
/// # #[macro_use] extern crate tarpc;
/// # extern crate serde;
/// # fn main() {}
/// # service! {
/// #[doc="Say hello"]
/// rpc hello(name: String) -> String;
/// # }
/// ```
///
/// Attributes can be attached to each rpc. These attributes
/// will then be attached to the generated `Service` trait's
/// corresponding method, as well as to the `Client` stub's rpcs methods.
///
/// The following items are expanded in the enclosing module:
///
/// * `Service` -- the trait defining the RPC service
/// * `Client` -- a client that makes synchronous requests to the RPC server
/// * `AsyncClient` -- a client that makes asynchronous requests to the RPC server
/// * `Future` -- a handle for asynchronously retrieving the result of an RPC
/// * `serve` -- the function that starts the RPC server
///
/// **Warning**: In addition to the above items, there are a few expanded items that
/// are considered implementation details. As with the above items, shadowing
/// these item names in the enclosing module is likely to break things in confusing
/// ways:
///
/// * `__Server` -- an implementation detail
/// * `__Request` -- an implementation detail
/// * `__Reply` -- an implementation detail
#[macro_export]
macro_rules! service {
    (
        $( $tokens:tt )*
    ) => {
        service_inner! {{
            $( $tokens )*
        }}
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! service_inner {
    // Pattern for when the next rpc has an implicit unit return type
    (
        {
            $(#[$attr:meta])*
            rpc $fn_name:ident( $( $arg:ident : $in_:ty ),* );

            $( $unexpanded:tt )*
        }
        $( $expanded:tt )*
    ) => {
        service_inner! {
            { $( $unexpanded )* }

            $( $expanded )*

            $(#[$attr])*
            rpc $fn_name( $( $arg : $in_ ),* ) -> ();
        }
    };
    // Pattern for when the next rpc has an explicit return type
    (
        {
            $(#[$attr:meta])*
            rpc $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;

            $( $unexpanded:tt )*
        }
        $( $expanded:tt )*
    ) => {
        service_inner! {
            { $( $unexpanded )* }

            $( $expanded )*

            $(#[$attr])*
            rpc $fn_name( $( $arg : $in_ ),* ) -> $out;
        }
    };
    // Pattern when all return types have been expanded
    (
        { } // none left to expand
        $(
            $(#[$attr:meta])*
            rpc $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;
        )*
    ) => {
        #[doc="Defines the RPC service"]
        pub trait Service: Send + Sync {
            $(
                $(#[$attr])*
                fn $fn_name(&self, $($arg:$in_),*) -> $out;
            )*
        }

        impl<P, S> Service for P
            where P: Send + Sync + ::std::ops::Deref<Target=S>,
                  S: Service
        {
            $(
                $(#[$attr])*
                fn $fn_name(&self, $($arg:$in_),*) -> $out {
                    Service::$fn_name(&**self, $($arg),*)
                }
            )*
        }

        define_request!($($fn_name($($in_),*))*);

        #[allow(non_camel_case_types)]
        #[derive(Debug, Serialize, Deserialize)]
        enum __Reply {
            $(
                $fn_name($out),
            )*
        }

        /// An asynchronous RPC call
        pub struct Future<T> {
            future: $crate::protocol::Future<__Reply>,
            mapper: fn(__Reply) -> T,
        }

        impl<T> Future<T> {
            /// Block until the result of the RPC call is available
            pub fn get(self) -> $crate::Result<T> {
                self.future.get().map(self.mapper)
            }
        }

        #[doc="The client stub that makes RPC calls to the server."]
        pub struct Client($crate::protocol::Client<__Request, __Reply>);

        impl Client {
            #[doc="Create a new client that connects to the given address."]
            pub fn new<A>(addr: A, timeout: ::std::option::Option<::std::time::Duration>)
                -> $crate::Result<Self>
                where A: ::std::net::ToSocketAddrs,
            {
                let inner = try!($crate::protocol::Client::new(addr, timeout));
                Ok(Client(inner))
            }

            client_methods!(
                $(
                    { $(#[$attr])* }
                    $fn_name($($arg: $in_),*) -> $out
                )*
            );
        }

        #[doc="The client stub that makes asynchronous RPC calls to the server."]
        pub struct AsyncClient($crate::protocol::Client<__Request, __Reply>);

        impl AsyncClient {
            #[doc="Create a new asynchronous client that connects to the given address."]
            pub fn new<A>(addr: A, timeout: ::std::option::Option<::std::time::Duration>)
                -> $crate::Result<Self>
                where A: ::std::net::ToSocketAddrs,
            {
                let inner = try!($crate::protocol::Client::new(addr, timeout));
                Ok(AsyncClient(inner))
            }

            async_client_methods!(
                $(
                    { $(#[$attr])* }
                    $fn_name($($arg: $in_),*) -> $out
                )*
            );
        }

        struct __Server<S: 'static + Service>(S);

        impl<S> $crate::protocol::Serve for __Server<S>
            where S: 'static + Service
        {
            type Request = __Request;
            type Reply = __Reply;
            fn serve(&self, request: __Request) -> __Reply {
                match request {
                    $(
                        request_variant!($fn_name $($arg),*) =>
                            __Reply::$fn_name((self.0).$fn_name($($arg),*)),
                     )*
                }
            }
        }

        #[doc="Start a running service."]
        pub fn serve<A, S>(addr: A,
                           service: S,
                           read_timeout: ::std::option::Option<::std::time::Duration>)
            -> $crate::Result<$crate::protocol::ServeHandle>
            where A: ::std::net::ToSocketAddrs,
                  S: 'static + Service
        {
            let server = ::std::sync::Arc::new(__Server(service));
            Ok(try!($crate::protocol::serve_async(addr, server, read_timeout)))
        }
    }
}

#[cfg(test)]
#[allow(dead_code)] // because we're testing that the macro expansion compiles
mod test {
    extern crate env_logger;
    use std::time::Duration;

    fn test_timeout() -> Option<Duration> {
        Some(Duration::from_secs(5))
    }

    #[derive(PartialEq, Debug, Serialize, Deserialize)]
    pub struct Foo {
        pub message: String
    }
    mod my_server {
        use super::Foo;
        service! {
            rpc hello(foo: Foo) -> Foo;
            rpc add(x: i32, y: i32) -> i32;
        }
    }

    struct Server;
    impl my_server::Service for Server {
        fn hello(&self, s: Foo) -> Foo {
            Foo { message: format!("Hello, {}", &s.message) }
        }
        fn add(&self, x: i32, y: i32) -> i32 {
            x + y
        }
    }

    #[test]
    fn serve_arc_server() {
        my_server::serve("localhost:0", ::std::sync::Arc::new(Server), None)
            .unwrap()
            .shutdown();
    }

    #[test]
    fn simple() {
        let handle = my_server::serve( "localhost:0", Server, test_timeout()).unwrap();
        let client = my_server::Client::new(handle.local_addr(), None).unwrap();
        assert_eq!(3, client.add(1, 2).unwrap());
        let foo = Foo { message: "Adam".into() };
        let want = Foo { message: format!("Hello, {}", &foo.message) };
        assert_eq!(want, client.hello(Foo { message: "Adam".into() }).unwrap());
        drop(client);
        handle.shutdown();
    }

    #[test]
    fn simple_async() {
        let handle = my_server::serve("localhost:0", Server, test_timeout()).unwrap();
        let client = my_server::AsyncClient::new(handle.local_addr(), None).unwrap();
        assert_eq!(3, client.add(1, 2).get().unwrap());
        let foo = Foo { message: "Adam".into() };
        let want = Foo { message: format!("Hello, {}", &foo.message) };
        assert_eq!(want, client.hello(Foo { message: "Adam".into() }).get().unwrap());
        drop(client);
        handle.shutdown();
    }

    /// Tests a service definition with a fn that takes no args
    mod qux {
        service! {
            rpc hello() -> String;
        }
    }

    /// Tests a service definition with an import
    mod foo {
        use std::collections::HashMap;
        service! {
            #[doc="Hello bob"]
            #[inline(always)]
            rpc baz(s: String) -> HashMap<String, String>;
        }
    }

    /// Tests a service definition with an attribute but no doc comment
    mod bar {
        use std::collections::HashMap;
        service! {
            #[inline(always)]
            rpc baz(s: String) -> HashMap<String, String>;
        }
    }

    /// Tests a service definition with an attribute and a doc comment
    #[deny(missing_docs)]
    #[allow(unused)]
    mod baz {
        use std::collections::HashMap;
        pub struct Debuggable;
        service! {
            #[doc="Hello bob"]
            #[inline(always)]
            rpc baz(s: String) -> HashMap<String, String>;
        }
    }

    mod no_return {
        service! {
            rpc ack();
        }
    }
}

#[cfg(test)]
#[allow(dead_code)] // because we're not using all expanded types
mod benchmarks {
    extern crate env_logger;
    use ServeHandle;
    use std::sync::{Arc, Mutex};
    use test::Bencher;

    mod hi {
        service! {
            rpc hello(s: String) -> String;
        }
    }

    struct HelloServer;

    impl hi::Service for HelloServer {
        fn hello(&self, s: String) -> String {
            format!("Hello, {}!", s)
        }
    }
    // Prevents resource exhaustion when benching
    lazy_static! {
        static ref HANDLE: Arc<Mutex<ServeHandle>> = {
            let handle = hi::serve("localhost:0", HelloServer, None).unwrap();
            Arc::new(Mutex::new(handle))
        };
        static ref CLIENT: Arc<Mutex<hi::AsyncClient>> = {
            let addr = HANDLE.lock().unwrap().local_addr().clone();
            let client = hi::AsyncClient::new(addr, None).unwrap();
            Arc::new(Mutex::new(client))
        };
    }

    #[bench]
    fn hello(bencher: &mut Bencher) {
        let _ = env_logger::init();
        let client = CLIENT.lock().unwrap();
        let concurrency = 100;
        let mut futures = Vec::with_capacity(concurrency);
        let mut count = 0;
        bencher.iter(|| {
            futures.push(client.hello("Bob".into()));
            count += 1;
            if count % concurrency == 0 {
                // We can't block on each rpc call, otherwise we'd be
                // benchmarking latency instead of throughput. It's also
                // not ideal to call more than one rpc per iteration, because
                // it makes the output of the bencher harder to parse (you have
                // to mentally divide the number by `concurrency` to get
                // the ns / iter for one rpc
                for f in futures.drain(..) {
                    f.get().unwrap();
                }
            }
        });
    }
}
<|endoftext|>


<commit_before>import ptr::{null, addr_of};
import result::{result, ok, err, extensions};
import libc::c_char;
import name_pool::{name_pool, methods};
import str::unsafe::from_c_str;
import io::writer_util;
import libc::types::common::c99::*;
import jsapi::*;
import jsapi::bindgen::*;

export JSOPTION_STRICT;
export JSOPTION_WERROR;
export JSOPTION_VAROBJFIX;
export JSOPTION_METHODJIT;

export JSCLASS_GLOBAL_FLAGS;

export crust;
export rust;

export jsapi;
export global;

// These are just macros in jsapi.h
import JS_NewRuntime = jsapi::bindgen::JS_Init;
export JS_NewRuntime;
import JS_DestroyRuntime = jsapi::bindgen::JS_Finish;
export JS_DestroyRuntime;
/*
FIXME: Not sure where JS_Lock is
import JS_LockRuntime = jsapi::bindgen::JS_Lock;
export JS_LockRuntime;
import JS_UnlockRuntime = jsapi::bindgen::JS_Unlock;
export JS_UnlockRuntime;
*/

export JS_ARGV;
export JS_SET_RVAL;
export JSVAL_VOID;
export JSVAL_NULL;
export JSVAL_ZERO;
export JSVAL_ONE;
export JSVAL_FALSE;
export JSVAL_TRUE;

/* Look in this directory for spidermonkey */
#[link_args = "-L."]
/* Link to the static js library */
#[link_args = "-ljs_static"]
native mod m { }

// FIXME: Add the remaining options
const JSOPTION_STRICT: uint32_t =    0b00000000000001u32;
const JSOPTION_WERROR: uint32_t =    0b00000000000010u32;
const JSOPTION_VAROBJFIX: uint32_t = 0b00000000000100u32;
const JSOPTION_METHODJIT: uint32_t = 0b10000000000000u32;

const JSCLASS_GLOBAL_FLAGS: uint32_t = 0x47d00du32;

const default_heapsize: u32 = 8_u32 * 1024_u32 * 1024_u32;
const default_stacksize: uint = 8192u;
const ERR: JSBool = 0_i32;

const JSVAL_VOID: u64 =  0x0001fff2_00000000_u64;
const JSVAL_NULL: u64 =  0x0001fff6_00000000_u64;
const JSVAL_ZERO: u64 =  0x0001fff1_00000000_u64;
const JSVAL_ONE: u64 =   0x0001fff1_00000001_u64;
const JSVAL_FALSE: u64 = 0x0001fff3_00000000_u64;
const JSVAL_TRUE: u64 =  0x0001fff3_00000001_u64;

fn result(n: JSBool) -> result<(),()> {
    if n != ERR {ok(())} else {err(())}
}

type named_functions = @{
    names: [str],
    funcs: [JSFunctionSpec]
};

impl ptr_methods<T: copy> for *T {
    unsafe fn +(idx: uint) -> *T {
        ptr::offset(self, idx)
    }
    unsafe fn [](idx: uint) -> T {
        *(self + idx)
    }
}

unsafe fn JS_ARGV(_cx: *JSContext, vp: *jsval) -> *jsval {
    vp + 2u
}

unsafe fn JS_SET_RVAL(_cx: *JSContext, vp: *jsval, v: jsval) {
    let vp: *mut jsval = unsafe::reinterpret_cast(vp);
    *vp = v;
}

<commit_msg>Result extensions are imported by default now<commit_after>import ptr::{null, addr_of};
import result::{result, ok, err};
import libc::c_char;
import name_pool::{name_pool, methods};
import str::unsafe::from_c_str;
import io::writer_util;
import libc::types::common::c99::*;
import jsapi::*;
import jsapi::bindgen::*;

export JSOPTION_STRICT;
export JSOPTION_WERROR;
export JSOPTION_VAROBJFIX;
export JSOPTION_METHODJIT;

export JSCLASS_GLOBAL_FLAGS;

export crust;
export rust;

export jsapi;
export global;

// These are just macros in jsapi.h
import JS_NewRuntime = jsapi::bindgen::JS_Init;
export JS_NewRuntime;
import JS_DestroyRuntime = jsapi::bindgen::JS_Finish;
export JS_DestroyRuntime;
/*
FIXME: Not sure where JS_Lock is
import JS_LockRuntime = jsapi::bindgen::JS_Lock;
export JS_LockRuntime;
import JS_UnlockRuntime = jsapi::bindgen::JS_Unlock;
export JS_UnlockRuntime;
*/

export JS_ARGV;
export JS_SET_RVAL;
export JSVAL_VOID;
export JSVAL_NULL;
export JSVAL_ZERO;
export JSVAL_ONE;
export JSVAL_FALSE;
export JSVAL_TRUE;

/* Look in this directory for spidermonkey */
#[link_args = "-L."]
/* Link to the static js library */
#[link_args = "-ljs_static"]
native mod m { }

// FIXME: Add the remaining options
const JSOPTION_STRICT: uint32_t =    0b00000000000001u32;
const JSOPTION_WERROR: uint32_t =    0b00000000000010u32;
const JSOPTION_VAROBJFIX: uint32_t = 0b00000000000100u32;
const JSOPTION_METHODJIT: uint32_t = 0b10000000000000u32;

const JSCLASS_GLOBAL_FLAGS: uint32_t = 0x47d00du32;

const default_heapsize: u32 = 8_u32 * 1024_u32 * 1024_u32;
const default_stacksize: uint = 8192u;
const ERR: JSBool = 0_i32;

const JSVAL_VOID: u64 =  0x0001fff2_00000000_u64;
const JSVAL_NULL: u64 =  0x0001fff6_00000000_u64;
const JSVAL_ZERO: u64 =  0x0001fff1_00000000_u64;
const JSVAL_ONE: u64 =   0x0001fff1_00000001_u64;
const JSVAL_FALSE: u64 = 0x0001fff3_00000000_u64;
const JSVAL_TRUE: u64 =  0x0001fff3_00000001_u64;

fn result(n: JSBool) -> result<(),()> {
    if n != ERR {ok(())} else {err(())}
}

type named_functions = @{
    names: [str],
    funcs: [JSFunctionSpec]
};

impl ptr_methods<T: copy> for *T {
    unsafe fn +(idx: uint) -> *T {
        ptr::offset(self, idx)
    }
    unsafe fn [](idx: uint) -> T {
        *(self + idx)
    }
}

unsafe fn JS_ARGV(_cx: *JSContext, vp: *jsval) -> *jsval {
    vp + 2u
}

unsafe fn JS_SET_RVAL(_cx: *JSContext, vp: *jsval, v: jsval) {
    let vp: *mut jsval = unsafe::reinterpret_cast(vp);
    *vp = v;
}

<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::types::TypeName;
use indoc::indoc;
use lazy_static::lazy_static;
use proc_macro2::Span;
use std::collections::HashMap;
use syn::{parse_quote, Ident, TypePath};

/// Whether this type should be included in the 'prelude'
/// passed to bindgen, and if so, how.
#[derive(Debug)]
enum PreludePolicy {
    Exclude,
    IncludeNormal,
    IncludeTemplated,
}

/// Details about known special types, mostly primitives.
#[derive(Debug)]
struct TypeDetails {
    /// The name used by cxx (in Rust code) for this type.
    rs_name: String,
    /// C++ equivalent name for a Rust type.
    cpp_name: String,
    /// Whether this can be safely represented by value.
    by_value_safe: bool,
    /// Whether and how to include this in the prelude given to bindgen.
    prelude_policy: PreludePolicy,
    /// Whether this is a & on the Rust side but a value on the C++
    /// side. Only applies to &str.
    de_referencicate: bool,
}

impl TypeDetails {
    fn new(
        rs_name: String,
        cpp_name: String,
        by_value_safe: bool,
        prelude_policy: PreludePolicy,
        de_referencicate: bool,
    ) -> Self {
        TypeDetails {
            rs_name,
            cpp_name,
            by_value_safe,
            prelude_policy,
            de_referencicate,
        }
    }

    fn get_prelude_entry(&self) -> Option<String> {
        match self.prelude_policy {
            PreludePolicy::Exclude => None,
            PreludePolicy::IncludeNormal | PreludePolicy::IncludeTemplated => {
                let cxx_name = &self.rs_name;
                let (templating, payload) = match self.prelude_policy {
                    PreludePolicy::IncludeNormal => ("", "char* ptr"),
                    PreludePolicy::IncludeTemplated => ("template<typename T> ", "T* ptr"),
                    _ => unreachable!(),
                };
                Some(format!(
                    indoc! {"
                    /**
                    *

                    */
                    {}class {} {{
                        {};
                    }};

                    "},
                    self.cpp_name, templating, cxx_name, payload
                ))
            }
        }
    }
}

/// Database of known types.
pub(crate) struct TypeDatabase {
    by_rs_name: HashMap<TypeName, TypeDetails>,
    by_cppname: HashMap<String, String>,
}

lazy_static! {
    /// Database of known types.
    static ref KNOWN_TYPES: TypeDatabase = create_type_database();
}

fn create_type_database() -> TypeDatabase {
    let mut by_rs_name = HashMap::new();

    let mut do_insert =
        |td: TypeDetails| by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    do_insert(TypeDetails::new(
        "UniquePtr".into(),
        "std::unique_ptr".into(),
        true,
        PreludePolicy::IncludeTemplated,
        false,
    ));
    do_insert(TypeDetails::new(
        "CxxString".into(),
        "std::string".into(),
        false,
        PreludePolicy::IncludeNormal,
        false,
    ));
    do_insert(TypeDetails::new(
        "str".into(),
        "rust::Str".into(),
        true,
        PreludePolicy::IncludeNormal,
        true,
    ));
    do_insert(TypeDetails::new(
        "String".into(),
        "rust::String".into(),
        true,
        PreludePolicy::IncludeNormal,
        false,
    ));
    for (cpp_type, rust_type) in (3..7)
        .map(|x| 2i32.pow(x))
        .map(|x| {
            vec![
                (format!("uint{}_t", x), format!("u{}", x)),
                (format!("int{}_t", x), format!("i{}", x)),
            ]
        })
        .flatten()
    {
        do_insert(TypeDetails::new(
            rust_type,
            cpp_type,
            true,
            PreludePolicy::Exclude,
            false,
        ));
    }
    do_insert(TypeDetails::new(
        "bool".into(),
        "bool".into(),
        true,
        PreludePolicy::Exclude,
        false,
    ));
    do_insert(TypeDetails::new(
        "std::os::raw::c_ulong".into(),
        "ulong".into(),
        true,
        PreludePolicy::Exclude,
        false,
    ));

    let mut by_cppname = HashMap::new();
    for td in by_rs_name.values() {
        by_cppname.insert(td.cpp_name.clone(), td.rs_name.clone());
    }

    TypeDatabase {
        by_rs_name,
        by_cppname,
    }
}

/// This is worked out basically using trial and error.
/// Excluding std* and rust* is obvious, but the other items...
/// in theory bindgen ought to be smart enough to work out that
/// they're not used and therefore not generate code for them.
/// But it doesm unless we blocklist them. This is obviously
/// a bit sensitive to the particular STL in use so one day
/// it would be good to dig into bindgen's behavior here - TODO.
const BINDGEN_BLOCKLIST: &[&str] = &["std.*", "__gnu.*", ".*mbstate_t.*", "rust.*"];

/// Prelude of C++ for squirting into bindgen. This configures
/// bindgen to output simpler types to replace some STL types
/// that bindgen just can't cope with. Although we then replace
/// those types with cxx types (e.g. UniquePtr), this intermediate
/// step is still necessary because bindgen can't otherwise
/// give us the templated types (e.g. when faced with the STL
/// unique_ptr, bindgen would normally give us std_unique_ptr
/// as opposed to std_unique_ptr<T>.)
pub(crate) fn get_prelude() -> String {
    itertools::join(
        KNOWN_TYPES
            .by_rs_name
            .values()
            .filter_map(|t| t.get_prelude_entry()),
        "\n",
    )
}

/// Types which are known to be safe (or unsafe) to hold and pass by
/// value in Rust.
pub(crate) fn get_pod_safe_types() -> Vec<(TypeName, bool)> {
    KNOWN_TYPES
        .by_rs_name
        .iter()
        .map(|(_, td)| (TypeName::new_from_user_input(&td.rs_name), td.by_value_safe))
        .collect()
}

/// Get the list of types to give to bindgen to ask it _not_ to
/// generate code for.
pub(crate) fn get_initial_blocklist() -> Vec<String> {
    BINDGEN_BLOCKLIST.iter().map(|s| s.to_string()).collect()
}

/// Whether this TypePath should be treated as a value in C++
/// but a reference in Rust. This only applies to rust::Str
/// (C++ name) which is &str in Rust.
pub(crate) fn should_dereference_in_cpp(typ: &TypePath) -> bool {
    let tn = TypeName::from_cxx_type_path(typ);
    let td = KNOWN_TYPES.by_rs_name.get(&tn);
    if let Some(td) = td {
        td.de_referencicate
    } else {
        false
    }
}

/// Here we substitute any names which we know are Special from
/// our type database, e.g. std::unique_ptr -> UniquePtr.
/// The 'without_arguments' bit means we strip off and ignore
/// any PathArguments within this TypePath - callers should
/// put them back again if needs be.
pub(crate) fn replace_type_path_without_arguments(typ: TypePath) -> TypePath {
    let name = TypeName::from_cxx_type_path(&typ).to_cpp_name();
    match KNOWN_TYPES.by_cppname.get(&name) {
        Some(replacement_name) => {
            let id = make_ident(replacement_name);
            parse_quote! {
                #id
            }
        }
        None => typ,
    }
}

pub(crate) fn special_cpp_name(rs: &TypeName) -> Option<String> {
    KNOWN_TYPES
        .by_rs_name
        .get(rs)
        .map(|x| x.cpp_name.to_string())
}

fn make_ident(id: &str) -> Ident {
    Ident::new(id, Span::call_site())
}
<commit_msg>Support more ctypes.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::types::TypeName;
use indoc::indoc;
use lazy_static::lazy_static;
use proc_macro2::Span;
use std::collections::HashMap;
use syn::{parse_quote, Ident, TypePath};

/// Whether this type should be included in the 'prelude'
/// passed to bindgen, and if so, how.
#[derive(Debug)]
enum PreludePolicy {
    Exclude,
    IncludeNormal,
    IncludeTemplated,
}

/// Details about known special types, mostly primitives.
#[derive(Debug)]
struct TypeDetails {
    /// The name used by cxx (in Rust code) for this type.
    rs_name: String,
    /// C++ equivalent name for a Rust type.
    cpp_name: String,
    /// Whether this can be safely represented by value.
    by_value_safe: bool,
    /// Whether and how to include this in the prelude given to bindgen.
    prelude_policy: PreludePolicy,
    /// Whether this is a & on the Rust side but a value on the C++
    /// side. Only applies to &str.
    de_referencicate: bool,
}

impl TypeDetails {
    fn new(
        rs_name: String,
        cpp_name: String,
        by_value_safe: bool,
        prelude_policy: PreludePolicy,
        de_referencicate: bool,
    ) -> Self {
        TypeDetails {
            rs_name,
            cpp_name,
            by_value_safe,
            prelude_policy,
            de_referencicate,
        }
    }

    fn get_prelude_entry(&self) -> Option<String> {
        match self.prelude_policy {
            PreludePolicy::Exclude => None,
            PreludePolicy::IncludeNormal | PreludePolicy::IncludeTemplated => {
                let cxx_name = &self.rs_name;
                let (templating, payload) = match self.prelude_policy {
                    PreludePolicy::IncludeNormal => ("", "char* ptr"),
                    PreludePolicy::IncludeTemplated => ("template<typename T> ", "T* ptr"),
                    _ => unreachable!(),
                };
                Some(format!(
                    indoc! {"
                    /**
                    *

                    */
                    {}class {} {{
                        {};
                    }};

                    "},
                    self.cpp_name, templating, cxx_name, payload
                ))
            }
        }
    }
}

/// Database of known types.
pub(crate) struct TypeDatabase {
    by_rs_name: HashMap<TypeName, TypeDetails>,
    by_cppname: HashMap<String, String>,
}

lazy_static! {
    /// Database of known types.
    static ref KNOWN_TYPES: TypeDatabase = create_type_database();
}

fn create_type_database() -> TypeDatabase {
    let mut by_rs_name = HashMap::new();

    let mut do_insert =
        |td: TypeDetails| by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);

    do_insert(TypeDetails::new(
        "UniquePtr".into(),
        "std::unique_ptr".into(),
        true,
        PreludePolicy::IncludeTemplated,
        false,
    ));
    do_insert(TypeDetails::new(
        "CxxString".into(),
        "std::string".into(),
        false,
        PreludePolicy::IncludeNormal,
        false,
    ));
    do_insert(TypeDetails::new(
        "str".into(),
        "rust::Str".into(),
        true,
        PreludePolicy::IncludeNormal,
        true,
    ));
    do_insert(TypeDetails::new(
        "String".into(),
        "rust::String".into(),
        true,
        PreludePolicy::IncludeNormal,
        false,
    ));
    for (cpp_type, rust_type) in (3..7)
        .map(|x| 2i32.pow(x))
        .map(|x| {
            vec![
                (format!("uint{}_t", x), format!("u{}", x)),
                (format!("int{}_t", x), format!("i{}", x)),
            ]
        })
        .flatten()
    {
        do_insert(TypeDetails::new(
            rust_type,
            cpp_type,
            true,
            PreludePolicy::Exclude,
            false,
        ));
    }
    do_insert(TypeDetails::new(
        "bool".into(),
        "bool".into(),
        true,
        PreludePolicy::Exclude,
        false,
    ));

    let mut insert_ctype = |cname: &str| {
        let td = TypeDetails::new(
            format!("std::os::raw::c_{}", cname),
            cname.into(),
            true,
            PreludePolicy::Exclude,
            false,
        );
        by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);
    };

    insert_ctype("ulong");
    insert_ctype("uint");
    insert_ctype("long");
    insert_ctype("int");

    let mut by_cppname = HashMap::new();
    for td in by_rs_name.values() {
        by_cppname.insert(td.cpp_name.clone(), td.rs_name.clone());
    }

    TypeDatabase {
        by_rs_name,
        by_cppname,
    }
}

/// This is worked out basically using trial and error.
/// Excluding std* and rust* is obvious, but the other items...
/// in theory bindgen ought to be smart enough to work out that
/// they're not used and therefore not generate code for them.
/// But it doesm unless we blocklist them. This is obviously
/// a bit sensitive to the particular STL in use so one day
/// it would be good to dig into bindgen's behavior here - TODO.
const BINDGEN_BLOCKLIST: &[&str] = &["std.*", "__gnu.*", ".*mbstate_t.*", "rust.*"];

/// Prelude of C++ for squirting into bindgen. This configures
/// bindgen to output simpler types to replace some STL types
/// that bindgen just can't cope with. Although we then replace
/// those types with cxx types (e.g. UniquePtr), this intermediate
/// step is still necessary because bindgen can't otherwise
/// give us the templated types (e.g. when faced with the STL
/// unique_ptr, bindgen would normally give us std_unique_ptr
/// as opposed to std_unique_ptr<T>.)
pub(crate) fn get_prelude() -> String {
    itertools::join(
        KNOWN_TYPES
            .by_rs_name
            .values()
            .filter_map(|t| t.get_prelude_entry()),
        "\n",
    )
}

/// Types which are known to be safe (or unsafe) to hold and pass by
/// value in Rust.
pub(crate) fn get_pod_safe_types() -> Vec<(TypeName, bool)> {
    KNOWN_TYPES
        .by_rs_name
        .iter()
        .map(|(_, td)| (TypeName::new_from_user_input(&td.rs_name), td.by_value_safe))
        .collect()
}

/// Get the list of types to give to bindgen to ask it _not_ to
/// generate code for.
pub(crate) fn get_initial_blocklist() -> Vec<String> {
    BINDGEN_BLOCKLIST.iter().map(|s| s.to_string()).collect()
}

/// Whether this TypePath should be treated as a value in C++
/// but a reference in Rust. This only applies to rust::Str
/// (C++ name) which is &str in Rust.
pub(crate) fn should_dereference_in_cpp(typ: &TypePath) -> bool {
    let tn = TypeName::from_cxx_type_path(typ);
    let td = KNOWN_TYPES.by_rs_name.get(&tn);
    if let Some(td) = td {
        td.de_referencicate
    } else {
        false
    }
}

/// Here we substitute any names which we know are Special from
/// our type database, e.g. std::unique_ptr -> UniquePtr.
/// The 'without_arguments' bit means we strip off and ignore
/// any PathArguments within this TypePath - callers should
/// put them back again if needs be.
pub(crate) fn replace_type_path_without_arguments(typ: TypePath) -> TypePath {
    let name = TypeName::from_cxx_type_path(&typ).to_cpp_name();
    match KNOWN_TYPES.by_cppname.get(&name) {
        Some(replacement_name) => {
            let id = make_ident(replacement_name);
            parse_quote! {
                #id
            }
        }
        None => typ,
    }
}

pub(crate) fn special_cpp_name(rs: &TypeName) -> Option<String> {
    KNOWN_TYPES
        .by_rs_name
        .get(rs)
        .map(|x| x.cpp_name.to_string())
}

fn make_ident(id: &str) -> Ident {
    Ident::new(id, Span::call_site())
}
<|endoftext|>


<commit_before><commit_msg>Fixes for the fast line intersection algorithms<commit_after><|endoftext|>


<commit_before><commit_msg>Fix bug in column_running_sum, document panic conditions (#368)<commit_after><|endoftext|>


<commit_before>//! Generate autopush.h via cbindgen
extern crate cbindgen;

use std::env;

fn main() {
    let crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR undefined");
    let pkg_name = env::var("CARGO_PKG_NAME").expect("CARGO_PKG_NAME undefined");
    let target = format!("{}/target/{}.h", crate_dir, pkg_name);
    cbindgen::Builder::new()
        .with_crate(crate_dir)
        .with_language(cbindgen::Language::C)
        .generate()
        .expect("cbindgen unable to generate bindings")
        .write_to_file(target.as_str());
}
<commit_msg>fix: let the build continue to rustc on cbindgen failures<commit_after>//! Generate autopush.h via cbindgen
extern crate cbindgen;

use std::{env, fs, path::PathBuf};

fn main() {
    let crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR undefined");
    let pkg_name = env::var("CARGO_PKG_NAME").expect("CARGO_PKG_NAME undefined");
    let target = PathBuf::from(format!("{}/target/{}.h", crate_dir, pkg_name));

    let result = cbindgen::Builder::new()
        .with_crate(crate_dir)
        .with_language(cbindgen::Language::C)
        .generate();
    match result {
        Ok(bindings) => {
            bindings.write_to_file(target);
        }
        Err(e) => {
            eprintln!("cbindgen unable to generate bindings: {}", e);
            if target.exists() {
                fs::remove_file(target).unwrap();
            }
        }
    }
}
<|endoftext|>


<commit_before>use futures::executor::block_on;
use futures::pin_mut;
use futures::stream::{self, Peekable, StreamExt};

#[test]
fn peekable() {
    block_on(async {
        let peekable: Peekable<_> = stream::iter(vec![1u8, 2, 3]).peekable();
        pin_mut!(peekable);
        assert_eq!(peekable.as_mut().peek().await, Some(&1u8));
        assert_eq!(peekable.collect::<Vec<u8>>().await, vec![1, 2, 3]);
    });
}
<commit_msg>futures: tests/stream_peekable.rs: Don't break w/o "executor"<commit_after>#[cfg(feature = "executor")] // executor::
#[test]
fn peekable() {
    use futures::executor::block_on;
    use futures::pin_mut;
    use futures::stream::{self, Peekable, StreamExt};

    block_on(async {
        let peekable: Peekable<_> = stream::iter(vec![1u8, 2, 3]).peekable();
        pin_mut!(peekable);
        assert_eq!(peekable.as_mut().peek().await, Some(&1u8));
        assert_eq!(peekable.collect::<Vec<u8>>().await, vec![1, 2, 3]);
    });
}
<|endoftext|>


<commit_before>#![warn(clippy::all, clippy::pedantic)]

// TOO_MANY_LINES
fn good_lines() {
    /* println!("This is good."); */
    // println!("This is good.");
    /* */ // println!("This is good.");
    /* */ // println!("This is good.");
    /* */ // println!("This is good.");
    /* */ // println!("This is good.");
    /* println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good."); */
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
}

fn bad_lines() {
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
}

fn main() {}
<commit_msg>Updating number of lines for the failing test to be > 100.<commit_after>#![warn(clippy::all, clippy::pedantic)]

// TOO_MANY_LINES
fn good_lines() {
    /* println!("This is good."); */
    // println!("This is good.");
    /* */ // println!("This is good.");
    /* */ // println!("This is good.");
    /* */ // println!("This is good.");
    /* */ // println!("This is good.");
    /* println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good."); */
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
    println!("This is good.");
}

fn bad_lines() {
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
    println!("This is bad.");
}

fn main() {}
<|endoftext|>


<commit_before>pub fn production_rate_per_hour(speed: u8) -> f64 {
    const CARS_PER_HOUR: u32 = 221;
    let production = CARS_PER_HOUR * speed as u32;
    let success_rate = success_rate(speed);
    let result = success_rate * production as f64;
    println!("result {result} for speed {speed}");
    return result
    // 1989 * .70 = 1392.3
}

pub fn success_rate(speed: u8) -> f64 {
    if speed >= 1 && speed <= 4 {
        return 1.0;
    }
    if speed >= 5 && speed <= 8 {
        return 0.90;
    }
    if speed >= 9 && speed <= 10 {
        return 0.77;
    }
    // Ideally this would throw an error
    return 0.0;
}

pub fn working_items_per_minute(speed: u8) -> u32 {
    return production_rate_per_hour(speed) as u32 / 60;
}
<commit_msg>Remove comment<commit_after>pub fn production_rate_per_hour(speed: u8) -> f64 {
    const CARS_PER_HOUR: u32 = 221;
    let production = CARS_PER_HOUR * speed as u32;
    let success_rate = success_rate(speed);
    return success_rate * production as f64;
}

pub fn success_rate(speed: u8) -> f64 {
    if speed >= 1 && speed <= 4 {
        return 1.0;
    }
    if speed >= 5 && speed <= 8 {
        return 0.90;
    }
    if speed >= 9 && speed <= 10 {
        return 0.77;
    }
    // Ideally this would throw an error
    return 0.0;
}

pub fn working_items_per_minute(speed: u8) -> u32 {
    return production_rate_per_hour(speed) as u32 / 60;
}
<|endoftext|>


<commit_before>// tuples can be used as function arguments and as return values
fn reverse(pair: (int, bool)) -> (bool, int) {
    // `let` can be used to bind the members of a tuple to variables
    let (integer, boolean) = pair;

    (boolean, integer)
}

fn main() {
    // a tuple with a bunch of different types
    let long_tuple = (1u8, 2u16, 3u32, 4u64,
                      -1i8, -2i16, -3i32, -4i64,
                      0.1f32, 0.2f64,
                      'a', true);

    // values can be extracted from the tuple using the valN methods
    println!("long tuple first value: {}", long_tuple.val0());
    println!("long tuple second value: {}", long_tuple.val1());

    // tuples can be tuple members
    let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);

    // tuples are printable
    let pair = (1, true);
    println!("pair is {}", pair);

    println!("the reversed pair is {}", reverse(pair));

    // to create one element tuples, the comma is required to tell them
    // apart from a literal surrounded by parentheses
    println!("one element tuple: {}", (5,))
    println!("just an integer: {}", (5))
}
<commit_msg>tuples: fix style<commit_after>// Tuples can be used as function arguments and as return values
fn reverse(pair: (int, bool)) -> (bool, int) {
    // `let` can be used to bind the members of a tuple to variables
    let (integer, boolean) = pair;

    (boolean, integer)
}

fn main() {
    // A tuple with a bunch of different types
    let long_tuple = (1u8, 2u16, 3u32, 4u64,
                      -1i8, -2i16, -3i32, -4i64,
                      0.1f32, 0.2f64,
                      'a', true);

    // Values can be extracted from the tuple using the `valN` methods
    println!("long tuple first value: {}", long_tuple.val0());
    println!("long tuple second value: {}", long_tuple.val1());

    // Tuples can be tuple members
    let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);

    // Tuples are printable
    println!("tuple of tuples: {}", tuple_of_tuples);

    let pair = (1, true);
    println!("pair is {}", pair);

    println!("the reversed pair is {}", reverse(pair));

    // To create one element tuples, the comma is required to tell them apart
    // from a literal surrounded by parentheses
    println!("one element tuple: {}", (5,))
    println!("just an integer: {}", (5))
}
<|endoftext|>


<commit_before>use nom::{self, IResult};
use std::str;

pub enum Expr<'a> {
    StrLit(&'a str),
    Var(&'a [u8]),
    Filter(&'a str, Box<Expr<'a>>),
    Compare(&'a str, Box<Expr<'a>>, Box<Expr<'a>>),
}

pub enum Target<'a> {
    Name(&'a [u8]),
}

pub enum Node<'a> {
    Lit(&'a [u8]),
    Expr(Expr<'a>),
    Cond(Vec<(Option<Expr<'a>>, Vec<Node<'a>>)>),
    Loop(Target<'a>, Expr<'a>, Vec<Node<'a>>),
    Extends(Expr<'a>),
    BlockDef(&'a str, Vec<Node<'a>>),
    Block(&'a str),
}

pub type Nodes<'a> = Vec<Node<'a>>;
pub type Conds<'a> = Vec<(Option<Expr<'a>>, Nodes<'a>)>;

fn take_content(i: &[u8]) -> IResult<&[u8], Node> {
    if i.len() < 1 || i[0] == b'{' {
        return IResult::Error(error_position!(nom::ErrorKind::TakeUntil, i));
    }
    for (j, c) in i.iter().enumerate() {
        if *c == b'{' {
            if i.len() < j + 2 {
                return IResult::Done(&i[..0], Node::Lit(&i[..]));
            } else if i[j + 1] == '{' as u8 {
                return IResult::Done(&i[j..], Node::Lit(&i[..j]));
            } else if i[j + 1] == '%' as u8 {
                return IResult::Done(&i[j..], Node::Lit(&i[..j]));
            }
        }
    }
    IResult::Done(&i[..0], Node::Lit(&i[..]))
}

named!(expr_str_lit<Expr>, map!(
    delimited!(char!('"'), is_not!("\""), char!('"')),
    |s| Expr::StrLit(str::from_utf8(s).unwrap())));

named!(expr_var<Expr>, map!(nom::alphanumeric, Expr::Var));

named!(target_single<Target>, map!(nom::alphanumeric, Target::Name));

fn expr_filtered(i: &[u8]) -> IResult<&[u8], Expr> {
    let (mut left, mut expr) = match expr_var(i) {
        IResult::Error(err) => { return IResult::Error(err); },
        IResult::Incomplete(needed) => { return IResult::Incomplete(needed); },
        IResult::Done(left, res) => (left, res),
    };
    while left[0] == b'|' {
        match nom::alphanumeric(&left[1..]) {
            IResult::Error(err) => {
                return IResult::Error(err);
            },
            IResult::Incomplete(needed) => {
                return IResult::Incomplete(needed);
            },
            IResult::Done(new_left, res) => {
                left = new_left;
                expr = Expr::Filter(str::from_utf8(res).unwrap(), Box::new(expr));
            },
        };
    }
    return IResult::Done(left, expr);
}

named!(expr_compare<Expr>, do_parse!(
    left: expr_filtered >>
    op: ws!(alt!(
        tag_s!("==") | tag_s!("!=") |
        tag_s!(">=") | tag_s!(">") |
        tag_s!("<=") | tag_s!("<")
    )) >>
    right: expr_filtered >>
    (Expr::Compare(str::from_utf8(op).unwrap(),
                   Box::new(left), Box::new(right)))));

named!(expr_any<Expr>, alt!(
    expr_compare |
    expr_filtered |
    expr_str_lit));

named!(expr_node<Node>, map!(
    delimited!(tag_s!("{{"), ws!(expr_any), tag_s!("}}")),
    Node::Expr));

named!(cond_if<Expr>, do_parse!(
    ws!(tag_s!("if")) >>
    cond: ws!(expr_any) >>
    (cond)));

named!(cond_block<(Option<Expr>, Nodes)>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("else")) >>
    cond: opt!(cond_if) >>
    tag_s!("%}") >>
    block: parse_template >>
    (cond, block)));

named!(block_if<Node>, do_parse!(
    tag_s!("{%") >>
    cond: ws!(cond_if) >>
    tag_s!("%}") >>
    block: parse_template >>
    elifs: many0!(cond_block) >>
    tag_s!("{%") >>
    ws!(tag_s!("endif")) >>
    tag_s!("%}") >>
    ({
        let mut res = Vec::new();
        res.push((Some(cond), block));
        res.extend(elifs);
        Node::Cond(res)
    })));

named!(block_for<Node>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("for")) >>
    var: ws!(target_single) >>
    ws!(tag_s!("in")) >>
    iter: ws!(expr_any) >>
    tag_s!("%}") >>
    block: parse_template >>
    tag_s!("{%") >>
    ws!(tag_s!("endfor")) >>
    tag_s!("%}") >>
    (Node::Loop(var, iter, block))));

named!(block_extends<Node>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("extends")) >>
    name: ws!(expr_str_lit) >>
    tag_s!("%}") >>
    (Node::Extends(name))));

named!(block_block<Node>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("block")) >>
    name: ws!(nom::alphanumeric) >>
    tag_s!("%}") >>
    contents: parse_template >>
    tag_s!("{%") >>
    ws!(tag_s!("endblock")) >>
    tag_s!("%}") >>
    (Node::BlockDef(str::from_utf8(name).unwrap(), contents))));

named!(parse_template<Nodes>, many0!(alt!(
    take_content |
    expr_node |
    block_if |
    block_for |
    block_extends |
    block_block)));

pub fn parse<'a>(src: &'a str) -> Nodes {
    match parse_template(src.as_bytes()) {
        IResult::Done(_, res) => res,
        IResult::Error(err) => panic!("problems parsing template source: {}", err),
        IResult::Incomplete(_) => panic!("parsing incomplete"),
    }
}
<commit_msg>Fold identical branches in parser (as suggested by clippy)<commit_after>use nom::{self, IResult};
use std::str;

pub enum Expr<'a> {
    StrLit(&'a str),
    Var(&'a [u8]),
    Filter(&'a str, Box<Expr<'a>>),
    Compare(&'a str, Box<Expr<'a>>, Box<Expr<'a>>),
}

pub enum Target<'a> {
    Name(&'a [u8]),
}

pub enum Node<'a> {
    Lit(&'a [u8]),
    Expr(Expr<'a>),
    Cond(Vec<(Option<Expr<'a>>, Vec<Node<'a>>)>),
    Loop(Target<'a>, Expr<'a>, Vec<Node<'a>>),
    Extends(Expr<'a>),
    BlockDef(&'a str, Vec<Node<'a>>),
    Block(&'a str),
}

pub type Nodes<'a> = Vec<Node<'a>>;
pub type Conds<'a> = Vec<(Option<Expr<'a>>, Nodes<'a>)>;

fn take_content(i: &[u8]) -> IResult<&[u8], Node> {
    if i.len() < 1 || i[0] == b'{' {
        return IResult::Error(error_position!(nom::ErrorKind::TakeUntil, i));
    }
    for (j, c) in i.iter().enumerate() {
        if *c == b'{' {
            if i.len() < j + 2 {
                return IResult::Done(&i[..0], Node::Lit(&i[..]));
            } else if i[j + 1] == b'{' || i[j + 1] == b'%' {
                return IResult::Done(&i[j..], Node::Lit(&i[..j]));
            }
        }
    }
    IResult::Done(&i[..0], Node::Lit(&i[..]))
}

named!(expr_str_lit<Expr>, map!(
    delimited!(char!('"'), is_not!("\""), char!('"')),
    |s| Expr::StrLit(str::from_utf8(s).unwrap())));

named!(expr_var<Expr>, map!(nom::alphanumeric, Expr::Var));

named!(target_single<Target>, map!(nom::alphanumeric, Target::Name));

fn expr_filtered(i: &[u8]) -> IResult<&[u8], Expr> {
    let (mut left, mut expr) = match expr_var(i) {
        IResult::Error(err) => { return IResult::Error(err); },
        IResult::Incomplete(needed) => { return IResult::Incomplete(needed); },
        IResult::Done(left, res) => (left, res),
    };
    while left[0] == b'|' {
        match nom::alphanumeric(&left[1..]) {
            IResult::Error(err) => {
                return IResult::Error(err);
            },
            IResult::Incomplete(needed) => {
                return IResult::Incomplete(needed);
            },
            IResult::Done(new_left, res) => {
                left = new_left;
                expr = Expr::Filter(str::from_utf8(res).unwrap(), Box::new(expr));
            },
        };
    }
    return IResult::Done(left, expr);
}

named!(expr_compare<Expr>, do_parse!(
    left: expr_filtered >>
    op: ws!(alt!(
        tag_s!("==") | tag_s!("!=") |
        tag_s!(">=") | tag_s!(">") |
        tag_s!("<=") | tag_s!("<")
    )) >>
    right: expr_filtered >>
    (Expr::Compare(str::from_utf8(op).unwrap(),
                   Box::new(left), Box::new(right)))));

named!(expr_any<Expr>, alt!(
    expr_compare |
    expr_filtered |
    expr_str_lit));

named!(expr_node<Node>, map!(
    delimited!(tag_s!("{{"), ws!(expr_any), tag_s!("}}")),
    Node::Expr));

named!(cond_if<Expr>, do_parse!(
    ws!(tag_s!("if")) >>
    cond: ws!(expr_any) >>
    (cond)));

named!(cond_block<(Option<Expr>, Nodes)>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("else")) >>
    cond: opt!(cond_if) >>
    tag_s!("%}") >>
    block: parse_template >>
    (cond, block)));

named!(block_if<Node>, do_parse!(
    tag_s!("{%") >>
    cond: ws!(cond_if) >>
    tag_s!("%}") >>
    block: parse_template >>
    elifs: many0!(cond_block) >>
    tag_s!("{%") >>
    ws!(tag_s!("endif")) >>
    tag_s!("%}") >>
    ({
        let mut res = Vec::new();
        res.push((Some(cond), block));
        res.extend(elifs);
        Node::Cond(res)
    })));

named!(block_for<Node>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("for")) >>
    var: ws!(target_single) >>
    ws!(tag_s!("in")) >>
    iter: ws!(expr_any) >>
    tag_s!("%}") >>
    block: parse_template >>
    tag_s!("{%") >>
    ws!(tag_s!("endfor")) >>
    tag_s!("%}") >>
    (Node::Loop(var, iter, block))));

named!(block_extends<Node>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("extends")) >>
    name: ws!(expr_str_lit) >>
    tag_s!("%}") >>
    (Node::Extends(name))));

named!(block_block<Node>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("block")) >>
    name: ws!(nom::alphanumeric) >>
    tag_s!("%}") >>
    contents: parse_template >>
    tag_s!("{%") >>
    ws!(tag_s!("endblock")) >>
    tag_s!("%}") >>
    (Node::BlockDef(str::from_utf8(name).unwrap(), contents))));

named!(parse_template<Nodes>, many0!(alt!(
    take_content |
    expr_node |
    block_if |
    block_for |
    block_extends |
    block_block)));

pub fn parse<'a>(src: &'a str) -> Nodes {
    match parse_template(src.as_bytes()) {
        IResult::Done(_, res) => res,
        IResult::Error(err) => panic!("problems parsing template source: {}", err),
        IResult::Incomplete(_) => panic!("parsing incomplete"),
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

use super::Result;

pub type Patch = BTreeMap<Vec<u8>, Change>;
pub type Iter<'a> = Box<Iterator<Item=(&'a [u8], &'a [u8])> + 'a>;

#[derive(Clone)]
pub enum Change {
    Put(Vec<u8>),
    Delete,
}

pub struct Fork {
    snapshot: Box<Snapshot>,
    changes: Patch
}

pub trait Database: Sized + Clone + Send + Sync + 'static {
    fn snapshot(&self) -> Box<Snapshot>;
    fn fork(&self) -> Fork {
        Fork {
            snapshot: self.snapshot(),
            changes: Patch::new(),
        }
    }
    fn merge(&mut self, patch: Patch) -> Result<()>;
}

pub trait Snapshot {
    fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>>;
    fn contains(&self, key: &[u8]) -> Result<bool> {
        Ok(self.get(key)?.is_some())
    }
    fn iter<'a>(&'a self, from: Option<&[u8]>) -> Iter<'a>;
}

impl Snapshot for Fork {
    fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
        match self.changes.get(key) {
            Some(change) => Ok(match *change {
                Change::Put(ref v) => Some(v.clone()),
                Change::Delete => None,
            }),
            None => self.snapshot.get(key)
        }
    }

    fn contains(&self, key: &[u8]) -> Result<bool> {
        Ok(match self.changes.get(key) {
            Some(change) => match *change {
                Change::Put(..) => true,
                Change::Delete => false,
            },
            None => self.snapshot.get(key)?.is_some()
        })
    }

    fn iter<'a>(&'a self, from: Option<&[u8]>) -> Iter<'a> {
        // FIXME: implement ForkIter
        self.snapshot.iter(from)
    }
}

impl Fork {
    pub fn put(&mut self, key: Vec<u8>, value: Vec<u8>) {
        self.changes.insert(key, Change::Put(value));
    }

    pub fn delete(&mut self, key: Vec<u8>) {
        self.changes.insert(key, Change::Delete);
    }

    pub fn as_snapshot(&self) -> &Snapshot {
        &*self.snapshot
    }

    pub fn into_patch(self) -> Patch {
        self.changes
    }
}
<commit_msg>Start to implementing ForkIter<commit_after>use std::iter::Iterator;
use std::collections::btree_map::{BTreeMap, Range};

use super::Result;

pub type Patch = BTreeMap<Vec<u8>, Change>;
pub type Iter<'a> = Box<Iterator<Item=(&'a [u8], &'a [u8])> + 'a>;

#[derive(Clone)]
pub enum Change {
    Put(Vec<u8>),
    Delete,
}

pub struct Fork {
    snapshot: Box<Snapshot>,
    changes: Patch
}

pub struct ForkIter<'a> {
    snapshot: Iter<'a>,
    changes: Range<'a, Vec<u8>, Change>
}

pub trait Database: Sized + Clone + Send + Sync + 'static {
    fn snapshot(&self) -> Box<Snapshot>;
    fn fork(&self) -> Fork {
        Fork {
            snapshot: self.snapshot(),
            changes: Patch::new(),
        }
    }
    fn merge(&mut self, patch: Patch) -> Result<()>;
}

pub trait Snapshot {
    fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>>;
    fn contains(&self, key: &[u8]) -> Result<bool> {
        Ok(self.get(key)?.is_some())
    }
    fn iter<'a>(&'a self, from: Option<&[u8]>) -> Iter<'a>;
}

impl Snapshot for Fork {
    fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
        match self.changes.get(key) {
            Some(change) => Ok(match *change {
                Change::Put(ref v) => Some(v.clone()),
                Change::Delete => None,
            }),
            None => self.snapshot.get(key)
        }
    }

    fn contains(&self, key: &[u8]) -> Result<bool> {
        Ok(match self.changes.get(key) {
            Some(change) => match *change {
                Change::Put(..) => true,
                Change::Delete => false,
            },
            None => self.snapshot.get(key)?.is_some()
        })
    }

    fn iter<'a>(&'a self, from: Option<&[u8]>) -> Iter<'a> {
        use std::collections::Bound::*;
        Box::new(ForkIter {
            snapshot: self.snapshot.iter(from),
            changes: if let Some(seek) = from {
                self.changes.range::<[u8], _>((Included(seek), Unbounded))
            } else {
                self.changes.range::<[u8], _>(..)
            }
        })
    }
}

impl Fork {
    pub fn put(&mut self, key: Vec<u8>, value: Vec<u8>) {
        self.changes.insert(key, Change::Put(value));
    }

    pub fn delete(&mut self, key: Vec<u8>) {
        self.changes.insert(key, Change::Delete);
    }

    pub fn as_snapshot(&self) -> &Snapshot {
        &*self.snapshot
    }

    pub fn into_patch(self) -> Patch {
        self.changes
    }
}

impl<'a> Iterator for ForkIter<'a> {
    type Item = (&'a [u8], &'a [u8]);

    fn next(&mut self) -> Option<Self::Item> {
        self.snapshot.next()
    }
}
<|endoftext|>


<commit_before>const EPS: i64 = 1 * 1000 * 1000; // 1 second

#[derive(serde::Deserialize)]
pub struct Config {
    pub encoder: EncoderConfig,
    pub redis: RedisConfig,
    pub sqs: SqsConfig,
}

#[derive(serde::Deserialize)]
pub struct EncoderConfig {
    pub base_dir: String,
    pub ffmpeg_args: Vec<String>,
}

#[derive(serde::Deserialize)]
pub struct RedisConfig {
    pub url: String,
}

#[derive(serde::Deserialize)]
pub struct SqsConfig {
    pub queue_url: String,
}

pub fn load_config() -> Result<Config, anyhow::Error> {
    let body = std::fs::read("config.toml")?;
    Ok(toml::from_slice(&body)?)
}

pub async fn encode<P>(config: &Config, ts_path: P) -> Result<(), anyhow::Error>
where
    P: AsRef<std::path::Path>,
{
    let ts_path = ts_path.as_ref();
    let mp4_path = ts_path.with_extension("mp4");
    let ts_duration_micro = ffmpeg::format::input(&ts_path)?.duration();

    let status = tokio::process::Command::new("ffmpeg")
        .arg("-i")
        .arg(&ts_path)
        .args(&config.encoder.ffmpeg_args)
        .arg(&mp4_path)
        .status()
        .await?;
    if !status.success() {
        anyhow::anyhow!("Encode failure!");
    }

    let mp4_duration_micro = ffmpeg::format::input(&ts_path)?.duration();
    if (ts_duration_micro - mp4_duration_micro).abs() > EPS {
        anyhow::anyhow!(
            "Duration mismatch: TS {}, MP4 {} (microsecond)",
            ts_duration_micro,
            mp4_duration_micro
        );
    }
    verify_audio_and_video(&mp4_path)?;

    let ts_fname = ts_path.file_name().unwrap().to_str().unwrap();
    let orig_fname = regex::Regex::new(r#"\A\d+_\d+"#)?
        .find(ts_fname)
        .expect("Unexpected filename")
        .as_str();
    let orig_path = ts_path
        .parent()
        .unwrap()
        .join(orig_fname)
        .with_extension("ts");

    std::fs::remove_file(ts_path)?;
    std::fs::remove_file(orig_path)?;
    Ok(())
}

fn verify_audio_and_video<P>(mp4_path: P) -> Result<(), anyhow::Error>
where
    P: AsRef<std::path::Path>,
{
    let audio_path = tempfile::NamedTempFile::new()?.into_temp_path();
    let status = std::process::Command::new("ffmpeg")
        .args(&["-y", "-i"])
        .arg(mp4_path.as_ref())
        .args(&["-vn", "-acodec", "copy", "-f", "mp4"])
        .arg(&audio_path)
        .status()?;
    if !status.success() {
        anyhow::anyhow!("ffmpeg -vn failed");
    }

    let video_path = tempfile::NamedTempFile::new()?.into_temp_path();
    let status = std::process::Command::new("ffmpeg")
        .args(&["-y", "-i"])
        .arg(mp4_path.as_ref())
        .args(&["-an", "-vcodec", "copy", "-f", "mp4"])
        .arg(&video_path)
        .status()?;
    if !status.success() {
        anyhow::anyhow!("ffmpeg -an failed");
    }

    let audio_duration_micro = ffmpeg::format::input(&audio_path)?.duration();
    let video_duration_micro = ffmpeg::format::input(&video_path)?.duration();
    if (audio_duration_micro - video_duration_micro).abs() > EPS {
        anyhow::anyhow!(
            "Duration mismatch! audio:{} video:{} (microsecond)",
            audio_duration_micro,
            video_duration_micro
        );
    }
    Ok(())
}
<commit_msg>Fix anyhow! usage<commit_after>const EPS: i64 = 1 * 1000 * 1000; // 1 second

#[derive(serde::Deserialize)]
pub struct Config {
    pub encoder: EncoderConfig,
    pub redis: RedisConfig,
    pub sqs: SqsConfig,
}

#[derive(serde::Deserialize)]
pub struct EncoderConfig {
    pub base_dir: String,
    pub ffmpeg_args: Vec<String>,
}

#[derive(serde::Deserialize)]
pub struct RedisConfig {
    pub url: String,
}

#[derive(serde::Deserialize)]
pub struct SqsConfig {
    pub queue_url: String,
}

pub fn load_config() -> Result<Config, anyhow::Error> {
    let body = std::fs::read("config.toml")?;
    Ok(toml::from_slice(&body)?)
}

pub async fn encode<P>(config: &Config, ts_path: P) -> Result<(), anyhow::Error>
where
    P: AsRef<std::path::Path>,
{
    let ts_path = ts_path.as_ref();
    let mp4_path = ts_path.with_extension("mp4");
    let ts_duration_micro = ffmpeg::format::input(&ts_path)?.duration();

    let status = tokio::process::Command::new("ffmpeg")
        .arg("-i")
        .arg(&ts_path)
        .args(&config.encoder.ffmpeg_args)
        .arg(&mp4_path)
        .status()
        .await?;
    if !status.success() {
        return Err(anyhow::anyhow!("Encode failure!"));
    }

    let mp4_duration_micro = ffmpeg::format::input(&ts_path)?.duration();
    if (ts_duration_micro - mp4_duration_micro).abs() > EPS {
        return Err(anyhow::anyhow!(
            "Duration mismatch: TS {}, MP4 {} (microsecond)",
            ts_duration_micro,
            mp4_duration_micro
        ));
    }
    verify_audio_and_video(&mp4_path)?;

    let ts_fname = ts_path.file_name().unwrap().to_str().unwrap();
    let orig_fname = regex::Regex::new(r#"\A\d+_\d+"#)?
        .find(ts_fname)
        .expect("Unexpected filename")
        .as_str();
    let orig_path = ts_path
        .parent()
        .unwrap()
        .join(orig_fname)
        .with_extension("ts");

    std::fs::remove_file(ts_path)?;
    std::fs::remove_file(orig_path)?;
    Ok(())
}

fn verify_audio_and_video<P>(mp4_path: P) -> Result<(), anyhow::Error>
where
    P: AsRef<std::path::Path>,
{
    let audio_path = tempfile::NamedTempFile::new()?.into_temp_path();
    let status = std::process::Command::new("ffmpeg")
        .args(&["-y", "-i"])
        .arg(mp4_path.as_ref())
        .args(&["-vn", "-acodec", "copy", "-f", "mp4"])
        .arg(&audio_path)
        .status()?;
    if !status.success() {
        return Err(anyhow::anyhow!("ffmpeg -vn failed"));
    }

    let video_path = tempfile::NamedTempFile::new()?.into_temp_path();
    let status = std::process::Command::new("ffmpeg")
        .args(&["-y", "-i"])
        .arg(mp4_path.as_ref())
        .args(&["-an", "-vcodec", "copy", "-f", "mp4"])
        .arg(&video_path)
        .status()?;
    if !status.success() {
        return Err(anyhow::anyhow!("ffmpeg -an failed"));
    }

    let audio_duration_micro = ffmpeg::format::input(&audio_path)?.duration();
    let video_duration_micro = ffmpeg::format::input(&video_path)?.duration();
    if (audio_duration_micro - video_duration_micro).abs() > EPS {
        return Err(anyhow::anyhow!(
            "Duration mismatch! audio:{} video:{} (microsecond)",
            audio_duration_micro,
            video_duration_micro
        ));
    }
    Ok(())
}
<|endoftext|>