<commit_before>/*!
This crate provides stable, partial implementations of the `parse_generics!` and `parse_where!` macros proposed in [RFC #1583].  These macros serve two purposes:

1. They allow crate authors to use the macros in a limited capacity whether or not the RFC is accepted.
2. They demonstrate to the Rust core team that there is demand for this functionality.
3. They provide a migration path from the partial implementation to the full one, assuming the RFC does get accepted.

Because these macros are implemented using `macro_rules!`, they have the following limitations:

- In general, only lifetimes `'a` through `'z` are accepted.
- Only a subset of the full output formats are supported.
- They are significantly less efficient, and consume a non-trivial amount of the recursion limit.

[RFC #1583]: https://github.com/rust-lang/rfcs/pull/1583

## `parse_generics_shim!`

```ignore
macro_rules! parse_generics_shim {
    (
        { $($fields:ident),+ },
        then $callback_name:ident ! ( $($callback_args:tt)* ),
        $($code:tt)*
    ) => { ... };
}
```

Parses a generic parameter list (if present) from the start of `$($code:tt)*`, expanding to the parsed information plus the unconsumed tokens *after* the parameter list.  The general form of the expansion is:

```ignore
$callback_name! {
    $($callback_args)*
    {
        $(
            $fields: [ .. ],
        )+
    },
    $($tail)*
}
```

### Callback

`$callback_name` and `$callback_args` specify the macro to invoke with the result of parsing.  Note that `$callback_args` may be contained in *any* of `( .. )`, `[ .. ]`, or `{ .. }`.

### Fields

`$fields` indicates which pieces of information you want in the expansion.  The available fields are:

- `constr` - comma-terminated list of generic parameters plus their constraints.
- `params` - comma-terminated list of generic parameter names (both lifetimes and types).
- `ltimes` - comma-terminated list of generic lifetime names.
- `tnames` - comma-terminated list of generic type names.

The shim *only* supports the following combinations:

- `{ constr, params, ltimes, tnames }`
- `{ constr }`
- `{ .. }`

The fields will appear in the output in the same order they appear in the input.  One special case is `{ .. }` which causes *all* fields to be emitted, followed by a literal `..` token.

**Warning**: there is explicitly *no* guarantee that the list of fields will stay the same over time.  As such, it is **strongly** recommended that you never directly match the `..` token after the fields.  Instead, you should use the following construct:

```ignore
macro_rules! match_output {
    (
        {
            // Match the fields you care about.
            constr: $constr:tt,
            params: [ $($params:tt,)* ],

            // Ignore the rest; *never* explicitly match `..`!
            $($_fields:tt)*
        },

        $($tail:tt)*
    ) => { ... };
}
```

### Code

`$code` is the actual source code to be parsed.  If it starts with `<`, the macro will parse a generic parameter list.  If it *does not* start with `<`, the macro will proceed as though the input started with an empty generic parameter list (*i.e.* `<>`).

### Examples

The following show how the various invocation forms affect the output:

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_generics_shim! {
    { constr, params, ltimes, tnames },
    then stringify!(output:),
    <'a, T, U: 'a + Copy> X
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        constr: [ 'a, T, U: 'a + Copy, ],
        params: [ 'a, T, U, ],
        ltimes: [ 'a, ],
        tnames: [ T, U, ],
    },
    X
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_generics_shim! {
    { constr },
    then stringify!(output:),
    <'a, T, U: 'a + Copy> X
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        constr: [ 'a, T, U: 'a + Copy, ],
    },
    X
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_generics_shim! {
    { .. },
    then stringify!(output:),
    <'a, T, U: 'a + Copy> X
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        constr: [ 'a, T, U: 'a + Copy, ],
        params: [ 'a, T, U, ],
        ltimes: [ 'a, ],
        tnames: [ T, U, ],
        ..
    },
    X
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

The input does not *have* to start with a generic parameter list.  Note that both of the invocations below expand to the same result:

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_generics_shim! {
    { constr, params, ltimes, tnames },
    then stringify!(output:),
    <> X
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        constr: [],
        params: [],
        ltimes: [],
        tnames: [],
    },
    X
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_generics_shim! {
    { constr, params, ltimes, tnames },
    then stringify!(output:),
    X
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        constr: [],
        params: [],
        ltimes: [],
        tnames: [],
    },
    X
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

## `parse_where!`

```ignore
macro_rules! parse_where_shim {
    (
        { $($fields:ident),+ },
        then $callback_name:ident ! ( $($callback_args:tt)* ),
        $($code:tt)*
    ) => { ... };
}
```

Parses a `where` clause (if present) from the start of `$($code:tt)*`, expanding to the parsed information plus the unconsumed tokens *after* the clause.  The general form of the expansion is:

```ignore
$callback_name! {
    $($callback_args)*
    {
        $(
            $fields: [ .. ],
        )+
    },
    $($tail)*
}
```

### Callback

`$callback_name` and `$callback_args` specify the macro to invoke with the result of parsing.  Note that `$callback_args` may be contained in *any* of `( .. )`, `[ .. ]`, or `{ .. }`.

### Fields

`$fields` indicates which pieces of information you want in the expansion.  The available fields are:

- `preds` - comma-terminated list of predicates.

The shim *only* supports the following combinations:

- `{ preds }`
- `{ .. }`

The fields will appear in the output in the same order they appear in the input.  One special case is `{ .. }` which causes *all* fields to be emitted, followed by a literal `..` token.

**Warning**: there is explicitly *no* guarantee that the list of fields will stay the same over time.  As such, it is **strongly** recommended that you never directly match the `..` token after the fields.  Instead, you should use the following construct:

```ignore
macro_rules! match_output {
    (
        {
            // Match the fields you care about.
            preds: [ $($preds:tt)* ],

            // Ignore the rest; *never* explicitly match `..`!
            $($_fields:tt)*
        },

        $($tail:tt)*
    ) => { ... };
}
```

### Code

`$code` is the actual source code to be parsed.  If it starts with `where`, the macro will parse a `where` clause, stopping when it encounters any of the following: `;`, `{`, or `=`.  If it *does not* start with `where`, the macro will expand with an empty predicate list.

### Examples

The following show how the various invocation forms affect the output:

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_where_shim! {
    { preds },
    then stringify!(output:),
    where
        'a: 'b,
        T: 'a + Copy,
        for<'c> U: Foo<'c>,
    { struct fields... }
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        preds: [ 'a: 'b, T: 'a + Copy, for<'c,> U: Foo<'c>, ],
    },
    { struct fields... }
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_where_shim! {
    { .. },
    then stringify!(output:),
    where
        'a: 'b,
        T: 'a + Copy,
        for<'c> U: Foo<'c>,
    { struct fields... }
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        preds: [ 'a: 'b, T: 'a + Copy, for<'c,> U: Foo<'c>, ],
        ..
    },
    { struct fields... }
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

The input does not *have* to start with a `where` clause:

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_where_shim! {
    { preds },
    then stringify!(output:),
    ; X
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        preds: [],
    },
    ; X
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```
*/
#![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
#![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]

#[cfg(not(feature="use-parse-generics-poc"))]
#[doc(hidden)]
#[macro_export]
macro_rules! parse_generics_shim_util {
    (
        @callback
        ($cb_name:ident ! ($($cb_arg:tt)*)),
        $($tail:tt)*
    ) => {
        $cb_name! { $($cb_arg)* $($tail)* }
    };

    (
        @callback
        ($cb_name:ident ! [$($cb_arg:tt)*]),
        $($tail:tt)*
    ) => {
        $cb_name! { $($cb_arg)* $($tail)* }
    };

    (
        @callback
        ($cb_name:ident ! {$($cb_arg:tt)*}),
        $($tail:tt)*
    ) => {
        $cb_name! { $($cb_arg)* $($tail)* }
    };
}

