<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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.

#[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.
#[macro_export]
macro_rules! service {
    (
        // List any rpc methods: rpc foo(arg1: Arg1, ..., argN: ArgN) -> Out
        $(
            $(#[$attr:meta])*
            rpc $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;
        )*
    ) => {
        #[doc="The provided 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 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)
        }
    }

    #[bench]
    fn hello(bencher: &mut Bencher) {
        let _ = env_logger::init();
        let handle = hi::serve("localhost:0", HelloServer, None).unwrap();
        let client = hi::AsyncClient::new(handle.local_addr(), None).unwrap();
        let concurrency = 100;
        let mut rpcs = Vec::with_capacity(concurrency);
        bencher.iter(|| {
            for _ in 0..concurrency {
                rpcs.push(client.hello("Bob".into()));
            }
            for _ in 0..concurrency {
                rpcs.pop().unwrap().get().unwrap();
            }
        });
        drop(client);
        handle.shutdown();
    }
}
<commit_msg>Add documentation to the macro<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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.

#[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:
///
///     #[attr]
///     rpc fn_name(arg1: Ty1, ..., argN, TyN) -> ReturnTy;
///
/// 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 generic type returned by `AsyncClient`'s rpc's
/// * `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="The provided 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 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)
        }
    }

    #[bench]
    fn hello(bencher: &mut Bencher) {
        let _ = env_logger::init();
        let handle = hi::serve("localhost:0", HelloServer, None).unwrap();
        let client = hi::AsyncClient::new(handle.local_addr(), None).unwrap();
        let concurrency = 100;
        let mut rpcs = Vec::with_capacity(concurrency);
        bencher.iter(|| {
            for _ in 0..concurrency {
                rpcs.push(client.hello("Bob".into()));
            }
            for _ in 0..concurrency {
                rpcs.pop().unwrap().get().unwrap();
            }
        });
        drop(client);
        handle.shutdown();
    }
}
<|endoftext|>


<commit_before>use nom::*;

use std::iter::Zip;
use std::slice::Iter;
use std::vec::IntoIter;

#[derive(Debug)]
struct ForkExit {
    pid: i32,
    ppid: i32,
    tid: i32,
    ptid: i32,
    time: i32
    // sample id?
}

struct Throttle {
    time: u64,
    id: u64,
    stream_id: u64
    // sample id?
}

struct ThreadId {
    pid: i32,
    tid: i32
}

struct Cpu {
    cpu: u32,
    res: u32
}

struct Callchain {

}

struct Event {
    identifier: u64,
    ip: u64,
    tid: ThreadId,
    time: u64,
    add: u64,
    id: u64,
    stream_id: u64,
    cpu: Cpu,
    period: u64,
    read: u8, // XXX
    caller: Vec<u64>,

}

enum EventType {
    Mmap,
    Lost,
    Comm,
    Throttle,
    Unthrottle,
    Fork,
    Read,
    Sample,
    Mmap2,
    TracingData,
    FinishedRound,
    IdIndex,
    AuxtraceInfo,
    Auxtrace,
    AuxtraceError
}

#[derive(Debug)]
struct EventHeader {
    event_type: u32,
    flags: u16,
    size: u16,

}

/// Parse a file section
named!(parse_event_header<&[u8], EventHeader>,
    chain!(
        event_type: le_u32 ~
        flags: le_u16 ~
        size: le_u16,
        || EventHeader { event_type: event_type, flags: flags, size: size }
    )
);

/*
def perf_event_header():
    return Embedded(Struct(None,
                           Enum(UNInt32("type"),
                                MMAP			= 1,
                                LOST			= 2,
                                COMM			= 3,
                                EXIT			= 4,
                                THROTTLE		= 5,
                                UNTHROTTLE		= 6,
                                FORK			= 7,
                                READ			= 8,
                                SAMPLE			= 9,
                                MMAP2			= 10,
                                TRACING_DATA            = 66,
                                FINISHED_ROUND          = 68,
                                ID_INDEX                = 69,
                                AUXTRACE_INFO           = 70,
                                AUXTRACE                = 71,
                                AUXTRACE_ERROR          = 72),
                           Embedded(BitStruct(None,
                                              Padding(1),
                                              Enum(BitField("cpumode", 7),
                                                   UNKNOWN = 0,
                                                   KERNEL = 1,
                                                   USER = 2,
                                                   HYPERVISOR = 3,
                                                   GUEST_KERNEL = 4,
                                                   GUEST_USER = 5),

                                              Flag("ext_reserved"),
                                              Flag("exact_ip"),
                                              Flag("mmap_data"),
                                              Padding(5))),
                           UNInt16("size"),
                           If(has_sample_id_all,
                                 Pointer(lambda ctx: ctx.start + ctx.size - 8,
                                   UNInt64("end_id"))),
                           Value("attr", lookup_event_attr)))
*/

#[derive(Debug, Clone, Copy)]
pub struct PerfFileSection {
    offset: u64,
    size: u64
}

/// Parse a file section
named!(parse_file_section<&[u8], PerfFileSection>,
    chain!(
        offset: le_u64 ~
        size: le_u64,
        || PerfFileSection { offset: offset, size: size }
    )
);

#[derive(Debug, Clone, Copy)]
pub enum HeaderFlag {
    NrCpus,
    Arch,
    Version,
    OsRelease,
    Hostname,
    BuildId,
    TracingData,
    BranchStack,
    NumaTopology,
    CpuTopology,
    EventDesc,
    CmdLine,
    TotalMem,
    CpuId,
    CpuDesc,
    GroupDesc,
    PmuMappings
}

#[derive(Debug)]
pub struct HeaderFlags {
    nrcpus: bool,
    arch: bool,
    version: bool,
    osrelease: bool,
    hostname: bool,
    build_id: bool,
    tracing_data: bool,
    branch_stack: bool,
    numa_topology: bool,
    cpu_topology: bool,
    event_desc: bool,
    cmdline: bool,
    total_mem: bool,
    cpuid: bool,
    cpudesc: bool,
    group_desc: bool,
    pmu_mappings: bool,
}

impl HeaderFlags {
    fn collect(&self) -> Vec<HeaderFlag> {
        let mut flags = Vec::with_capacity(17);

        if self.nrcpus {
            flags.push(HeaderFlag::NrCpus);
        }
        if self.arch {
            flags.push(HeaderFlag::Arch);
        }
        if self.version {
            flags.push(HeaderFlag::Version);
        }
        if self.osrelease {
            flags.push(HeaderFlag::OsRelease);
        }
        if self.hostname {
            flags.push(HeaderFlag::Hostname);
        }
        if self.build_id {
            flags.push(HeaderFlag::BuildId);
        }
        if self.tracing_data {
            flags.push(HeaderFlag::TracingData);
        }
        if self.branch_stack {
            flags.push(HeaderFlag::BranchStack);
        }
        if self.numa_topology {
            flags.push(HeaderFlag::NumaTopology);
        }
        if self.cpu_topology {
            flags.push(HeaderFlag::CpuTopology);
        }
        if self.event_desc {
            flags.push(HeaderFlag::EventDesc);
        }
        if self.cmdline {
            flags.push(HeaderFlag::CmdLine);
        }
        if self.total_mem {
            flags.push(HeaderFlag::TotalMem);
        }
        if self.cpuid {
            flags.push(HeaderFlag::CpuId);
        }
        if self.cpudesc {
            flags.push(HeaderFlag::CpuDesc);
        }
        if self.group_desc {
            flags.push(HeaderFlag::GroupDesc);
        }
        if self.pmu_mappings {
            flags.push(HeaderFlag::PmuMappings);
        }

        flags
    }
}

#[derive(Debug)]
pub struct PerfFileHeader {
    size: u64,
    attr_size: u64,
    attrs: PerfFileSection,
    data: PerfFileSection,
    event_types: PerfFileSection,

    flags: HeaderFlags,
}

