<commit_before>//! This module provides two utility macros for testing custom derives. They can
//! be used together to eliminate some of the boilerplate required in order to
//! declare and test custom derive implementations.

// Re-exports used by the decl_derive! and test_derive!
pub use syn::{parse_str, parse, DeriveInput};
pub use proc_macro::TokenStream as TokenStream;
pub use proc_macro2::TokenStream as TokenStream2;

/// The `decl_derive!` macro declares a custom derive wrapper. It will parse the
/// incoming `TokenStream` into a `synstructure::Structure` object, and pass it
/// into the inner function.
///
/// Your inner function should have the following type:
///
/// ```
/// # extern crate quote;
/// # extern crate proc_macro2;
/// # extern crate synstructure;
/// fn derive(input: synstructure::Structure) -> proc_macro2::TokenStream {
///     unimplemented!()
/// }
/// ```
///
/// # Usage
///
/// ### Without Attributes
/// ```
/// # #[macro_use] extern crate quote;
/// # extern crate proc_macro2;
/// # extern crate synstructure;
/// # fn main() {}
/// fn derive_interesting(_input: synstructure::Structure) -> proc_macro2::TokenStream {
///     quote! { ... }
/// }
///
/// # const _IGNORE: &'static str = stringify! {
/// decl_derive!([Interesting] => derive_interesting);
/// # };
/// ```
///
/// ### With Attributes
/// ```
/// # #[macro_use] extern crate quote;
/// # extern crate proc_macro2;
/// # extern crate synstructure;
/// # fn main() {}
/// fn derive_interesting(_input: synstructure::Structure) -> proc_macro2::TokenStream {
///     quote! { ... }
/// }
///
/// # const _IGNORE: &'static str = stringify! {
/// decl_derive!([Interesting, attributes(interesting_ignore)] => derive_interesting);
/// # };
/// ```
#[macro_export]
macro_rules! decl_derive {
    // XXX: Switch to using this variant everywhere?
    ([$derives:ident $($derive_t:tt)*] => $inner:path) => {
        #[proc_macro_derive($derives $($derive_t)*)]
        #[allow(non_snake_case)]
        pub fn $derives(
            i: $crate::macros::TokenStream
        ) -> $crate::macros::TokenStream
        {
            let parsed = $crate::macros::parse::<$crate::macros::DeriveInput>(i)
                .expect(concat!("Failed to parse input to `#[derive(",
                                stringify!($derives),
                                ")]`"));
            $inner($crate::Structure::new(&parsed)).into()
        }
    };
}

/// Run a test on a custom derive. This macro expands both the original struct
/// and the expansion to ensure that they compile correctly, and confirms that
/// feeding the original struct into the named derive will produce the written
/// output.
///
/// You can add `no_build` to the end of the macro invocation to disable
/// checking that the written code compiles. This is useful in contexts where
/// the procedural macro cannot depend on the crate where it is used during
/// tests.
///
/// # Usage
///
/// ```
/// # #[macro_use] extern crate quote;
/// # extern crate proc_macro2;
/// # #[macro_use] extern crate synstructure;
/// fn test_derive_example(_s: synstructure::Structure) -> proc_macro2::TokenStream {
///     quote! { const YOUR_OUTPUT: &'static str = "here"; }
/// }
///
/// fn main() {
///     test_derive!{
///         test_derive_example {
///             struct A;
///         }
///         expands to {
///             const YOUR_OUTPUT: &'static str = "here";
///         }
///     }
/// }
/// ```
#[macro_export]
macro_rules! test_derive {
    ($name:path { $($i:tt)* } expands to { $($o:tt)* }) => {
        {
            #[allow(dead_code)]
            fn ensure_compiles() {
                $($i)*
                $($o)*
            }

            test_derive!($name { $($i)* } expands to { $($o)* } no_build);
        }
    };

    ($name:path { $($i:tt)* } expands to { $($o:tt)* } no_build) => {
        {
            let i = stringify!( $($i)* );
            let parsed = $crate::macros::parse_str::<$crate::macros::DeriveInput>(i)
                .expect(concat!("Failed to parse input to `#[derive(",
                                stringify!($name),
                                ")]`"));

            let res = $name($crate::Structure::new(&parsed));
            let expected = stringify!( $($o)* )
                .parse::<$crate::macros::TokenStream2>()
                .expect("output should be a valid TokenStream");
            let mut expected_toks = $crate::macros::TokenStream2::from(expected);
            if res.to_string() != expected_toks.to_string() {
                panic!("\
test_derive failed:
expected:
```
{}
```

got:
```
{}
```\n",
                    $crate::unpretty_print(&expected_toks),
                    $crate::unpretty_print(&res),
                );
            }
            // assert_eq!(res, expected_toks)
        }
    };
}