mod parse_constr;
mod parse_generics_shim;
mod parse_where_shim;
<commit_msg>Added more docs to parse-generics-shim.<commit_after>/*!
This crate provides stable, partial implementations of the `parse_generics!` and `parse_where!` macros proposed in [RFC #1583].  These macros serve two purposes:

1. They allow crate authors to use the macros in a limited capacity whether or not the RFC is accepted.
2. They demonstrate to the Rust core team that there is demand for this functionality.
3. They provide a migration path from the partial implementation to the full one, assuming the RFC does get accepted.

Because these macros are implemented using `macro_rules!`, they have the following limitations:

- In general, only lifetimes `'a` through `'z` are accepted.
- Only a subset of the full output formats are supported.
- They are significantly less efficient, and consume a non-trivial amount of the recursion limit.

# Table of Contents

- [`parse_generics_shim!`](#parse_generics_shim)
- [`parse_where_shim!`](#parse_where_shim)
- [Supporting `parse-generics-poc`](#supporting-parse-generics-poc)

[RFC #1583]: https://github.com/rust-lang/rfcs/pull/1583

## `parse_generics_shim!`

```ignore
macro_rules! parse_generics_shim {
    (
        { $($fields:ident),+ },
        then $callback_name:ident ! ( $($callback_args:tt)* ),
        $($code:tt)*
    ) => { ... };
}
```

Parses a generic parameter list (if present) from the start of `$($code:tt)*`, expanding to the parsed information plus the unconsumed tokens *after* the parameter list.  The general form of the expansion is:

```ignore
$callback_name! {
    $($callback_args)*
    {
        $(
            $fields: [ .. ],
        )+
    },
    $($tail)*
}
```

### Callback

`$callback_name` and `$callback_args` specify the macro to invoke with the result of parsing.  Note that `$callback_args` may be contained in *any* of `( .. )`, `[ .. ]`, or `{ .. }`.

### Fields

`$fields` indicates which pieces of information you want in the expansion.  The available fields are:

- `constr` - comma-terminated list of generic parameters plus their constraints.
- `params` - comma-terminated list of generic parameter names (both lifetimes and types).
- `ltimes` - comma-terminated list of generic lifetime names.
- `tnames` - comma-terminated list of generic type names.

The shim *only* supports the following combinations:

- `{ constr, params, ltimes, tnames }`
- `{ constr }`
- `{ .. }`

The fields will appear in the output in the same order they appear in the input.  One special case is `{ .. }` which causes *all* fields to be emitted, followed by a literal `..` token.

**Warning**: there is explicitly *no* guarantee that the list of fields will stay the same over time.  As such, it is **strongly** recommended that you never directly match the `..` token after the fields.  Instead, you should use the following construct:

```ignore
macro_rules! match_output {
    (
        {
            // Match the fields you care about.
            constr: $constr:tt,
            params: [ $($params:tt,)* ],

            // Ignore the rest; *never* explicitly match `..`!
            $($_fields:tt)*
        },

        $($tail:tt)*
    ) => { ... };
}
```

### Code

`$code` is the actual source code to be parsed.  If it starts with `<`, the macro will parse a generic parameter list.  If it *does not* start with `<`, the macro will proceed as though the input started with an empty generic parameter list (*i.e.* `<>`).

### Examples

The following show how the various invocation forms affect the output:

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_generics_shim! {
    { constr, params, ltimes, tnames },
    then stringify!(output:),
    <'a, T, U: 'a + Copy> X
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        constr: [ 'a, T, U: 'a + Copy, ],
        params: [ 'a, T, U, ],
        ltimes: [ 'a, ],
        tnames: [ T, U, ],
    },
    X
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_generics_shim! {
    { constr },
    then stringify!(output:),
    <'a, T, U: 'a + Copy> X
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        constr: [ 'a, T, U: 'a + Copy, ],
    },
    X
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_generics_shim! {
    { .. },
    then stringify!(output:),
    <'a, T, U: 'a + Copy> X
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        constr: [ 'a, T, U: 'a + Copy, ],
        params: [ 'a, T, U, ],
        ltimes: [ 'a, ],
        tnames: [ T, U, ],
        ..
    },
    X
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

The input does not *have* to start with a generic parameter list.  Note that both of the invocations below expand to the same result:

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_generics_shim! {
    { constr, params, ltimes, tnames },
    then stringify!(output:),
    <> X
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        constr: [],
        params: [],
        ltimes: [],
        tnames: [],
    },
    X
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_generics_shim! {
    { constr, params, ltimes, tnames },
    then stringify!(output:),
    X
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        constr: [],
        params: [],
        ltimes: [],
        tnames: [],
    },
    X
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

## `parse_where_shim!`

```ignore
macro_rules! parse_where_shim {
    (
        { $($fields:ident),+ },
        then $callback_name:ident ! ( $($callback_args:tt)* ),
        $($code:tt)*
    ) => { ... };
}
```

Parses a `where` clause (if present) from the start of `$($code:tt)*`, expanding to the parsed information plus the unconsumed tokens *after* the clause.  The general form of the expansion is:

```ignore
$callback_name! {
    $($callback_args)*
    {
        $(
            $fields: [ .. ],
        )+
    },
    $($tail)*
}
```

### Callback

`$callback_name` and `$callback_args` specify the macro to invoke with the result of parsing.  Note that `$callback_args` may be contained in *any* of `( .. )`, `[ .. ]`, or `{ .. }`.

### Fields

`$fields` indicates which pieces of information you want in the expansion.  The available fields are:

- `preds` - comma-terminated list of predicates.

The shim *only* supports the following combinations:

- `{ preds }`
- `{ .. }`

The fields will appear in the output in the same order they appear in the input.  One special case is `{ .. }` which causes *all* fields to be emitted, followed by a literal `..` token.

**Warning**: there is explicitly *no* guarantee that the list of fields will stay the same over time.  As such, it is **strongly** recommended that you never directly match the `..` token after the fields.  Instead, you should use the following construct:

```ignore
macro_rules! match_output {
    (
        {
            // Match the fields you care about.
            preds: [ $($preds:tt)* ],

            // Ignore the rest; *never* explicitly match `..`!
            $($_fields:tt)*
        },

        $($tail:tt)*
    ) => { ... };
}
```

### Code

`$code` is the actual source code to be parsed.  If it starts with `where`, the macro will parse a `where` clause, stopping when it encounters any of the following: `;`, `{`, or `=`.  If it *does not* start with `where`, the macro will expand with an empty predicate list.

### Examples

The following show how the various invocation forms affect the output:

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_where_shim! {
    { preds },
    then stringify!(output:),
    where
        'a: 'b,
        T: 'a + Copy,
        for<'c> U: Foo<'c>,
    { struct fields... }
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        preds: [ 'a: 'b, T: 'a + Copy, for<'c,> U: Foo<'c>, ],
    },
    { struct fields... }
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_where_shim! {
    { .. },
    then stringify!(output:),
    where
        'a: 'b,
        T: 'a + Copy,
        for<'c> U: Foo<'c>,
    { struct fields... }
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        preds: [ 'a: 'b, T: 'a + Copy, for<'c,> U: Foo<'c>, ],
        ..
    },
    { struct fields... }
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

The input does not *have* to start with a `where` clause:

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# fn main() {
# assert_eq!( (
parse_where_shim! {
    { preds },
    then stringify!(output:),
    ; X
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , "
    output: {
        preds: [],
    },
    ; X
# ".replace(char::is_whitespace, "")); /*
)
# */ }
```

## Supporting `parse-generics-poc`

If you wish to enable support for the full `parse_generics!` and `parse_where!` macros *instead* of the shim implementations, you need to create a feature which will enable the POC macros.  This can be done by adding the following to your `Cargo.toml` manifest:

```toml
[features]
use-parse-generics-poc = [
    "parse-generics-poc",
    "parse-generics-shim/use-parse-generics-poc",
]