/// Parse a perf header
named!(parse_header<&[u8], PerfFileHeader>,
    chain!(
        tag!("PERFILE2") ~
        size: le_u64 ~
        attr_size: le_u64 ~
        attrs: parse_file_section ~
        data: parse_file_section ~
        event_types: parse_file_section ~
        flags: bits!(chain!(
            nrcpus: take_bits!(u8, 1) ~
            arch: take_bits!(u8, 1) ~
            version: take_bits!(u8, 1) ~
            osrelease: take_bits!(u8, 1) ~
            hostname: take_bits!(u8, 1) ~
            build_id: take_bits!(u8, 1) ~
            tracing_data: take_bits!(u8, 1) ~
            reserved: take_bits!(u8, 1) ~

            branch_stack: take_bits!(u8, 1) ~
            numa_topology: take_bits!(u8, 1) ~
            cpu_topology: take_bits!(u8, 1) ~
            event_desc: take_bits!(u8, 1) ~
            cmdline: take_bits!(u8, 1) ~
            total_mem: take_bits!(u8, 1) ~
            cpuid: take_bits!(u8, 1) ~
            cpudesc: take_bits!(u8, 1) ~

            pad1: take_bits!(u8, 6) ~
            group_desc: take_bits!(u8, 1) ~
            pmu_mappings: take_bits!(u8, 1),
            || {
                HeaderFlags {
                    nrcpus: nrcpus == 1,
                    arch: arch == 1,
                    version: version == 1,
                    osrelease: osrelease == 1,
                    hostname: hostname == 1,
                    build_id: build_id == 1,
                    tracing_data: tracing_data == 1,
                    branch_stack: branch_stack == 1,
                    numa_topology: numa_topology == 1,
                    cpu_topology: cpu_topology == 1,
                    event_desc: event_desc == 1,
                    cmdline: cmdline == 1,
                    total_mem: total_mem == 1,
                    cpuid: cpuid == 1,
                    cpudesc: cpudesc == 1,
                    group_desc: group_desc == 1,
                    pmu_mappings: pmu_mappings == 1
                }
            }
        )) ~
        reserved: take!(29),
        || PerfFileHeader { size: size, attr_size: attr_size, attrs: attrs, data: data, event_types: event_types, flags: flags }
    )
);

#[derive(Debug)]
pub struct PerfFile {
    bytes: Vec<u8>,
    pub header: PerfFileHeader,
    //sections: Vec<PerfFileSection>,
}

impl PerfFile {
    pub fn new(bytes: Vec<u8>) -> PerfFile {
        let header = match parse_header(bytes.as_slice()) {
            IResult::Done(rest, h) => h,
            IResult::Error(e) => panic!("{:?}", e),
            IResult::Incomplete(_) => panic!("Incomplete data?"),
        };

        PerfFile { header: header, bytes: bytes }
    }

    pub fn data(&self) {
        let data_start = self.header.data.offset as usize;
        let slice: &[u8] = &self.bytes[data_start..];
        println!("{:?}", parse_event_header(slice));
    }

    pub fn sections(&self) -> Vec<(HeaderFlag, PerfFileSection)> {
        let sections: Vec<PerfFileSection> = self.parse_header_sections().unwrap().1;
        let flags: Vec<HeaderFlag> = self.header.flags.collect();
        assert!(sections.len() == flags.len());

        flags.into_iter().zip(sections).collect()
    }

    fn parse_header_sections(&self) -> IResult<&[u8], Vec<PerfFileSection>> {
        let sections_start: usize = (self.header.data.offset + self.header.data.size) as usize;
        let slice: &[u8] = &self.bytes[sections_start..];
        let flags: Vec<HeaderFlag> = self.header.flags.collect();

        count!(slice, parse_file_section, flags.len())
    }
}
<commit_msg>Update parser.<commit_after>use nom::*;

use std::iter::Zip;
use std::slice::Iter;
use std::vec::IntoIter;

#[derive(Debug)]
struct ForkExit {
    pid: i32,
    ppid: i32,
    tid: i32,
    ptid: i32,
    time: i32
    // sample id?
}

struct Throttle {
    time: u64,
    id: u64,
    stream_id: u64
    // sample id?
}

#[derive(Debug)]
struct ThreadId {
    pid: i32,
    tid: i32
}

#[derive(Debug)]
struct Cpu {
    cpu: u32,
    res: u32
}

struct Callchain {

}

#[derive(Debug, Eq, PartialEq)]
enum EventType {
    Mmap,
    Lost,
    Comm,
    Exit,
    Throttle,
    Unthrottle,
    Fork,
    Read,
    Sample,
    Mmap2
}

impl EventType {
    fn new(event_type: u32) -> EventType {
        match event_type {
            1 => EventType::Mmap,
            2 => EventType::Lost,
            3 => EventType::Comm,
            4 => EventType::Exit,
            5 => EventType::Throttle,
            6 => EventType::Unthrottle,
            7 => EventType::Fork,
            8 => EventType::Read,
            9 => EventType::Sample,
            10 => EventType::Mmap2,
            _ => panic!("Unknown event type ({}) encountered, update the enum?", event_type)
        }
    }
}

#[derive(Debug)]
struct EventHeader {
    event_type: EventType,
    misc: u16,
    size: u16,
}

impl EventHeader {
    pub fn size(&self) -> usize {
        self.size as usize
    }
}

/// Parse a file section
named!(parse_event_header<&[u8], EventHeader>,
    chain!(
        event_type: le_u32 ~
        misc: le_u16 ~
        size: le_u16,
        || EventHeader { event_type: EventType::new(event_type), misc: misc, size: size }
    )
);

/// The MMAP events record the PROT_EXEC mappings so that we can correlate user-space IPs to code.
#[derive(Debug)]
pub struct MMAPRecord {
    pid: i32,
    tid: u32,
    addr: u64,
    len: u64,
    pgoff: u64,
    filename: String
}

#[derive(Default, Debug)]
pub struct FileReadFormat {
    /// The value of the event
    pub value: u64,
    /// if PERF_FORMAT_TOTAL_TIME_ENABLED
    pub time_enabled: u64,
    /// if PERF_FORMAT_TOTAL_TIME_RUNNING
    pub time_running: u64,
    /// if PERF_FORMAT_ID
    pub id: u64,
}

#[derive(Debug)]
pub struct ReadRecord {
    pid: u32,
    tid: u32,
    value: FileReadFormat, // TODO with PERF_FORMAT_GROUP: values: Vec<FileReadFormat>
}

#[derive(Debug)]
struct BranchEntry {
    pub from: u64,
    pub to: u64,
    flags: u64,
}

/// This record indicates a sample.
#[derive(Debug)]
pub struct SampleRecord {
    /// if PERF_SAMPLE_IP
    ip: Option<u64>,
    /// if PERF_SAMPLE_TID
    pid_tid: Option<ThreadId>,
    /// if PERF_SAMPLE_TIME
    time: Option<u64>,
    /// if PERF_SAMPLE_ADDR
    addr: Option<u64>,
    /// if PERF_SAMPLE_ID
    id: Option<u64>,
    /// if PERF_SAMPLE_STREAM_ID
    stream_id: Option<u64>,
    /// if PERF_SAMPLE_CPU
    cpu_res: Option<Cpu>,
    /// if PERF_SAMPLE_PERIOD
    period: Option<u64>,
    /// if PERF_SAMPLE_READ
    v: FileReadFormat, // # TODO FILE GROUP FORMAT is different...
    /// if PERF_SAMPLE_CALLCHAIN
    ips: Option<Vec<u64>>,
    /// if PERF_SAMPLE_RAW
    raw_sample: Option<Vec<u8>>,
    /// if PERF_SAMPLE_REGS_USER & PERF_SAMPLE_BRANCH_STACK
    lbr: Option<Vec<BranchEntry>>,
    /// PERF_SAMPLE_STACK_USER
    abi_user: Option<u64>,
    /// PERF_SAMPLE_STACK_USER
    regs_user: Option<Vec<u64>>,
    /// PERF_SAMPLE_STACK_USER
    user_stack: Option<Vec<u8>>,
    /// PERF_SAMPLE_STACK_USER
    dyn_size: Option<u64>,
    /// if PERF_SAMPLE_WEIGHT
    weight: Option<u64>,
    /// if PERF_SAMPLE_DATA_SRC
    data_src: Option<u64>,
    /// if PERF_SAMPLE_TRANSACTION
    transaction: Option<u64>,
    /// if PERF_SAMPLE_REGS_INTR
    abi_intr: Option<u64>,
    /// if PERF_SAMPLE_REGS_INTR
    regs_intr: Option<Vec<u64>>
}