/// A helper macro for declaring relatively straightforward derive
/// implementations. It provides mechanisms for operating over structures
/// performing modifications on each field etc.
///
/// This macro doesn't define the actual derive, but rather the implementation
/// method. Use `decl_derive!` to generate the implementation wrapper.
///
/// # Stability Warning
///
/// This is an unstable experimental macro API, which may be changed or removed
/// in a future version. I'm not yet confident enough that this API is useful
/// enough to warrant its complexity and inclusion in `synstructure`.
///
/// # Caveat
///
/// The `quote!` macro from `quote` must be imported in the calling crate, as
/// this macro depends on it.
///
/// # Note
///
/// This feature is implemented behind the `simple-derive` feature, and is only
/// avaliable when that feature is enabled.
///
/// # Example
///
/// ```
/// extern crate syn;
/// #[macro_use]
/// extern crate quote;
/// #[macro_use]
/// extern crate synstructure;
/// extern crate proc_macro2;
/// # const _IGNORE: &'static str = stringify! {
/// decl_derive!([Interest] => derive_interest);
/// # };
///
/// simple_derive! {
///     // This macro implements the `Interesting` method exported by the `aa`
///     // crate. It will explicitly add an `extern crate` invocation to import the
///     // crate into the expanded context.
///     derive_interest impl synstructure_test_traits::Interest {
///         // A "filter" block can be added. It evaluates its body with the (s)
///         // variable bound to a mutable reference to the input `Structure`
///         // object.
///         //
///         // This block can be used to perform general transformations, such as
///         // filtering out fields which should be ignored by all methods and for
///         // the purposes of binding type parameters.
///         filter(s) {
///             s.filter(|bi| bi.ast().ident != Some(syn::Ident::new("a",
///                 proc_macro2::Span::call_site())));
///         }
///
///         // This is an implementation of a method in the implemented crate. The
///         // return value should be the series of match patterns to destructure
///         // the `self` argument with.
///         fn interesting(&self as s) -> bool {
///             s.fold(false, |acc, bi| {
///                 quote!(#acc || synstructure_test_traits::Interest::interesting(#bi))
///             })
///         }
///     }
/// }
///
/// fn main() {
///     test_derive!{
///         derive_interest {
///             struct A<T> {
///                 x: i32,
///                 a: bool, // Will be ignored by filter
///                 c: T,
///             }
///         }
///         expands to {
///             #[allow(non_upper_case_globals)]
///             const _DERIVE_synstructure_test_traits_Interest_FOR_A: () = {
///                 extern crate synstructure_test_traits;
///                 impl<T> synstructure_test_traits::Interest for A<T>
///                     where T: synstructure_test_traits::Interest
///                 {
///                     fn interesting(&self) -> bool {
///                         match *self {
///                             A {
///                                 x: ref __binding_0,
///                                 c: ref __binding_2,
///                                 ..
///                             } => {
///                                 false ||
///                                     synstructure_test_traits::Interest::interesting(__binding_0) ||
///                                     synstructure_test_traits::Interest::interesting(__binding_2)
///                             }
///                         }
///                     }
///                 }
///             };
///         }
///     }
/// }
/// ```
#[cfg(feature = "simple-derive")]
#[macro_export]
macro_rules! simple_derive {
    // entry point
    (
        $iname:ident impl $path:path { $($rest:tt)* }
    ) => {
        simple_derive!(__I [$iname, $path] { $($rest)* } [] []);
    };

    // Adding a filter block
    (
        __I $opt:tt {
            filter($s:ident) {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            __I $opt { $($rest)* } [$($done)*] [
                $($filter)*
                [
                    st_name = $s,
                    body = {
                        $($body)*
                    },
                ]
            ]
        );
    };

    // &self bound method
    (
        __I $opt:tt {
            fn $fn_name:ident (&self as $s:ident $($params:tt)*) $(-> $t:ty)* {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            __I $opt { $($rest)* } [
                $($done)*
                [
                    st_name = $s,
                    bind_style = Ref,
                    body = { $($body)* },
                    result = result,
                    expanded = {
                        fn $fn_name(&self $($params)*) $(-> $t)* {
                            match *self { #result }
                        }
                    },
                ]
            ] [$($filter)*]
        );
    };

    // &mut self bound method
    (
        __I $opt:tt {
            fn $fn_name:ident (&mut self as $s:ident $($params:tt)*) $(-> $t:ty)* {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            __I $opt { $($rest)* } [
                $($done)*
                [
                    st_name = $s,
                    bind_style = RefMut,
                    body = { $($body)* },
                    result = result,
                    expanded = {
                        fn $fn_name(&mut self $($params)*) $(-> $t)* {
                            match *self { #result }
                        }
                    },
                ]
            ] [$($filter)*]
        );
    };

    // self bound method
    (
        __I $opt:tt {
            fn $fn_name:ident (self as $s:ident $($params:tt)*) $(-> $t:ty)* {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            __I $opt { $($rest)* } [
                $($done)*
                [
                    st_name = $s,
                    bind_style = Move,
                    body = { $($body)* },
                    result = result,
                    expanded = {
                        fn $fn_name(self $($params)*) $(-> $t)* {
                            match self { #result }
                        }
                    },
                ]
            ] [$($filter)*]
        );
    };

    // XXX: Static methods?

    // codegen after data collection
    (
        __I [$iname:ident, $path:path] {} [$(
            [
                st_name = $st_name:ident,
                bind_style = $bind_style:ident,
                body = $body:tt,
                result = $result:ident,
                expanded = { $($expanded:tt)* },
            ]
        )*] [$(
            [
                st_name = $filter_st_name:ident,
                body = $filter_body:tt,
            ]
        )*]
    ) => {
        fn $iname(mut st: $crate::Structure) -> $crate::macros::TokenStream2 {
            let _ = &mut st; // Silence the unused mut warning

            // Filter/transform the `Structure` object before cloning it for
            // individual methods.
            $(
                {
                    let $filter_st_name = &mut st;
                    $filter_body
                }
            )*

            // Clone the `Structure` object and set the correct binding style,
            // then perform method specific expansion.
            $(
                let $result = {
                    let mut $st_name = st.clone();
                    $st_name.bind_with(|_| ::synstructure::BindStyle::$bind_style);
                    let $result = {
                        $body
                    };
                    quote!{ $($expanded)* }
                };
            )*

            st.bound_impl(quote!($path), quote!{
                $(#$result)*
            })
        }
    }
}
<commit_msg>Fix typo ('avaliable', misplaced 'i')<commit_after>//! This module provides two utility macros for testing custom derives. They can
//! be used together to eliminate some of the boilerplate required in order to
//! declare and test custom derive implementations.

// Re-exports used by the decl_derive! and test_derive!
pub use syn::{parse_str, parse, DeriveInput};
pub use proc_macro::TokenStream as TokenStream;
pub use proc_macro2::TokenStream as TokenStream2;

/// The `decl_derive!` macro declares a custom derive wrapper. It will parse the
/// incoming `TokenStream` into a `synstructure::Structure` object, and pass it
/// into the inner function.
///
/// Your inner function should have the following type:
///
/// ```
/// # extern crate quote;
/// # extern crate proc_macro2;
/// # extern crate synstructure;
/// fn derive(input: synstructure::Structure) -> proc_macro2::TokenStream {
///     unimplemented!()
/// }
/// ```
///
/// # Usage
///
/// ### Without Attributes
/// ```
/// # #[macro_use] extern crate quote;
/// # extern crate proc_macro2;
/// # extern crate synstructure;
/// # fn main() {}
/// fn derive_interesting(_input: synstructure::Structure) -> proc_macro2::TokenStream {
///     quote! { ... }
/// }
///
/// # const _IGNORE: &'static str = stringify! {
/// decl_derive!([Interesting] => derive_interesting);
/// # };
/// ```
///
/// ### With Attributes
/// ```
/// # #[macro_use] extern crate quote;
/// # extern crate proc_macro2;
/// # extern crate synstructure;
/// # fn main() {}
/// fn derive_interesting(_input: synstructure::Structure) -> proc_macro2::TokenStream {
///     quote! { ... }
/// }
///
/// # const _IGNORE: &'static str = stringify! {
/// decl_derive!([Interesting, attributes(interesting_ignore)] => derive_interesting);
/// # };
/// ```
#[macro_export]
macro_rules! decl_derive {
    // XXX: Switch to using this variant everywhere?
    ([$derives:ident $($derive_t:tt)*] => $inner:path) => {
        #[proc_macro_derive($derives $($derive_t)*)]
        #[allow(non_snake_case)]
        pub fn $derives(
            i: $crate::macros::TokenStream
        ) -> $crate::macros::TokenStream
        {
            let parsed = $crate::macros::parse::<$crate::macros::DeriveInput>(i)
                .expect(concat!("Failed to parse input to `#[derive(",
                                stringify!($derives),
                                ")]`"));
            $inner($crate::Structure::new(&parsed)).into()
        }
    };
}

/// Run a test on a custom derive. This macro expands both the original struct
/// and the expansion to ensure that they compile correctly, and confirms that
/// feeding the original struct into the named derive will produce the written
/// output.
///
/// You can add `no_build` to the end of the macro invocation to disable
/// checking that the written code compiles. This is useful in contexts where
/// the procedural macro cannot depend on the crate where it is used during
/// tests.
///
/// # Usage
///
/// ```
/// # #[macro_use] extern crate quote;
/// # extern crate proc_macro2;
/// # #[macro_use] extern crate synstructure;
/// fn test_derive_example(_s: synstructure::Structure) -> proc_macro2::TokenStream {
///     quote! { const YOUR_OUTPUT: &'static str = "here"; }
/// }
///
/// fn main() {
///     test_derive!{
///         test_derive_example {
///             struct A;
///         }
///         expands to {
///             const YOUR_OUTPUT: &'static str = "here";
///         }
///     }
/// }
/// ```
#[macro_export]
macro_rules! test_derive {
    ($name:path { $($i:tt)* } expands to { $($o:tt)* }) => {
        {
            #[allow(dead_code)]
            fn ensure_compiles() {
                $($i)*
                $($o)*
            }

            test_derive!($name { $($i)* } expands to { $($o)* } no_build);
        }
    };

    ($name:path { $($i:tt)* } expands to { $($o:tt)* } no_build) => {
        {
            let i = stringify!( $($i)* );
            let parsed = $crate::macros::parse_str::<$crate::macros::DeriveInput>(i)
                .expect(concat!("Failed to parse input to `#[derive(",
                                stringify!($name),
                                ")]`"));

            let res = $name($crate::Structure::new(&parsed));
            let expected = stringify!( $($o)* )
                .parse::<$crate::macros::TokenStream2>()
                .expect("output should be a valid TokenStream");
            let mut expected_toks = $crate::macros::TokenStream2::from(expected);
            if res.to_string() != expected_toks.to_string() {
                panic!("\
test_derive failed:
expected:
```
{}
```

got:
```
{}
```\n",
                    $crate::unpretty_print(&expected_toks),
                    $crate::unpretty_print(&res),
                );
            }
            // assert_eq!(res, expected_toks)
        }
    };
}

/// A helper macro for declaring relatively straightforward derive
/// implementations. It provides mechanisms for operating over structures
/// performing modifications on each field etc.
///
/// This macro doesn't define the actual derive, but rather the implementation
/// method. Use `decl_derive!` to generate the implementation wrapper.
///
/// # Stability Warning
///
/// This is an unstable experimental macro API, which may be changed or removed
/// in a future version. I'm not yet confident enough that this API is useful
/// enough to warrant its complexity and inclusion in `synstructure`.
///
/// # Caveat
///
/// The `quote!` macro from `quote` must be imported in the calling crate, as
/// this macro depends on it.
///
/// # Note
///
/// This feature is implemented behind the `simple-derive` feature, and is only
/// available when that feature is enabled.
///
/// # Example
///
/// ```
/// extern crate syn;
/// #[macro_use]
/// extern crate quote;
/// #[macro_use]
/// extern crate synstructure;
/// extern crate proc_macro2;
/// # const _IGNORE: &'static str = stringify! {
/// decl_derive!([Interest] => derive_interest);
/// # };
///
/// simple_derive! {
///     // This macro implements the `Interesting` method exported by the `aa`
///     // crate. It will explicitly add an `extern crate` invocation to import the
///     // crate into the expanded context.
///     derive_interest impl synstructure_test_traits::Interest {
///         // A "filter" block can be added. It evaluates its body with the (s)
///         // variable bound to a mutable reference to the input `Structure`
///         // object.
///         //
///         // This block can be used to perform general transformations, such as
///         // filtering out fields which should be ignored by all methods and for
///         // the purposes of binding type parameters.
///         filter(s) {
///             s.filter(|bi| bi.ast().ident != Some(syn::Ident::new("a",
///                 proc_macro2::Span::call_site())));
///         }
///
///         // This is an implementation of a method in the implemented crate. The
///         // return value should be the series of match patterns to destructure
///         // the `self` argument with.
///         fn interesting(&self as s) -> bool {
///             s.fold(false, |acc, bi| {
///                 quote!(#acc || synstructure_test_traits::Interest::interesting(#bi))
///             })
///         }
///     }
/// }
///
/// fn main() {
///     test_derive!{
///         derive_interest {
///             struct A<T> {
///                 x: i32,
///                 a: bool, // Will be ignored by filter
///                 c: T,
///             }
///         }
///         expands to {
///             #[allow(non_upper_case_globals)]
///             const _DERIVE_synstructure_test_traits_Interest_FOR_A: () = {
///                 extern crate synstructure_test_traits;
///                 impl<T> synstructure_test_traits::Interest for A<T>
///                     where T: synstructure_test_traits::Interest
///                 {
///                     fn interesting(&self) -> bool {
///                         match *self {
///                             A {
///                                 x: ref __binding_0,
///                                 c: ref __binding_2,
///                                 ..
///                             } => {
///                                 false ||
///                                     synstructure_test_traits::Interest::interesting(__binding_0) ||
///                                     synstructure_test_traits::Interest::interesting(__binding_2)
///                             }
///                         }
///                     }
///                 }
///             };
///         }
///     }
/// }
/// ```
#[cfg(feature = "simple-derive")]
#[macro_export]
macro_rules! simple_derive {
    // entry point
    (
        $iname:ident impl $path:path { $($rest:tt)* }
    ) => {
        simple_derive!(__I [$iname, $path] { $($rest)* } [] []);
    };

    // Adding a filter block
    (
        __I $opt:tt {
            filter($s:ident) {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            __I $opt { $($rest)* } [$($done)*] [
                $($filter)*
                [
                    st_name = $s,
                    body = {
                        $($body)*
                    },
                ]
            ]
        );
    };

    // &self bound method
    (
        __I $opt:tt {
            fn $fn_name:ident (&self as $s:ident $($params:tt)*) $(-> $t:ty)* {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            __I $opt { $($rest)* } [
                $($done)*
                [
                    st_name = $s,
                    bind_style = Ref,
                    body = { $($body)* },
                    result = result,
                    expanded = {
                        fn $fn_name(&self $($params)*) $(-> $t)* {
                            match *self { #result }
                        }
                    },
                ]
            ] [$($filter)*]
        );
    };

    // &mut self bound method
    (
        __I $opt:tt {
            fn $fn_name:ident (&mut self as $s:ident $($params:tt)*) $(-> $t:ty)* {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            __I $opt { $($rest)* } [
                $($done)*
                [
                    st_name = $s,
                    bind_style = RefMut,
                    body = { $($body)* },
                    result = result,
                    expanded = {
                        fn $fn_name(&mut self $($params)*) $(-> $t)* {
                            match *self { #result }
                        }
                    },
                ]
            ] [$($filter)*]
        );
    };

    // self bound method
    (
        __I $opt:tt {
            fn $fn_name:ident (self as $s:ident $($params:tt)*) $(-> $t:ty)* {
                $($body:tt)*
            }
            $($rest:tt)*
        } [$($done:tt)*] [$($filter:tt)*]
    ) => {
        simple_derive!(
            __I $opt { $($rest)* } [
                $($done)*
                [
                    st_name = $s,
                    bind_style = Move,
                    body = { $($body)* },
                    result = result,
                    expanded = {
                        fn $fn_name(self $($params)*) $(-> $t)* {
                            match self { #result }
                        }
                    },
                ]
            ] [$($filter)*]
        );
    };

    // XXX: Static methods?

    // codegen after data collection
    (
        __I [$iname:ident, $path:path] {} [$(
            [
                st_name = $st_name:ident,
                bind_style = $bind_style:ident,
                body = $body:tt,
                result = $result:ident,
                expanded = { $($expanded:tt)* },
            ]
        )*] [$(
            [
                st_name = $filter_st_name:ident,
                body = $filter_body:tt,
            ]
        )*]
    ) => {
        fn $iname(mut st: $crate::Structure) -> $crate::macros::TokenStream2 {
            let _ = &mut st; // Silence the unused mut warning

            // Filter/transform the `Structure` object before cloning it for
            // individual methods.
            $(
                {
                    let $filter_st_name = &mut st;
                    $filter_body
                }
            )*

            // Clone the `Structure` object and set the correct binding style,
            // then perform method specific expansion.
            $(
                let $result = {
                    let mut $st_name = st.clone();
                    $st_name.bind_with(|_| ::synstructure::BindStyle::$bind_style);
                    let $result = {
                        $body
                    };
                    quote!{ $($expanded)* }
                };
            )*

            st.bound_impl(quote!($path), quote!{
                $(#$result)*
            })
        }
    }
}
<|endoftext|>


<commit_before>use crate::{Dummy, Faker};
use rand::distributions::{Distribution, Uniform};
use rand::Rng;
use std::ops;

macro_rules! faker_impl {
    ($typ:ty) => {
        impl Dummy<$typ> for $typ {
            fn dummy(t: &$typ) -> Self {
                t.clone()
            }

            fn dummy_with_rng<R: Rng + ?Sized>(t: &$typ, _rng: &mut R) -> Self {
                t.clone()
            }
        }

        impl Dummy<Faker> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(_: &Faker, rng: &mut R) -> Self {
                rng.gen()
            }
        }
    };
}

macro_rules! range_impl {
    ($typ:ident) => {
        impl Dummy<ops::Range<Self>> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(range: &ops::Range<Self>, rng: &mut R) -> Self {
                rng.gen_range(range.start, range.end)
            }
        }

        impl Dummy<ops::RangeFrom<Self>> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(range: &ops::RangeFrom<Self>, rng: &mut R) -> Self {
                let u = Uniform::new_inclusive(range.start, std::$typ::MAX);
                u.sample(rng)
            }
        }

        impl Dummy<ops::RangeFull> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(_: &ops::RangeFull, rng: &mut R) -> Self {
                let u = Uniform::new_inclusive(std::$typ::MIN, std::$typ::MAX);
                u.sample(rng)
            }
        }

        impl Dummy<ops::RangeInclusive<Self>> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(
                range: &ops::RangeInclusive<Self>,
                rng: &mut R,
            ) -> Self {
                let u = Uniform::new_inclusive(range.start(), range.end());
                u.sample(rng)
            }
        }

        impl Dummy<ops::RangeTo<Self>> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(range: &ops::RangeTo<Self>, rng: &mut R) -> Self {
                rng.gen_range(std::$typ::MIN, range.end)
            }
        }

        impl Dummy<ops::RangeToInclusive<Self>> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(
                range: &ops::RangeToInclusive<Self>,
                rng: &mut R,
            ) -> Self {
                let u = Uniform::new_inclusive(std::$typ::MIN, range.end);
                u.sample(rng)
            }
        }
    };
}

macro_rules! number_impl {
    ($typ:ident) => {
        impl Dummy<Uniform<Self>> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(dist: &Uniform<Self>, rng: &mut R) -> Self {
                dist.sample(rng)
            }
        }
    };
}

macro_rules! integer_impl {
    ($typ:ident) => {
        faker_impl!($typ);
        number_impl!($typ);
        range_impl!($typ);
    };
}

macro_rules! float_impl {
    ($typ:ident) => {
        faker_impl!($typ);
        number_impl!($typ);
        range_impl!($typ);
    };
}

faker_impl!(());
faker_impl!(bool);
faker_impl!(char);

integer_impl!(u8);
integer_impl!(u16);
integer_impl!(u32);
integer_impl!(u64);
integer_impl!(u128);
integer_impl!(usize);

integer_impl!(i8);
integer_impl!(i16);
integer_impl!(i32);
integer_impl!(i64);
integer_impl!(i128);
integer_impl!(isize);

float_impl!(f32);
float_impl!(f64);
<commit_msg>Allow crate to work on emscripten<commit_after>use crate::{Dummy, Faker};
use rand::distributions::{Distribution, Uniform};
use rand::Rng;
use std::ops;

macro_rules! faker_impl {
    ($typ:ty) => {
        impl Dummy<$typ> for $typ {
            fn dummy(t: &$typ) -> Self {
                t.clone()
            }

            fn dummy_with_rng<R: Rng + ?Sized>(t: &$typ, _rng: &mut R) -> Self {
                t.clone()
            }
        }

        impl Dummy<Faker> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(_: &Faker, rng: &mut R) -> Self {
                rng.gen()
            }
        }
    };
}

macro_rules! range_impl {
    ($typ:ident) => {
        impl Dummy<ops::Range<Self>> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(range: &ops::Range<Self>, rng: &mut R) -> Self {
                rng.gen_range(range.start, range.end)
            }
        }

        impl Dummy<ops::RangeFrom<Self>> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(range: &ops::RangeFrom<Self>, rng: &mut R) -> Self {
                let u = Uniform::new_inclusive(range.start, std::$typ::MAX);
                u.sample(rng)
            }
        }

        impl Dummy<ops::RangeFull> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(_: &ops::RangeFull, rng: &mut R) -> Self {
                let u = Uniform::new_inclusive(std::$typ::MIN, std::$typ::MAX);
                u.sample(rng)
            }
        }

        impl Dummy<ops::RangeInclusive<Self>> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(
                range: &ops::RangeInclusive<Self>,
                rng: &mut R,
            ) -> Self {
                let u = Uniform::new_inclusive(range.start(), range.end());
                u.sample(rng)
            }
        }

        impl Dummy<ops::RangeTo<Self>> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(range: &ops::RangeTo<Self>, rng: &mut R) -> Self {
                rng.gen_range(std::$typ::MIN, range.end)
            }
        }

        impl Dummy<ops::RangeToInclusive<Self>> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(
                range: &ops::RangeToInclusive<Self>,
                rng: &mut R,
            ) -> Self {
                let u = Uniform::new_inclusive(std::$typ::MIN, range.end);
                u.sample(rng)
            }
        }
    };
}