[dependencies]
parse-generics-poc = { version = "0.1.0", optional = true }
parse-generics-shim = "0.1.0"
```

You should also pass the following information on to your users (or direct them here):

### Using `parse-generics-poc`

To activate `parse-generics-poc` support in the `whizzo` crate, you must:

1. Enable the `use-parse-generics-poc` feature in your crate.  This is best done using a forwarding feature in your `Cargo.toml` so that your code is not unavoidably dependant on a nightly compiler:

    ```toml
    [features]
    use-parse-generics-poc = [
        "parse-generics-poc",
        "whizzo/use-parse-generics-poc"
    ]
    ```

2. Depend on both the relevant macro crates.  Because compiler plugins and macros can't be re-exported, this is sadly unavoidable.

    ```toml
    [dependencies]
    parse-generics-poc = { version = "0.1.0", optional = true }
    parse-generics-shim = "0.1.0"
    ```

3. You have to use a nightly compiler compatible with `parse-generics-poc`.  The documentation for `parse-generics-poc` should specify *which* nightly it is known to be compatible with.  If you are using `rustup`, you can configure your crate to use the appropriate compiler using the following (replacing the date shown with the one listed in the `parse-generics-poc` documentation):

    ```sh
    rustup override add nightly-2016-04-06
    ```

4. You must add the following attributes to the top of your crate's root module:

    ```rust
    #![cfg_attr(feature="parse-generics-poc", feature(plugin))]
    #![cfg_attr(feature="parse-generics-poc", plugin(parse_generics_poc))]
    #[macro_use] extern crate parse_generics_shim;
    ```
*/
#![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
#![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]

#[cfg(not(feature="use-parse-generics-poc"))]
#[doc(hidden)]
#[macro_export]
macro_rules! parse_generics_shim_util {
    (
        @callback
        ($cb_name:ident ! ($($cb_arg:tt)*)),
        $($tail:tt)*
    ) => {
        $cb_name! { $($cb_arg)* $($tail)* }
    };

    (
        @callback
        ($cb_name:ident ! [$($cb_arg:tt)*]),
        $($tail:tt)*
    ) => {
        $cb_name! { $($cb_arg)* $($tail)* }
    };

    (
        @callback
        ($cb_name:ident ! {$($cb_arg:tt)*}),
        $($tail:tt)*
    ) => {
        $cb_name! { $($cb_arg)* $($tail)* }
    };
}

mod parse_constr;
mod parse_generics_shim;
mod parse_where_shim;
<|endoftext|>


<commit_before>#![no_std]

extern crate alloc;
extern crate lang_items;
extern crate libtock_drivers;

use core::fmt::Write;
use libtock_drivers::console::Console;

#[cfg(not(feature = "with_nfc"))]
mod example {
    use super::Console;
    use super::Write;

    pub fn nfc(console: &mut Console) {
        writeln!(console, "NFC feature flag is missing!").unwrap();
    }
}

#[cfg(feature = "with_nfc")]
mod example {
    use super::Console;
    use super::Write;
    use libtock_core::result::CommandError;
    use libtock_drivers::nfc::NfcTag;
    use libtock_drivers::nfc::RecvOp;
    use libtock_drivers::result::FlexUnwrap;
    use libtock_drivers::result::TockError;
    use libtock_drivers::timer;
    use libtock_drivers::timer::Timer;
    use libtock_drivers::timer::Timestamp;

    /// Helper function to write on console the received packet.
    fn print_rx_buffer(buf: &mut [u8]) {
        if let Some((last, bytes)) = buf.split_last() {
            let mut console = Console::new();
            write!(console, "RX:").unwrap();
            for byte in bytes {
                write!(console, " {:02x?}", byte).unwrap();
            }
            writeln!(console, " {:02x?}", last).unwrap();
            console.flush();
        }
    }

    /// Function to identify the time elapsed for a transmission request.
    fn bench_transmit(console: &mut Console, timer: &Timer, title: &str, mut buf: &mut [u8]) {
        let amount = buf.len();
        let start = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
        match NfcTag::transmit(&mut buf, amount) {
            Ok(_) => (),
            Err(_) => writeln!(Console::new(), " -- tx error!").unwrap(),
        }
        let end = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
        let elapsed = (end - start).ms();
        writeln!(
            console,
            "{}\n{:.2} ms elapsed for {} bytes ({:.2} kbit/s)",
            title,
            elapsed,
            amount,
            (amount as f64) / elapsed * 8.
        )
        .unwrap();
        console.flush();
    }

    fn receive_packet(console: &mut Console, mut buf: &mut [u8; 256]) -> bool {
        match NfcTag::receive(&mut buf) {
            Ok(RecvOp {
                recv_amount: amount,
                ..
            }) => {
                if amount <= buf.len() {
                    print_rx_buffer(&mut buf[..amount]);
                }
            }
            Err(TockError::Command(CommandError {
                return_code: -4, /* EOFF: Not Ready */
                ..
            })) => return false,
            // For the example app, just print any other received error without handling.
            Err(TockError::Command(CommandError {
                return_code: value, ..
            })) => writeln!(console, " -- Err({})!", value).unwrap(),
            Err(_) => writeln!(console, " -- RX Err").unwrap(),
        }
        true
    }

    fn transmit_reply(mut console: &mut Console, timer: &Timer, buf: &[u8]) -> bool {
        match buf[0] {
            0xe0 /* RATS */=> {
                let mut answer_to_select = [0x05, 0x78, 0x80, 0xB1, 0x00];
                bench_transmit(&mut console, &timer, "TX: ATS", &mut answer_to_select);
            }
            0xc2 /* DESELECT */ => {
                // Ignore the request
                let mut command_error = [0x6A, 0x81];
                bench_transmit(&mut console, &timer, "TX: DESELECT", &mut command_error);
            }
            0x02 | 0x03 /* APDU Prefix */ => match buf[2] {
                // If the received packet is applet selection command (FIDO 2)
                0xa4 /* SELECT */ => if buf[3] == 0x04 && buf[5] == 0x08 && buf[6] == 0xa0 {
                        // Vesion: "FIDO_2_0"
                        let mut reply = [buf[0], 0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x30, 0x90, 0x00,];
                        bench_transmit(&mut console, &timer, "TX: Version Str", &mut reply);
                    } else {
                        let mut reply = [buf[0], 0x90, 0x00];
                        bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
                    }
                0xb0 /* READ */ =>  match buf[5] {
                        0x02 => {
                        let mut reply = [buf[0], 0x12, 0x90, 0x00,];
                        bench_transmit(&mut console, &timer, "TX: File Size", &mut reply);
                    }
                    0x12 => {
                        let mut reply = [buf[0], 0xd1, 0x01, 0x0e, 0x55, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x70, 0x65,
                        0x6e, 0x73, 0x6b, 0x2e, 0x64, 0x65, 0x76, 0x90, 0x00,];
                        bench_transmit(&mut console, &timer, "TX: NDEF", &mut reply);
                    }
                    0x0f => {
                        let mut reply = [buf[0], 0x00, 0x0f, 0x20, 0x00, 0x7f, 0x00, 0x7f, 0x04, 0x06, 0xe1, 0x04,
                        0x00, 0x7f, 0x00, 0x00, 0x90, 0x00,];
                        bench_transmit(&mut console, &timer, "TX: CC", &mut reply);
                    }
                    _ => {
                        let mut reply = [buf[0], 0x90, 0x00];
                        bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
                    }
                }
                _ => {
                    let mut reply = [buf[0], 0x90, 0x00];
                    bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
                }
            }
            0x26 | 0x52 | 0x50 /* REQA | WUPA | Halt */ => {
                if NfcTag::disable_emulation() {
                    writeln!(console, " -- TAG DISABLED").unwrap();
                }
                return false;
            }
            _ => (),
        }
        true
    }

    pub fn nfc(mut console: &mut Console) {
        // Setup the timer with a dummy callback (we only care about reading the current time, but the
        // API forces us to set an alarm callback too).
        let mut with_callback = timer::with_callback(|_, _| {});
        let timer = with_callback.init().flex_unwrap();

        writeln!(
            console,
            "Clock frequency: {} Hz",
            timer.clock_frequency().hz()
        )
        .unwrap();

        let mut state_change_counter = 0;
        loop {
            while !NfcTag::enable_emulation() {}
            // Configure Type 4 tag
            while !NfcTag::configure(4) {}
            state_change_counter += 1;
            loop {
                let mut rx_buf = [0; 256];
                // Await a successful receive
                while !receive_packet(&mut console, &mut rx_buf) {}
                // If the reader restarts the communication and we can't
                // reply to the received packet, then disable the tag.
                if !transmit_reply(&mut console, &timer, &rx_buf) {
                    state_change_counter += 1;
                    break;
                }
            }
            if state_change_counter > 100 {
                break;
            }
        }
    }
}

fn main() {
    let mut console = Console::new();
    writeln!(console, "****************************************").unwrap();
    writeln!(console, "nfct_test application is installed").unwrap();
    example::nfc(&mut console);
    writeln!(console, "****************************************").unwrap();
}
<commit_msg>Update in the application's workflow<commit_after>#![no_std]

extern crate alloc;
extern crate lang_items;
extern crate libtock_drivers;

use core::fmt::Write;
use libtock_drivers::console::Console;

#[cfg(not(feature = "with_nfc"))]
mod example {
    use super::Console;
    use super::Write;

    pub fn nfc(console: &mut Console) {
        writeln!(console, "NFC feature flag is missing!").unwrap();
    }
}

#[cfg(feature = "with_nfc")]
mod example {
    use super::Console;
    use super::Write;
    use libtock_core::result::CommandError;
    use libtock_drivers::nfc::NfcTag;
    use libtock_drivers::nfc::RecvOp;
    use libtock_drivers::result::FlexUnwrap;
    use libtock_drivers::result::TockError;
    use libtock_drivers::timer;
    use libtock_drivers::timer::Timer;
    use libtock_drivers::timer::Timestamp;

    #[derive(Copy, Clone, Debug, PartialEq)]
    enum ReturnCode {
        /// Operation completed successfully
        SUCCESS,
        /// Generic failure condition
        FAIL,
        /// Underlying system is busy; retry
        EBUSY,
        /// The component is powered down
        EOFF,
        /// An invalid parameter was passed
        EINVAL,
        /// Operation canceled by a call
        ECANCEL,
        /// Memory required not available
        ENOMEM,
        /// Operation or command is unsupported
        ENOSUPPORT,
    }

    impl From<isize> for ReturnCode {
        fn from(original: isize) -> ReturnCode {
            match original {
                0 => ReturnCode::SUCCESS,
                -1 => ReturnCode::FAIL,
                -2 => ReturnCode::EBUSY,
                -4 => ReturnCode::EOFF,
                -6 => ReturnCode::EINVAL,
                -8 => ReturnCode::ECANCEL,
                -9 => ReturnCode::ENOMEM,
                _ => ReturnCode::ENOSUPPORT,
            }
        }
    }

    /// Helper function to write on console the received packet.
    fn print_rx_buffer(buf: &mut [u8]) {
        if let Some((last, bytes)) = buf.split_last() {
            let mut console = Console::new();
            write!(console, "RX:").unwrap();
            for byte in bytes {
                write!(console, " {:02x?}", byte).unwrap();
            }
            writeln!(console, " {:02x?}", last).unwrap();
            console.flush();
        }
    }

    /// Function to identify the time elapsed for a transmission request.
    fn bench_transmit(
        console: &mut Console,
        timer: &Timer,
        title: &str,
        mut buf: &mut [u8],
    ) -> ReturnCode {
        let amount = buf.len();
        let start = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
        match NfcTag::transmit(&mut buf, amount) {
            Ok(_) => (),
            Err(TockError::Command(CommandError {
                return_code: -8, /* ECANCEL: No Field*/
                ..
            })) => return ReturnCode::ECANCEL,
            Err(_) => writeln!(Console::new(), " -- tx error!").unwrap(),
        }
        let end = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
        let elapsed = (end - start).ms();
        writeln!(
            console,
            "{}\n{:.2} ms elapsed for {} bytes ({:.2} kbit/s)",
            title,
            elapsed,
            amount,
            (amount as f64) / elapsed * 8.
        )
        .unwrap();
        console.flush();
        ReturnCode::SUCCESS
    }

    fn receive_packet(console: &mut Console, mut buf: &mut [u8; 256]) -> ReturnCode {
        match NfcTag::receive(&mut buf) {
            Ok(RecvOp {
                recv_amount: amount,
                ..
            }) => {
                if amount <= buf.len() {
                    print_rx_buffer(&mut buf[..amount]);
                }
            }
            Err(TockError::Command(CommandError { return_code, .. })) => return return_code.into(),
            Err(_) => {
                writeln!(console, " -- RX Err").unwrap();
                return ReturnCode::ECANCEL;
            }
        }
        ReturnCode::SUCCESS
    }

    fn transmit_reply(mut console: &mut Console, timer: &Timer, buf: &[u8]) -> ReturnCode {
        let mut return_code = ReturnCode::SUCCESS;
        match buf[0] {
            0xe0 /* RATS */=> {
                let mut answer_to_select = [0x05, 0x78, 0x80, 0xB1, 0x00];
                return_code = bench_transmit(&mut console, &timer, "TX: ATS", &mut answer_to_select);
            }
            0xc2 /* DESELECT */ => {
                // Ignore the request
                let mut command_error = [0x6A, 0x81];
                return_code = bench_transmit(&mut console, &timer, "TX: DESELECT", &mut command_error);
            }
            0x02 | 0x03 /* APDU Prefix */ => match buf[2] {
                // If the received packet is applet selection command (FIDO 2)
                0xa4 /* SELECT */ => if buf[3] == 0x04 && buf[5] == 0x08 && buf[6] == 0xa0 {
                    // Vesion: "FIDO_2_0"
                    let mut reply = [buf[0], 0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x30, 0x90, 0x00,];
                    return_code = bench_transmit(&mut console, &timer, "TX: Version Str", &mut reply);
                } else if (buf[6] == 0xd2 && buf[7] == 0x76) || (buf[6] == 0xe1 && (buf[7] == 0x03 || buf[7] == 0x04)){
                    let mut reply = [buf[0], 0x90, 0x00];
                    return_code = bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
                } else /* Unknown file */ {
                    let mut reply = [buf[0], 0x6a, 0x82];
                    return_code = bench_transmit(&mut console, &timer, "TX: 0x6A82", &mut reply);
                }
                0xb0 /* READ */ =>  match buf[5] {
                    0x02 => {
                        let mut reply = [buf[0], 0x12, 0x90, 0x00,];
                        return_code = bench_transmit(&mut console, &timer, "TX: File Size", &mut reply);
                    }
                    0x12 => {
                        let mut reply = [buf[0], 0xd1, 0x01, 0x0e, 0x55, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x70, 0x65,
                        0x6e, 0x73, 0x6b, 0x2e, 0x64, 0x65, 0x76, 0x90, 0x00,];
                        return_code = bench_transmit(&mut console, &timer, "TX: NDEF", &mut reply);
                    }
                    0x0f => {
                        let mut reply = [buf[0], 0x00, 0x0f, 0x20, 0x00, 0x7f, 0x00, 0x7f, 0x04, 0x06, 0xe1, 0x04,
                        0x00, 0x7f, 0x00, 0x00, 0x90, 0x00,];
                        return_code = bench_transmit(&mut console, &timer, "TX: CC", &mut reply);
                    }
                    _ => {
                        let mut reply = [buf[0], 0x90, 0x00];
                        return_code = bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
                    }
                }
                _ => {
                    let mut reply = [buf[0], 0x90, 0x00];
                    return_code = bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
                }
            }
            0x26 | 0x52 | 0x50 /* REQA | WUPA | Halt */ => {
                return ReturnCode::EOFF;
            }
            _ => (),
        }
        return_code
    }

    pub fn nfc(mut console: &mut Console) {
        // Setup the timer with a dummy callback (we only care about reading the current time, but the
        // API forces us to set an alarm callback too).
        let mut with_callback = timer::with_callback(|_, _| {});
        let timer = with_callback.init().flex_unwrap();

        writeln!(
            console,
            "Clock frequency: {} Hz",
            timer.clock_frequency().hz()
        )
        .unwrap();

        let mut state_change_counter = 0;
        loop {
            let mut rx_buf = [0; 256];
            match receive_packet(&mut console, &mut rx_buf) {
                ReturnCode::EOFF => {
                    // Not configured
                    while !NfcTag::enable_emulation() {}
                    // Configure Type 4 tag
                    while !NfcTag::configure(4) {}
                }
                ReturnCode::ECANCEL /* field lost */ => {
                    NfcTag::disable_emulation();
                }
                ReturnCode::EBUSY /* awaiting select*/ => (),
                ReturnCode::ENOMEM => {
                    writeln!(console, " -- Amount more than buffer limit").unwrap()
                }
                ReturnCode::FAIL => writeln!(console, " -- Invalid CRC").unwrap(),
                ReturnCode::EINVAL /* covered in driver interface */ => (),
                ReturnCode::ENOSUPPORT => (),
                ReturnCode::SUCCESS => {
                    // If the reader restarts the communication then disable the tag.
                    match transmit_reply(&mut console, &timer, &rx_buf) {
                        ReturnCode::ECANCEL | ReturnCode::EOFF => {
                            if NfcTag::disable_emulation() {
                                writeln!(console, " -- TAG DISABLED").unwrap();
                            }
                            state_change_counter += 1;
                        }
                        _ => (),
                    }
                }
            }
            if state_change_counter > 100 {
                break;
            }
        }
    }
}

fn main() {
    let mut console = Console::new();
    writeln!(console, "****************************************").unwrap();
    writeln!(console, "nfct_test application is installed").unwrap();
    example::nfc(&mut console);
    writeln!(console, "****************************************").unwrap();
}
<|endoftext|>


<commit_before>use ansi_term::ANSIStrings;

use colours::Colours;
use file::File;
use filetype::file_colour;

pub use self::details::Details;
pub use self::grid::Grid;
pub use self::lines::Lines;
pub use self::grid_details::GridDetails;

mod grid;
pub mod details;
mod lines;
mod grid_details;

pub fn filename(file: &File, colours: &Colours, links: bool) -> String {
    if links && file.is_link() {
        symlink_filename(file, colours)
    }
    else {
        let style = file_colour(colours, file);
        style.paint(&file.name).to_string()
    }
}

fn symlink_filename(file: &File, colours: &Colours) -> String {
    match file.link_target() {
        Ok(target) => format!("{} {} {}",
                              file_colour(colours, file).paint(&file.name),
                              colours.punctuation.paint("=>"),
                              ANSIStrings(&[ colours.symlink_path.paint(&target.path_prefix()),
                                             file_colour(colours, &target).paint(&target.name) ])),

        Err(filename) => format!("{} {} {}",
                                 file_colour(colours, file).paint(&file.name),
                                 colours.broken_arrow.paint("=>"),
                                 colours.broken_filename.paint(&filename)),
    }
}
<commit_msg>Slim down symlink arrow<commit_after>use ansi_term::ANSIStrings;

use colours::Colours;
use file::File;
use filetype::file_colour;

pub use self::details::Details;
pub use self::grid::Grid;
pub use self::lines::Lines;
pub use self::grid_details::GridDetails;

mod grid;
pub mod details;
mod lines;
mod grid_details;

pub fn filename(file: &File, colours: &Colours, links: bool) -> String {
    if links && file.is_link() {
        symlink_filename(file, colours)
    }
    else {
        let style = file_colour(colours, file);
        style.paint(&file.name).to_string()
    }
}

fn symlink_filename(file: &File, colours: &Colours) -> String {
    match file.link_target() {
        Ok(target) => format!("{} {} {}",
                              file_colour(colours, file).paint(&file.name),
                              colours.punctuation.paint("->"),
                              ANSIStrings(&[ colours.symlink_path.paint(&target.path_prefix()),
                                             file_colour(colours, &target).paint(&target.name) ])),

        Err(filename) => format!("{} {} {}",
                                 file_colour(colours, file).paint(&file.name),
                                 colours.broken_arrow.paint("->"),
                                 colours.broken_filename.paint(&filename)),
    }
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate sdl2_game_window;
extern crate opengl_graphics;

use opengl_graphics::{
    Gl,
    Texture,
};
use sdl2_game_window::WindowSDL2;
use piston::{
    AssetStore,
    EventIterator,
    EventSettings,
    WindowSettings,
};
use piston::graphics::{
    AddBorder,
    AddEllipse,
    AddRectangle,
    AddColor,
    Context,
    Draw,
    ImageSize,
};
use piston::graphics::deform::DeformGrid;
use piston::drag_controller::{
    DragController,
    StartDrag,
    MoveDrag,
    EndDrag,
    InterruptDrag,
};
use piston::event::{
    PressEvent,
    RenderEvent,
};
use piston::input::{
    keyboard,
    Keyboard,
};

fn main() {
    println!("Click in the red square and drag.");
    println!("Toggle grid with G.");
    println!("Reset grid with R.");

    let opengl = piston::shader_version::opengl::OpenGL_3_2;
    let mut window = WindowSDL2::new(
        opengl,
        WindowSettings {
            title: "Deform".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

    let asset_store = AssetStore::from_folder("../bin/assets");
    let image = asset_store.path("rust-logo.png").unwrap();
    let image = Texture::from_path(&image).unwrap();

    let (width, height) = image.get_size();
    let width = width as f64;
    let height = height as f64;
    let mut grid = DeformGrid::new(
        [0.0, 0.0, width, height],
        20, 20
    );

    let event_settings = EventSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };
    let ref mut gl = Gl::new(opengl);
    let mut drag = DragController::new();
    let mut draw_grid = true;
    for e in EventIterator::new(&mut window, &event_settings) {
        drag.event(&e, |action| {
            match action {
                StartDrag(x, y) => {
                    match grid.hit([x, y]) {
                        None => {
                            // Did not hit deformed grid.
                            grid.add_control_point([x, y]);
                        }
                        Some(pos) => {
                            // Add point to deformed grid.
                            grid.add_control_point(pos);
                            grid.set_current(-1, [x, y]);
                        }
                    }
                    grid.update();
                    true
                }
                MoveDrag(x, y) => {
                    grid.set_current(-1, [x, y]);
                    grid.update();
                    true
                }
                EndDrag(_, _) => false,
                // Continue dragging when receiving focus.
                InterruptDrag => true,
            }
        });
        e.press(|button| {
            if button == Keyboard(keyboard::G) {
                draw_grid = !draw_grid;
                println!("Draw grid {}", draw_grid);
            } else if button == Keyboard(keyboard::R) {
                grid.reset_control_points();
                grid.reset_vertices_and_texture_coords();
                grid.update();
                println!("Reset grid");
            }
        });
        e.render(|args| {
            gl.viewport(0, 0,
                        args.width as i32, args.height as i32);
            let c = Context::abs(
                args.width as f64,
                args.height as f64
            );
            // Clear background.
            c.rgb(1.0, 1.0, 1.0).draw(gl);

            // Draw deformed image.
            grid.draw_image(&c, gl, &image);

            if draw_grid {
                // Draw grid.
                grid.draw_vertical_lines(
                    &c.rgb(0.0, 1.0, 0.0),
                    gl, 1.0
                );
                grid.draw_horizontal_lines(
                    &c.rgb(0.0, 0.0, 1.0),
                    gl, 1.0
                );
            }

            // Draw rect of the original grid.
            c.rgb(1.0, 0.0, 0.0)
            .rect(0.0, 0.0, width, height)
            .border_width(3.0)
            .draw(gl);

            // Draw control points.
            for i in range(0, grid.ps.len()) {
                // Original positions.
                let x = grid.ps[i][0];
                let y = grid.ps[i][1];
                c.rgba(1.0, 0.0, 0.0, 0.5)
                .circle(x, y, 3.0)
                .draw(gl);

                // Current positions.
                let x = grid.qs[i][0];
                let y = grid.qs[i][1];
                c.rgba(0.0, 0.0, 0.0, 0.5)
                .circle(x, y, 3.0)
                .draw(gl)
            };
        });
    }
}

<commit_msg>Upgraded to latest Graphics<commit_after>extern crate piston;
extern crate sdl2_game_window;
extern crate opengl_graphics;

use opengl_graphics::{
    Gl,
    Texture,
};
use sdl2_game_window::WindowSDL2;
use piston::{
    AssetStore,
    EventIterator,
    EventSettings,
    WindowSettings,
};
use piston::graphics::{
    AddBorder,
    AddEllipse,
    AddRectangle,
    AddColor,
    Context,
    Draw,
    ImageSize,
};
use piston::graphics::deform::DeformGrid;
use piston::drag_controller::{
    DragController,
    StartDrag,
    MoveDrag,
    EndDrag,
    InterruptDrag,
};
use piston::event::{
    PressEvent,
    RenderEvent,
};
use piston::input::{
    keyboard,
    Keyboard,
};

fn main() {
    println!("Click in the red square and drag.");
    println!("Toggle grid with G.");
    println!("Reset grid with R.");

    let opengl = piston::shader_version::opengl::OpenGL_3_2;
    let mut window = WindowSDL2::new(
        opengl,
        WindowSettings {
            title: "Deform".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

    let asset_store = AssetStore::from_folder("../bin/assets");
    let image = asset_store.path("rust-logo.png").unwrap();
    let image = Texture::from_path(&image).unwrap();

    let (width, height) = image.get_size();
    let width = width as f64;
    let height = height as f64;
    let mut grid = DeformGrid::new(
        [0.0, 0.0, width, height],
        20, 20
    );

    let event_settings = EventSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };
    let ref mut gl = Gl::new(opengl);
    let mut drag = DragController::new();
    let mut draw_grid = true;
    for e in EventIterator::new(&mut window, &event_settings) {
        drag.event(&e, |action| {
            match action {
                StartDrag(x, y) => {
                    match grid.hit([x, y]) {
                        None => {
                            // Did not hit deformed grid.
                            grid.add_control_point([x, y]);
                        }
                        Some(pos) => {
                            // Add point to deformed grid.
                            grid.add_control_point(pos);
                            let n = grid.ps.len();
                            grid.set_current(n - 1, [x, y]);
                        }
                    }
                    grid.update();
                    true
                }
                MoveDrag(x, y) => {
                    let n = grid.ps.len();
                    grid.set_current(n - 1, [x, y]);
                    grid.update();
                    true
                }
                EndDrag(_, _) => false,
                // Continue dragging when receiving focus.
                InterruptDrag => true,
            }
        });
        e.press(|button| {
            if button == Keyboard(keyboard::G) {
                draw_grid = !draw_grid;
                println!("Draw grid {}", draw_grid);
            } else if button == Keyboard(keyboard::R) {
                grid.reset_control_points();
                grid.reset_vertices_and_texture_coords();
                grid.update();
                println!("Reset grid");
            }
        });
        e.render(|args| {
            gl.viewport(0, 0,
                        args.width as i32, args.height as i32);
            let c = Context::abs(
                args.width as f64,
                args.height as f64
            );
            // Clear background.
            c.rgb(1.0, 1.0, 1.0).draw(gl);

            // Draw deformed image.
            grid.draw_image(&c, gl, &image);

            if draw_grid {
                // Draw grid.
                grid.draw_vertical_lines(
                    &c.rgb(0.0, 1.0, 0.0),
                    gl, 1.0
                );
                grid.draw_horizontal_lines(
                    &c.rgb(0.0, 0.0, 1.0),
                    gl, 1.0
                );
            }

            // Draw rect of the original grid.
            c.rgb(1.0, 0.0, 0.0)
            .rect(0.0, 0.0, width, height)
            .border_width(3.0)
            .draw(gl);

            // Draw control points.
            for i in range(0, grid.ps.len()) {
                // Original positions.
                let x = grid.ps[i][0];
                let y = grid.ps[i][1];
                c.rgba(1.0, 0.0, 0.0, 0.5)
                .circle(x, y, 3.0)
                .draw(gl);

                // Current positions.
                let x = grid.qs[i][0];
                let y = grid.qs[i][1];
                c.rgba(0.0, 0.0, 0.0, 0.5)
                .circle(x, y, 3.0)
                .draw(gl)
            };
        });
    }
}

<|endoftext|>


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

use ::resource::ResourceManager;
use ::renderer::RenderManager;
use ::util::{Directory, Version, Logger};

use std::cell::RefCell;
use std::rc::Rc;
use std::boxed::Box;
use std::path::Path;
use std::fs;
use std::process;

/*===============================================================================================*/
/*------STATIC VARIABLES-------------------------------------------------------------------------*/
/*===============================================================================================*/

static mut APP_POINTER: Option <*mut App> = None;

/*===============================================================================================*/
/*------APP STRUCT-------------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The app
///
/// This is the main control center of ionCore.
/// It is in charge of initialization, updating, and shutdown of all modules,
/// as well as the handing of any inter-module communication.
pub struct App {

    // Public
    /// The resource manager.
    pub resource_mgr: Rc<RefCell<ResourceManager>>,
    /// The render manager.
    pub render_mgr: Rc<RefCell<RenderManager>>,

    /// The project name.
    pub project_name: String,
    /// The project developer,
    pub project_developer: String,
    /// The project version.
    pub project_version: Version,

    // Private
    _is_in_main_loop: bool,
    _should_exit: bool,
}

/*===============================================================================================*/
/*------APP PUBLIC METHODS-----------------------------------------------------------------------*/
/*===============================================================================================*/

impl App {

    /// Initializes the app
    pub fn init (&self) {

        self._check_dirs_for_errors ();

        Logger::init (&format! ("{}ionEngine.log", Directory::get_persistent_data_directory ()), true).unwrap ();
        info! ("Initializing ionCore | Version: {}", env! ("CARGO_PKG_VERSION"));

        // Init the managers
        self._init_managers ();
    }

/*-----------------------------------------------------------------------------------------------*/

    /// The main app loop.
    pub fn run (&mut self) {

        self._is_in_main_loop = true;

        loop {

            let should_exit = self._should_exit;

            if !should_exit {
                self.render_mgr.borrow_mut ().process_window_events ();
            }

            else {

                self._is_in_main_loop = false;
                return;
            }
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Releases all resources, and exits the application.
    pub fn exit (&mut self) {

        // Check if in main loop
        if self._is_in_main_loop {

            info! ("Exiting main loop.");
            self._should_exit = true;
        }

        else {

            info! ("Shutting down ion Core.");

            // Release the managers, and release self
            self._release_managers ();
            App::_terminate ();
        }
    }

/*===============================================================================================*/
/*------APP PUBLIC STATIC METHODS----------------------------------------------------------------*/
/*===============================================================================================*/

    /// Returns a new App Builder.
    pub fn builder () -> AppBuilder {
        AppBuilder::new ()
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Checks if the app has been initialized.
    ///
    /// # Return value
    /// A bool returning whether the app has been initialized.
    pub fn is_initialized () -> bool {

        unsafe {

            match APP_POINTER {

                Some (pointer) => !pointer.is_null (),
                None => false
            }
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a reference to the app instance.
    pub fn get_instance () -> Result<&'static App, ()> {

        if App::is_initialized () {
            return Ok (unsafe {&*APP_POINTER.unwrap ()});
        }

        Err (())
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a mutable reference to the app instance.
    pub fn get_instance_mut () -> Result<&'static mut App, ()> {

        if App::is_initialized () {
            return Ok (unsafe {&mut *APP_POINTER.unwrap ()});
        }

        Err (())
    }

/*===============================================================================================*/
/*------APP PRIVATE METHODS----------------------------------------------------------------------*/
/*===============================================================================================*/

    // Initializes the various managers.
    fn _init_managers (&self) {

        self.resource_mgr.borrow_mut ().init ();
        self.render_mgr.borrow_mut   ().init ();
    }

/*-----------------------------------------------------------------------------------------------*/

    // Checks diretories for errors
    fn _check_dirs_for_errors (&self) {

        let res_dir = Directory::get_resource_directory ();
        let bin_dir = Directory::get_binary_directory ();
        let plg_dir = Directory::get_plugin_directory ();
        let cfg_dir = Directory::get_config_directory ();
        let pdd_dir = Directory::get_persistent_data_directory ();
        let pcd_dir = Directory::get_persistent_config_directory ();

        // Resource directory
        if !Path::new (&res_dir).exists () {
            panic! ("Resource path \"{}\" does not exist.\nApplication cannot continue.", &res_dir);
        }

        // Bin directory
        if !Path::new (&bin_dir).exists () {
            panic! ("Binary path \"{}\" does not exist.\nApplication cannot continue.", &bin_dir);
        }

        // Plugin directory
        if !Path::new (&plg_dir).exists () {
            panic! ("Plugin path \"{}\" does not exist.\nApplication cannot continue.", &plg_dir);
        }

        // Config directory
        if !Path::new (&cfg_dir).exists () {
            panic! ("Config path \"{}\" does not exist.\nApplication cannot continue.", &cfg_dir);
        }

        // Persistent data directory
        if !Path::new (&pdd_dir).exists () {

            if let Err (e) = fs::create_dir_all (&pdd_dir) {
                panic! ("Persistent data path \"{}\" could not be created.\n{}.\nApplication cannot continue.", &pdd_dir, e);
            }
        }

        // Persistent config directory
        if !Path::new (&pcd_dir).exists () {

            if let Err (e) = fs::create_dir_all (&pcd_dir) {
                panic! ("Persistent config path \"{}\" could not be created.\n{}.\nApplication cannot continue.", &pcd_dir, e);
            }
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    // Releases the managers
    fn _release_managers (&self) {
        self.render_mgr.borrow_mut ().release ();
    }

/*===============================================================================================*/
/*------APP PRIVATE STATIC METHODS---------------------------------------------------------------*/
/*===============================================================================================*/

    // Release the app pointer, and terminate the application.
    fn _terminate () {

        unsafe {

            drop (Box::from_raw (APP_POINTER.unwrap ()));
            APP_POINTER = None;
        };

        // Release the logger, and shutdown the application
        info! ("Terminating the application.");
        Logger::release ();

        process::exit (0);
    }
}

/*===============================================================================================*/
/*------APP BUILDER STRUCT-----------------------------------------------------------------------*/
/*===============================================================================================*/

/// Used for building a new, static app instance.
pub struct AppBuilder {

    // Private
    _project_name: String,
    _project_developer: String,
    _project_version: Version,
}

/*===============================================================================================*/
/*------APP BUILDER PUBLIC METHODS---------------------------------------------------------------*/
/*===============================================================================================*/

impl AppBuilder {

    /// Sets the app name.
    pub fn project_name (&mut self, name: &str) -> &mut Self {

        self._project_name = name.to_string ();
        self
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Sets the app developer.
    pub fn project_developer (&mut self, developer: &str) -> &mut Self {

        self._project_developer = developer.to_string ();
        self
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Sets the app version
    pub fn project_version (&mut self, version: Version) -> &mut Self {

        self._project_version = version;
        self
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Builds the app.
    pub fn build (&self) -> Result<&'static mut App, ()> {

        // Check if initialized
        if !App::is_initialized () {

            let ab = Box::new (App {

                resource_mgr:      Rc::new (RefCell::new (ResourceManager::new ())),
                render_mgr:        Rc::new (RefCell::new (RenderManager::new ())),

                project_name:      self._project_name.clone (),
                project_developer: self._project_developer.clone (),
                project_version:   self._project_version,

                _is_in_main_loop:  false,
                _should_exit:      false,
            });

            unsafe {APP_POINTER = Some (Box::into_raw (ab))};
        }

        App::get_instance_mut ()
    }

/*===============================================================================================*/
/*------APP BUILDER PUBLIC STATIC METHODS--------------------------------------------------------*/
/*===============================================================================================*/

    /// Returns a new app builder instance.
    pub fn new () -> AppBuilder {

        AppBuilder {

            _project_name:      "Untitled".to_string (),
            _project_developer: "Unknown".to_string (),
            _project_version:   Version::default (),
        }
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Default for AppBuilder {

    fn default () -> AppBuilder {
        AppBuilder::new ()
    }
}
<commit_msg>Removed the "_should_exit" bool<commit_after>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

use ::resource::ResourceManager;
use ::renderer::RenderManager;
use ::util::{Directory, Version, Logger};

use std::cell::RefCell;
use std::rc::Rc;
use std::boxed::Box;
use std::path::Path;
use std::fs;
use std::process;

/*===============================================================================================*/
/*------STATIC VARIABLES-------------------------------------------------------------------------*/
/*===============================================================================================*/

static mut APP_POINTER: Option <*mut App> = None;

/*===============================================================================================*/
/*------APP STRUCT-------------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The app
///
/// This is the main control center of ionCore.
/// It is in charge of initialization, updating, and shutdown of all modules,
/// as well as the handing of any inter-module communication.
pub struct App {

    // Public
    /// The resource manager.
    pub resource_mgr: Rc<RefCell<ResourceManager>>,
    /// The render manager.
    pub render_mgr: Rc<RefCell<RenderManager>>,

    /// The project name.
    pub project_name: String,
    /// The project developer,
    pub project_developer: String,
    /// The project version.
    pub project_version: Version,

    // Private
    _is_in_main_loop: bool,
}

/*===============================================================================================*/
/*------APP PUBLIC METHODS-----------------------------------------------------------------------*/
/*===============================================================================================*/

impl App {

    /// Initializes the app
    pub fn init (&self) {

        self._check_dirs_for_errors ();

        Logger::init (&format! ("{}ionEngine.log", Directory::get_persistent_data_directory ()), true).unwrap ();
        info! ("Initializing ionCore | Version: {}", env! ("CARGO_PKG_VERSION"));

        // Init the managers
        self._init_managers ();
    }

/*-----------------------------------------------------------------------------------------------*/

    /// The main app loop.
    pub fn run (&mut self) {

        self._is_in_main_loop = true;

        loop {

            if self._is_in_main_loop {
                self.render_mgr.borrow_mut ().process_window_events ();
            }

            else {
                return;
            }
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Releases all resources, and exits the application.
    pub fn exit (&mut self) {

        // Check if in main loop
        if self._is_in_main_loop {

            info! ("Exiting main loop.");
            self._is_in_main_loop = false;
        }

        else {

            info! ("Shutting down ion Core.");

            // Release the managers, and release self
            self._release_managers ();
            App::_terminate ();
        }
    }

/*===============================================================================================*/
/*------APP PUBLIC STATIC METHODS----------------------------------------------------------------*/
/*===============================================================================================*/

    /// Returns a new App Builder.
    pub fn builder () -> AppBuilder {
        AppBuilder::new ()
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Checks if the app has been initialized.
    ///
    /// # Return value
    /// A bool returning whether the app has been initialized.
    pub fn is_initialized () -> bool {

        unsafe {

            match APP_POINTER {

                Some (pointer) => !pointer.is_null (),
                None => false
            }
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a reference to the app instance.
    pub fn get_instance () -> Result<&'static App, ()> {

        if App::is_initialized () {
            return Ok (unsafe {&*APP_POINTER.unwrap ()});
        }

        Err (())
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns a mutable reference to the app instance.
    pub fn get_instance_mut () -> Result<&'static mut App, ()> {

        if App::is_initialized () {
            return Ok (unsafe {&mut *APP_POINTER.unwrap ()});
        }

        Err (())
    }

/*===============================================================================================*/
/*------APP PRIVATE METHODS----------------------------------------------------------------------*/
/*===============================================================================================*/

    // Initializes the various managers.
    fn _init_managers (&self) {

        self.resource_mgr.borrow_mut ().init ();
        self.render_mgr.borrow_mut   ().init ();
    }

/*-----------------------------------------------------------------------------------------------*/

    // Checks directories for errors
    fn _check_dirs_for_errors (&self) {

        let res_dir = Directory::get_resource_directory ();
        let bin_dir = Directory::get_binary_directory ();
        let plg_dir = Directory::get_plugin_directory ();
        let cfg_dir = Directory::get_config_directory ();
        let pdd_dir = Directory::get_persistent_data_directory ();
        let pcd_dir = Directory::get_persistent_config_directory ();

        // Resource directory
        if !Path::new (&res_dir).exists () {
            panic! ("Resource path \"{}\" does not exist.\nApplication cannot continue.", &res_dir);
        }

        // Bin directory
        if !Path::new (&bin_dir).exists () {
            panic! ("Binary path \"{}\" does not exist.\nApplication cannot continue.", &bin_dir);
        }

        // Plugin directory
        if !Path::new (&plg_dir).exists () {
            panic! ("Plugin path \"{}\" does not exist.\nApplication cannot continue.", &plg_dir);
        }

        // Config directory
        if !Path::new (&cfg_dir).exists () {
            panic! ("Config path \"{}\" does not exist.\nApplication cannot continue.", &cfg_dir);
        }

        // Persistent data directory
        if !Path::new (&pdd_dir).exists () {

            if let Err (e) = fs::create_dir_all (&pdd_dir) {
                panic! ("Persistent data path \"{}\" could not be created.\n{}.\nApplication cannot continue.", &pdd_dir, e);
            }
        }

        // Persistent config directory
        if !Path::new (&pcd_dir).exists () {

            if let Err (e) = fs::create_dir_all (&pcd_dir) {
                panic! ("Persistent config path \"{}\" could not be created.\n{}.\nApplication cannot continue.", &pcd_dir, e);
            }
        }
    }

/*-----------------------------------------------------------------------------------------------*/

    // Releases the managers
    fn _release_managers (&self) {
        self.render_mgr.borrow_mut ().release ();
    }

/*===============================================================================================*/
/*------APP PRIVATE STATIC METHODS---------------------------------------------------------------*/
/*===============================================================================================*/

    // Release the app pointer, and terminate the application.
    fn _terminate () {

        unsafe {

            drop (Box::from_raw (APP_POINTER.unwrap ()));
            APP_POINTER = None;
        };

        // Release the logger, and shutdown the application
        info! ("Terminating the application.");
        Logger::release ();

        process::exit (0);
    }
}

/*===============================================================================================*/
/*------APP BUILDER STRUCT-----------------------------------------------------------------------*/
/*===============================================================================================*/

/// Used for building a new, static app instance.
pub struct AppBuilder {

    // Private
    _project_name: String,
    _project_developer: String,
    _project_version: Version,
}

/*===============================================================================================*/
/*------APP BUILDER PUBLIC METHODS---------------------------------------------------------------*/
/*===============================================================================================*/

impl AppBuilder {

    /// Sets the app name.
    pub fn project_name (&mut self, name: &str) -> &mut Self {

        self._project_name = name.to_string ();
        self
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Sets the app developer.
    pub fn project_developer (&mut self, developer: &str) -> &mut Self {

        self._project_developer = developer.to_string ();
        self
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Sets the app version
    pub fn project_version (&mut self, version: Version) -> &mut Self {

        self._project_version = version;
        self
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Builds the app.
    pub fn build (&self) -> Result<&'static mut App, ()> {

        // Check if initialized
        if !App::is_initialized () {

            let ab = Box::new (App {

                resource_mgr:      Rc::new (RefCell::new (ResourceManager::new ())),
                render_mgr:        Rc::new (RefCell::new (RenderManager::new ())),

                project_name:      self._project_name.clone (),
                project_developer: self._project_developer.clone (),
                project_version:   self._project_version,

                _is_in_main_loop:  false,
            });

            unsafe {APP_POINTER = Some (Box::into_raw (ab))};
        }

        App::get_instance_mut ()
    }

/*===============================================================================================*/
/*------APP BUILDER PUBLIC STATIC METHODS--------------------------------------------------------*/
/*===============================================================================================*/

    /// Returns a new app builder instance.
    pub fn new () -> AppBuilder {

        AppBuilder {

            _project_name:      "Untitled".to_string (),
            _project_developer: "Unknown".to_string (),
            _project_version:   Version::default (),
        }
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Default for AppBuilder {

    fn default () -> AppBuilder {
        AppBuilder::new ()
    }
}
<|endoftext|>


<commit_before>//! This is the actual Bot module. For ergonomic reasons there is a RcBot which composes the real
//! bot as an underlying field. You should always use RcBot.

use error::Error;
use objects;

use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::rc::Rc;
use std::str;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};

use curl::easy::{Easy, List};
use futures::sync::mpsc;
use futures::sync::mpsc::UnboundedSender;
use futures::{stream, Future, IntoFuture, Stream};
use serde::de::DeserializeOwned;
use serde_json;
use tokio_core::reactor::{Handle, Interval};
use tokio_curl::Session;

const UPDATE_ID_EXPIRATION: Duration = Duration::from_secs(604800);

/// A clonable, single threaded bot
///
/// The outer API gets implemented on RcBot
#[derive(Clone)]
pub struct RcBot {
    pub inner: Rc<Bot>,
}

impl RcBot {
    pub fn new<'a>(handle: Handle, key: &str) -> impl Future<Item = RcBot, Error = Error> + 'a {
        use functions::FunctionGetMe;
        let bot = RcBot {
            inner: Rc::new(Bot::new(handle, key)),
        };
        bot.get_me().send().map(|(mut bot, me)| {
            Rc::get_mut(&mut bot.inner).as_mut().unwrap().id = me.id;
            Rc::get_mut(&mut bot.inner).as_mut().unwrap().username = me.username.unwrap();
            bot
        })
    }
}

/// The main bot structure
pub struct Bot {
    pub key: String,
    pub handle: Handle,
    pub last_id: Cell<u32>,
    pub timestamp: Cell<Instant>,
    pub update_interval: Cell<u64>,
    pub handlers: RefCell<HashMap<String, UnboundedSender<(RcBot, objects::Message)>>>,
    pub session: Session,
    pub username: String,
    pub id: i64,
}

impl Bot {
    pub fn new(handle: Handle, key: &str) -> Bot {
        Bot {
            handle: handle.clone(),
            key: key.into(),
            last_id: Cell::new(0),
            timestamp: Cell::new(Instant::now()),
            update_interval: Cell::new(1000),
            handlers: RefCell::new(HashMap::new()),
            session: Session::new(handle.clone()),
            username: String::new(),
            id: 0,
        }
    }

    /// Creates a new request and adds a JSON message to it. The returned Future contains a the
    /// reply as a string.  This method should be used if no file is added because a JSON msg is
    /// always compacter than a formdata one.
    pub fn fetch_json<'a, T: DeserializeOwned + 'a>(
        &self,
        func: &str,
        msg: &str,
    ) -> impl Future<Item = T, Error = Error> + 'a {
        debug!("Send JSON: {}", msg);

        let mut header = List::new();
        header.append("Content-Type: application/json").unwrap();

        let mut req = Easy::new();
        req.http_headers(header).unwrap();
        req.post_fields_copy(msg.as_bytes()).unwrap();
        req.post(true).unwrap();

        self.fetch(func, req)
    }

    /// calls cURL and parses the result for an error
    pub fn fetch<'a, T: DeserializeOwned + 'a>(
        &self,
        func: &str,
        mut req: Easy,
    ) -> impl Future<Item = T, Error = Error> + 'a {
        let result = Arc::new(Mutex::new(Vec::new()));

        req.url(&format!(
            "https://api.telegram.org/bot{}/{}",
            self.key, func
        )).unwrap();

        let r2 = result.clone();
        req.write_function(move |data| {
            r2.lock().unwrap().extend_from_slice(data);
            Ok(data.len())
        }).unwrap();

        self.session
            .perform(req)
            .map_err(|e| e.into())
            .and_then(move |_| {
                let response = result.lock().unwrap();
                let response = str::from_utf8(&response).unwrap();
                let response: Response<T> = serde_json::from_str(&response)?;
                if response.ok {
                    Ok(response.result.unwrap())
                } else {
                    Err(Error::Telegram(
                        response.error_code.unwrap(),
                        response.description.unwrap(),
                        response.parameters,
                    ))
                }
            })
    }
}

#[derive(Deserialize)]
struct Response<T> {
    ok: bool,
    result: Option<T>,
    error_code: Option<u32>,
    description: Option<String>,
    parameters: Option<objects::ResponseParameters>,
}

impl RcBot {
    /// Sets the update interval to an integer in milliseconds
    pub fn update_interval(self, interval: u64) -> RcBot {
        self.inner.update_interval.set(interval);

        self
    }

    /// Creates a new command and returns a stream which
    /// will yield a message when the command is send
    pub fn new_cmd(
        &self,
        cmd: &str,
    ) -> impl Stream<Item = (RcBot, objects::Message), Error = Error> {
        let (sender, receiver) = mpsc::unbounded();

        self.inner.handlers.borrow_mut().insert(cmd.into(), sender);

        receiver.map_err(|_| Error::Unknown)
    }

    /// Register a new commnd
    pub fn register<T>(&self, hnd: T)
    where
        T: Stream + 'static,
    {
        self.inner.handle.spawn(
            hnd.for_each(|_| Ok(()))
                .into_future()
                .map(|_| ())
                .map_err(|_| ()),
        );
    }

    /// The main update loop, the update function is called every update_interval milliseconds
    /// When an update is available the last_id will be updated and the message is filtered
    /// for commands
    /// The message is forwarded to the returned stream if no command was found
    pub fn get_stream<'a>(
        &'a self,
    ) -> impl Stream<Item = (RcBot, objects::Update), Error = Error> + 'a {
        use functions::*;

        Interval::new(
            Duration::from_millis(self.inner.update_interval.get()),
            &self.inner.handle,
        ).unwrap()
            .map_err(|_| Error::Unknown)
            .and_then(move |_| {
                self.get_updates()
                    .offset(self.inner.last_id.get())
                    .timeout(60)
                    .send()
            })
            .map(|(_, x)| stream::iter_ok(x.0))
            .flatten()
            .filter(move |x| {
                // If there are no new updates for at least a week, then update_id will be randomly.
                let fresh_update_id = Instant::now().duration_since(self.inner.timestamp.get()) < UPDATE_ID_EXPIRATION;
                let valid_update_id = self.inner.last_id.get() < x.update_id as u32 + 1;
                if !fresh_update_id || valid_update_id {
                    self.inner.timestamp.set(Instant::now());
                    self.inner.last_id.set(x.update_id as u32 + 1);
                }
                !fresh_update_id || valid_update_id
            })
            .filter_map(move |mut val| {
                debug!("Got an update from Telegram: {:?}", val);
                let mut forward: Option<String> = None;

                if let Some(ref mut message) = val.message {
                    if let Some(text) = message.text.clone() {
                        let mut content = text.split_whitespace();
                        if let Some(cmd) = content.next() {
                            let s: Vec<&str> = cmd.split("@").take(2).collect();
                            if s.len() > 0 && (s.len() < 2 || s[1] == self.inner.username)
                                && self.inner.handlers.borrow().contains_key(s[0])
                            {
                                message.text = Some(content.collect::<Vec<&str>>().join(" "));

                                forward = Some(s[0].into());
                            }
                        }
                    }
                }

                if let Some(cmd) = forward {
                    if let Some(sender) = self.inner.handlers.borrow_mut().get_mut(&cmd) {
                        sender
                            .unbounded_send((self.clone(), val.message.unwrap()))
                            .unwrap();
                    }
                    return None;
                } else {
                    return Some((self.clone(), val));
                }
            })
    }
}
<commit_msg>Format<commit_after>//! This is the actual Bot module. For ergonomic reasons there is a RcBot which composes the real
//! bot as an underlying field. You should always use RcBot.

use error::Error;
use objects;

use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::rc::Rc;
use std::str;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};

use curl::easy::{Easy, List};
use futures::sync::mpsc;
use futures::sync::mpsc::UnboundedSender;
use futures::{stream, Future, IntoFuture, Stream};
use serde::de::DeserializeOwned;
use serde_json;
use tokio_core::reactor::{Handle, Interval};
use tokio_curl::Session;

const UPDATE_ID_EXPIRATION: Duration = Duration::from_secs(604800);

/// A clonable, single threaded bot
///
/// The outer API gets implemented on RcBot
#[derive(Clone)]
pub struct RcBot {
    pub inner: Rc<Bot>,
}

impl RcBot {
    pub fn new<'a>(handle: Handle, key: &str) -> impl Future<Item = RcBot, Error = Error> + 'a {
        use functions::FunctionGetMe;
        let bot = RcBot {
            inner: Rc::new(Bot::new(handle, key)),
        };
        bot.get_me().send().map(|(mut bot, me)| {
            Rc::get_mut(&mut bot.inner).as_mut().unwrap().id = me.id;
            Rc::get_mut(&mut bot.inner).as_mut().unwrap().username = me.username.unwrap();
            bot
        })
    }
}

/// The main bot structure
pub struct Bot {
    pub key: String,
    pub handle: Handle,
    pub last_id: Cell<u32>,
    pub timestamp: Cell<Instant>,
    pub update_interval: Cell<u64>,
    pub handlers: RefCell<HashMap<String, UnboundedSender<(RcBot, objects::Message)>>>,
    pub session: Session,
    pub username: String,
    pub id: i64,
}

impl Bot {
    pub fn new(handle: Handle, key: &str) -> Bot {
        Bot {
            handle: handle.clone(),
            key: key.into(),
            last_id: Cell::new(0),
            timestamp: Cell::new(Instant::now()),
            update_interval: Cell::new(1000),
            handlers: RefCell::new(HashMap::new()),
            session: Session::new(handle.clone()),
            username: String::new(),
            id: 0,
        }
    }

    /// Creates a new request and adds a JSON message to it. The returned Future contains a the
    /// reply as a string.  This method should be used if no file is added because a JSON msg is
    /// always compacter than a formdata one.
    pub fn fetch_json<'a, T: DeserializeOwned + 'a>(
        &self,
        func: &str,
        msg: &str,
    ) -> impl Future<Item = T, Error = Error> + 'a {
        debug!("Send JSON: {}", msg);

        let mut header = List::new();
        header.append("Content-Type: application/json").unwrap();

        let mut req = Easy::new();
        req.http_headers(header).unwrap();
        req.post_fields_copy(msg.as_bytes()).unwrap();
        req.post(true).unwrap();

        self.fetch(func, req)
    }

    /// calls cURL and parses the result for an error
    pub fn fetch<'a, T: DeserializeOwned + 'a>(
        &self,
        func: &str,
        mut req: Easy,
    ) -> impl Future<Item = T, Error = Error> + 'a {
        let result = Arc::new(Mutex::new(Vec::new()));

        req.url(&format!(
            "https://api.telegram.org/bot{}/{}",
            self.key, func
        ))
        .unwrap();

        let r2 = result.clone();
        req.write_function(move |data| {
            r2.lock().unwrap().extend_from_slice(data);
            Ok(data.len())
        })
        .unwrap();

        self.session
            .perform(req)
            .map_err(|e| e.into())
            .and_then(move |_| {
                let response = result.lock().unwrap();
                let response = str::from_utf8(&response).unwrap();
                let response: Response<T> = serde_json::from_str(&response)?;
                if response.ok {
                    Ok(response.result.unwrap())
                } else {
                    Err(Error::Telegram(
                        response.error_code.unwrap(),
                        response.description.unwrap(),
                        response.parameters,
                    ))
                }
            })
    }
}

#[derive(Deserialize)]
struct Response<T> {
    ok: bool,
    result: Option<T>,
    error_code: Option<u32>,
    description: Option<String>,
    parameters: Option<objects::ResponseParameters>,
}

impl RcBot {
    /// Sets the update interval to an integer in milliseconds
    pub fn update_interval(self, interval: u64) -> RcBot {
        self.inner.update_interval.set(interval);

        self
    }

    /// Creates a new command and returns a stream which
    /// will yield a message when the command is send
    pub fn new_cmd(
        &self,
        cmd: &str,
    ) -> impl Stream<Item = (RcBot, objects::Message), Error = Error> {
        let (sender, receiver) = mpsc::unbounded();

        self.inner.handlers.borrow_mut().insert(cmd.into(), sender);

        receiver.map_err(|_| Error::Unknown)
    }

    /// Register a new commnd
    pub fn register<T>(&self, hnd: T)
    where
        T: Stream + 'static,
    {
        self.inner.handle.spawn(
            hnd.for_each(|_| Ok(()))
                .into_future()
                .map(|_| ())
                .map_err(|_| ()),
        );
    }

    /// The main update loop, the update function is called every update_interval milliseconds
    /// When an update is available the last_id will be updated and the message is filtered
    /// for commands
    /// The message is forwarded to the returned stream if no command was found
    pub fn get_stream<'a>(
        &'a self,
    ) -> impl Stream<Item = (RcBot, objects::Update), Error = Error> + 'a {
        use functions::*;

        Interval::new(
            Duration::from_millis(self.inner.update_interval.get()),
            &self.inner.handle,
        )
        .unwrap()
        .map_err(|_| Error::Unknown)
        .and_then(move |_| {
            self.get_updates()
                .offset(self.inner.last_id.get())
                .timeout(60)
                .send()
        })
        .map(|(_, x)| stream::iter_ok(x.0))
        .flatten()
        .filter(move |x| {
            // If there are no new updates for at least a week, then update_id will be randomly.
            let fresh_update_id =
                Instant::now().duration_since(self.inner.timestamp.get()) < UPDATE_ID_EXPIRATION;
            let valid_update_id = self.inner.last_id.get() < x.update_id as u32 + 1;
            if !fresh_update_id || valid_update_id {
                self.inner.timestamp.set(Instant::now());
                self.inner.last_id.set(x.update_id as u32 + 1);
            }
            !fresh_update_id || valid_update_id
        })
        .filter_map(move |mut val| {
            debug!("Got an update from Telegram: {:?}", val);
            let mut forward: Option<String> = None;

            if let Some(ref mut message) = val.message {
                if let Some(text) = message.text.clone() {
                    let mut content = text.split_whitespace();
                    if let Some(cmd) = content.next() {
                        let s: Vec<&str> = cmd.split("@").take(2).collect();
                        if s.len() > 0
                            && (s.len() < 2 || s[1] == self.inner.username)
                            && self.inner.handlers.borrow().contains_key(s[0])
                        {
                            message.text = Some(content.collect::<Vec<&str>>().join(" "));

                            forward = Some(s[0].into());
                        }
                    }
                }
            }

            if let Some(cmd) = forward {
                if let Some(sender) = self.inner.handlers.borrow_mut().get_mut(&cmd) {
                    sender
                        .unbounded_send((self.clone(), val.message.unwrap()))
                        .unwrap();
                }
                return None;
            } else {
                return Some((self.clone(), val));
            }
        })
    }
}
<|endoftext|>