#[derive(Debug)]
pub struct LostRecord {

}

#[derive(Debug)]
struct Event {
    header: EventHeader,
    data: EventData,
}

#[derive(Debug)]
pub enum EventData {
    MMAP(MMAPRecord),
    Lost(LostRecord),
    //Comm(CommRecord),
    //Exit(ExitRecord),
    //Throttle(ThrottleRecord),
    //Unthrottle(ThrottleRecord),
    //Fork(ForkRecord),
    //Read(ReadRecord),
    //Sample(SampleRecord),
}

fn is_nul_byte(c: &u8) -> bool {
    *c == 0x0
}

named!(parse_c_string, take_till!(is_nul_byte));

named!(parse_mmap_event<&[u8], EventData>,
    chain!(
        pid: le_i32 ~
        tid: le_u32 ~
        addr: le_u64 ~
        len: le_u64 ~
        pgoff: le_u64 ~
        filename: parse_c_string,
        || EventData::MMAP(MMAPRecord {
                pid: pid,
                tid: tid,
                addr: addr,
                len: len,
                pgoff: pgoff,
                filename: unsafe { String::from_utf8_unchecked(filename.to_vec()) }
        })
    )
);

/// Parse a file section
named!(parse_event<&[u8], Event>,
    chain!(
        header: parse_event_header ~
        event: alt!(
            cond_reduce!(header.event_type == EventType::Mmap, parse_mmap_event) |
            cond_reduce!(header.event_type == EventType::Lost, parse_mmap_event)
        ),
        || Event { header: header, data: event })
);

/*
def perf_event_header():
    return Embedded(Struct(None,
                           Enum(UNInt32("type"),
                                MMAP			= 1,
                                LOST			= 2,
                                COMM			= 3,
                                EXIT			= 4,
                                THROTTLE		= 5,
                                UNTHROTTLE		= 6,
                                FORK			= 7,
                                READ			= 8,
                                SAMPLE			= 9,
                                MMAP2			= 10,
                                TRACING_DATA            = 66,
                                FINISHED_ROUND          = 68,
                                ID_INDEX                = 69,
                                AUXTRACE_INFO           = 70,
                                AUXTRACE                = 71,
                                AUXTRACE_ERROR          = 72),
                           Embedded(BitStruct(None,
                                              Padding(1),
                                              Enum(BitField("cpumode", 7),
                                                   UNKNOWN = 0,
                                                   KERNEL = 1,
                                                   USER = 2,
                                                   HYPERVISOR = 3,
                                                   GUEST_KERNEL = 4,
                                                   GUEST_USER = 5),

                                              Flag("ext_reserved"),
                                              Flag("exact_ip"),
                                              Flag("mmap_data"),
                                              Padding(5))),
                           UNInt16("size"),
                           If(has_sample_id_all,
                                 Pointer(lambda ctx: ctx.start + ctx.size - 8,
                                   UNInt64("end_id"))),
                           Value("attr", lookup_event_attr)))
*/

#[derive(Debug, Clone, Copy)]
pub struct PerfFileSection {
    offset: u64,
    size: u64
}

impl PerfFileSection {
    fn start(&self) -> usize {
        self.offset as usize
    }

    fn end(&self) -> usize {
        (self.offset + self.size) as usize
    }
}

/// Parse a file section
named!(parse_file_section<&[u8], PerfFileSection>,
    chain!(
        offset: le_u64 ~
        size: le_u64,
        || PerfFileSection { offset: offset, size: size }
    )
);

#[derive(Debug, Clone, Copy)]
pub enum HeaderFlag {
    NrCpus,
    Arch,
    Version,
    OsRelease,
    Hostname,
    BuildId,
    TracingData,
    BranchStack,
    NumaTopology,
    CpuTopology,
    EventDesc,
    CmdLine,
    TotalMem,
    CpuId,
    CpuDesc,
    GroupDesc,
    PmuMappings
}

#[derive(Debug)]
pub struct HeaderFlags {
    nrcpus: bool,
    arch: bool,
    version: bool,
    osrelease: bool,
    hostname: bool,
    build_id: bool,
    tracing_data: bool,
    branch_stack: bool,
    numa_topology: bool,
    cpu_topology: bool,
    event_desc: bool,
    cmdline: bool,
    total_mem: bool,
    cpuid: bool,
    cpudesc: bool,
    group_desc: bool,
    pmu_mappings: bool,
}

impl HeaderFlags {
    fn collect(&self) -> Vec<HeaderFlag> {
        let mut flags = Vec::with_capacity(17);

        if self.nrcpus {
            flags.push(HeaderFlag::NrCpus);
        }
        if self.arch {
            flags.push(HeaderFlag::Arch);
        }
        if self.version {
            flags.push(HeaderFlag::Version);
        }
        if self.osrelease {
            flags.push(HeaderFlag::OsRelease);
        }
        if self.hostname {
            flags.push(HeaderFlag::Hostname);
        }
        if self.build_id {
            flags.push(HeaderFlag::BuildId);
        }
        if self.tracing_data {
            flags.push(HeaderFlag::TracingData);
        }
        if self.branch_stack {
            flags.push(HeaderFlag::BranchStack);
        }
        if self.numa_topology {
            flags.push(HeaderFlag::NumaTopology);
        }
        if self.cpu_topology {
            flags.push(HeaderFlag::CpuTopology);
        }
        if self.event_desc {
            flags.push(HeaderFlag::EventDesc);
        }
        if self.cmdline {
            flags.push(HeaderFlag::CmdLine);
        }
        if self.total_mem {
            flags.push(HeaderFlag::TotalMem);
        }
        if self.cpuid {
            flags.push(HeaderFlag::CpuId);
        }
        if self.cpudesc {
            flags.push(HeaderFlag::CpuDesc);
        }
        if self.group_desc {
            flags.push(HeaderFlag::GroupDesc);
        }
        if self.pmu_mappings {
            flags.push(HeaderFlag::PmuMappings);
        }

        flags
    }
}

#[derive(Debug)]
pub struct PerfFileHeader {
    size: u64,
    attr_size: u64,
    attrs: PerfFileSection,
    data: PerfFileSection,
    event_types: PerfFileSection,

    flags: HeaderFlags,
}

/// Parse a perf header
named!(parse_header<&[u8], PerfFileHeader>,
    chain!(
        tag!("PERFILE2") ~
        size: le_u64 ~
        attr_size: le_u64 ~
        attrs: parse_file_section ~
        data: parse_file_section ~
        event_types: parse_file_section ~
        flags: bits!(chain!(
            nrcpus: take_bits!(u8, 1) ~
            arch: take_bits!(u8, 1) ~
            version: take_bits!(u8, 1) ~
            osrelease: take_bits!(u8, 1) ~
            hostname: take_bits!(u8, 1) ~
            build_id: take_bits!(u8, 1) ~
            tracing_data: take_bits!(u8, 1) ~
            reserved: take_bits!(u8, 1) ~

            branch_stack: take_bits!(u8, 1) ~
            numa_topology: take_bits!(u8, 1) ~
            cpu_topology: take_bits!(u8, 1) ~
            event_desc: take_bits!(u8, 1) ~
            cmdline: take_bits!(u8, 1) ~
            total_mem: take_bits!(u8, 1) ~
            cpuid: take_bits!(u8, 1) ~
            cpudesc: take_bits!(u8, 1) ~

            pad1: take_bits!(u8, 6) ~
            group_desc: take_bits!(u8, 1) ~
            pmu_mappings: take_bits!(u8, 1),
            || {
                HeaderFlags {
                    nrcpus: nrcpus == 1,
                    arch: arch == 1,
                    version: version == 1,
                    osrelease: osrelease == 1,
                    hostname: hostname == 1,
                    build_id: build_id == 1,
                    tracing_data: tracing_data == 1,
                    branch_stack: branch_stack == 1,
                    numa_topology: numa_topology == 1,
                    cpu_topology: cpu_topology == 1,
                    event_desc: event_desc == 1,
                    cmdline: cmdline == 1,
                    total_mem: total_mem == 1,
                    cpuid: cpuid == 1,
                    cpudesc: cpudesc == 1,
                    group_desc: group_desc == 1,
                    pmu_mappings: pmu_mappings == 1
                }
            }
        )) ~
        reserved: take!(29),
        || PerfFileHeader { size: size, attr_size: attr_size, attrs: attrs, data: data, event_types: event_types, flags: flags }
    )
);