macro_rules! number_impl {
    ($typ:ident) => {
        impl Dummy<Uniform<Self>> for $typ {
            fn dummy_with_rng<R: Rng + ?Sized>(dist: &Uniform<Self>, rng: &mut R) -> Self {
                dist.sample(rng)
            }
        }
    };
}

macro_rules! integer_impl {
    ($typ:ident) => {
        faker_impl!($typ);
        number_impl!($typ);
        range_impl!($typ);
    };
}

macro_rules! float_impl {
    ($typ:ident) => {
        faker_impl!($typ);
        number_impl!($typ);
        range_impl!($typ);
    };
}

faker_impl!(());
faker_impl!(bool);
faker_impl!(char);

integer_impl!(u8);
integer_impl!(u16);
integer_impl!(u32);
integer_impl!(u64);
#[cfg(not(target_os = "emscripten"))]
integer_impl!(u128);
integer_impl!(usize);

integer_impl!(i8);
integer_impl!(i16);
integer_impl!(i32);
integer_impl!(i64);
#[cfg(not(target_os = "emscripten"))]
integer_impl!(i128);
integer_impl!(isize);

float_impl!(f32);
float_impl!(f64);
<|endoftext|>


<commit_before>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::slice;

use ::Result;
use ::Error;

use octets;
use crypto;
use rand;
use stream;

const FORM_BIT: u8 = 0x80;
const KEY_PHASE_BIT: u8 = 0x40;
const DEMUX_BIT: u8 = 0x08;

const TYPE_MASK: u8 = 0x7f;

const MAX_CID_LEN: u8 = 18;

#[derive(PartialEq, Copy, Clone, Debug)]
pub enum Type {
    Initial,
    Retry,
    Handshake,
    ZeroRTT,
    VersionNegotiation,
    Application,
}

pub fn has_long_header(b: u8) -> bool {
    b & FORM_BIT != 0
}

#[derive(Clone, Debug)]
pub struct Header {
    pub ty: Type,
    pub version: u32,
    pub flags: u8,
    pub dcid: Vec<u8>,
    pub scid: Vec<u8>,
    pub token: Option<Vec<u8>>,
}

impl Header {
    pub fn decode_long(buf: &mut [u8]) -> Result<Header> {
        let mut b = octets::Bytes::new(buf);
        Header::long_from_bytes(&mut b)
    }

    pub fn decode_short(buf: &mut [u8], dcil: usize) -> Result<Header> {
        let mut b = octets::Bytes::new(buf);
        Header::short_from_bytes(&mut b, dcil)
    }

    pub fn long_from_bytes(b: &mut octets::Bytes) -> Result<Header> {
        let first = b.get_u8()?;

        if !has_long_header(first) {
            return Err(Error::WrongForm);
        }

        let version = b.get_u32()?;

        let ty = if version == 0 {
            Type::VersionNegotiation
        } else {
            match first & TYPE_MASK {
                0x7f => Type::Initial,
                0x7e => Type::Retry,
                0x7d => Type::Handshake,
                0x7c => Type::ZeroRTT,
                _    => return Err(Error::UnknownPacket),
            }
        };

        let (dcil, scil) = match b.get_u8() {
            Ok(v) => {
                let mut dcil = v >> 4;
                let mut scil = v & 0xf;

                if dcil > MAX_CID_LEN || scil > MAX_CID_LEN {
                    return Err(Error::InvalidPacket);
                }

                if dcil > 0 {
                    dcil += 3;
                }

                if scil > 0 {
                    scil += 3;
                }

                (dcil, scil)
            },

            Err(_) => return Err(Error::BufferTooShort),
        };

        let dcid = b.get_bytes(dcil as usize)?.to_vec();
        let scid = b.get_bytes(scil as usize)?.to_vec();

        // End of invariants.

        let mut token: Option<Vec<u8>> = None;

        match ty {
            Type::Initial => {
                token = Some(b.get_bytes_with_varint_length()?.to_vec());
            },

            Type::Retry => {
                panic!("Retry not supported");
            },

            Type::VersionNegotiation => {
                panic!("Retry not supported");
            },

            _ => (),
        };

        Ok(Header {
            ty,
            flags: first & FORM_BIT,
            version,
            dcid,
            scid,
            token,
        })
    }

    pub fn long_to_bytes(hdr: &Header, out: &mut octets::Bytes) -> Result<()> {
        let ty: u8 = match hdr.ty {
                Type::Initial   => 0x7f,
                Type::Retry     => 0x7e,
                Type::Handshake => 0x7d,
                Type::ZeroRTT   => 0x7c,
                // TODO: unify handling of version negotiation
                _               => return Err(Error::UnknownPacket),
        };

        let first = FORM_BIT | ty;

        out.put_u8(first)?;

        out.put_u32(hdr.version)?;

        let mut cil: u8 = 0;

        if hdr.dcid.len() > 0 {
            cil |= ((hdr.dcid.len() - 3) as u8) << 4;
        }

        if hdr.scid.len() > 0 {
            cil |= ((hdr.scid.len() - 3) as u8) & 0xf;
        }

        out.put_u8(cil)?;

        out.put_bytes(&hdr.dcid)?;
        out.put_bytes(&hdr.scid)?;

        // Only Initial packet have a token.
        if hdr.ty == Type::Initial {
            match hdr.token {
                Some(ref v) => {
                    out.put_bytes(v)?;
                },

                None => {
                    // No token, so lemgth = 0.
                    out.put_varint(0)?;
                }
            }
        }

        Ok(())
    }

    pub fn short_from_bytes(b: &mut octets::Bytes, dcil: usize) -> Result<Header> {
        let first = b.get_u8()?;

        if has_long_header(first) {
            return Err(Error::WrongForm);
        }

        let dcid = b.get_bytes(dcil)?;

        Ok(Header {
            ty: Type::Application,
            flags: first & FORM_BIT,
            version: 0,
            dcid: dcid.to_vec(),
            scid: Vec::new(),
            token: None,
        })
    }

    pub fn short_to_bytes(hdr: &Header, out: &mut octets::Bytes) -> Result<()> {
        let mut first = rand::rand_u8();

        // Unset form bit for short header.
        first &= !FORM_BIT;

        // TODO: support key update
        first &= !KEY_PHASE_BIT;

        // "The third bit (0x20) of octet 0 is set to 1."
        first |= 0x20;

        // "The fourth bit (0x10) of octet 0 is set to 1."
        first |= 0x10;

        // Clear Google QUIC demultiplexing bit
        first &= !DEMUX_BIT;

        out.put_u8(first)?;
        out.put_bytes(&hdr.dcid)?;

        Ok(())
    }
}

pub fn pkt_num_len(pn: u64) -> Result<usize> {
    let len = if pn < 128 {
        1
    } else if pn < 16384 {
        2
    } else if pn < 1_073_741_824 {
        4
    } else {
        return Err(Error::InvalidPacket);
    };

    Ok(len)
}

pub fn decrypt_pkt_num(b: &mut octets::Bytes, aead: &crypto::Open)
                                                    -> Result<(u64,usize)> {
    let max_pn_len = if b.cap() < aead.nonce_len() + 4 + 4 {
        b.cap() - aead.nonce_len() - 4
    } else {
        4
    };

    let mut pn_and_sample = b.peek_bytes(max_pn_len + aead.nonce_len() + 4)?;

    let (mut ciphertext, sample) = pn_and_sample.split_at(max_pn_len).unwrap();

    let ciphertext = ciphertext.as_mut();

    // Decrypt first byte of pkt num into separate buffer to get length.
    let mut first: u8 = ciphertext[0];

    aead.xor_keystream(sample.as_ref(), slice::from_mut(&mut first))?;

    let len = if first >> 7 == 0 {
        1
    } else {
        // Map most significant 2 bits to actual pkt num length.
        match first >> 6 {
            2 => 2,
            3 => 4,
            _ => return Err(Error::InvalidPacket),
        }
    };

    // Decrypt full pkt num in-place.
    aead.xor_keystream(sample.as_ref(), &mut ciphertext[..len])?;

    let mut plaintext = Vec::with_capacity(len);
    plaintext.extend_from_slice(&ciphertext[..len]);

    // Mask the 2 most significant bits to remove the encoded length.
    if len > 1 {
        plaintext[0] &= 0x3f;
    }

    let mut b = octets::Bytes::new(&mut plaintext);

    // Extract packet number corresponding to the decoded length.
    let out = match len {
        1 => u64::from(b.get_u8()?),
        2 => u64::from(b.get_u16()?),
        4 => u64::from(b.get_u32()?),
        _ => return Err(Error::InvalidPacket),
    };

    // TODO: implement packet number truncation
    Ok((out as u64, len))
}

pub fn encode_pkt_num(pn: u64, b: &mut octets::Bytes) -> Result<()> {
    let len = pkt_num_len(pn)?;

    match len {
        1 => {
            let mut buf = b.put_u8(pn as u8)?;
            buf[0] &= !0x80;
        },

        2 => {
            let mut buf = b.put_u16(pn as u16)?;
            buf[0] &= !0xc0;
            buf[0] |= 0x80;
        },

        4 => {
            let mut buf = b.put_u32(pn as u32)?;
            buf[0] |= 0xc0;
        },

        _ => return Err(Error::InvalidPacket),
    };

    Ok(())
}

pub fn decrypt_pkt(payload: &mut [u8], pn: u64, ad: &[u8], aead: &crypto::Open)
                                                            -> Result<usize> {
    aead.open_with_u64_counter(pn, ad, payload)
}

pub fn encrypt_pkt(payload: &mut [u8], pn: u64, ad: &[u8], aead: &crypto::Seal)
                                                            -> Result<usize> {
    aead.seal_with_u64_counter(pn, ad, payload)
}