#[derive(Debug)]
pub struct PerfFile {
    bytes: Vec<u8>,
    pub header: PerfFileHeader,
    //sections: Vec<PerfFileSection>,
}

impl PerfFile {
    pub fn new(bytes: Vec<u8>) -> PerfFile {
        let header = match parse_header(bytes.as_slice()) {
            IResult::Done(rest, h) => h,
            IResult::Error(e) => panic!("{:?}", e),
            IResult::Incomplete(_) => panic!("Incomplete data?"),
        };

        PerfFile { header: header, bytes: bytes }
    }

    pub fn data(&self) {
        let mut slice: &[u8] = &self.bytes[self.header.data.start()..self.header.data.end()];

        while slice.len() > 0 {
            let r = parse_event(slice);
            match r {
                IResult::Done(rest, ev) => {
                    println!("{:?}", ev);
                    println!("Parsed bytes: {:?}", slice.len() - rest.len());
                    println!("Event size: {:?}", ev.header.size());
                    println!("Padding: {:?}", ev.header.size() - (slice.len() - rest.len()) );
                    slice = rest.split_at( ev.header.size() - (slice.len() - rest.len()) ).1;
                },
                _ => break
            }
        }
    }

    pub fn sections(&self) -> Vec<(HeaderFlag, PerfFileSection)> {
        let sections: Vec<PerfFileSection> = self.parse_header_sections().unwrap().1;
        let flags: Vec<HeaderFlag> = self.header.flags.collect();
        assert!(sections.len() == flags.len());

        flags.into_iter().zip(sections).collect()
    }

    fn parse_header_sections(&self) -> IResult<&[u8], Vec<PerfFileSection>> {
        let sections_start: usize = (self.header.data.offset + self.header.data.size) as usize;
        let slice: &[u8] = &self.bytes[sections_start..];
        let flags: Vec<HeaderFlag> = self.header.flags.collect();

        count!(slice, parse_file_section, flags.len())
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "cargo-clippy", allow(unneeded_field_pattern))]

#[macro_use]
mod macros;
mod errors;
mod trivia;
mod strings;
mod numbers;
mod datetime;
mod array;
mod inline_table;
mod value;
mod table;
mod document;
mod key;

pub use self::errors::TomlError;

pub(crate) use self::key::key;
pub(crate) use self::value::value;

use document::Document;
use table::Table;

pub struct TomlParser {
    document: Document,
    current_table: *mut Table,
}

impl Default for TomlParser {
    fn default() -> Self {
        let mut doc = Document::new();
        let root = doc.root_mut() as *mut Table;
        Self {
            document: doc,
            current_table: root,
        }
    }
}

#[cfg(test)]
mod tests {
    use parser::*;
    use std;
    use combine::*;

    macro_rules! parsed_eq {
        ($parsed:ident, $expected:expr) => (
            {
                assert!($parsed.is_ok());
                let (v, rest) = $parsed.unwrap();
                assert_eq!(v, $expected);
                assert!(rest.input.is_empty());
            }
        );
    }

    macro_rules! parsed_float_eq {
        ($input:ident, $expected:expr) => (
            {
                let parsed = numbers::float().parse(State::new($input));
                assert!(parsed.is_ok());
                let (v, rest) = parsed.unwrap();
                assert!(($expected - v).abs() < std::f64::EPSILON);
                assert!(rest.input.is_empty());
            }
        );
    }

    macro_rules! parsed_value_eq {
        ($input:expr) => (
            let parsed = value::value().parse(State::new(*$input));
            assert!(parsed.is_ok());
            let (v, rest) = parsed.unwrap();
            assert_eq!(v.to_string(), *$input);
            assert!(rest.input.is_empty());
        );
    }

    macro_rules! parsed_date_time_eq {
        ($input:expr, $is:ident) => (
            {
                let parsed = value::value().parse(State::new(*$input));
                assert!(parsed.is_ok());
                let (v, rest) = parsed.unwrap();
                assert_eq!(v.to_string(), *$input);
                assert!(rest.input.is_empty());
                assert!(v.is_date_time());
                assert!(v.as_date_time().unwrap().$is());
            }
        );
    }

    #[test]
    fn integers() {
        let cases = [
            ("+99", 99),
            ("42", 42),
            ("0", 0),
            ("-17", -17),
            ("1_000", 1_000),
            ("5_349_221", 5_349_221),
            ("1_2_3_4_5", 1_2_3_4_5),
            (&std::i64::MIN.to_string()[..], std::i64::MIN),
            (&std::i64::MAX.to_string()[..], std::i64::MAX),
        ];
        for &(input, expected) in &cases {
            let parsed = numbers::integer().parse(State::new(input));
            parsed_eq!(parsed, expected);
        }

        let overflow = "1000000000000000000000000000000000";
        let parsed = numbers::integer().parse(State::new(overflow));
        assert!(parsed.is_err());
    }

    #[test]
    fn floats() {
        let cases = [
            ("+1.0", 1.0),
            ("3.1419", 3.1419),
            ("-0.01", -0.01),
            ("5e+22", 5e+22),
            ("1e6", 1e6),
            ("-2E-2", -2E-2),
            ("6.626e-34", 6.626e-34),
            ("9_224_617.445_991_228_313", 9_224_617.445_991_228_313),
            ("-1.7976931348623157e+308", std::f64::MIN),
            ("1.7976931348623157e+308", std::f64::MAX),
            // ("1e+400", std::f64::INFINITY),
        ];
        for &(input, expected) in &cases {
            parsed_float_eq!(input, expected);
        }
    }

    #[test]
    fn basic_string() {
        let input =
            r#""I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF. \U0002070E""#;
        let parsed = strings::string().parse(State::new(input));
        parsed_eq!(
            parsed,
            "I\'m a string. \"You can quote me\". Name\tJosé\nLocation\tSF. \u{2070E}"
        )
    }