pub fn negotiate_version(hdr: &Header, out: &mut [u8]) -> Result<usize> {
    let mut b = octets::Bytes::new(out);

    let first = rand::rand_u8() | FORM_BIT;

    b.put_u8(first)?;
    b.put_u32(0)?;

    // Invert client's scid and dcid.
    let mut cil: u8 = 0;
    if hdr.scid.len() > 0 {
        cil |= ((hdr.scid.len() - 3) as u8) << 4;
    }

    if hdr.dcid.len() > 0 {
        cil |= ((hdr.dcid.len() - 3) as u8) & 0xf;
    }

    b.put_u8(cil)?;
    b.put_bytes(&hdr.scid)?;
    b.put_bytes(&hdr.dcid)?;
    b.put_u32(::VERSION_DRAFT15)?;

    Ok(b.off())
}

pub struct PktNumSpace {
    pub pkt_type: Type,

    pub expected_pkt_num: u64,

    pub last_pkt_num: u64,

    pub need_ack: Vec<u64>,

    pub crypto_level: crypto::Level,

    pub crypto_open: Option<crypto::Open>,
    pub crypto_seal: Option<crypto::Seal>,

    pub crypto_stream: stream::Stream,
}

impl PktNumSpace {
    pub fn new(ty: Type, crypto_level: crypto::Level) -> PktNumSpace {
        PktNumSpace {
            pkt_type: ty,

            expected_pkt_num: 0,

            last_pkt_num: 0,

            need_ack: Vec::new(),

            crypto_level,

            crypto_open: None,
            crypto_seal: None,

            crypto_stream: stream::Stream::new(),
        }
    }

    pub fn overhead(&self) -> usize {
        self.crypto_seal.as_ref().unwrap().tag_len()
    }
}

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

    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn decrypt_initial() {
        decrypt_initial_helper("test_data/initial_ngtcp2.txt");
        decrypt_initial_helper("test_data/initial_quicly.txt");
    }

    fn decrypt_initial_helper(file_name: &'static str) {
        let mut file = File::open(file_name).unwrap();

        let mut buf = Vec::new();
        file.read_to_end(&mut buf).unwrap();

        let mut b = octets::Bytes::new(&mut buf);

        let hdr = Header::long_from_bytes(&mut b).unwrap();

        let payload_len = b.get_varint().unwrap() as usize;

        let (aead_open, _) =
            crypto::derive_initial_key_material(&hdr.dcid, true).unwrap();

        let (pn, pn_len) = decrypt_pkt_num(&mut b, &aead_open).unwrap();
        b.skip(pn_len).unwrap();

        let payload_offset = b.off();

        let (header, mut payload) = b.split_at(payload_offset).unwrap();

        decrypt_pkt(payload.slice(payload_len - pn_len).unwrap(),
                    pn, header.as_ref(), &aead_open).unwrap();
    }
}
<commit_msg>packet: implement custom Debug for Header<commit_after>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::fmt;
use std::slice;

use ::Result;
use ::Error;

use octets;
use crypto;
use rand;
use stream;

const FORM_BIT: u8 = 0x80;
const KEY_PHASE_BIT: u8 = 0x40;
const DEMUX_BIT: u8 = 0x08;

const TYPE_MASK: u8 = 0x7f;

const MAX_CID_LEN: u8 = 18;

#[derive(PartialEq, Copy, Clone, Debug)]
pub enum Type {
    Initial,
    Retry,
    Handshake,
    ZeroRTT,
    VersionNegotiation,
    Application,
}

pub fn has_long_header(b: u8) -> bool {
    b & FORM_BIT != 0
}

#[derive(Clone)]
pub struct Header {
    pub ty: Type,
    pub version: u32,
    pub flags: u8,
    pub dcid: Vec<u8>,
    pub scid: Vec<u8>,
    pub token: Option<Vec<u8>>,
}

impl Header {
    pub fn decode_long(buf: &mut [u8]) -> Result<Header> {
        let mut b = octets::Bytes::new(buf);
        Header::long_from_bytes(&mut b)
    }

    pub fn decode_short(buf: &mut [u8], dcil: usize) -> Result<Header> {
        let mut b = octets::Bytes::new(buf);
        Header::short_from_bytes(&mut b, dcil)
    }

    pub fn long_from_bytes(b: &mut octets::Bytes) -> Result<Header> {
        let first = b.get_u8()?;

        if !has_long_header(first) {
            return Err(Error::WrongForm);
        }

        let version = b.get_u32()?;

        let ty = if version == 0 {
            Type::VersionNegotiation
        } else {
            match first & TYPE_MASK {
                0x7f => Type::Initial,
                0x7e => Type::Retry,
                0x7d => Type::Handshake,
                0x7c => Type::ZeroRTT,
                _    => return Err(Error::UnknownPacket),
            }
        };

        let (dcil, scil) = match b.get_u8() {
            Ok(v) => {
                let mut dcil = v >> 4;
                let mut scil = v & 0xf;

                if dcil > MAX_CID_LEN || scil > MAX_CID_LEN {
                    return Err(Error::InvalidPacket);
                }

                if dcil > 0 {
                    dcil += 3;
                }

                if scil > 0 {
                    scil += 3;
                }

                (dcil, scil)
            },

            Err(_) => return Err(Error::BufferTooShort),
        };

        let dcid = b.get_bytes(dcil as usize)?.to_vec();
        let scid = b.get_bytes(scil as usize)?.to_vec();

        // End of invariants.

        let mut token: Option<Vec<u8>> = None;

        match ty {
            Type::Initial => {
                token = Some(b.get_bytes_with_varint_length()?.to_vec());
            },

            Type::Retry => {
                panic!("Retry not supported");
            },

            Type::VersionNegotiation => {
                panic!("Retry not supported");
            },

            _ => (),
        };

        Ok(Header {
            ty,
            flags: first & FORM_BIT,
            version,
            dcid,
            scid,
            token,
        })
    }

    pub fn long_to_bytes(hdr: &Header, out: &mut octets::Bytes) -> Result<()> {
        let ty: u8 = match hdr.ty {
                Type::Initial   => 0x7f,
                Type::Retry     => 0x7e,
                Type::Handshake => 0x7d,
                Type::ZeroRTT   => 0x7c,
                // TODO: unify handling of version negotiation
                _               => return Err(Error::UnknownPacket),
        };

        let first = FORM_BIT | ty;

        out.put_u8(first)?;

        out.put_u32(hdr.version)?;

        let mut cil: u8 = 0;

        if hdr.dcid.len() > 0 {
            cil |= ((hdr.dcid.len() - 3) as u8) << 4;
        }

        if hdr.scid.len() > 0 {
            cil |= ((hdr.scid.len() - 3) as u8) & 0xf;
        }

        out.put_u8(cil)?;

        out.put_bytes(&hdr.dcid)?;
        out.put_bytes(&hdr.scid)?;

        // Only Initial packet have a token.
        if hdr.ty == Type::Initial {
            match hdr.token {
                Some(ref v) => {
                    out.put_bytes(v)?;
                },

                None => {
                    // No token, so lemgth = 0.
                    out.put_varint(0)?;
                }
            }
        }

        Ok(())
    }

    pub fn short_from_bytes(b: &mut octets::Bytes, dcil: usize) -> Result<Header> {
        let first = b.get_u8()?;

        if has_long_header(first) {
            return Err(Error::WrongForm);
        }

        let dcid = b.get_bytes(dcil)?;

        Ok(Header {
            ty: Type::Application,
            flags: first & FORM_BIT,
            version: 0,
            dcid: dcid.to_vec(),
            scid: Vec::new(),
            token: None,
        })
    }

    pub fn short_to_bytes(hdr: &Header, out: &mut octets::Bytes) -> Result<()> {
        let mut first = rand::rand_u8();

        // Unset form bit for short header.
        first &= !FORM_BIT;

        // TODO: support key update
        first &= !KEY_PHASE_BIT;

        // "The third bit (0x20) of octet 0 is set to 1."
        first |= 0x20;

        // "The fourth bit (0x10) of octet 0 is set to 1."
        first |= 0x10;

        // Clear Google QUIC demultiplexing bit
        first &= !DEMUX_BIT;

        out.put_u8(first)?;
        out.put_bytes(&hdr.dcid)?;

        Ok(())
    }
}

impl fmt::Debug for Header {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.ty);

        if self.ty != Type::Application {
            write!(f, " vers={:x}", self.version);
        }

        let vec: Vec<String> = self.dcid.iter()
                                        .map(|b| format!("{:02x}", b))
                                        .collect();

        write!(f, " dcid={}", vec.join(""));

        if self.ty != Type::Application {
            let vec: Vec<String> = self.scid.iter()
                                            .map(|b| format!("{:02x}", b))
                                            .collect();

            write!(f, " scid={}", vec.join(""));
        }

        Ok(())
    }
}

pub fn pkt_num_len(pn: u64) -> Result<usize> {
    let len = if pn < 128 {
        1
    } else if pn < 16384 {
        2
    } else if pn < 1_073_741_824 {
        4
    } else {
        return Err(Error::InvalidPacket);
    };

    Ok(len)
}

pub fn decrypt_pkt_num(b: &mut octets::Bytes, aead: &crypto::Open)
                                                    -> Result<(u64,usize)> {
    let max_pn_len = if b.cap() < aead.nonce_len() + 4 + 4 {
        b.cap() - aead.nonce_len() - 4
    } else {
        4
    };

    let mut pn_and_sample = b.peek_bytes(max_pn_len + aead.nonce_len() + 4)?;

    let (mut ciphertext, sample) = pn_and_sample.split_at(max_pn_len).unwrap();

    let ciphertext = ciphertext.as_mut();

    // Decrypt first byte of pkt num into separate buffer to get length.
    let mut first: u8 = ciphertext[0];

    aead.xor_keystream(sample.as_ref(), slice::from_mut(&mut first))?;

    let len = if first >> 7 == 0 {
        1
    } else {
        // Map most significant 2 bits to actual pkt num length.
        match first >> 6 {
            2 => 2,
            3 => 4,
            _ => return Err(Error::InvalidPacket),
        }
    };

    // Decrypt full pkt num in-place.
    aead.xor_keystream(sample.as_ref(), &mut ciphertext[..len])?;

    let mut plaintext = Vec::with_capacity(len);
    plaintext.extend_from_slice(&ciphertext[..len]);

    // Mask the 2 most significant bits to remove the encoded length.
    if len > 1 {
        plaintext[0] &= 0x3f;
    }

    let mut b = octets::Bytes::new(&mut plaintext);

    // Extract packet number corresponding to the decoded length.
    let out = match len {
        1 => u64::from(b.get_u8()?),
        2 => u64::from(b.get_u16()?),
        4 => u64::from(b.get_u32()?),
        _ => return Err(Error::InvalidPacket),
    };

    // TODO: implement packet number truncation
    Ok((out as u64, len))
}

pub fn encode_pkt_num(pn: u64, b: &mut octets::Bytes) -> Result<()> {
    let len = pkt_num_len(pn)?;

    match len {
        1 => {
            let mut buf = b.put_u8(pn as u8)?;
            buf[0] &= !0x80;
        },

        2 => {
            let mut buf = b.put_u16(pn as u16)?;
            buf[0] &= !0xc0;
            buf[0] |= 0x80;
        },

        4 => {
            let mut buf = b.put_u32(pn as u32)?;
            buf[0] |= 0xc0;
        },

        _ => return Err(Error::InvalidPacket),
    };

    Ok(())
}

pub fn decrypt_pkt(payload: &mut [u8], pn: u64, ad: &[u8], aead: &crypto::Open)
                                                            -> Result<usize> {
    aead.open_with_u64_counter(pn, ad, payload)
}

pub fn encrypt_pkt(payload: &mut [u8], pn: u64, ad: &[u8], aead: &crypto::Seal)
                                                            -> Result<usize> {
    aead.seal_with_u64_counter(pn, ad, payload)
}

pub fn negotiate_version(hdr: &Header, out: &mut [u8]) -> Result<usize> {
    let mut b = octets::Bytes::new(out);

    let first = rand::rand_u8() | FORM_BIT;

    b.put_u8(first)?;
    b.put_u32(0)?;

    // Invert client's scid and dcid.
    let mut cil: u8 = 0;
    if hdr.scid.len() > 0 {
        cil |= ((hdr.scid.len() - 3) as u8) << 4;
    }

    if hdr.dcid.len() > 0 {
        cil |= ((hdr.dcid.len() - 3) as u8) & 0xf;
    }

    b.put_u8(cil)?;
    b.put_bytes(&hdr.scid)?;
    b.put_bytes(&hdr.dcid)?;
    b.put_u32(::VERSION_DRAFT15)?;

    Ok(b.off())
}

pub struct PktNumSpace {
    pub pkt_type: Type,

    pub expected_pkt_num: u64,

    pub last_pkt_num: u64,

    pub need_ack: Vec<u64>,

    pub crypto_level: crypto::Level,

    pub crypto_open: Option<crypto::Open>,
    pub crypto_seal: Option<crypto::Seal>,

    pub crypto_stream: stream::Stream,
}

impl PktNumSpace {
    pub fn new(ty: Type, crypto_level: crypto::Level) -> PktNumSpace {
        PktNumSpace {
            pkt_type: ty,

            expected_pkt_num: 0,

            last_pkt_num: 0,

            need_ack: Vec::new(),

            crypto_level,

            crypto_open: None,
            crypto_seal: None,

            crypto_stream: stream::Stream::new(),
        }
    }

    pub fn overhead(&self) -> usize {
        self.crypto_seal.as_ref().unwrap().tag_len()
    }
}

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

    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn decrypt_initial() {
        decrypt_initial_helper("test_data/initial_ngtcp2.txt");
        decrypt_initial_helper("test_data/initial_quicly.txt");
    }

    fn decrypt_initial_helper(file_name: &'static str) {
        let mut file = File::open(file_name).unwrap();

        let mut buf = Vec::new();
        file.read_to_end(&mut buf).unwrap();

        let mut b = octets::Bytes::new(&mut buf);

        let hdr = Header::long_from_bytes(&mut b).unwrap();

        let payload_len = b.get_varint().unwrap() as usize;

        let (aead_open, _) =
            crypto::derive_initial_key_material(&hdr.dcid, true).unwrap();

        let (pn, pn_len) = decrypt_pkt_num(&mut b, &aead_open).unwrap();
        b.skip(pn_len).unwrap();

        let payload_offset = b.off();

        let (header, mut payload) = b.split_at(payload_offset).unwrap();

        decrypt_pkt(payload.slice(payload_len - pn_len).unwrap(),
                    pn, header.as_ref(), &aead_open).unwrap();
    }
}
<|endoftext|>


<commit_before>#![plugin(peg_syntax_ext)]

use std::collections::HashMap;

peg_file! gremlin("gremlin.rustpeg");

pub fn parse(g: &str) -> Result<ParsedGraphQuery, gremlin::ParseError> {
    let parsed = pre_parse(g);
    // verify all the steps actually make sense
    // is it a query to a single vertex or a global query?
    parsed
}

pub fn pre_parse(g: &str) -> Result<ParsedGraphQuery, gremlin::ParseError> {
    gremlin::query(g)
}

/*
returned from the peg parser
we'll need to take each of the steps
and use them to construct an actual GraphQuery
*/
pub struct ParsedGraphQuery {
    pub steps: Vec<RawStep>
}

/*
scope of the query.  determines if we're looking at the
entire graph or just from a handful of vertices
*/
pub enum Scope {
    Global,
    Vertex(Vec<i64>),
}

/*
generic step used in ParsedGraphQuery
will be turned into specific steps
*/
pub struct RawStep {
    pub name: String,
    pub args: Vec<Arg>,
}

#[derive(Debug, Display)]
pub enum Arg {
    Integer(i64),
    Float(f64),
    String(String),
}

impl RawStep {
    pub fn new(name: String, args: Vec<Arg>) -> RawStep {
        RawStep{name:name, args:args}
    }
}

struct GraphQueryResult;

impl ParsedGraphQuery {
    fn execute(&self) -> Result<GraphQueryResult, &str> {
        // get the starting point(s)

        // for now lets just put this hash table here

        let mut steps_table = HashMap::new();
        steps_table.insert("outV", traverse_out);
        steps_table.insert("inV", traverse_out);

        // i'm tempted to say global graph traversals must include a
        // starting point, g.v(predicate)

        // execute each of the steps sequentially
        for step in self.steps.iter() {
            // lookup step in hash table
            // execute function, passing step args
        }
        Result::Err("meh")
    }
}

fn traverse_out() {

}

fn traverse_in() {

}
<commit_msg>returning a result from traversals<commit_after>#![plugin(peg_syntax_ext)]

use std::collections::HashMap;

peg_file! gremlin("gremlin.rustpeg");

pub fn parse(g: &str) -> Result<ParsedGraphQuery, gremlin::ParseError> {
    let parsed = pre_parse(g);
    // verify all the steps actually make sense
    // is it a query to a single vertex or a global query?
    parsed
}

pub fn pre_parse(g: &str) -> Result<ParsedGraphQuery, gremlin::ParseError> {
    gremlin::query(g)
}

/*
returned from the peg parser
we'll need to take each of the steps
and use them to construct an actual GraphQuery
*/
pub struct ParsedGraphQuery {
    pub steps: Vec<RawStep>
}

/*
scope of the query.  determines if we're looking at the
entire graph or just from a handful of vertices
*/
pub enum Scope {
    Global,
    Vertex(Vec<i64>),
}

/*
generic step used in ParsedGraphQuery
will be turned into specific steps
*/
pub struct RawStep {
    pub name: String,
    pub args: Vec<Arg>,
}

#[derive(Debug, Display)]
pub enum Arg {
    Integer(i64),
    Float(f64),
    String(String),
}

impl RawStep {
    pub fn new(name: String, args: Vec<Arg>) -> RawStep {
        RawStep{name:name, args:args}
    }
}

struct GraphQueryResult;

impl ParsedGraphQuery {
    fn execute(&self) -> Result<GraphQueryResult, &str> {
        // get the starting point(s)

        // for now lets just put this hash table here

        let mut steps_table = HashMap::new();
        steps_table.insert("outV", traverse_out);
        steps_table.insert("inV", traverse_out);

        // i'm tempted to say global graph traversals must include a
        // starting point, g.v(predicate)

        // execute each of the steps sequentially
        for step in self.steps.iter() {
            // lookup step in hash table

            // execute function, passing step args
        }
        Result::Err("meh")
    }
}