    #[test]
    fn ml_basic_string() {
        let cases = [
            (
                r#""""
Roses are red
Violets are blue""""#,
                r#"Roses are red
Violets are blue"#,
            ),
            (r#"""" \""" """"#, " \"\"\" "),
            (r#"""" \\""""#, " \\"),
        ];

        for &(input, expected) in &cases {
            let parsed = strings::string().parse(State::new(input));
            parsed_eq!(parsed, expected);
        }

        let invalid_cases = [r#""""  """#, r#""""  \""""#];

        for input in &invalid_cases {
            let parsed = strings::ml_basic_string().parse(State::new(*input));
            assert!(parsed.is_err());
        }
    }

    #[test]
    fn ml_basic_string_escape_ws() {
        let inputs = [
            r#""""
The quick brown \

  fox jumps over \
    the lazy dog.""""#,
            r#""""\
       The quick brown \
       fox jumps over \
       the lazy dog.\
       """"#,
        ];
        for input in &inputs {
            let parsed = strings::string().parse(State::new(*input));
            parsed_eq!(parsed, "The quick brown fox jumps over the lazy dog.");
        }
        let empties = [
            r#""""\
       """"#,
            r#""""
\
  \
""""#,
        ];
        for empty in &empties {
            let parsed = strings::string().parse(State::new(*empty));
            parsed_eq!(parsed, "");
        }
    }

    #[test]
    fn literal_string() {
        let inputs = [
            r#"'C:\Users\nodejs\templates'"#,
            r#"'\\ServerX\admin$\system32\'"#,
            r#"'Tom "Dubs" Preston-Werner'"#,
            r#"'<\i\c*\s*>'"#,
        ];

        for input in &inputs {
            let parsed = strings::string().parse(State::new(*input));
            parsed_eq!(parsed, &input[1..input.len() - 1]);
        }
    }

    #[test]
    fn ml_literal_string() {
        let input = r#"'''I [dw]on't need \d{2} apples'''"#;
        let parsed = strings::string().parse(State::new(input));
        parsed_eq!(parsed, &input[3..input.len() - 3]);
        let input = r#"'''
The first newline is
trimmed in raw strings.
   All other whitespace
   is preserved.
'''"#;
        let parsed = strings::string().parse(State::new(input));
        parsed_eq!(parsed, &input[4..input.len() - 3]);
    }

    #[test]
    fn offset_date_time() {
        let inputs = [
            "1979-05-27T07:32:00Z",
            "1979-05-27T00:32:00-07:00",
            "1979-05-27T00:32:00.999999-07:00",
        ];
        for input in &inputs {
            parsed_date_time_eq!(input, is_offset_date_time);
        }
    }

    #[test]
    fn local_date_time() {
        let inputs = ["1979-05-27T07:32:00", "1979-05-27T00:32:00.999999"];
        for input in &inputs {
            parsed_date_time_eq!(input, is_local_date_time);
        }
    }

    #[test]
    fn local_date() {
        let inputs = ["1979-05-27", "2017-07-20"];
        for input in &inputs {
            parsed_date_time_eq!(input, is_local_date);
        }
    }

    #[test]
    fn local_time() {
        let inputs = ["07:32:00", "00:32:00.999999"];
        for input in &inputs {
            parsed_date_time_eq!(input, is_local_time);
        }
    }

    #[test]
    fn trivia() {
        let inputs = [
            "",
            r#" "#,
            r#"
"#,
            r#"
# comment

# comment2

"#,
            r#"
        "#,
            r#"# comment
# comment2

   "#,
        ];
        for input in &inputs {
            let parsed = trivia::ws_comment_newline().parse(State::new(*input));
            assert!(parsed.is_ok());
            let (t, rest) = parsed.unwrap();
            assert!(rest.input.is_empty());
            assert_eq!(&t, input);
        }
    }

    #[test]
    fn arrays() {
        let inputs = [
            r#"[]"#,
            r#"[   ]"#,
            r#"[
  1, 2, 3
]"#,
            r#"[
  1,
  2, # this is ok
]"#,
            r#"[# comment
# comment2

   ]"#,
            //             r#"[# comment
// # comment2
//       1

// #sd
// ,
// # comment3

//    ]"#,
            r#"[1]"#,
            r#"[1,]"#,
            r#"[ "all", 'strings', """are the same""", '''type''']"#,
            r#"[ 100, -2,]"#,
            r#"[1, 2, 3]"#,
            r#"[ [ 1, 2 ], [3, 4, 5] ]"#,
            r#"[1.1, 2.1, 3.1]"#,
            r#"["a", "b", "c"]"#,
            r#"[ [ 1, 2 ], [3, 4, 5] ]"#,
            r#"[ [ 1, 2 ], ["a", "b", "c"] ]"#,
            r#"[ { x = 1, a = "2" }, {a = "a",b = "b",     c =    "c"} ]"#,
        ];
        for input in &inputs {
            parsed_value_eq!(input);
        }

        let invalid_inputs = [r#"["#, r#"[,]"#, r#"[,2]"#, r#"[1e165,,]"#, r#"[ 1, 2.0 ]"#];
        for input in &invalid_inputs {
            let parsed = array::array().parse(State::new(*input));
            assert!(parsed.is_err());
        }
    }

    #[test]
    fn inline_tables() {
        let inputs = [
            r#"{}"#,
            r#"{   }"#,
            r#"{a = 1e165}"#,
            r#"{ hello = "world", a = 1}"#,
        ];
        for input in &inputs {
            parsed_value_eq!(input);
        }
        let invalid_inputs = [r#"{a = 1e165"#, r#"{ hello = "world", a = 2, hello = 1}"#];
        for input in &invalid_inputs {
            let parsed = inline_table::inline_table().parse(State::new(*input));
            assert!(parsed.is_err());
        }
    }

    #[test]
    fn keys() {
        let cases = [
            ("a", "a"),
            (r#""hello\n ""#, "hello\n "),
            (r#"'hello\n '"#, "hello\\n "),
        ];

        for &(input, expected) in &cases {
            let parsed = key::key().parse(State::new(input));
            assert!(parsed.is_ok());
            let ((.., k), rest) = parsed.unwrap();
            assert_eq!(k, expected);
            assert_eq!(rest.input.len(), 0);
        }
    }

    #[test]
    fn values() {
        let inputs = [
            "1979-05-27T00:32:00.999999",
            "-239",
            "1e200",
            "9_224_617.445_991_228_313",
            r#"'''I [dw]on't need \d{2} apples'''"#,
            r#"'''
The first newline is
trimmed in raw strings.
   All other whitespace
   is preserved.
'''"#,
            r#""Jos\u00E9\n""#,
            r#""\\\"\b\/\f\n\r\t\u00E9\U000A0000""#,
            r#"{ hello = "world", a = 1}"#,
            r#"[ { x = 1, a = "2" }, {a = "a",b = "b",     c =    "c"} ]"#,
        ];
        for input in &inputs {
            parsed_value_eq!(input);
        }
    }

    #[test]
    fn documents() {
        let documents = [
            r#"
# This is a TOML document.

title = "TOML Example"

    [owner]
    name = "Tom Preston-Werner"
    dob = 1979-05-27T07:32:00-08:00 # First class dates

    [database]
    server = "192.168.1.1"
    ports = [ 8001, 8001, 8002 ]
    connection_max = 5000
    enabled = true

    [servers]

    # Indentation (tabs and/or spaces) is allowed but not required
[servers.alpha]
    ip = "10.0.0.1"
    dc = "eqdc10"

    [servers.beta]
    ip = "10.0.0.2"
    dc = "eqdc10"

    [clients]
    data = [ ["gamma", "delta"], [1, 2] ]

    # Line breaks are OK when inside arrays
hosts = [
    "alpha",
    "omega"
]

   'some.wierd .stuff'   =  """
                         like
                         that
                      #   """ # this broke my sintax highlighting
   " also. like " = '''
that
'''
   double = 2e39 # this number looks familiar
# trailing comment"#,
            r#""#,
        ];
        for document in &documents {
            let doc = TomlParser::parse(document);

            assert!(doc.is_ok());
            let doc = doc.unwrap();

            assert_eq!(&doc.to_string(), document);
        }
    }
}
<commit_msg>refactor(test): remove duplicate test case<commit_after>#![cfg_attr(feature = "cargo-clippy", allow(unneeded_field_pattern))]

#[macro_use]
mod macros;
mod errors;
mod trivia;
mod strings;
mod numbers;
mod datetime;
mod array;
mod inline_table;
mod value;
mod table;
mod document;
mod key;

pub use self::errors::TomlError;

pub(crate) use self::key::key;
pub(crate) use self::value::value;

use document::Document;
use table::Table;

pub struct TomlParser {
    document: Document,
    current_table: *mut Table,
}

impl Default for TomlParser {
    fn default() -> Self {
        let mut doc = Document::new();
        let root = doc.root_mut() as *mut Table;
        Self {
            document: doc,
            current_table: root,
        }
    }
}

#[cfg(test)]
mod tests {
    use parser::*;
    use std;
    use combine::*;

    macro_rules! parsed_eq {
        ($parsed:ident, $expected:expr) => (
            {
                assert!($parsed.is_ok());
                let (v, rest) = $parsed.unwrap();
                assert_eq!(v, $expected);
                assert!(rest.input.is_empty());
            }
        );
    }

    macro_rules! parsed_float_eq {
        ($input:ident, $expected:expr) => (
            {
                let parsed = numbers::float().parse(State::new($input));
                assert!(parsed.is_ok());
                let (v, rest) = parsed.unwrap();
                assert!(($expected - v).abs() < std::f64::EPSILON);
                assert!(rest.input.is_empty());
            }
        );
    }

    macro_rules! parsed_value_eq {
        ($input:expr) => (
            let parsed = value::value().parse(State::new(*$input));
            assert!(parsed.is_ok());
            let (v, rest) = parsed.unwrap();
            assert_eq!(v.to_string(), *$input);
            assert!(rest.input.is_empty());
        );
    }

    macro_rules! parsed_date_time_eq {
        ($input:expr, $is:ident) => (
            {
                let parsed = value::value().parse(State::new(*$input));
                assert!(parsed.is_ok());
                let (v, rest) = parsed.unwrap();
                assert_eq!(v.to_string(), *$input);
                assert!(rest.input.is_empty());
                assert!(v.is_date_time());
                assert!(v.as_date_time().unwrap().$is());
            }
        );
    }

    #[test]
    fn integers() {
        let cases = [
            ("+99", 99),
            ("42", 42),
            ("0", 0),
            ("-17", -17),
            ("1_000", 1_000),
            ("5_349_221", 5_349_221),
            ("1_2_3_4_5", 1_2_3_4_5),
            (&std::i64::MIN.to_string()[..], std::i64::MIN),
            (&std::i64::MAX.to_string()[..], std::i64::MAX),
        ];
        for &(input, expected) in &cases {
            let parsed = numbers::integer().parse(State::new(input));
            parsed_eq!(parsed, expected);
        }

        let overflow = "1000000000000000000000000000000000";
        let parsed = numbers::integer().parse(State::new(overflow));
        assert!(parsed.is_err());
    }

    #[test]
    fn floats() {
        let cases = [
            ("+1.0", 1.0),
            ("3.1419", 3.1419),
            ("-0.01", -0.01),
            ("5e+22", 5e+22),
            ("1e6", 1e6),
            ("-2E-2", -2E-2),
            ("6.626e-34", 6.626e-34),
            ("9_224_617.445_991_228_313", 9_224_617.445_991_228_313),
            ("-1.7976931348623157e+308", std::f64::MIN),
            ("1.7976931348623157e+308", std::f64::MAX),
            // ("1e+400", std::f64::INFINITY),
        ];
        for &(input, expected) in &cases {
            parsed_float_eq!(input, expected);
        }
    }

    #[test]
    fn basic_string() {
        let input =
            r#""I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF. \U0002070E""#;
        let parsed = strings::string().parse(State::new(input));
        parsed_eq!(
            parsed,
            "I\'m a string. \"You can quote me\". Name\tJosé\nLocation\tSF. \u{2070E}"
        )
    }

    #[test]
    fn ml_basic_string() {
        let cases = [
            (
                r#""""
Roses are red
Violets are blue""""#,
                r#"Roses are red
Violets are blue"#,
            ),
            (r#"""" \""" """"#, " \"\"\" "),
            (r#"""" \\""""#, " \\"),
        ];

        for &(input, expected) in &cases {
            let parsed = strings::string().parse(State::new(input));
            parsed_eq!(parsed, expected);
        }

        let invalid_cases = [r#""""  """#, r#""""  \""""#];

        for input in &invalid_cases {
            let parsed = strings::ml_basic_string().parse(State::new(*input));
            assert!(parsed.is_err());
        }
    }

    #[test]
    fn ml_basic_string_escape_ws() {
        let inputs = [
            r#""""
The quick brown \

  fox jumps over \
    the lazy dog.""""#,
            r#""""\
       The quick brown \
       fox jumps over \
       the lazy dog.\
       """"#,
        ];
        for input in &inputs {
            let parsed = strings::string().parse(State::new(*input));
            parsed_eq!(parsed, "The quick brown fox jumps over the lazy dog.");
        }
        let empties = [
            r#""""\
       """"#,
            r#""""
\
  \
""""#,
        ];
        for empty in &empties {
            let parsed = strings::string().parse(State::new(*empty));
            parsed_eq!(parsed, "");
        }
    }

    #[test]
    fn literal_string() {
        let inputs = [
            r#"'C:\Users\nodejs\templates'"#,
            r#"'\\ServerX\admin$\system32\'"#,
            r#"'Tom "Dubs" Preston-Werner'"#,
            r#"'<\i\c*\s*>'"#,
        ];

        for input in &inputs {
            let parsed = strings::string().parse(State::new(*input));
            parsed_eq!(parsed, &input[1..input.len() - 1]);
        }
    }

    #[test]
    fn ml_literal_string() {
        let input = r#"'''I [dw]on't need \d{2} apples'''"#;
        let parsed = strings::string().parse(State::new(input));
        parsed_eq!(parsed, &input[3..input.len() - 3]);
        let input = r#"'''
The first newline is
trimmed in raw strings.
   All other whitespace
   is preserved.
'''"#;
        let parsed = strings::string().parse(State::new(input));
        parsed_eq!(parsed, &input[4..input.len() - 3]);
    }

    #[test]
    fn offset_date_time() {
        let inputs = [
            "1979-05-27T07:32:00Z",
            "1979-05-27T00:32:00-07:00",
            "1979-05-27T00:32:00.999999-07:00",
        ];
        for input in &inputs {
            parsed_date_time_eq!(input, is_offset_date_time);
        }
    }

    #[test]
    fn local_date_time() {
        let inputs = ["1979-05-27T07:32:00", "1979-05-27T00:32:00.999999"];
        for input in &inputs {
            parsed_date_time_eq!(input, is_local_date_time);
        }
    }

    #[test]
    fn local_date() {
        let inputs = ["1979-05-27", "2017-07-20"];
        for input in &inputs {
            parsed_date_time_eq!(input, is_local_date);
        }
    }

    #[test]
    fn local_time() {
        let inputs = ["07:32:00", "00:32:00.999999"];
        for input in &inputs {
            parsed_date_time_eq!(input, is_local_time);
        }
    }

    #[test]
    fn trivia() {
        let inputs = [
            "",
            r#" "#,
            r#"
"#,
            r#"
# comment

# comment2

"#,
            r#"
        "#,
            r#"# comment
# comment2

   "#,
        ];
        for input in &inputs {
            let parsed = trivia::ws_comment_newline().parse(State::new(*input));
            assert!(parsed.is_ok());
            let (t, rest) = parsed.unwrap();
            assert!(rest.input.is_empty());
            assert_eq!(&t, input);
        }
    }

    #[test]
    fn arrays() {
        let inputs = [
            r#"[]"#,
            r#"[   ]"#,
            r#"[
  1, 2, 3
]"#,
            r#"[
  1,
  2, # this is ok
]"#,
            r#"[# comment
# comment2

   ]"#,
            //             r#"[# comment
// # comment2
//       1

// #sd
// ,
// # comment3

//    ]"#,
            r#"[1]"#,
            r#"[1,]"#,
            r#"[ "all", 'strings', """are the same""", '''type''']"#,
            r#"[ 100, -2,]"#,
            r#"[1, 2, 3]"#,
            r#"[1.1, 2.1, 3.1]"#,
            r#"["a", "b", "c"]"#,
            r#"[ [ 1, 2 ], [3, 4, 5] ]"#,
            r#"[ [ 1, 2 ], ["a", "b", "c"] ]"#,
            r#"[ { x = 1, a = "2" }, {a = "a",b = "b",     c =    "c"} ]"#,
        ];
        for input in &inputs {
            parsed_value_eq!(input);
        }

        let invalid_inputs = [r#"["#, r#"[,]"#, r#"[,2]"#, r#"[1e165,,]"#, r#"[ 1, 2.0 ]"#];
        for input in &invalid_inputs {
            let parsed = array::array().parse(State::new(*input));
            assert!(parsed.is_err());
        }
    }

    #[test]
    fn inline_tables() {
        let inputs = [
            r#"{}"#,
            r#"{   }"#,
            r#"{a = 1e165}"#,
            r#"{ hello = "world", a = 1}"#,
        ];
        for input in &inputs {
            parsed_value_eq!(input);
        }
        let invalid_inputs = [r#"{a = 1e165"#, r#"{ hello = "world", a = 2, hello = 1}"#];
        for input in &invalid_inputs {
            let parsed = inline_table::inline_table().parse(State::new(*input));
            assert!(parsed.is_err());
        }
    }

    #[test]
    fn keys() {
        let cases = [
            ("a", "a"),
            (r#""hello\n ""#, "hello\n "),
            (r#"'hello\n '"#, "hello\\n "),
        ];

        for &(input, expected) in &cases {
            let parsed = key::key().parse(State::new(input));
            assert!(parsed.is_ok());
            let ((.., k), rest) = parsed.unwrap();
            assert_eq!(k, expected);
            assert_eq!(rest.input.len(), 0);
        }
    }

    #[test]
    fn values() {
        let inputs = [
            "1979-05-27T00:32:00.999999",
            "-239",
            "1e200",
            "9_224_617.445_991_228_313",
            r#"'''I [dw]on't need \d{2} apples'''"#,
            r#"'''
The first newline is
trimmed in raw strings.
   All other whitespace
   is preserved.
'''"#,
            r#""Jos\u00E9\n""#,
            r#""\\\"\b\/\f\n\r\t\u00E9\U000A0000""#,
            r#"{ hello = "world", a = 1}"#,
            r#"[ { x = 1, a = "2" }, {a = "a",b = "b",     c =    "c"} ]"#,
        ];
        for input in &inputs {
            parsed_value_eq!(input);
        }
    }

    #[test]
    fn documents() {
        let documents = [
            r#"
# This is a TOML document.

title = "TOML Example"

    [owner]
    name = "Tom Preston-Werner"
    dob = 1979-05-27T07:32:00-08:00 # First class dates

    [database]
    server = "192.168.1.1"
    ports = [ 8001, 8001, 8002 ]
    connection_max = 5000
    enabled = true

    [servers]

    # Indentation (tabs and/or spaces) is allowed but not required
[servers.alpha]
    ip = "10.0.0.1"
    dc = "eqdc10"

    [servers.beta]
    ip = "10.0.0.2"
    dc = "eqdc10"

    [clients]
    data = [ ["gamma", "delta"], [1, 2] ]

    # Line breaks are OK when inside arrays
hosts = [
    "alpha",
    "omega"
]

   'some.wierd .stuff'   =  """
                         like
                         that
                      #   """ # this broke my sintax highlighting
   " also. like " = '''
that
'''
   double = 2e39 # this number looks familiar
# trailing comment"#,
            r#""#,
        ];
        for document in &documents {
            let doc = TomlParser::parse(document);

            assert!(doc.is_ok());
            let doc = doc.unwrap();

            assert_eq!(&doc.to_string(), document);
        }
    }
}
<|endoftext|>


<commit_before>use rand::{distributions::Uniform, rngs::OsRng, Rng};
use sha2::{Digest, Sha256};

const TOKEN_LENGTH: usize = 32;

pub(crate) struct SecureToken {
    sha256: Vec<u8>,
}

impl SecureToken {
    pub(crate) fn generate(kind: SecureTokenKind) -> NewSecureToken {
        let plaintext = format!(
            "{}{}",
            kind.prefix(),
            generate_secure_alphanumeric_string(TOKEN_LENGTH)
        );
        let sha256 = Sha256::digest(plaintext.as_bytes()).as_slice().to_vec();

        NewSecureToken {
            plaintext,
            inner: Self { sha256 },
        }
    }

    pub(crate) fn parse(kind: SecureTokenKind, plaintext: &str) -> Option<Self> {
        // This will both reject tokens without a prefix and tokens of the wrong kind.
        if SecureTokenKind::from_token(plaintext) != Some(kind) {
            return None;
        }

        let sha256 = Sha256::digest(plaintext.as_bytes()).as_slice().to_vec();
        Some(Self { sha256 })
    }

    pub(crate) fn sha256(&self) -> &[u8] {
        &self.sha256
    }
}

pub(crate) struct NewSecureToken {
    plaintext: String,
    inner: SecureToken,
}

impl NewSecureToken {
    pub(crate) fn plaintext(&self) -> &str {
        &self.plaintext
    }
}

impl std::ops::Deref for NewSecureToken {
    type Target = SecureToken;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

fn generate_secure_alphanumeric_string(len: usize) -> String {
    const CHARS: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    OsRng
        .sample_iter(Uniform::from(0..CHARS.len()))
        .map(|idx| CHARS[idx] as char)
        .take(len)
        .collect()
}

macro_rules! secure_token_kind {
    ($(#[$attr:meta])* $vis:vis enum $name:ident { $($key:ident => $repr:expr,)* }) => {
        $(#[$attr])*
        $vis enum $name {
            $($key,)*
        }

        impl $name {
            fn from_token(token: &str) -> Option<Self> {
                $(
                    if token.starts_with($repr) {
                        return Some(Self::$key);
                    }
                )*
                None
            }

            fn prefix(&self) -> &'static str {
                match self {
                    $(
                        Self::$key => $repr,
                    )*
                }
            }
        }
    }
}

secure_token_kind! {
    /// Represents every kind of secure token generated by crates.io. When you need to generate a
    /// new kind of token you should also add its own kind with its own unique prefix.
    ///
    /// NEVER CHANGE THE PREFIX OF EXISTING TOKEN TYPES!!! Doing so will implicitly revoke all the
    /// tokens of that kind, distrupting production users.
    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
    pub(crate) enum SecureTokenKind {
        API => "cio", // Crates.IO
    }
}

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

    #[test]
    fn test_generated_and_parse() {
        const KIND: SecureTokenKind = SecureTokenKind::API;

        let token = SecureToken::generate(KIND);
        assert!(token.plaintext().starts_with(KIND.prefix()));
        assert_eq!(
            token.sha256(),
            Sha256::digest(token.plaintext().as_bytes()).as_slice()
        );

        let parsed =
            SecureToken::parse(KIND, &token.plaintext()).expect("failed to parse back the token");
        assert_eq!(parsed.sha256(), token.sha256());
    }

    #[test]
    fn test_parse_no_kind() {
        assert!(SecureToken::parse(SecureTokenKind::API, "nokind").is_none());
    }
}
<commit_msg>util: extract SecureTokenKind::from_token out of the macro<commit_after>use rand::{distributions::Uniform, rngs::OsRng, Rng};
use sha2::{Digest, Sha256};

const TOKEN_LENGTH: usize = 32;

pub(crate) struct SecureToken {
    sha256: Vec<u8>,
}

impl SecureToken {
    pub(crate) fn generate(kind: SecureTokenKind) -> NewSecureToken {
        let plaintext = format!(
            "{}{}",
            kind.prefix(),
            generate_secure_alphanumeric_string(TOKEN_LENGTH)
        );
        let sha256 = Sha256::digest(plaintext.as_bytes()).as_slice().to_vec();

        NewSecureToken {
            plaintext,
            inner: Self { sha256 },
        }
    }

    pub(crate) fn parse(kind: SecureTokenKind, plaintext: &str) -> Option<Self> {
        // This will both reject tokens without a prefix and tokens of the wrong kind.
        if SecureTokenKind::from_token(plaintext) != Some(kind) {
            return None;
        }

        let sha256 = Sha256::digest(plaintext.as_bytes()).as_slice().to_vec();
        Some(Self { sha256 })
    }

    pub(crate) fn sha256(&self) -> &[u8] {
        &self.sha256
    }
}

pub(crate) struct NewSecureToken {
    plaintext: String,
    inner: SecureToken,
}

impl NewSecureToken {
    pub(crate) fn plaintext(&self) -> &str {
        &self.plaintext
    }
}

impl std::ops::Deref for NewSecureToken {
    type Target = SecureToken;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

fn generate_secure_alphanumeric_string(len: usize) -> String {
    const CHARS: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    OsRng
        .sample_iter(Uniform::from(0..CHARS.len()))
        .map(|idx| CHARS[idx] as char)
        .take(len)
        .collect()
}

macro_rules! secure_token_kind {
    ($(#[$attr:meta])* $vis:vis enum $name:ident { $($key:ident => $repr:expr,)* }) => {
        $(#[$attr])*
        $vis enum $name {
            $($key,)*
        }

        impl $name {
            const VARIANTS: &'static [Self] = &[$(Self::$key,)*];

            fn prefix(&self) -> &'static str {
                match self {
                    $(Self::$key => $repr,)*
                }
            }
        }
    }
}

secure_token_kind! {
    /// Represents every kind of secure token generated by crates.io. When you need to generate a
    /// new kind of token you should also add its own kind with its own unique prefix.
    ///
    /// NEVER CHANGE THE PREFIX OF EXISTING TOKEN TYPES!!! Doing so will implicitly revoke all the
    /// tokens of that kind, distrupting production users.
    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
    pub(crate) enum SecureTokenKind {
        API => "cio", // Crates.IO
    }
}

impl SecureTokenKind {
    fn from_token(token: &str) -> Option<Self> {
        Self::VARIANTS
            .iter()
            .find(|v| token.starts_with(v.prefix()))
            .copied()
    }
}

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

    #[test]
    fn test_generated_and_parse() {
        const KIND: SecureTokenKind = SecureTokenKind::API;

        let token = SecureToken::generate(KIND);
        assert!(token.plaintext().starts_with(KIND.prefix()));
        assert_eq!(
            token.sha256(),
            Sha256::digest(token.plaintext().as_bytes()).as_slice()
        );

        let parsed =
            SecureToken::parse(KIND, &token.plaintext()).expect("failed to parse back the token");
        assert_eq!(parsed.sha256(), token.sha256());
    }

    #[test]
    fn test_parse_no_kind() {
        assert!(SecureToken::parse(SecureTokenKind::API, "nokind").is_none());
    }
}
<|endoftext|>


<commit_before>extern crate tiny_http;
extern crate multipart;

use multipart::server::{Multipart, Entries, SaveResult};
use tiny_http::{Response, StatusCode, Request};
fn main() {
    // Starting a server on `localhost:80`
    let server = tiny_http::Server::http("localhost:80").unwrap();
    loop {
        // This blocks until the next request is received
        let mut request = server.recv().unwrap();
        process_multipart(&mut request).unwrap();

        // Answering with an HTTP OK and a string
        let response_string = "Multipart data is received!".as_bytes();
        let response = Response::new(StatusCode(200),
                                     vec![],
                                     response_string,
                                     Some(response_string.len()),
                                     None);
        request.respond(response).unwrap();
    }
}

fn process_multipart(request: &mut Request) -> Result<(), Error> {
    // Getting a multipart reader wrapper
    let mut multipart = Multipart::from_request(request).unwrap();
    // Fetching all data and processing it
    match multipart.save_all() {
        SaveResult::Full(entries) => process_entries(entries),
        SaveResult::Partial(entries, error) => {
            try!(process_entries(entries));
            Err(error)
        }
        SaveResult::Error(error) => Err(error),
    }
}
use std::fs::File;
use std::io::{Error, Read};
fn process_entries(entries: Entries) -> Result<(), Error> {
    for (name, field) in entries.fields {
        println!(r#"Field "{}": "{}""#, name, field);
    }

    for (name, savedfile) in entries.files {
        let filename = match savedfile.filename {
            Some(s) => s,
            None => "None".into(),
        };
        let mut file = try!(File::open(savedfile.path));
        let mut contents = String::new();
        try!(file.read_to_string(&mut contents));

        println!(r#"Field "{}" is file "{}":"#, name, filename);
        println!("{}", contents);
    }
    Ok(())
}
<commit_msg>Refactored tiny_http sample<commit_after>extern crate tiny_http;
extern crate multipart;

use std::fs::File;
use std::io::{Error, Read};
use multipart::server::{Multipart, Entries, SaveResult};
use tiny_http::{Response, StatusCode, Request};
fn main() {
    // Starting a server on `localhost:80`
    let server = tiny_http::Server::http("localhost:80").expect("Could not bind localhost:80");
    loop {
        // This blocks until the next request is received
        let mut request = server.recv().unwrap();

        // Processes a request and returns response or an occured error
        let result = process_request(&mut request);
        let resp = match result {
            Ok(resp) => resp,
            Err(e) => {
                println!("An error has occured during request proccessing: {:?}", e);
                build_response(500, "The received data was not correctly proccessed on the server")
            }
        };

        // Answers with a response to a client
        request.respond(resp).unwrap();
    }
}

/// Processes a request and returns response or an occured error.
fn process_request<'a, 'b>(request: &'a mut Request) -> Result<Response<&'b [u8]>, Error> {
    // Getting a multipart reader wrapper
    match Multipart::from_request(request) {
        Ok(mut multipart) => {
            // Fetching all data and processing it.
            // save_all() reads the request fully, parsing all fields and saving all files
            // in a new temporary directory under the OS temporary directory.
            match multipart.save_all() {
                SaveResult::Full(entries) => process_entries(entries),
                SaveResult::Partial(entries, error) => {
                    try!(process_entries(entries));
                    Err(error)
                }
                SaveResult::Error(error) => Err(error),
            }
        }
        Err(_) => Ok(build_response(400, "The request is not multipart")),
    }
}

/// Processes saved entries from multipart request.
/// Returns an OK response or an error.
fn process_entries<'a>(entries: Entries) -> Result<Response<&'a [u8]>, Error> {
    for (name, field) in entries.fields {
        println!(r#"Field "{}": "{}""#, name, field);
    }

    for (name, savedfile) in entries.files {
        let filename = match savedfile.filename {
            Some(s) => s,
            None => "None".into(),
        };
        let mut file = try!(File::open(savedfile.path));
        let mut contents = String::new();
        try!(file.read_to_string(&mut contents));

        println!(r#"Field "{}" is file "{}":"#, name, filename);
        println!("{}", contents);
    }
    Ok(build_response(200, "Multipart data is received!".into()))
}

/// A utility function to build responses using only two arguments
fn build_response(status_code: u16, response: &str) -> Response<&[u8]> {
    let bytes = response.as_bytes();
    Response::new(StatusCode(status_code),
                  vec![],
                  bytes,
                  Some(bytes.len()),
                  None)
}
<|endoftext|>


<commit_before>extern crate may;
extern crate mimalloc;
extern crate num_cpus;
#[macro_use]
extern crate serde_derive;
extern crate may_minihttp;
extern crate serde_json;

use may_minihttp::{HttpServer, HttpService, Request, Response};
use std::io;

use mimalloc::MiMalloc;

#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;

#[derive(Serialize)]
struct Message<'a> {
    message: &'a str,
}

struct Techempower;

impl HttpService for Techempower {
    fn call(&self, req: Request) -> io::Result<Response> {
        let mut resp = Response::new();

        // Bare-bones router
        match req.path() {
            "/plaintext" => {
                resp.header("Content-Type", "text/plain")
                    .body("Hello, World!");
            }
            "/json" => {
                resp.header("Content-Type", "application/json");
                serde_json::to_writer(
                    resp.body_mut(),
                    &Message {
                        message: "Hello, World!",
                    },
                )
                .unwrap();
            }
            _ => {
                resp.status_code("404", "Not Found");
            }
        }

        Ok(resp)
    }
}

fn main() {
    may::config()
        .set_io_workers(num_cpus::get())
        .set_pool_capacity(20000)
        .set_stack_size(0x800);

    let mut servers = Vec::new();
    for _ in 0..num_cpus::get() {
        let server = HttpServer(Techempower).start("0.0.0.0:8080").unwrap();
        servers.push(server);
    }

    for server in servers {
        server.join().unwrap();
    }
}
<commit_msg>may_minihttp reserve enough buf for json serialize (#4920)<commit_after>extern crate may;
extern crate mimalloc;
extern crate num_cpus;
#[macro_use]
extern crate serde_derive;
extern crate may_minihttp;
extern crate serde_json;

use may_minihttp::{BodyWriter, HttpServer, HttpService, Request, Response};
use std::io;

use mimalloc::MiMalloc;

#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;

#[derive(Serialize)]
struct Message<'a> {
    message: &'a str,
}

struct Techempower;

impl HttpService for Techempower {
    fn call(&self, req: Request) -> io::Result<Response> {
        let mut resp = Response::new();

        // Bare-bones router
        match req.path() {
            "/plaintext" => {
                resp.header("Content-Type", "text/plain")
                    .body("Hello, World!");
            }
            "/json" => {
                resp.header("Content-Type", "application/json");
                let body = resp.body_mut();
                body.reserve(27);
                serde_json::to_writer(
                    BodyWriter(body),
                    &Message {
                        message: "Hello, World!",
                    },
                )
                .unwrap();
            }
            _ => {
                resp.status_code("404", "Not Found");
            }
        }

        Ok(resp)
    }
}

fn main() {
    may::config()
        .set_io_workers(num_cpus::get())
        .set_pool_capacity(20000)
        .set_stack_size(0x800);

    let mut servers = Vec::new();
    for _ in 0..num_cpus::get() {
        let server = HttpServer(Techempower).start("0.0.0.0:8080").unwrap();
        servers.push(server);
    }

    for server in servers {
        server.join().unwrap();
    }
}
<|endoftext|>