fn traverse_out() -> Result<&'static str, &'static str>  {
    Ok("cool")
}

fn traverse_in() -> Result<&'static str, &'static str>  {
    Ok("cool")

}
<|endoftext|>


<commit_before>use regex::Regex;

#[deriving(Show)]
pub enum Block<'s> {
    Header(Vec<Span<'s>>, uint),
    Break,
    Paragraph(Vec<Span<'s>>)
}

#[deriving(Show)]
pub enum Span<'s> {
    Text(&'s str),
    Emphasis(&'s str),
    Strong(&'s str),
    Code(&'s str),
    Link(&'s str, &'s str, &'s str),
    Image(&'s str, &'s str, &'s str)
}

// Block Patters
static SPLIT           : Regex = regex!(r"\n\n");
static ATX_HEADER      : Regex = regex!(r"(?P<level>#{1,6})\s(?P<text>.*)");
static SETEXT_HEADER_1 : Regex = regex!(r"(?P<text>.+)\n===+");
static SETEXT_HEADER_2 : Regex = regex!(r"(?P<text>.+)\n---+");
static BREAK           : Regex = regex!(r"  ");

// Span Patters
static SPANS : Regex = regex!(r"(!?\[.*\]\([^\(\)]*\))|(\*[^\*].+?\*)|(\*\*.+?\*\*)|(_[^_].+?_)|(__.+?__)|(`[^`].+?`)|(``.+?``)");
static LINK  : Regex = regex!(r"\[(?P<text>.*)\]\((?P<url>.*?)(?:\s(?P<title>.*?))?\)");
static EMPHASIS_UNDERSCORE  : Regex = regex!(r"^_(?P<text>[^_].+?)_");
static EMPHASIS_STAR  : Regex = regex!(r"^\*(?P<text>[^\*].+?)\*");

pub fn parse (md : &str) -> Vec<Block> {
    let mut split = SPLIT.split(md);
    let mut tokens = vec![];
    for block in split{
        match parse_block(block) {
            Some(e) => tokens.push(e),
            None => {},
        };
    }
    tokens
}

fn parse_spans(text : &str) -> Vec<Span>{
    let mut tokens = vec![];
    let mut current = 0;
    for (begin, end) in SPANS.find_iter(text) {
        tokens.push(Text(text.slice(current, begin)));
        tokens.push(parse_span(text.slice(begin, end)));
        current = end;
    }
    tokens.push(Text(text.slice(current, text.len())));
    tokens
}

fn parse_span(text : &str) -> Span{
    if LINK.is_match(text){
        let caps = LINK.captures(text).unwrap();
        return Link(
            caps.name("text"),
            caps.name("url"),
            caps.name("title")
            );
    }else if EMPHASIS_UNDERSCORE.is_match(text){
        let caps = EMPHASIS_UNDERSCORE.captures(text).unwrap();
        return Emphasis(caps.name("text"));
    }else if EMPHASIS_STAR.is_match(text){
        let caps = EMPHASIS_STAR.captures(text).unwrap();
        return Emphasis(caps.name("text"));
    }
    return Text(text);
}

fn parse_block (text : &str) -> Option<Block>{
    if text.is_empty(){
        return None;
    }else if ATX_HEADER.is_match(text){
        let caps = ATX_HEADER.captures(text).unwrap();
        return Some(
            Header(
                parse_spans(caps.name("text")),
                caps.name("level").len()
                )
            );
    }else if SETEXT_HEADER_1.is_match(text){
        let caps = SETEXT_HEADER_1.captures(text).unwrap();
        return Some(
            Header(
                parse_spans(caps.name("text")),
                1
                )
            );
    }else if SETEXT_HEADER_2.is_match(text){
        let caps = SETEXT_HEADER_2.captures(text).unwrap();
        return Some(
            Header(
                parse_spans(caps.name("text")),
                2
                )
            );
    }else if BREAK.is_match(text){
        return Some(Break);
    }
    return Some(Paragraph(parse_spans(text)));
}

<commit_msg>start testing<commit_after>use regex::Regex;

#[deriving(Show)]
pub enum Block<'s> {
    Header(Vec<Span<'s>>, uint),
    Break,
    Paragraph(Vec<Span<'s>>)
}

#[deriving(Show)]
pub enum Span<'s> {
    Text(&'s str),
    Emphasis(&'s str),
    Strong(&'s str),
    Code(&'s str),
    Link(&'s str, &'s str, &'s str),
    Image(&'s str, &'s str, &'s str)
}

// Block Patters
static SPLIT           : Regex = regex!(r"\n\n");
static ATX_HEADER      : Regex = regex!(r"(?P<level>#{1,6})\s(?P<text>.*)");
static SETEXT_HEADER_1 : Regex = regex!(r"(?P<text>.+)\n===+");
static SETEXT_HEADER_2 : Regex = regex!(r"(?P<text>.+)\n---+");
static BREAK           : Regex = regex!(r"  ");

// Span Patters
static SPANS : Regex = regex!(r"(!?\[.*\]\([^\(\)]*\))|(\*[^\*].+?\*)|(\*\*.+?\*\*)|(_[^_].+?_)|(__.+?__)|(`[^`].+?`)|(``.+?``)");
static LINK  : Regex = regex!(r"\[(?P<text>.*)\]\((?P<url>.*?)(?:\s(?P<title>.*?))?\)");
static EMPHASIS_UNDERSCORE  : Regex = regex!(r"^_(?P<text>[^_].+?)_");
static EMPHASIS_STAR  : Regex = regex!(r"^\*(?P<text>[^\*].+?)\*");

pub fn parse (md : &str) -> Vec<Block> {
    let mut split = SPLIT.split(md);
    let mut tokens = vec![];
    for block in split{
        match parse_block(block) {
            Some(e) => tokens.push(e),
            None => {},
        };
    }
    tokens
}

fn parse_spans(text : &str) -> Vec<Span>{
    let mut tokens = vec![];
    let mut current = 0;
    for (begin, end) in SPANS.find_iter(text) {
        tokens.push(Text(text.slice(current, begin)));
        tokens.push(parse_span(text.slice(begin, end)));
        current = end;
    }
    tokens.push(Text(text.slice(current, text.len())));
    tokens
}

#[test]
fn parse_link_test() {
    match parse_span("[an example](example.com \"Title\")"){
      Link("an example", "example.com", "Title") => {},
      _ => fail!()
    }
}

fn parse_span(text : &str) -> Span{
    if LINK.is_match(text){
        let caps = LINK.captures(text).unwrap();
        return Link(
            caps.name("text"),
            caps.name("url"),
            caps.name("title")
            );
    }else if EMPHASIS_UNDERSCORE.is_match(text){
        let caps = EMPHASIS_UNDERSCORE.captures(text).unwrap();
        return Emphasis(caps.name("text"));
    }else if EMPHASIS_STAR.is_match(text){
        let caps = EMPHASIS_STAR.captures(text).unwrap();
        return Emphasis(caps.name("text"));
    }
    return Text(text);
}

fn parse_block (text : &str) -> Option<Block>{
    if text.is_empty(){
        return None;
    }else if ATX_HEADER.is_match(text){
        let caps = ATX_HEADER.captures(text).unwrap();
        return Some(
            Header(
                parse_spans(caps.name("text")),
                caps.name("level").len()
                )
            );
    }else if SETEXT_HEADER_1.is_match(text){
        let caps = SETEXT_HEADER_1.captures(text).unwrap();
        return Some(
            Header(
                parse_spans(caps.name("text")),
                1
                )
            );
    }else if SETEXT_HEADER_2.is_match(text){
        let caps = SETEXT_HEADER_2.captures(text).unwrap();
        return Some(
            Header(
                parse_spans(caps.name("text")),
                2
                )
            );
    }else if BREAK.is_match(text){
        return Some(Break);
    }
    return Some(Paragraph(parse_spans(text)));
}

<|endoftext|>


<commit_before>//! frust query parser
//!
//! # Talkin' Syntax
//! For now the precendence of 'and' and 'or' is not implemented, nor are brackets supported.
//! This meens that if you want (f1 and f2) or f3, you have to express it as f3 or f1 and f2.
//! I know this is limitting and I'm going to improve this in the future...

use std::string::String;
use filter;
use filter_tree;
use query;

named!(komma, ws!(tag!(",")));
named!(comp_op<filter::CompOp>, alt!(
          tag!("<")  => { |_| filter::CompOp::Lower }
        | tag!("<=") => { |_| filter::CompOp::LowerEqual }
        | tag!("==") => { |_| filter::CompOp::Equal }
        | tag!("not =") => { |_| filter::CompOp::Unequal }
        | tag!("!=") => { |_| filter::CompOp::Unequal }
        | tag!(">=") => { |_| filter::CompOp::GreaterEqual }
        | tag!(">")  => { |_| filter::CompOp::Greater }
        | tag!("~")  => { |_| filter::CompOp::Like }
        | tag!("not ~")  => { |_| filter::CompOp::Unlike }
        )
    );

named!(logic_op<filter_tree::LogicOp>,
       alt!(
        ws!(tag!("or")) =>  { |_| filter_tree::LogicOp::Or }
        |
        ws!(tag!("and")) => { |_| filter_tree::LogicOp::And }
        )
);

named!(from_keyword, ws!(tag!("from")));
named!(where_keyword, ws!(tag!("where")));
named!(exec_keyword, ws!(tag!("exec")));
named!(attribute<filter::Attribute>,
       do_parse!(
           tag: ws!(alt!(
                      tag!("name")     => { |_| filter::Attribute::Name }
                    | tag!("size")     => { |_| filter::Attribute::Size }
                    | tag!("mtime")    => { |_| filter::Attribute::Mtime }
                    | tag!("ctime")    => { |_| filter::Attribute::Ctime }
                    | tag!("atime")    => { |_| filter::Attribute::Atime }
                    | tag!("type") => { |_| filter::Attribute::Filetype }
                    | tag!("mimetype") => { |_| filter::Attribute::Mimetype }
                    | tag!("inode")    => { |_| filter::Attribute::Inode }
                    | tag!("basename") => { |_| filter::Attribute::Basename }
                    | tag!("uid")      => { |_| filter::Attribute::Uid }
                    | tag!("gid")      => { |_| filter::Attribute::Gid }
                )
               ) >>
               (tag)
           )
       );

named!(directory<String>,
       do_parse!(
           dir: re_bytes_find!("^/?([^/\0,; ]*(/)?)+") >>
           (String::from_utf8_lossy(dir).into_owned())
       )
   );
named!(num_paramter, re_bytes_find!("-?[0-9]+(\\.[0-9]*)?[a-zA-Z]*"));
named!(str_paramter,
       do_parse!(
           tag!("'") >>
           pattern: re_bytes_find!("[^']+") >>
           tag!("'") >>
           (pattern)
           )
       );
named!(date_parameter, re_bytes_find!("(([0-9]{4}-[0-9]{2}-[0-9]{2})? ?[0-9]{1,2}:[0-9]{2})|([0-9]{4}-[0-9]{2}-[0-9]{2})"));

named!(parameter, alt!(num_paramter | str_paramter | date_parameter));

named!(filter<filter_tree::FilterTuple>,
       do_parse!(
           attr: attribute >>
           op  : ws!(comp_op)   >>
           param: ws!(parameter) >>
           (filter_tree::FilterTuple::new(attr,
                                op,
                                String::from_utf8_lossy(param).into_owned()
                                )
           )
     )
);

named!(directory_list<Vec<String>>, separated_list!(komma, directory));
named!(attribute_list<Vec<filter::Attribute>>, separated_list!(komma, attribute));

named!(filter_expr<filter_tree::FilterTree>,
           do_parse!(
               lhs : filter         >>
               op  : opt!(logic_op) >>
               rhs : opt!(filter_expr)   >>
               ( match rhs {
                   Some(r) => filter_tree::FilterTree::new(Some(lhs), op, Some(Box::new(r))),
                   None    => filter_tree::FilterTree::new(Some(lhs), None, None),
                 }
               )
           )
       );

named!(command<String>,
       do_parse!(
       cmd: re_bytes_find!("[^;]+") >>
        (String::from_utf8_lossy(cmd).into_owned())
    )
);

named!(select_part<Option<Vec<filter::Attribute>>>,
       opt!(
           do_parse!(
               attrs: attribute_list >>
               (attrs)
           )
       )
   );

named!(from_part<Option<Vec<String>>>,
       opt!(
           do_parse!(
               from_keyword >>
               dirs: directory_list >>
               (dirs)
           )
       )
   );

named!(where_part<Option<filter_tree::FilterTree>>,
       opt!(
           do_parse!(
               where_keyword >>
               filters: filter_expr >>
               (filters)
           )
       )
   );

named!(exec_part<Option<String>>,
       opt!(
           do_parse!(
               exec_keyword >>
               cmd : command >>
               (cmd)
           )
       )
   );

named!(pub query<query::Query>, do_parse!(
        attributes: select_part >>
        directories: from_part >>
        filters: where_part >>
        command: exec_part >>
        (query::Query::new(attributes, directories, filters, command))
        )
    );
<commit_msg>Bug fixed: order parsers from more to less specific<commit_after>//! frust query parser
//!
//! # Talkin' Syntax
//! For now the precendence of 'and' and 'or' is not implemented, nor are brackets supported.
//! This meens that if you want (f1 and f2) or f3, you have to express it as f3 or f1 and f2.
//! I know this is limitting and I'm going to improve this in the future...

use std::string::String;
use filter;
use filter_tree;
use query;

named!(komma, ws!(tag!(",")));
named!(comp_op<filter::CompOp>, alt!(
          tag!("<")  => { |_| filter::CompOp::Lower }
        | tag!("<=") => { |_| filter::CompOp::LowerEqual }
        | tag!("==") => { |_| filter::CompOp::Equal }
        | tag!("not =") => { |_| filter::CompOp::Unequal }
        | tag!("!=") => { |_| filter::CompOp::Unequal }
        | tag!(">=") => { |_| filter::CompOp::GreaterEqual }
        | tag!(">")  => { |_| filter::CompOp::Greater }
        | tag!("~")  => { |_| filter::CompOp::Like }
        | tag!("not ~")  => { |_| filter::CompOp::Unlike }
        )
    );

named!(logic_op<filter_tree::LogicOp>,
       alt!(
        ws!(tag!("or")) =>  { |_| filter_tree::LogicOp::Or }
        |
        ws!(tag!("and")) => { |_| filter_tree::LogicOp::And }
        )
);

named!(from_keyword, ws!(tag!("from")));
named!(where_keyword, ws!(tag!("where")));
named!(exec_keyword, ws!(tag!("exec")));
named!(attribute<filter::Attribute>,
       do_parse!(
           tag: ws!(alt!(
                      tag!("name")     => { |_| filter::Attribute::Name }
                    | tag!("size")     => { |_| filter::Attribute::Size }
                    | tag!("mtime")    => { |_| filter::Attribute::Mtime }
                    | tag!("ctime")    => { |_| filter::Attribute::Ctime }
                    | tag!("atime")    => { |_| filter::Attribute::Atime }
                    | tag!("type") => { |_| filter::Attribute::Filetype }
                    | tag!("mimetype") => { |_| filter::Attribute::Mimetype }
                    | tag!("inode")    => { |_| filter::Attribute::Inode }
                    | tag!("basename") => { |_| filter::Attribute::Basename }
                    | tag!("uid")      => { |_| filter::Attribute::Uid }
                    | tag!("gid")      => { |_| filter::Attribute::Gid }
                )
               ) >>
               (tag)
           )
       );

named!(directory<String>,
       do_parse!(
           dir: re_bytes_find!("^/?([^/\0,; ]*(/)?)+") >>
           (String::from_utf8_lossy(dir).into_owned())
       )
   );
named!(num_paramter, re_bytes_find!("-?[0-9]+(\\.[0-9]*)?[a-zA-Z]*"));
named!(str_paramter,
       do_parse!(
           tag!("'") >>
           pattern: re_bytes_find!("[^']+") >>
           tag!("'") >>
           (pattern)
           )
       );
named!(date_parameter, re_bytes_find!("(([0-9]{4}-[0-9]{2}-[0-9]{2})? ?[0-9]{1,2}:[0-9]{2})|([0-9]{4}-[0-9]{2}-[0-9]{2})"));

named!(parameter, alt!(str_paramter | date_parameter | num_paramter));

named!(filter<filter_tree::FilterTuple>,
       do_parse!(
           attr: attribute >>
           op  : ws!(comp_op)   >>
           param: ws!(parameter) >>
           (filter_tree::FilterTuple::new(attr,
                                op,
                                String::from_utf8_lossy(param).into_owned()
                                )
           )
     )
);

named!(directory_list<Vec<String>>, separated_list!(komma, directory));
named!(attribute_list<Vec<filter::Attribute>>, separated_list!(komma, attribute));

named!(filter_expr<filter_tree::FilterTree>,
           do_parse!(
               lhs : filter         >>
               op  : opt!(logic_op) >>
               rhs : opt!(filter_expr)   >>
               ( match rhs {
                   Some(r) => filter_tree::FilterTree::new(Some(lhs), op, Some(Box::new(r))),
                   None    => filter_tree::FilterTree::new(Some(lhs), None, None),
                 }
               )
           )
       );

named!(command<String>,
       do_parse!(
       cmd: re_bytes_find!("[^;]+") >>
        (String::from_utf8_lossy(cmd).into_owned())
    )
);

named!(select_part<Option<Vec<filter::Attribute>>>,
       opt!(
           do_parse!(
               attrs: attribute_list >>
               (attrs)
           )
       )
   );

named!(from_part<Option<Vec<String>>>,
       opt!(
           do_parse!(
               from_keyword >>
               dirs: directory_list >>
               (dirs)
           )
       )
   );

named!(where_part<Option<filter_tree::FilterTree>>,
       opt!(
           do_parse!(
               where_keyword >>
               filters: filter_expr >>
               (filters)
           )
       )
   );

named!(exec_part<Option<String>>,
       opt!(
           do_parse!(
               exec_keyword >>
               cmd : command >>
               (cmd)
           )
       )
   );

named!(pub query<query::Query>, do_parse!(
        attributes: select_part >>
        directories: from_part >>
        filters: where_part >>
        command: exec_part >>
        (query::Query::new(attributes, directories, filters, command))
        )
    );
<|endoftext|>