<commit_before>// vim: tw=80
//! Test double adapter for use with Mockall
//!
//! This crate provides [`[#double]`](macro@double), which can swap in Mock
//! objects for real objects while in test mode.  It's intended to be used in
//! tandem with the [`mockall`](https://docs.rs/mockall/latest/mockall) crate.
//! However, it is defined in its own crate so that the bulk of Mockall can
//! remain a dev-dependency, instead of a regular dependency.

#![cfg_attr(feature = "nightly", feature(proc_macro_diagnostic))]
#![cfg_attr(test, deny(warnings))]
extern crate proc_macro;

use cfg_if::cfg_if;
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{
    *,
    spanned::Spanned
};

cfg_if! {
    // proc-macro2's Span::unstable method requires the nightly feature, and it
    // doesn't work in test mode.
    // https://github.com/alexcrichton/proc-macro2/issues/159
    if #[cfg(all(feature = "nightly", not(test)))] {
        fn compile_error(span: Span, msg: &'static str) {
            span.unstable()
                .error(msg)
                .emit();
        }
    } else {
        fn compile_error(_span: Span, msg: &str) {
            panic!("{}.  More information may be available when mockall_double is built with the \"nightly\" feature.", msg);
        }
    }
}

fn do_double(_attrs: TokenStream, input: TokenStream) -> TokenStream {
    let mut use_stmt: ItemUse = match parse2(input.clone()) {
        Ok(u) => u,
        Err(e) => return e.to_compile_error()
    };
    mock_itemuse(&mut use_stmt);
    quote!(
        #[cfg(not(test))]
        #input
        #[cfg(test)]
        #use_stmt
    )
}

/// Import a mock type in test mode, or a real type otherwise.
///
/// In a regular build, this macro is a no-op.  But when `#[cfg(test)]`, it
/// substitutes "MockXXX" for any imported "XXX".  This makes it easy to to use
/// mock objects, especially structs, in your unit tests.
///
/// This macro uses the same naming convention as
/// [`mockall`](https://docs.rs/mockall/latest/mockall), but doesn't strictly
/// require it.  It can work with hand-built Mock objects, or any other crate
/// using the same naming convention.
///
/// This is the most common way to use `#[double]`.  In order to replace a type,
/// it must come from a separate module.  So to mock type `Foo`, place it into a
/// submodule, along with its mock counterpart.  Then simply import `Foo` with
/// `#[double]` like this:
/// ```no_run
/// # use mockall_double::double;
/// mod foo {
///     pub(super) struct Foo {
///         // ...
///     }
///     #[cfg(test)]
///     pub(super) struct MockFoo {
///         // ...
///     }
/// }
/// #[double]
/// use foo::Foo;
/// ```
/// That will expand to the following:
/// ```no_run
/// # use mockall_double::double;
/// # mod foo { pub struct Foo {} }
/// #[cfg(not(test))]
/// use foo::Foo;
/// #[cfg(test)]
/// use foo::MockFoo as Foo;
/// ```
/// `#[double]` can handle deeply nested paths,
/// ```no_run
/// # use mockall_double::double;
/// # mod foo { pub mod bar { pub struct Baz{} } }
/// #[double]
/// use foo::bar::Baz;
/// ```
/// grouped imports,
/// ```no_run
/// # mod foo { pub mod bar { pub struct Baz{} pub struct Bean {} } }
/// # use mockall_double::double;
/// #[double]
/// use foo::bar::{
///     Baz,
///     Bean
/// };
/// ```
/// and renamed imports, too.  With renamed imports, it isn't even necessary to
/// declare a submodule.
/// ```no_run
/// # use mockall_double::double;
/// # struct Foo {}
/// #[double]
/// use Foo as Bar;
/// ```
/// Finally, `#[double]` can also import entire mocked modules, not just
/// structures.  In this case the naming convention is different.  It will
/// replace "xxx" with "mock_xxx".  For example:
/// ```no_run
/// # use mockall_double::double;
/// mod foo {
///     pub mod inner {
///         // ...
///     }
///     pub mod mock_inner {
///         // ...
///     }
/// }
/// #[double]
/// use foo::inner;
/// ```
/// will expand to:
/// ```no_run
/// # use mockall_double::double;
/// # mod foo { pub mod inner { } pub mod mock_inner { } }
/// #[cfg(not(test))]
/// use foo::inner;
/// #[cfg(test)]
/// use foo::mock_inner as inner;
/// ```
///
#[proc_macro_attribute]
pub fn double(attrs: proc_macro::TokenStream, input: proc_macro::TokenStream)
    -> proc_macro::TokenStream
{
    do_double(attrs.into(), input.into()).into()
}

fn mock_itemuse(orig: &mut ItemUse) {
    if let UseTree::Name(un) = &orig.tree {
        compile_error(un.span(),
            "Cannot double types in the current module.  Use a submodule (use foo::Foo) or a rename (use Foo as Bar)");
    } else {
        mock_usetree(&mut orig.tree)
    }
}

fn mock_ident(i: &Ident) -> Ident {
    let is_type = format!("{}", i)
        .chars()
        .next()
        .expect("zero-length ident?")
        .is_uppercase();
    if is_type {
        // probably a Type
        format_ident!("Mock{}", i)
    } else {
        // probably a module
        format_ident!("mock_{}", i)
    }
}

fn mock_usetree(mut orig: &mut UseTree) {
    match &mut orig {
        UseTree::Glob(star) => {
            compile_error(star.span(),
                "Cannot double glob imports.  Import by fully qualified name instead.");
        },
        UseTree::Group(ug) => {
            for ut in ug.items.iter_mut() {
                mock_usetree(ut);
            }
        },
        UseTree::Name(un) => {
            *orig = UseTree::Rename(UseRename {
                ident: mock_ident(&un.ident),
                as_token: <Token![as]>::default(),
                rename: un.ident.clone()
            });
        },
        UseTree::Path(up) => {
            mock_usetree(up.tree.as_mut());
        },
        UseTree::Rename(ur) => {
            ur.ident = mock_ident(&ur.ident)
        },
    }
}

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

mod double {
    use super::*;
    use std::str::FromStr;

    fn cmp(attrs: &str, code: &str, expected: &str) {
        let attrs_ts = TokenStream::from_str(attrs).unwrap();
        let code_ts = TokenStream::from_str(code).unwrap();
        let output = do_double(attrs_ts, code_ts);
        let output = output.to_string();
        // Round-trip expected through proc_macro2 so whitespace will be
        // identically formatted
        let expected = TokenStream::from_str(expected)
            .unwrap()
            .to_string();
        assert_eq!(output, expected);
    }

    #[test]
    #[should_panic(expected = "Cannot double glob")]
    fn glob() {
        let code = r#"use foo::*;"#;
        cmp("", &code, "");
    }

    #[test]
    fn group() {
        let code = r#"
            use foo::bar::{
                Baz,
                Bean
            };
        "#;
        let expected = r#"
            #[cfg(not(test))]
            use foo::bar::{
                Baz,
                Bean
            };
            #[cfg(test)]
            use foo::bar::{
                MockBaz as Baz,
                MockBean as Bean
            };
        "#;
        cmp("", &code, &expected);
    }

    #[test]
    fn module() {
        let code = r#"use foo::bar;"#;
        let expected = r#"
            #[cfg(not(test))]
            use foo::bar;
            #[cfg(test)]
            use foo::mock_bar as bar;
        "#;
        cmp("", &code, &expected);
    }

    #[test]
    #[should_panic(expected = "Cannot double types in the current module")]
    fn name() {
        let code = r#"use Foo;"#;
        cmp("", &code, "");
    }

    #[test]
    fn path() {
        let code = r#"use foo::bar::Baz;"#;
        let expected = r#"
            #[cfg(not(test))]
            use foo::bar::Baz;
            #[cfg(test)]
            use foo::bar::MockBaz as Baz;
        "#;
        cmp("", &code, &expected);
    }

    #[test]
    fn rename() {
        let code = r#"use Foo as Bar;"#;
        let expected = r#"
            #[cfg(not(test))]
            use Foo as Bar;
            #[cfg(test)]
            use MockFoo as Bar;
        "#;
        cmp("", &code, &expected);
    }

    #[test]
    fn not_use_stmt() {
        let code = r#"struct Foo{}"#;
        cmp("", &code, "compile_error!{\"expected `use`\"}");
    }
}
}

<commit_msg>corrected transposed letters<commit_after>// vim: tw=80
//! Test double adapter for use with Mockall
//!
//! This crate provides [`#[double]`](macro@double), which can swap in Mock
//! objects for real objects while in test mode.  It's intended to be used in
//! tandem with the [`mockall`](https://docs.rs/mockall/latest/mockall) crate.
//! However, it is defined in its own crate so that the bulk of Mockall can
//! remain a dev-dependency, instead of a regular dependency.

#![cfg_attr(feature = "nightly", feature(proc_macro_diagnostic))]
#![cfg_attr(test, deny(warnings))]
extern crate proc_macro;

use cfg_if::cfg_if;
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{
    *,
    spanned::Spanned
};

cfg_if! {
    // proc-macro2's Span::unstable method requires the nightly feature, and it
    // doesn't work in test mode.
    // https://github.com/alexcrichton/proc-macro2/issues/159
    if #[cfg(all(feature = "nightly", not(test)))] {
        fn compile_error(span: Span, msg: &'static str) {
            span.unstable()
                .error(msg)
                .emit();
        }
    } else {
        fn compile_error(_span: Span, msg: &str) {
            panic!("{}.  More information may be available when mockall_double is built with the \"nightly\" feature.", msg);
        }
    }
}

fn do_double(_attrs: TokenStream, input: TokenStream) -> TokenStream {
    let mut use_stmt: ItemUse = match parse2(input.clone()) {
        Ok(u) => u,
        Err(e) => return e.to_compile_error()
    };
    mock_itemuse(&mut use_stmt);
    quote!(
        #[cfg(not(test))]
        #input
        #[cfg(test)]
        #use_stmt
    )
}

/// Import a mock type in test mode, or a real type otherwise.
///
/// In a regular build, this macro is a no-op.  But when `#[cfg(test)]`, it
/// substitutes "MockXXX" for any imported "XXX".  This makes it easy to to use
/// mock objects, especially structs, in your unit tests.
///
/// This macro uses the same naming convention as
/// [`mockall`](https://docs.rs/mockall/latest/mockall), but doesn't strictly
/// require it.  It can work with hand-built Mock objects, or any other crate
/// using the same naming convention.
///
/// This is the most common way to use `#[double]`.  In order to replace a type,
/// it must come from a separate module.  So to mock type `Foo`, place it into a
/// submodule, along with its mock counterpart.  Then simply import `Foo` with
/// `#[double]` like this:
/// ```no_run
/// # use mockall_double::double;
/// mod foo {
///     pub(super) struct Foo {
///         // ...
///     }
///     #[cfg(test)]
///     pub(super) struct MockFoo {
///         // ...
///     }
/// }
/// #[double]
/// use foo::Foo;
/// ```
/// That will expand to the following:
/// ```no_run
/// # use mockall_double::double;
/// # mod foo { pub struct Foo {} }
/// #[cfg(not(test))]
/// use foo::Foo;
/// #[cfg(test)]
/// use foo::MockFoo as Foo;
/// ```
/// `#[double]` can handle deeply nested paths,
/// ```no_run
/// # use mockall_double::double;
/// # mod foo { pub mod bar { pub struct Baz{} } }
/// #[double]
/// use foo::bar::Baz;
/// ```
/// grouped imports,
/// ```no_run
/// # mod foo { pub mod bar { pub struct Baz{} pub struct Bean {} } }
/// # use mockall_double::double;
/// #[double]
/// use foo::bar::{
///     Baz,
///     Bean
/// };
/// ```
/// and renamed imports, too.  With renamed imports, it isn't even necessary to
/// declare a submodule.
/// ```no_run
/// # use mockall_double::double;
/// # struct Foo {}
/// #[double]
/// use Foo as Bar;
/// ```
/// Finally, `#[double]` can also import entire mocked modules, not just
/// structures.  In this case the naming convention is different.  It will
/// replace "xxx" with "mock_xxx".  For example:
/// ```no_run
/// # use mockall_double::double;
/// mod foo {
///     pub mod inner {
///         // ...
///     }
///     pub mod mock_inner {
///         // ...
///     }
/// }
/// #[double]
/// use foo::inner;
/// ```
/// will expand to:
/// ```no_run
/// # use mockall_double::double;
/// # mod foo { pub mod inner { } pub mod mock_inner { } }
/// #[cfg(not(test))]
/// use foo::inner;
/// #[cfg(test)]
/// use foo::mock_inner as inner;
/// ```
///
#[proc_macro_attribute]
pub fn double(attrs: proc_macro::TokenStream, input: proc_macro::TokenStream)
    -> proc_macro::TokenStream
{
    do_double(attrs.into(), input.into()).into()
}

fn mock_itemuse(orig: &mut ItemUse) {
    if let UseTree::Name(un) = &orig.tree {
        compile_error(un.span(),
            "Cannot double types in the current module.  Use a submodule (use foo::Foo) or a rename (use Foo as Bar)");
    } else {
        mock_usetree(&mut orig.tree)
    }
}

fn mock_ident(i: &Ident) -> Ident {
    let is_type = format!("{}", i)
        .chars()
        .next()
        .expect("zero-length ident?")
        .is_uppercase();
    if is_type {
        // probably a Type
        format_ident!("Mock{}", i)
    } else {
        // probably a module
        format_ident!("mock_{}", i)
    }
}

fn mock_usetree(mut orig: &mut UseTree) {
    match &mut orig {
        UseTree::Glob(star) => {
            compile_error(star.span(),
                "Cannot double glob imports.  Import by fully qualified name instead.");
        },
        UseTree::Group(ug) => {
            for ut in ug.items.iter_mut() {
                mock_usetree(ut);
            }
        },
        UseTree::Name(un) => {
            *orig = UseTree::Rename(UseRename {
                ident: mock_ident(&un.ident),
                as_token: <Token![as]>::default(),
                rename: un.ident.clone()
            });
        },
        UseTree::Path(up) => {
            mock_usetree(up.tree.as_mut());
        },
        UseTree::Rename(ur) => {
            ur.ident = mock_ident(&ur.ident)
        },
    }
}

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

mod double {
    use super::*;
    use std::str::FromStr;

    fn cmp(attrs: &str, code: &str, expected: &str) {
        let attrs_ts = TokenStream::from_str(attrs).unwrap();
        let code_ts = TokenStream::from_str(code).unwrap();
        let output = do_double(attrs_ts, code_ts);
        let output = output.to_string();
        // Round-trip expected through proc_macro2 so whitespace will be
        // identically formatted
        let expected = TokenStream::from_str(expected)
            .unwrap()
            .to_string();
        assert_eq!(output, expected);
    }

    #[test]
    #[should_panic(expected = "Cannot double glob")]
    fn glob() {
        let code = r#"use foo::*;"#;
        cmp("", &code, "");
    }

    #[test]
    fn group() {
        let code = r#"
            use foo::bar::{
                Baz,
                Bean
            };
        "#;
        let expected = r#"
            #[cfg(not(test))]
            use foo::bar::{
                Baz,
                Bean
            };
            #[cfg(test)]
            use foo::bar::{
                MockBaz as Baz,
                MockBean as Bean
            };
        "#;
        cmp("", &code, &expected);
    }

    #[test]
    fn module() {
        let code = r#"use foo::bar;"#;
        let expected = r#"
            #[cfg(not(test))]
            use foo::bar;
            #[cfg(test)]
            use foo::mock_bar as bar;
        "#;
        cmp("", &code, &expected);
    }

    #[test]
    #[should_panic(expected = "Cannot double types in the current module")]
    fn name() {
        let code = r#"use Foo;"#;
        cmp("", &code, "");
    }

    #[test]
    fn path() {
        let code = r#"use foo::bar::Baz;"#;
        let expected = r#"
            #[cfg(not(test))]
            use foo::bar::Baz;
            #[cfg(test)]
            use foo::bar::MockBaz as Baz;
        "#;
        cmp("", &code, &expected);
    }

    #[test]
    fn rename() {
        let code = r#"use Foo as Bar;"#;
        let expected = r#"
            #[cfg(not(test))]
            use Foo as Bar;
            #[cfg(test)]
            use MockFoo as Bar;
        "#;
        cmp("", &code, &expected);
    }

    #[test]
    fn not_use_stmt() {
        let code = r#"struct Foo{}"#;
        cmp("", &code, "compile_error!{\"expected `use`\"}");
    }
}
}

<|endoftext|>


<commit_before>// Chains with comment.

fn main() {
    let x = y // comment
        .z;

    foo // foo
        // comment after parent
        .x
        .y
        // comment 1
        .bar() // comment after bar()
        // comment 2
        .foobar
        // comment after
        // comment 3
        .baz(x, y, z);

    self.rev_dep_graph
        .iter()
        // Remove nodes that are not dirty
        .filter(|&(unit, _)| dirties.contains(&unit))
        // Retain only dirty dependencies of the ones that are dirty
        .map(|(k, deps)| {
            (
                k.clone(),
                deps.iter()
                    .cloned()
                    .filter(|d| dirties.contains(&d))
                    .collect(),
            )
        });

    let y = expr
        /* comment */
        .kaas()?
        // comment
        .test();
    let loooooooooooooooooooooooooooooooooooooooooong = does_this?
        .look?
        .good?
        .should_we_break?
        .after_the_first_question_mark?;
    let zzzz = expr? // comment after parent
        // comment 0
        .another??? // comment 1
        .another???? // comment 2
        .another? // comment 3
        .another?;

    let y = a
        .very
        .loooooooooooooooooooooooooooooooooooooong()
        /* comment */
        .chain()
        .inside()
        /* comment */
        .weeeeeeeeeeeeeee()?
        .test()
        .0
        .x;

    parameterized(f, substs, def_id, Ns::Value, &[], |tcx| {
        tcx.lookup_item_type(def_id).generics
    })?;
    fooooooooooooooooooooooooooo()?
        .bar()?
        .baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz()?;

    // #2559
    App::new("cargo-cache")
        .version(crate_version!())
        .bin_name("cargo")
        .about("Manage cargo cache")
        .author("matthiaskrgr")
        .subcommand(
            SubCommand::with_name("cache")
                .version(crate_version!())
                .bin_name("cargo-cache")
                .about("Manage cargo cache")
                .author("matthiaskrgr")
                .arg(&list_dirs)
                .arg(&remove_dir)
                .arg(&gc_repos)
                .arg(&info)
                .arg(&keep_duplicate_crates)
                .arg(&dry_run)
                .arg(&auto_clean)
                .arg(&auto_clean_expensive),
        ) // subcommand
        .arg(&list_dirs);
}

// #2177
impl Foo {
    fn dirty_rev_dep_graph(
        &self,
        dirties: &HashSet<UnitKey>,
    ) -> HashMap<UnitKey, HashSet<UnitKey>> {
        let dirties = self.transitive_dirty_units(dirties);
        trace!("transitive_dirty_units: {:?}", dirties);

        self.rev_dep_graph
            .iter()
            // Remove nodes that are not dirty
            .filter(|&(unit, _)| dirties.contains(&unit))
            // Retain only dirty dependencies of the ones that are dirty
            .map(|(k, deps)| {
                (
                    k.clone(),
                    deps.iter()
                        .cloned()
                        .filter(|d| dirties.contains(&d))
                        .collect(),
                )
            })
    }
}

// #2907
fn foo() {
    let x = foo
        .bar??? // comment
        .baz;
    let x = foo
        .bar???
        // comment
        .baz;
    let x = foo
        .bar??? // comment
        // comment
        .baz;
    let x = foo
        .bar??????????????? // comment
        // comment
        // comment
        // comment
        // comment
        .baz;
}
<commit_msg>Update tests<commit_after>// Chains with comment.

fn main() {
    let x = y // comment
        .z;

    foo // foo
        // comment after parent
        .x
        .y
        // comment 1
        .bar() // comment after bar()
        // comment 2
        .foobar
        // comment after
        // comment 3
        .baz(x, y, z);

    self.rev_dep_graph
        .iter()
        // Remove nodes that are not dirty
        .filter(|&(unit, _)| dirties.contains(&unit))
        // Retain only dirty dependencies of the ones that are dirty
        .map(|(k, deps)| {
            (
                k.clone(),
                deps.iter()
                    .cloned()
                    .filter(|d| dirties.contains(&d))
                    .collect(),
            )
        });

    let y = expr /* comment */
        .kaas()?
        // comment
        .test();
    let loooooooooooooooooooooooooooooooooooooooooong = does_this?
        .look?
        .good?
        .should_we_break?
        .after_the_first_question_mark?;
    let zzzz = expr? // comment after parent
        // comment 0
        .another??? // comment 1
        .another???? // comment 2
        .another? // comment 3
        .another?;

    let y = a
        .very
        .loooooooooooooooooooooooooooooooooooooong() /* comment */
        .chain()
        .inside() /* comment */
        .weeeeeeeeeeeeeee()?
        .test()
        .0
        .x;

    parameterized(f, substs, def_id, Ns::Value, &[], |tcx| {
        tcx.lookup_item_type(def_id).generics
    })?;
    fooooooooooooooooooooooooooo()?
        .bar()?
        .baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz()?;

    // #2559
    App::new("cargo-cache")
        .version(crate_version!())
        .bin_name("cargo")
        .about("Manage cargo cache")
        .author("matthiaskrgr")
        .subcommand(
            SubCommand::with_name("cache")
                .version(crate_version!())
                .bin_name("cargo-cache")
                .about("Manage cargo cache")
                .author("matthiaskrgr")
                .arg(&list_dirs)
                .arg(&remove_dir)
                .arg(&gc_repos)
                .arg(&info)
                .arg(&keep_duplicate_crates)
                .arg(&dry_run)
                .arg(&auto_clean)
                .arg(&auto_clean_expensive),
        ) // subcommand
        .arg(&list_dirs);
}

// #2177
impl Foo {
    fn dirty_rev_dep_graph(
        &self,
        dirties: &HashSet<UnitKey>,
    ) -> HashMap<UnitKey, HashSet<UnitKey>> {
        let dirties = self.transitive_dirty_units(dirties);
        trace!("transitive_dirty_units: {:?}", dirties);

        self.rev_dep_graph
            .iter()
            // Remove nodes that are not dirty
            .filter(|&(unit, _)| dirties.contains(&unit))
            // Retain only dirty dependencies of the ones that are dirty
            .map(|(k, deps)| {
                (
                    k.clone(),
                    deps.iter()
                        .cloned()
                        .filter(|d| dirties.contains(&d))
                        .collect(),
                )
            })
    }
}

// #2907
fn foo() {
    let x = foo
        .bar??? // comment
        .baz;
    let x = foo
        .bar???
        // comment
        .baz;
    let x = foo
        .bar??? // comment
        // comment
        .baz;
    let x = foo
        .bar??????????????? // comment
        // comment
        // comment
        // comment
        // comment
        .baz;
}
<|endoftext|>


<commit_before>use std::net::SocketAddr;
use std::io;

use solicit::http::session::StreamState;
use solicit::http::connection::EndStream;
use solicit::http::connection::SendFrame;
use solicit::http::frame::*;
use solicit::http::StreamId;
use solicit::http::HttpScheme;
use solicit::http::HttpError;
use solicit::http::StaticHeader;
use hpack;

use futures;
use futures::Future;
use futures::stream::Stream;

use tokio_core;
use tokio_core::net::TcpStream;
use tokio_core::io as tokio_io;
use tokio_core::io::Io;
use tokio_core::io::WriteHalf;
use tokio_core::reactor;

use tokio_tls;

use futures_misc::*;

use solicit_async::*;
use solicit_misc::*;

use http_common::*;

struct GrpcHttpClientStream {
    common: GrpcHttpStreamCommon,
    response_handler: Option<tokio_core::channel::Sender<ResultOrEof<HttpStreamPart, HttpError>>>,
}

impl GrpcHttpStream for GrpcHttpClientStream {
    fn common(&self) -> &GrpcHttpStreamCommon {
        &self.common
    }

    fn common_mut(&mut self) -> &mut GrpcHttpStreamCommon {
        &mut self.common
    }

    fn new_data_chunk(&mut self, data: &[u8], last: bool) {
        if let Some(ref mut response_handler) = self.response_handler {
            response_handler.send(ResultOrEof::Item(HttpStreamPart {
                content: HttpStreamPartContent::Data(data.to_owned()),
                last: last,
            })).unwrap();
        }
    }

    fn close_remote(&mut self) {
        let next = match self.state() {
            StreamState::HalfClosedLocal => StreamState::Closed,
            _ => StreamState::HalfClosedRemote,
        };
        self.set_state(next);
        if let Some(response_handler) = self.response_handler.take() {
            response_handler.send(ResultOrEof::Eof).unwrap();
        }
    }
}

impl GrpcHttpClientStream {

    fn _close(&mut self) {
        self.set_state(StreamState::Closed);
    }

    fn _close_local(&mut self) {
        let next = match self.state() {
            StreamState::HalfClosedRemote => StreamState::Closed,
            _ => StreamState::HalfClosedLocal,
        };
        self.set_state(next);
    }

    fn _is_closed(&self) -> bool {
        self.state() == StreamState::Closed
    }

    fn _is_closed_local(&self) -> bool {
        match self.state() {
            StreamState::HalfClosedLocal | StreamState::Closed => true,
            _ => false,
        }
    }

    fn _is_closed_remote(&self) -> bool {
        match self.state() {
            StreamState::HalfClosedRemote | StreamState::Closed => true,
            _ => false,
        }
    }

    fn set_state(&mut self, state: StreamState) {
        self.common.state = state;
    }

    fn state(&self) -> StreamState {
        self.common.state
    }
}

struct GrpcHttpClientSessionState {
    next_stream_id: StreamId,
    decoder: hpack::Decoder<'static>,
    loop_handle: reactor::Handle,
}

struct ClientInner {
    common: LoopInnerCommon<GrpcHttpClientStream>,
    to_write_tx: tokio_core::channel::Sender<ClientToWriteMessage>,
    session_state: GrpcHttpClientSessionState,
}

impl ClientInner {
    fn insert_stream(&mut self, stream: GrpcHttpClientStream) -> StreamId {
        let id = self.session_state.next_stream_id;
        if let Some(..) = self.common.streams.insert(id, stream) {
            panic!("inserted stream that already existed");
        }
        self.session_state.next_stream_id += 2;
        id
    }

    fn _get_stream_ref(&self, stream_id: StreamId) -> Option<&GrpcHttpClientStream> {
        self.common.streams.get(&stream_id)
    }
}

impl LoopInner for ClientInner {
    type LoopHttpStream = GrpcHttpClientStream;

    fn common(&mut self) -> &mut LoopInnerCommon<GrpcHttpClientStream> {
        &mut self.common
    }

    fn send_common(&mut self, message: CommonToWriteMessage) {
        self.to_write_tx.send(ClientToWriteMessage::Common(message))
            .expect("read to write common");
    }

    fn process_headers_frame(&mut self, frame: HeadersFrame) {
        let headers = self.session_state.decoder
                               .decode(&frame.header_fragment())
                               .map_err(HttpError::CompressionError).unwrap();
        let headers: Vec<StaticHeader> = headers.into_iter().map(|h| h.into()).collect();

        let mut stream: &mut GrpcHttpClientStream = match self.common.get_stream_mut(frame.get_stream_id()) {
            None => {
                // TODO(mlalic): This means that the server's header is not associated to any
                //               request made by the client nor any server-initiated stream (pushed)
                return;
            }
            Some(stream) => stream,
        };
        // TODO: hack
        if headers.len() != 0 {

            if let Some(ref mut response_handler) = stream.response_handler {
                response_handler.send(ResultOrEof::Item(HttpStreamPart {
                    content: HttpStreamPartContent::Headers(headers),
                    last: frame.is_end_of_stream(),
                })).unwrap();
            }
        }
    }
}

pub struct HttpClientConnectionAsync {
    call_tx: tokio_core::channel::Sender<ClientToWriteMessage>,
    remote: reactor::Remote,
}

unsafe impl  Sync for HttpClientConnectionAsync {}

struct StartRequestMessage {
    headers: Vec<StaticHeader>,
    body: HttpStreamSend<Vec<u8>>,
    response_handler: tokio_core::channel::Sender<ResultOrEof<HttpStreamPart, HttpError>>,
}

struct BodyChunkMessage {
    stream_id: StreamId,
    chunk: Vec<u8>,
}

struct EndRequestMessage {
    stream_id: StreamId,
}

enum ClientToWriteMessage {
    Start(StartRequestMessage),
    BodyChunk(BodyChunkMessage),
    End(EndRequestMessage),
    Common(CommonToWriteMessage),
}

struct ClientWriteLoop<I : Io + Send + 'static> {
    write: WriteHalf<I>,
    inner: TaskRcMut<ClientInner>,
}

impl<I : Io + Send + 'static> WriteLoop for ClientWriteLoop<I> {
    type Inner = ClientInner;

    fn with_inner<G, R>(&self, f: G) -> R
        where G: FnOnce(&mut Self::Inner) -> R
    {
        self.inner.with(f)
    }

    fn write_all(self, buf: Vec<u8>) -> HttpFuture<Self> {
        let ClientWriteLoop { write, inner } = self;

        Box::new(tokio_io::write_all(write, buf)
            .map(move |(write, _)| ClientWriteLoop { write: write, inner: inner })
            .map_err(HttpError::from))
    }
}

impl<I : Io + Send + 'static> ClientWriteLoop<I> {
    fn process_start(self, start: StartRequestMessage) -> HttpFuture<Self> {
        let StartRequestMessage { headers, body, response_handler } = start;

        /*

        let stream_id = self.inner.with(move |inner: &mut ClientInner| {

            let stream = GrpcHttpClientStream {
                common: GrpcHttpStreamCommon::new(),
                response_handler: Some(response_handler),
            };

            stream.common.outgoing.push_back(HttpStreamPartContent::Headers(headers));

            inner.insert_stream(stream)
        });

        */

        let (buf, stream_id) = self.inner.with(move |inner: &mut ClientInner| {

            let stream = GrpcHttpClientStream {
                common: GrpcHttpStreamCommon::new(),
                response_handler: Some(response_handler),
            };
            let stream_id = inner.insert_stream(stream);

            let send_buf = inner.common.conn.send_headers_to_vec(stream_id, &headers, EndStream::No).unwrap();

            (send_buf, stream_id)
        });

        let to_write_tx_1 = self.inner.with(|inner| inner.to_write_tx.clone());
        let to_write_tx_2 = to_write_tx_1.clone();

        self.inner.with(|inner: &mut ClientInner| {
            let future = body
                .fold((), move |(), chunk| {
                    to_write_tx_1.send(ClientToWriteMessage::BodyChunk(BodyChunkMessage {
                        stream_id: stream_id,
                        chunk: chunk,
                    })).unwrap();
                    futures::finished::<_, HttpError>(())
                });
            let future = future
                .and_then(move |()| {
                    to_write_tx_2.send(ClientToWriteMessage::End(EndRequestMessage {
                        stream_id: stream_id,
                    })).unwrap();
                    futures::finished::<_, HttpError>(())
                });

            let future = future.map_err(|e| {
                warn!("{:?}", e);
                ()
            });

            inner.session_state.loop_handle.spawn(future);
        });

        Box::new(self.write_all(buf))
    }

    fn process_body_chunk(self, body_chunk: BodyChunkMessage) -> HttpFuture<Self> {
        let BodyChunkMessage { stream_id, chunk } = body_chunk;

        self.inner.with(move |inner: &mut ClientInner| {
            let stream = inner.common.get_stream_mut(stream_id)
                .expect(&format!("stream not found: {}", stream_id));
            // TODO: check stream state

            stream.common.outgoing.push_front(HttpStreamPartContent::Data(chunk));
        });

        self.send_outg_stream(stream_id)
    }

    fn process_end(self, end: EndRequestMessage) -> HttpFuture<Self> {
        let EndRequestMessage { stream_id } = end;

        let buf = self.inner.with(move |inner: &mut ClientInner| {
            inner.common.conn.send_end_of_stream_to_vec(stream_id).unwrap()
        });

        self.write_all(buf)
    }

    fn process_message(self, message: ClientToWriteMessage) -> HttpFuture<Self> {
        match message {
            ClientToWriteMessage::Start(start) => self.process_start(start),
            ClientToWriteMessage::BodyChunk(body_chunk) => self.process_body_chunk(body_chunk),
            ClientToWriteMessage::End(end) => self.process_end(end),
            ClientToWriteMessage::Common(common) => self.process_common(common),
        }
    }

    fn run(self, requests: HttpStreamSend<ClientToWriteMessage>) -> HttpFuture<()> {
        let requests = requests.map_err(HttpError::from);
        Box::new(requests
            .fold(self, move |wl, message: ClientToWriteMessage| {
                wl.process_message(message)
            })
            .map(|_| ()))
    }
}

type ClientReadLoop<I> = HttpReadLoopData<I, ClientInner>;

impl HttpClientConnectionAsync {
    fn connected<I : Io + Send + 'static>(lh: reactor::Handle, connect: HttpFutureSend<I>) -> (Self, HttpFuture<()>) {
        let (to_write_tx, to_write_rx) = tokio_core::channel::channel(&lh).unwrap();

        let to_write_rx = Box::new(to_write_rx.map_err(HttpError::from));

        let c = HttpClientConnectionAsync {
            remote: lh.remote().clone(),
            call_tx: to_write_tx.clone(),
        };

        let handshake = connect.and_then(client_handshake);

        let future = handshake.and_then(move |conn| {
            trace!("handshake done");
            let (read, write) = conn.split();

            let inner = TaskRcMut::new(ClientInner {
                common: LoopInnerCommon::new(HttpScheme::Http),
                to_write_tx: to_write_tx.clone(),
                session_state: GrpcHttpClientSessionState {
                    next_stream_id: 1,
                    decoder: hpack::Decoder::new(),
                    loop_handle: lh,
                }
            });

            let write_inner = inner.clone();
            let run_write = ClientWriteLoop { write: write, inner: write_inner }.run(to_write_rx);
            let run_read = ClientReadLoop { read: read, inner: inner.clone() }.run();

            run_write.join(run_read).map(|_| ())
        });

        (c, Box::new(future))
    }

    pub fn new_plain(lh: reactor::Handle, addr: &SocketAddr) -> (Self, HttpFuture<()>) {
        let addr = addr.clone();

        let connect = TcpStream::connect(&addr, &lh)
            .map(move |c| { info!("connected to {}", addr); c })
            .map_err(|e| e.into());

        HttpClientConnectionAsync::connected(lh, Box::new(connect))
    }

    pub fn new_tls(lh: reactor::Handle, addr: &SocketAddr) -> (Self, HttpFuture<()>) {
        unimplemented!()
        /*
        let addr = addr.clone();

        let connect = TcpStream::connect(&addr, &lh)
            .map(move |c| { info!("connected to {}", addr); c })
            .map_err(|e| e.into());

        let tls_conn = connect.and_then(|conn| {
            tokio_tls::ClientContext::new()
                .unwrap()
                .handshake("localhost", conn)
        });

        let tls_conn = tls_conn.map_err(HttpError::from);

        HttpClientConnectionAsync::connected(lh, Box::new(tls_conn))
        */
    }

    pub fn start_request(
        &self,
        headers: Vec<StaticHeader>,
        body: HttpStreamSend<Vec<u8>>)
            -> HttpStreamStreamSend
    {
        let (tx, rx) = futures::oneshot();

        let call_tx = self.call_tx.clone();

        self.remote.spawn(move |handle| {
            let (req_tx, req_rx) = tokio_core::channel::channel(&handle).unwrap();

            call_tx.send(ClientToWriteMessage::Start(StartRequestMessage {
                headers: headers,
                body: body,
                response_handler: req_tx,
            })).unwrap();

            let req_rx = req_rx.map_err(HttpError::from);

            tx.complete(stream_with_eof_and_error(req_rx, || HttpError::from(io::Error::new(io::ErrorKind::Other, "unexpected eof"))));

            Ok(())
        });

        let rx = rx.map_err(|_| HttpError::from(io::Error::new(io::ErrorKind::Other, "oneshot canceled")));

        Box::new(rx.flatten_stream())
    }
}
<commit_msg>do flow control on client<commit_after>use std::net::SocketAddr;
use std::io;

use solicit::http::session::StreamState;
use solicit::http::connection::EndStream;
use solicit::http::connection::SendFrame;
use solicit::http::frame::*;
use solicit::http::StreamId;
use solicit::http::HttpScheme;
use solicit::http::HttpError;
use solicit::http::StaticHeader;
use hpack;

use futures;
use futures::Future;
use futures::stream::Stream;

use tokio_core;
use tokio_core::net::TcpStream;
use tokio_core::io as tokio_io;
use tokio_core::io::Io;
use tokio_core::io::WriteHalf;
use tokio_core::reactor;

use tokio_tls;

use futures_misc::*;

use solicit_async::*;
use solicit_misc::*;

use http_common::*;

struct GrpcHttpClientStream {
    common: GrpcHttpStreamCommon,
    response_handler: Option<tokio_core::channel::Sender<ResultOrEof<HttpStreamPart, HttpError>>>,
}

impl GrpcHttpStream for GrpcHttpClientStream {
    fn common(&self) -> &GrpcHttpStreamCommon {
        &self.common
    }

    fn common_mut(&mut self) -> &mut GrpcHttpStreamCommon {
        &mut self.common
    }

    fn new_data_chunk(&mut self, data: &[u8], last: bool) {
        if let Some(ref mut response_handler) = self.response_handler {
            response_handler.send(ResultOrEof::Item(HttpStreamPart {
                content: HttpStreamPartContent::Data(data.to_owned()),
                last: last,
            })).unwrap();
        }
    }

    fn close_remote(&mut self) {
        let next = match self.state() {
            StreamState::HalfClosedLocal => StreamState::Closed,
            _ => StreamState::HalfClosedRemote,
        };
        self.set_state(next);
        if let Some(response_handler) = self.response_handler.take() {
            response_handler.send(ResultOrEof::Eof).unwrap();
        }
    }
}

impl GrpcHttpClientStream {

    fn _close(&mut self) {
        self.set_state(StreamState::Closed);
    }

    fn _close_local(&mut self) {
        let next = match self.state() {
            StreamState::HalfClosedRemote => StreamState::Closed,
            _ => StreamState::HalfClosedLocal,
        };
        self.set_state(next);
    }

    fn _is_closed(&self) -> bool {
        self.state() == StreamState::Closed
    }

    fn _is_closed_local(&self) -> bool {
        match self.state() {
            StreamState::HalfClosedLocal | StreamState::Closed => true,
            _ => false,
        }
    }

    fn _is_closed_remote(&self) -> bool {
        match self.state() {
            StreamState::HalfClosedRemote | StreamState::Closed => true,
            _ => false,
        }
    }

    fn set_state(&mut self, state: StreamState) {
        self.common.state = state;
    }

    fn state(&self) -> StreamState {
        self.common.state
    }
}

struct GrpcHttpClientSessionState {
    next_stream_id: StreamId,
    decoder: hpack::Decoder<'static>,
    loop_handle: reactor::Handle,
}

struct ClientInner {
    common: LoopInnerCommon<GrpcHttpClientStream>,
    to_write_tx: tokio_core::channel::Sender<ClientToWriteMessage>,
    session_state: GrpcHttpClientSessionState,
}

impl ClientInner {
    fn insert_stream(&mut self, stream: GrpcHttpClientStream) -> StreamId {
        let id = self.session_state.next_stream_id;
        if let Some(..) = self.common.streams.insert(id, stream) {
            panic!("inserted stream that already existed");
        }
        self.session_state.next_stream_id += 2;
        id
    }

    fn _get_stream_ref(&self, stream_id: StreamId) -> Option<&GrpcHttpClientStream> {
        self.common.streams.get(&stream_id)
    }
}

impl LoopInner for ClientInner {
    type LoopHttpStream = GrpcHttpClientStream;

    fn common(&mut self) -> &mut LoopInnerCommon<GrpcHttpClientStream> {
        &mut self.common
    }

    fn send_common(&mut self, message: CommonToWriteMessage) {
        self.to_write_tx.send(ClientToWriteMessage::Common(message))
            .expect("read to write common");
    }

    fn process_headers_frame(&mut self, frame: HeadersFrame) {
        let headers = self.session_state.decoder
                               .decode(&frame.header_fragment())
                               .map_err(HttpError::CompressionError).unwrap();
        let headers: Vec<StaticHeader> = headers.into_iter().map(|h| h.into()).collect();

        let mut stream: &mut GrpcHttpClientStream = match self.common.get_stream_mut(frame.get_stream_id()) {
            None => {
                // TODO(mlalic): This means that the server's header is not associated to any
                //               request made by the client nor any server-initiated stream (pushed)
                return;
            }
            Some(stream) => stream,
        };
        // TODO: hack
        if headers.len() != 0 {

            if let Some(ref mut response_handler) = stream.response_handler {
                response_handler.send(ResultOrEof::Item(HttpStreamPart {
                    content: HttpStreamPartContent::Headers(headers),
                    last: frame.is_end_of_stream(),
                })).unwrap();
            }
        }
    }
}

pub struct HttpClientConnectionAsync {
    call_tx: tokio_core::channel::Sender<ClientToWriteMessage>,
    remote: reactor::Remote,
}

unsafe impl  Sync for HttpClientConnectionAsync {}

struct StartRequestMessage {
    headers: Vec<StaticHeader>,
    body: HttpStreamSend<Vec<u8>>,
    response_handler: tokio_core::channel::Sender<ResultOrEof<HttpStreamPart, HttpError>>,
}

struct BodyChunkMessage {
    stream_id: StreamId,
    chunk: Vec<u8>,
}

struct EndRequestMessage {
    stream_id: StreamId,
}

enum ClientToWriteMessage {
    Start(StartRequestMessage),
    BodyChunk(BodyChunkMessage),
    End(EndRequestMessage),
    Common(CommonToWriteMessage),
}

struct ClientWriteLoop<I : Io + Send + 'static> {
    write: WriteHalf<I>,
    inner: TaskRcMut<ClientInner>,
}

impl<I : Io + Send + 'static> WriteLoop for ClientWriteLoop<I> {
    type Inner = ClientInner;

    fn with_inner<G, R>(&self, f: G) -> R
        where G: FnOnce(&mut Self::Inner) -> R
    {
        self.inner.with(f)
    }

    fn write_all(self, buf: Vec<u8>) -> HttpFuture<Self> {
        let ClientWriteLoop { write, inner } = self;

        Box::new(tokio_io::write_all(write, buf)
            .map(move |(write, _)| ClientWriteLoop { write: write, inner: inner })
            .map_err(HttpError::from))
    }
}

impl<I : Io + Send + 'static> ClientWriteLoop<I> {
    fn process_start(self, start: StartRequestMessage) -> HttpFuture<Self> {
        let StartRequestMessage { headers, body, response_handler } = start;

        let stream_id = self.inner.with(move |inner: &mut ClientInner| {

            let mut stream = GrpcHttpClientStream {
                common: GrpcHttpStreamCommon::new(),
                response_handler: Some(response_handler),
            };

            stream.common.outgoing.push_back(HttpStreamPartContent::Headers(headers));

            inner.insert_stream(stream)
        });

        let to_write_tx_1 = self.inner.with(|inner| inner.to_write_tx.clone());
        let to_write_tx_2 = to_write_tx_1.clone();

        self.inner.with(|inner: &mut ClientInner| {
            let future = body
                .fold((), move |(), chunk| {
                    to_write_tx_1.send(ClientToWriteMessage::BodyChunk(BodyChunkMessage {
                        stream_id: stream_id,
                        chunk: chunk,
                    })).unwrap();
                    futures::finished::<_, HttpError>(())
                });
            let future = future
                .and_then(move |()| {
                    to_write_tx_2.send(ClientToWriteMessage::End(EndRequestMessage {
                        stream_id: stream_id,
                    })).unwrap();
                    futures::finished::<_, HttpError>(())
                });

            let future = future.map_err(|e| {
                warn!("{:?}", e);
                ()
            });

            inner.session_state.loop_handle.spawn(future);
        });

        self.send_outg_stream(stream_id)
    }

    fn process_body_chunk(self, body_chunk: BodyChunkMessage) -> HttpFuture<Self> {
        let BodyChunkMessage { stream_id, chunk } = body_chunk;

        self.inner.with(move |inner: &mut ClientInner| {
            let stream = inner.common.get_stream_mut(stream_id)
                .expect(&format!("stream not found: {}", stream_id));
            // TODO: check stream state

            stream.common.outgoing.push_front(HttpStreamPartContent::Data(chunk));
        });

        self.send_outg_stream(stream_id)
    }

    fn process_end(self, end: EndRequestMessage) -> HttpFuture<Self> {
        let EndRequestMessage { stream_id } = end;

        let buf = self.inner.with(move |inner: &mut ClientInner| {
            inner.common.conn.send_end_of_stream_to_vec(stream_id).unwrap()
        });

        self.write_all(buf)
    }

    fn process_message(self, message: ClientToWriteMessage) -> HttpFuture<Self> {
        match message {
            ClientToWriteMessage::Start(start) => self.process_start(start),
            ClientToWriteMessage::BodyChunk(body_chunk) => self.process_body_chunk(body_chunk),
            ClientToWriteMessage::End(end) => self.process_end(end),
            ClientToWriteMessage::Common(common) => self.process_common(common),
        }
    }

    fn run(self, requests: HttpStreamSend<ClientToWriteMessage>) -> HttpFuture<()> {
        let requests = requests.map_err(HttpError::from);
        Box::new(requests
            .fold(self, move |wl, message: ClientToWriteMessage| {
                wl.process_message(message)
            })
            .map(|_| ()))
    }
}

type ClientReadLoop<I> = HttpReadLoopData<I, ClientInner>;

impl HttpClientConnectionAsync {
    fn connected<I : Io + Send + 'static>(lh: reactor::Handle, connect: HttpFutureSend<I>) -> (Self, HttpFuture<()>) {
        let (to_write_tx, to_write_rx) = tokio_core::channel::channel(&lh).unwrap();

        let to_write_rx = Box::new(to_write_rx.map_err(HttpError::from));

        let c = HttpClientConnectionAsync {
            remote: lh.remote().clone(),
            call_tx: to_write_tx.clone(),
        };

        let handshake = connect.and_then(client_handshake);

        let future = handshake.and_then(move |conn| {
            trace!("handshake done");
            let (read, write) = conn.split();

            let inner = TaskRcMut::new(ClientInner {
                common: LoopInnerCommon::new(HttpScheme::Http),
                to_write_tx: to_write_tx.clone(),
                session_state: GrpcHttpClientSessionState {
                    next_stream_id: 1,
                    decoder: hpack::Decoder::new(),
                    loop_handle: lh,
                }
            });

            let write_inner = inner.clone();
            let run_write = ClientWriteLoop { write: write, inner: write_inner }.run(to_write_rx);
            let run_read = ClientReadLoop { read: read, inner: inner.clone() }.run();

            run_write.join(run_read).map(|_| ())
        });

        (c, Box::new(future))
    }

    pub fn new_plain(lh: reactor::Handle, addr: &SocketAddr) -> (Self, HttpFuture<()>) {
        let addr = addr.clone();

        let connect = TcpStream::connect(&addr, &lh)
            .map(move |c| { info!("connected to {}", addr); c })
            .map_err(|e| e.into());

        HttpClientConnectionAsync::connected(lh, Box::new(connect))
    }

    pub fn new_tls(lh: reactor::Handle, addr: &SocketAddr) -> (Self, HttpFuture<()>) {
        unimplemented!()
        /*
        let addr = addr.clone();

        let connect = TcpStream::connect(&addr, &lh)
            .map(move |c| { info!("connected to {}", addr); c })
            .map_err(|e| e.into());

        let tls_conn = connect.and_then(|conn| {
            tokio_tls::ClientContext::new()
                .unwrap()
                .handshake("localhost", conn)
        });

        let tls_conn = tls_conn.map_err(HttpError::from);

        HttpClientConnectionAsync::connected(lh, Box::new(tls_conn))
        */
    }

    pub fn start_request(
        &self,
        headers: Vec<StaticHeader>,
        body: HttpStreamSend<Vec<u8>>)
            -> HttpStreamStreamSend
    {
        let (tx, rx) = futures::oneshot();

        let call_tx = self.call_tx.clone();

        self.remote.spawn(move |handle| {
            let (req_tx, req_rx) = tokio_core::channel::channel(&handle).unwrap();

            call_tx.send(ClientToWriteMessage::Start(StartRequestMessage {
                headers: headers,
                body: body,
                response_handler: req_tx,
            })).unwrap();

            let req_rx = req_rx.map_err(HttpError::from);

            tx.complete(stream_with_eof_and_error(req_rx, || HttpError::from(io::Error::new(io::ErrorKind::Other, "unexpected eof"))));

            Ok(())
        });

        let rx = rx.map_err(|_| HttpError::from(io::Error::new(io::ErrorKind::Other, "oneshot canceled")));

        Box::new(rx.flatten_stream())
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use xcb;
use xcb_util::{ewmh, icccm};
use xcb_util::keysyms::KeySymbols;

use debug;
use keys::{KeyCombo, KeyHandlers, ModKey};
use groups::Group;
use stack::Stack;

/// A handle to an X Window.
#[derive(Debug, PartialEq)]
pub struct WindowId(xcb::Window);

impl WindowId {
    fn to_x(&self) -> xcb::Window {
        self.0
    }
}

impl fmt::Display for WindowId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[allow(non_snake_case)]
struct InternedAtoms {
    WM_DELETE_WINDOW: xcb::Atom,
    WM_PROTOCOLS: xcb::Atom,
    _NET_NUMBER_OF_DESKTOPS: xcb::Atom,
    _NET_CURRENT_DESKTOP: xcb::Atom,
    _NET_DESKTOP_NAMES: xcb::Atom,
}

pub struct Connection {
    conn: ewmh::Connection,
    root: WindowId,
    screen_idx: i32,
    atoms: InternedAtoms,
}

impl Connection {
    /// Opens a connection to the X server, returning a new Connection object.
    pub fn connect() -> Result<Connection, String> {
        let (conn, screen_idx) = xcb::Connection::connect(None).unwrap();
        let conn = ewmh::Connection::connect(conn).map_err(|_| ()).unwrap();
        let root = conn.get_setup()
            .roots()
            .nth(screen_idx as usize)
            .ok_or("Invalid screen")?
            .root();

        let atoms = InternedAtoms {
            WM_PROTOCOLS: Self::intern_atom(&conn, "WM_PROTOCOLS").unwrap(),
            WM_DELETE_WINDOW: Self::intern_atom(&conn, "WM_DELETE_WINDOW").unwrap(),
            _NET_NUMBER_OF_DESKTOPS: Self::intern_atom(&conn, "_NET_NUMBER_OF_DESKTOPS").unwrap(),
            _NET_CURRENT_DESKTOP: Self::intern_atom(&conn, "_NET_CURRENT_DESKTOP").unwrap(),
            _NET_DESKTOP_NAMES: Self::intern_atom(&conn, "_NET_DESKTOP_NAMES").unwrap(),
        };

        Ok(Connection {
            conn,
            root: WindowId(root),
            screen_idx,
            atoms,
        })
    }

    /// Returns the Atom identifier associated with the atom_name str.
    fn intern_atom(
        conn: &xcb::Connection,
        atom_name: &str,
    ) -> Result<xcb::Atom, xcb::GenericError> {
        Ok(xcb::intern_atom(conn, false, atom_name).get_reply()?.atom())
    }

    fn flush(&self) {
        self.conn.flush();
    }

    /// Installs the Connection as a window manager, by registers for
    /// SubstructureNotify and SubstructureRedirect events on the root window.
    /// If there is already a window manager on the display, then this will
    /// fail.
    pub fn install_as_wm(&self, key_handlers: &KeyHandlers) -> Result<(), String> {
        let values = [
            (
                xcb::CW_EVENT_MASK,
                xcb::EVENT_MASK_SUBSTRUCTURE_NOTIFY | xcb::EVENT_MASK_SUBSTRUCTURE_REDIRECT,
            ),
        ];
        xcb::change_window_attributes_checked(&self.conn, self.root.to_x(), &values)
            .request_check()
            .or(Err(
                "Could not register SUBSTRUCTURE_NOTIFY/REDIRECT".to_owned(),
            ))?;

        self.enable_window_key_events(&self.root, key_handlers);

        Ok(())
    }

    /// Returns the ID of the root window.
    pub fn root_window_id(&self) -> &WindowId {
        &self.root
    }

    pub fn update_ewmh_desktops(&self, groups: &Stack<Group>) {
        let group_names = groups.iter().map(|g| g.name());
        ewmh::set_desktop_names(&self.conn, self.screen_idx, group_names);
        ewmh::set_number_of_desktops(&self.conn, self.screen_idx, groups.len() as u32);

        // Matching the current group on name isn't perfect, but it's good enough for
        // EWMH.
        let focused_idx = groups.focused().and_then(|focused| {
            groups.iter().position(|g| g.name() == focused.name())
        });
        match focused_idx {
            Some(idx) => {
                ewmh::set_current_desktop(&self.conn, self.screen_idx, idx as u32);
            }
            None => {
                error!("Invariant: failed to get active group index");
            }
        };
    }

    pub fn top_level_windows(&self) -> Result<Vec<WindowId>, xcb::GenericError> {
        let windows = xcb::query_tree(&self.conn, self.root.to_x())
            .get_reply()?
            .children()
            .iter()
            .map(|w| WindowId(*w))
            .collect();
        Ok(windows)
    }

    /// Queries the WM_PROTOCOLS property of a window, returning a list of the
    /// protocols that it supports.
    // TODO: Have this return a list of atoms, rather than a list of strings.
    // (Perhaps we should
    // have a separate function to convert to a list of strings for debugging?)
    fn get_wm_protocols(&self, window_id: &WindowId) -> Result<Vec<xcb::Atom>, xcb::GenericError> {
        let reply = icccm::get_wm_protocols(&self.conn, window_id.to_x(), self.atoms.WM_PROTOCOLS)
            .get_reply()?;
        Ok(reply.atoms().to_vec())
    }

    /// Closes a window.
    ///
    /// The window will be closed gracefully using the ICCCM WM_DELETE_WINDOW
    /// protocol if it is supported.
    pub fn close_window(&self, window_id: &WindowId) {
        let protocols = self.get_wm_protocols(window_id).unwrap();
        let has_wm_delete_window = protocols.contains(&self.atoms.WM_DELETE_WINDOW);

        // TODO: Use XDestroyWindow to forcefully close windows that do not support
        // WM_DELETE_WINDOW.
        if !has_wm_delete_window {
            panic!("Not implemented: closing windows that don't expose WM_DELETE_WINDOW");
        }

        let data = xcb::ClientMessageData::from_data32(
            [self.atoms.WM_DELETE_WINDOW, xcb::CURRENT_TIME, 0, 0, 0],
        );
        let event =
            xcb::ClientMessageEvent::new(32, window_id.to_x(), self.atoms.WM_PROTOCOLS, data);
        xcb::send_event(
            &self.conn,
            false,
            window_id.to_x(),
            xcb::EVENT_MASK_NO_EVENT,
            &event,
        );
    }

    /// Sets the window's position and size.
    pub fn configure_window(&self, window_id: &WindowId, x: u32, y: u32, width: u32, height: u32) {
        let values = [
            (xcb::CONFIG_WINDOW_X as u16, x),
            (xcb::CONFIG_WINDOW_Y as u16, y),
            (xcb::CONFIG_WINDOW_WIDTH as u16, width),
            (xcb::CONFIG_WINDOW_HEIGHT as u16, height),
        ];
        xcb::configure_window(&self.conn, window_id.to_x(), &values);
    }

    /// Get's the window's width and height.
    pub fn get_window_geometry(&self, window_id: &WindowId) -> (u32, u32) {
        let reply = xcb::get_geometry(&self.conn, window_id.to_x())
            .get_reply()
            .unwrap();
        // Cast as everywhere else uses u32.
        (reply.width() as u32, reply.height() as u32)
    }

    /// Map a window.
    pub fn map_window(&self, window_id: &WindowId) {
        xcb::map_window(&self.conn, window_id.to_x());
    }

    /// Unmap a window.
    pub fn unmap_window(&self, window_id: &WindowId) {
        xcb::unmap_window(&self.conn, window_id.to_x());
    }

    /// Registers for key events.
    pub fn enable_window_key_events(&self, window_id: &WindowId, key_handlers: &KeyHandlers) {
        let key_symbols = KeySymbols::new(&self.conn).expect("Failed to create KeySymbols");
        for key in key_handlers.key_combos() {
            let keycode = key_symbols.get_keycode(key.keysym);
            xcb::grab_key(
                &self.conn,
                false,
                window_id.to_x(),
                key.mod_mask as u16,
                keycode,
                xcb::GRAB_MODE_ASYNC as u8,
                xcb::GRAB_MODE_ASYNC as u8,
            );
        }
    }

    pub fn enable_window_focus_tracking(&self, window_id: &WindowId) {
        let values = [(xcb::CW_EVENT_MASK, xcb::EVENT_MASK_ENTER_WINDOW)];
        xcb::change_window_attributes(&self.conn, window_id.to_x(), &values);
    }

    pub fn disable_window_focus_tracking(&self, window_id: &WindowId) {
        let values = [(xcb::CW_EVENT_MASK, xcb::EVENT_MASK_NO_EVENT)];
        xcb::change_window_attributes(&self.conn, window_id.to_x(), &values);
    }

    pub fn focus_window(&self, window_id: &WindowId) {
        xcb::set_input_focus(
            &self.conn,
            xcb::INPUT_FOCUS_POINTER_ROOT as u8,
            window_id.to_x(),
            xcb::CURRENT_TIME,
        );
        ewmh::set_active_window(&self.conn, self.screen_idx, window_id.to_x());
    }

    pub fn get_event_loop(&self) -> EventLoop {
        EventLoop { connection: self }
    }
}

/// Events received from the `EventLoop`.
pub enum Event {
    MapRequest(WindowId),
    DestroyNotify(WindowId),
    KeyPress(KeyCombo),
    EnterNotify(WindowId),
}

/// An iterator that yields events from the X event loop.
///
/// Use `Connection::get_event_loop()` to get one.
pub struct EventLoop<'a> {
    connection: &'a Connection,
}

impl<'a> Iterator for EventLoop<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            // Flush any pending operations that came out of the event we (might
            // have) just yielded.
            self.connection.flush();

            let event = self.connection.conn.wait_for_event().expect(
                "wait_for_event() returned None: IO error?",
            );

            let propagate = match event.response_type() {
                xcb::CONFIGURE_REQUEST => self.on_configure_request(xcb::cast_event(&event)),
                xcb::MAP_REQUEST => self.on_map_request(xcb::cast_event(&event)),
                xcb::DESTROY_NOTIFY => self.on_destroy_notify(xcb::cast_event(&event)),
                xcb::KEY_PRESS => self.on_key_press(xcb::cast_event(&event)),
                xcb::ENTER_NOTIFY => self.on_enter_notify(xcb::cast_event(&event)),
                _ => {
                    debug!("Unhandled event: {}", debug::xcb_event_to_str(&event));
                    None
                }
            };

            if let Some(propagate_event) = propagate {
                return Some(propagate_event);
            }
        }
    }
}

impl<'a> EventLoop<'a> {
    fn on_configure_request(&self, event: &xcb::ConfigureRequestEvent) -> Option<Event> {
        // This request is not interesting for us: grant it unchanged.
        // Build a request with all attributes set, then filter out to only include
        // those from the original request.
        let values = vec![
            (xcb::CONFIG_WINDOW_X as u16, event.x() as u32),
            (xcb::CONFIG_WINDOW_Y as u16, event.y() as u32),
            (xcb::CONFIG_WINDOW_WIDTH as u16, event.width() as u32),
            (xcb::CONFIG_WINDOW_HEIGHT as u16, event.height() as u32),
            (
                xcb::CONFIG_WINDOW_BORDER_WIDTH as u16,
                event.border_width() as u32
            ),
            (xcb::CONFIG_WINDOW_SIBLING as u16, event.sibling() as u32),
            (
                xcb::CONFIG_WINDOW_STACK_MODE as u16,
                event.stack_mode() as u32
            ),
        ];
        let filtered_values: Vec<_> = values
            .into_iter()
            .filter(|&(mask, _)| mask & event.value_mask() != 0)
            .collect();
        xcb::configure_window(&self.connection.conn, event.window(), &filtered_values);

        // There's no value in propogating this event.
        None
    }

    fn on_map_request(&self, event: &xcb::MapRequestEvent) -> Option<Event> {
        Some(Event::MapRequest(WindowId(event.window())))
    }

    fn on_destroy_notify(&self, event: &xcb::DestroyNotifyEvent) -> Option<Event> {
        Some(Event::DestroyNotify(WindowId(event.window())))
    }

    fn on_key_press(&self, event: &xcb::KeyPressEvent) -> Option<Event> {
        let key_symbols =
            KeySymbols::new(&self.connection.conn).expect("Failed to create KeySymbols");
        let keysym = key_symbols.key_press_lookup_keysym(event, 0);
        let mod_mask = event.state() as u32 & ModKey::mask_all();
        let key = KeyCombo { mod_mask, keysym };
        Some(Event::KeyPress(key))
    }

    fn on_enter_notify(&self, event: &xcb::EnterNotifyEvent) -> Option<Event> {
        Some(Event::EnterNotify(WindowId(event.event())))
    }
}
<commit_msg>Add atoms!() macro.<commit_after>use std::fmt;

use xcb;
use xcb_util::{ewmh, icccm};
use xcb_util::keysyms::KeySymbols;

use debug;
use keys::{KeyCombo, KeyHandlers, ModKey};
use groups::Group;
use stack::Stack;

/// A handle to an X Window.
#[derive(Debug, PartialEq)]
pub struct WindowId(xcb::Window);

impl WindowId {
    fn to_x(&self) -> xcb::Window {
        self.0
    }
}

impl fmt::Display for WindowId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

macro_rules! atoms {
    ( $( $name:ident ),+ ) => {
        #[allow(non_snake_case)]
        struct InternedAtoms {
            $(
                pub $name: xcb::Atom
            ),*
        }

        impl InternedAtoms {
            pub fn new(conn: &xcb::Connection) -> Result<InternedAtoms, xcb::GenericError> {
                Ok(InternedAtoms {
                    $(
                        $name: Connection::intern_atom(conn, stringify!($atom))?
                    ),*
                })
            }
        }
    };
    // Allow trailing comma:
    ( $( $name:ident ),+ , ) => (atoms!($( $name ),+);)
}

atoms!(
    WM_DELETE_WINDOW,
    WM_PROTOCOLS,
    _NET_NUMBER_OF_DESKTOPS,
    _NET_CURRENT_DESKTOP,
    _NET_DESKTOP_NAMES,
);

pub struct Connection {
    conn: ewmh::Connection,
    root: WindowId,
    screen_idx: i32,
    atoms: InternedAtoms,
}

impl Connection {
    /// Opens a connection to the X server, returning a new Connection object.
    pub fn connect() -> Result<Connection, String> {
        let (conn, screen_idx) = xcb::Connection::connect(None).unwrap();
        let conn = ewmh::Connection::connect(conn).map_err(|_| ()).unwrap();
        let root = conn.get_setup()
            .roots()
            .nth(screen_idx as usize)
            .ok_or("Invalid screen")?
            .root();

        let atoms = InternedAtoms::new(&conn).or(Err("Failed to intern atoms"))?;

        Ok(Connection {
            conn,
            root: WindowId(root),
            screen_idx,
            atoms,
        })
    }

    /// Returns the Atom identifier associated with the atom_name str.
    fn intern_atom(
        conn: &xcb::Connection,
        atom_name: &str,
    ) -> Result<xcb::Atom, xcb::GenericError> {
        Ok(xcb::intern_atom(conn, false, atom_name).get_reply()?.atom())
    }

    fn flush(&self) {
        self.conn.flush();
    }

    /// Installs the Connection as a window manager, by registers for
    /// SubstructureNotify and SubstructureRedirect events on the root window.
    /// If there is already a window manager on the display, then this will
    /// fail.
    pub fn install_as_wm(&self, key_handlers: &KeyHandlers) -> Result<(), String> {
        let values = [
            (
                xcb::CW_EVENT_MASK,
                xcb::EVENT_MASK_SUBSTRUCTURE_NOTIFY | xcb::EVENT_MASK_SUBSTRUCTURE_REDIRECT,
            ),
        ];
        xcb::change_window_attributes_checked(&self.conn, self.root.to_x(), &values)
            .request_check()
            .or(Err(
                "Could not register SUBSTRUCTURE_NOTIFY/REDIRECT".to_owned(),
            ))?;

        self.enable_window_key_events(&self.root, key_handlers);

        Ok(())
    }

    /// Returns the ID of the root window.
    pub fn root_window_id(&self) -> &WindowId {
        &self.root
    }

    pub fn update_ewmh_desktops(&self, groups: &Stack<Group>) {
        let group_names = groups.iter().map(|g| g.name());
        ewmh::set_desktop_names(&self.conn, self.screen_idx, group_names);
        ewmh::set_number_of_desktops(&self.conn, self.screen_idx, groups.len() as u32);

        // Matching the current group on name isn't perfect, but it's good enough for
        // EWMH.
        let focused_idx = groups.focused().and_then(|focused| {
            groups.iter().position(|g| g.name() == focused.name())
        });
        match focused_idx {
            Some(idx) => {
                ewmh::set_current_desktop(&self.conn, self.screen_idx, idx as u32);
            }
            None => {
                error!("Invariant: failed to get active group index");
            }
        };
    }

    pub fn top_level_windows(&self) -> Result<Vec<WindowId>, xcb::GenericError> {
        let windows = xcb::query_tree(&self.conn, self.root.to_x())
            .get_reply()?
            .children()
            .iter()
            .map(|w| WindowId(*w))
            .collect();
        Ok(windows)
    }

    /// Queries the WM_PROTOCOLS property of a window, returning a list of the
    /// protocols that it supports.
    // TODO: Have this return a list of atoms, rather than a list of strings.
    // (Perhaps we should
    // have a separate function to convert to a list of strings for debugging?)
    fn get_wm_protocols(&self, window_id: &WindowId) -> Result<Vec<xcb::Atom>, xcb::GenericError> {
        let reply = icccm::get_wm_protocols(&self.conn, window_id.to_x(), self.atoms.WM_PROTOCOLS)
            .get_reply()?;
        Ok(reply.atoms().to_vec())
    }

    /// Closes a window.
    ///
    /// The window will be closed gracefully using the ICCCM WM_DELETE_WINDOW
    /// protocol if it is supported.
    pub fn close_window(&self, window_id: &WindowId) {
        let protocols = self.get_wm_protocols(window_id).unwrap();
        let has_wm_delete_window = protocols.contains(&self.atoms.WM_DELETE_WINDOW);

        // TODO: Use XDestroyWindow to forcefully close windows that do not support
        // WM_DELETE_WINDOW.
        if !has_wm_delete_window {
            panic!("Not implemented: closing windows that don't expose WM_DELETE_WINDOW");
        }

        let data = xcb::ClientMessageData::from_data32(
            [self.atoms.WM_DELETE_WINDOW, xcb::CURRENT_TIME, 0, 0, 0],
        );
        let event =
            xcb::ClientMessageEvent::new(32, window_id.to_x(), self.atoms.WM_PROTOCOLS, data);
        xcb::send_event(
            &self.conn,
            false,
            window_id.to_x(),
            xcb::EVENT_MASK_NO_EVENT,
            &event,
        );
    }

    /// Sets the window's position and size.
    pub fn configure_window(&self, window_id: &WindowId, x: u32, y: u32, width: u32, height: u32) {
        let values = [
            (xcb::CONFIG_WINDOW_X as u16, x),
            (xcb::CONFIG_WINDOW_Y as u16, y),
            (xcb::CONFIG_WINDOW_WIDTH as u16, width),
            (xcb::CONFIG_WINDOW_HEIGHT as u16, height),
        ];
        xcb::configure_window(&self.conn, window_id.to_x(), &values);
    }

    /// Get's the window's width and height.
    pub fn get_window_geometry(&self, window_id: &WindowId) -> (u32, u32) {
        let reply = xcb::get_geometry(&self.conn, window_id.to_x())
            .get_reply()
            .unwrap();
        // Cast as everywhere else uses u32.
        (reply.width() as u32, reply.height() as u32)
    }

    /// Map a window.
    pub fn map_window(&self, window_id: &WindowId) {
        xcb::map_window(&self.conn, window_id.to_x());
    }

    /// Unmap a window.
    pub fn unmap_window(&self, window_id: &WindowId) {
        xcb::unmap_window(&self.conn, window_id.to_x());
    }

    /// Registers for key events.
    pub fn enable_window_key_events(&self, window_id: &WindowId, key_handlers: &KeyHandlers) {
        let key_symbols = KeySymbols::new(&self.conn).expect("Failed to create KeySymbols");
        for key in key_handlers.key_combos() {
            let keycode = key_symbols.get_keycode(key.keysym);
            xcb::grab_key(
                &self.conn,
                false,
                window_id.to_x(),
                key.mod_mask as u16,
                keycode,
                xcb::GRAB_MODE_ASYNC as u8,
                xcb::GRAB_MODE_ASYNC as u8,
            );
        }
    }

    pub fn enable_window_focus_tracking(&self, window_id: &WindowId) {
        let values = [(xcb::CW_EVENT_MASK, xcb::EVENT_MASK_ENTER_WINDOW)];
        xcb::change_window_attributes(&self.conn, window_id.to_x(), &values);
    }

    pub fn disable_window_focus_tracking(&self, window_id: &WindowId) {
        let values = [(xcb::CW_EVENT_MASK, xcb::EVENT_MASK_NO_EVENT)];
        xcb::change_window_attributes(&self.conn, window_id.to_x(), &values);
    }

    pub fn focus_window(&self, window_id: &WindowId) {
        xcb::set_input_focus(
            &self.conn,
            xcb::INPUT_FOCUS_POINTER_ROOT as u8,
            window_id.to_x(),
            xcb::CURRENT_TIME,
        );
        ewmh::set_active_window(&self.conn, self.screen_idx, window_id.to_x());
    }

    pub fn get_event_loop(&self) -> EventLoop {
        EventLoop { connection: self }
    }
}

/// Events received from the `EventLoop`.
pub enum Event {
    MapRequest(WindowId),
    DestroyNotify(WindowId),
    KeyPress(KeyCombo),
    EnterNotify(WindowId),
}

/// An iterator that yields events from the X event loop.
///
/// Use `Connection::get_event_loop()` to get one.
pub struct EventLoop<'a> {
    connection: &'a Connection,
}

impl<'a> Iterator for EventLoop<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            // Flush any pending operations that came out of the event we (might
            // have) just yielded.
            self.connection.flush();

            let event = self.connection.conn.wait_for_event().expect(
                "wait_for_event() returned None: IO error?",
            );

            let propagate = match event.response_type() {
                xcb::CONFIGURE_REQUEST => self.on_configure_request(xcb::cast_event(&event)),
                xcb::MAP_REQUEST => self.on_map_request(xcb::cast_event(&event)),
                xcb::DESTROY_NOTIFY => self.on_destroy_notify(xcb::cast_event(&event)),
                xcb::KEY_PRESS => self.on_key_press(xcb::cast_event(&event)),
                xcb::ENTER_NOTIFY => self.on_enter_notify(xcb::cast_event(&event)),
                _ => {
                    debug!("Unhandled event: {}", debug::xcb_event_to_str(&event));
                    None
                }
            };

            if let Some(propagate_event) = propagate {
                return Some(propagate_event);
            }
        }
    }
}

impl<'a> EventLoop<'a> {
    fn on_configure_request(&self, event: &xcb::ConfigureRequestEvent) -> Option<Event> {
        // This request is not interesting for us: grant it unchanged.
        // Build a request with all attributes set, then filter out to only include
        // those from the original request.
        let values = vec![
            (xcb::CONFIG_WINDOW_X as u16, event.x() as u32),
            (xcb::CONFIG_WINDOW_Y as u16, event.y() as u32),
            (xcb::CONFIG_WINDOW_WIDTH as u16, event.width() as u32),
            (xcb::CONFIG_WINDOW_HEIGHT as u16, event.height() as u32),
            (
                xcb::CONFIG_WINDOW_BORDER_WIDTH as u16,
                event.border_width() as u32
            ),
            (xcb::CONFIG_WINDOW_SIBLING as u16, event.sibling() as u32),
            (
                xcb::CONFIG_WINDOW_STACK_MODE as u16,
                event.stack_mode() as u32
            ),
        ];
        let filtered_values: Vec<_> = values
            .into_iter()
            .filter(|&(mask, _)| mask & event.value_mask() != 0)
            .collect();
        xcb::configure_window(&self.connection.conn, event.window(), &filtered_values);

        // There's no value in propogating this event.
        None
    }

    fn on_map_request(&self, event: &xcb::MapRequestEvent) -> Option<Event> {
        Some(Event::MapRequest(WindowId(event.window())))
    }

    fn on_destroy_notify(&self, event: &xcb::DestroyNotifyEvent) -> Option<Event> {
        Some(Event::DestroyNotify(WindowId(event.window())))
    }

    fn on_key_press(&self, event: &xcb::KeyPressEvent) -> Option<Event> {
        let key_symbols =
            KeySymbols::new(&self.connection.conn).expect("Failed to create KeySymbols");
        let keysym = key_symbols.key_press_lookup_keysym(event, 0);
        let mod_mask = event.state() as u32 & ModKey::mask_all();
        let key = KeyCombo { mod_mask, keysym };
        Some(Event::KeyPress(key))
    }

    fn on_enter_notify(&self, event: &xcb::EnterNotifyEvent) -> Option<Event> {
        Some(Event::EnterNotify(WindowId(event.event())))
    }
}
<|endoftext|>


<commit_before>//! Types and traits related to serializing values for the database

use std::error::Error;
use std::fmt;
use std::io::{self, Write};
use std::result;

use crate::backend::{Backend, HasBindCollector};
use crate::query_builder::bind_collector::RawBytesBindCollector;
use crate::query_builder::BindCollector;

#[cfg(feature = "postgres_backend")]
pub use crate::pg::serialize::*;

/// A specialized result type representing the result of serializing
/// a value for the database.
pub type Result = result::Result<IsNull, Box<dyn Error + Send + Sync>>;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
/// Tiny enum to make the return type of `ToSql` more descriptive
pub enum IsNull {
    /// No data was written, as this type is null
    Yes,
    /// The value is not null
    ///
    /// This does not necessarily mean that any data was written to the buffer.
    /// For example, an empty string has no data to be sent over the wire, but
    /// also is not null.
    No,
}

/// Wraps a buffer to be written by `ToSql` with additional backend specific
/// utilities.
pub struct Output<'a, 'b, DB>
where
    DB: Backend,
    DB::MetadataLookup: 'a,
{
    out: <crate::backend::BindCollector<'a, DB> as BindCollector<'a, DB>>::Buffer,
    metadata_lookup: Option<&'b mut DB::MetadataLookup>,
}

impl<'a, 'b, DB: Backend> Output<'a, 'b, DB> {
    /// Construct a new `Output`
    pub fn new(
        out: <crate::backend::BindCollector<'a, DB> as BindCollector<'a, DB>>::Buffer,
        metadata_lookup: &'b mut DB::MetadataLookup,
    ) -> Self {
        Output {
            out,
            metadata_lookup: Some(metadata_lookup),
        }
    }

    #[cfg(feature = "sqlite")]
    pub(crate) fn into_inner(
        self,
    ) -> <crate::backend::BindCollector<'a, DB> as BindCollector<'a, DB>>::Buffer {
        self.out
    }

    /// Returns the backend's mechanism for dynamically looking up type
    /// metadata at runtime, if relevant for the given backend.
    pub fn metadata_lookup(&mut self) -> &mut DB::MetadataLookup {
        *self.metadata_lookup.as_mut().expect("Lookup is there")
    }
}

#[cfg(feature = "sqlite")]
impl<'a, 'b> Output<'a, 'b, crate::sqlite::Sqlite> {
    pub(crate) fn set_small_int(&mut self, i: i16) {
        self.out = crate::sqlite::SqliteBindValue::I32(i as i32);
    }

    pub(crate) fn set_int(&mut self, i: i32) {
        self.out = crate::sqlite::SqliteBindValue::I32(i);
    }

    pub(crate) fn set_big_int(&mut self, i: i64) {
        self.out = crate::sqlite::SqliteBindValue::I64(i);
    }

    pub(crate) fn set_float(&mut self, i: f32) {
        self.out = crate::sqlite::SqliteBindValue::F64(i as f64);
    }

    pub(crate) fn set_double(&mut self, i: f64) {
        self.out = crate::sqlite::SqliteBindValue::F64(i);
    }

    pub(crate) fn set_borrowed_string(&mut self, s: &'a str) {
        self.out = crate::sqlite::SqliteBindValue::BorrowedString(s);
    }

    pub(crate) fn set_borrowed_binary(&mut self, s: &'a [u8]) {
        self.out = crate::sqlite::SqliteBindValue::BorrowedBinary(s);
    }

    // this can be unused depending on the enabled features
    #[allow(dead_code)]
    pub(crate) fn set_owned_string(&mut self, s: String) {
        self.out = crate::sqlite::SqliteBindValue::String(s.into_boxed_str());
    }

    // This can be unused depending on the enabled features
    #[allow(dead_code)]
    pub(crate) fn set_owned_binary(&mut self, b: Vec<u8>) {
        self.out = crate::sqlite::SqliteBindValue::Binary(b.into_boxed_slice());
    }
}

#[cfg(test)]
impl<'a, DB: Backend> Output<'a, 'static, DB> {
    /// Returns a `Output` suitable for testing `ToSql` implementations.
    /// Unsafe to use for testing types which perform dynamic metadata lookup.
    pub fn test(
        buffer: <crate::backend::BindCollector<'a, DB> as BindCollector<'a, DB>>::Buffer,
    ) -> Self {
        Self {
            out: buffer,
            metadata_lookup: None,
        }
    }
}

impl<'a, 'b, DB: Backend<BindCollector = RawBytesBindCollector<DB>>> Write for Output<'a, 'b, DB> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.out.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.out.flush()
    }

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.out.write_all(buf)
    }

    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
        self.out.write_fmt(fmt)
    }
}

impl<'a, 'b, DB: Backend<BindCollector = RawBytesBindCollector<DB>>> Output<'a, 'b, DB> {
    /// Call this method whenever you pass an instance of `Output<DB>` by value.
    ///
    /// Effectively copies `self`, with a narrower lifetime. When passing a
    /// reference or a mutable reference, this is normally done by rust
    /// implicitly. This is why you can pass `&mut Foo` to multiple functions,
    /// even though mutable references are not `Copy`. However, this is only
    /// done implicitly for references. For structs with lifetimes it must be
    /// done explicitly. This method matches the semantics of what Rust would do
    /// implicitly if you were passing a mutable reference
    pub fn reborrow<'c>(&'c mut self) -> Output<'c, 'c, DB>
    where
        'a: 'c,
    {
        Output {
            out: RawBytesBindCollector::<DB>::reborrow_buffer(self.out),
            metadata_lookup: match &mut self.metadata_lookup {
                None => None,
                Some(m) => Some(&mut **m),
            },
        }
    }
}

impl<'a, 'b, DB> fmt::Debug for Output<'a, 'b, DB>
where
    <<DB as HasBindCollector<'a>>::BindCollector as BindCollector<'a, DB>>::Buffer: fmt::Debug,
    DB: Backend,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.out.fmt(f)
    }
}

/// Serializes a single value to be sent to the database.
///
/// The output is sent as a bind parameter, and the data must be written in the
/// expected format for the given backend.
///
/// When possible, implementations of this trait should prefer using an existing
/// implementation, rather than writing to `out` directly. (For example, if you
/// are implementing this for an enum, which is represented as an integer in the
/// database, you should use `i32::to_sql(x, out)` instead of writing to `out`
/// yourself.)
///
/// Any types which implement this trait should also
/// [`#[derive(AsExpression)]`](crate::AsExpression).
///
/// ### Backend specific details
///
/// - For PostgreSQL, the bytes will be sent using the binary protocol, not text.
/// - For SQLite, all implementations should be written in terms of an existing
///   `ToSql` implementation.
/// - For MySQL, the expected bytes will depend on the return value of
///   `type_metadata` for the given SQL type. See [`MysqlType`] for details.
/// - For third party backends, consult that backend's documentation.
///
/// [`MysqlType`]: ../mysql/enum.MysqlType.html
///
/// ### Examples
///
/// Most implementations of this trait will be defined in terms of an existing
/// implementation.
///
/// ```rust
/// # use diesel::backend::Backend;
/// # use diesel::expression::AsExpression;
/// # use diesel::sql_types::*;
/// # use diesel::serialize::{self, ToSql, Output};
/// # use std::io::Write;
/// #
/// #[repr(i32)]
/// #[derive(Debug, Clone, Copy, AsExpression)]
/// #[diesel(sql_type = Integer)]
/// pub enum MyEnum {
///     A = 1,
///     B = 2,
/// }
///
/// impl<DB> ToSql<Integer, DB> for MyEnum
/// where
///     DB: Backend,
///     i32: ToSql<Integer, DB>,
/// {
///     fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
///         match self {
///             MyEnum::A => 1.to_sql(out),
///             MyEnum::B => 2.to_sql(out),
///         }
///     }
/// }
/// ```
pub trait ToSql<A, DB: Backend>: fmt::Debug {
    /// See the trait documentation.
    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> Result;
}

impl<'a, A, T, DB> ToSql<A, DB> for &'a T
where
    DB: Backend,
    T: ToSql<A, DB> + ?Sized,
{
    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> Result {
        (*self).to_sql(out)
    }
}
<commit_msg>refer to derive<commit_after>//! Types and traits related to serializing values for the database

use std::error::Error;
use std::fmt;
use std::io::{self, Write};
use std::result;

use crate::backend::{Backend, HasBindCollector};
use crate::query_builder::bind_collector::RawBytesBindCollector;
use crate::query_builder::BindCollector;

#[cfg(feature = "postgres_backend")]
pub use crate::pg::serialize::*;

/// A specialized result type representing the result of serializing
/// a value for the database.
pub type Result = result::Result<IsNull, Box<dyn Error + Send + Sync>>;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
/// Tiny enum to make the return type of `ToSql` more descriptive
pub enum IsNull {
    /// No data was written, as this type is null
    Yes,
    /// The value is not null
    ///
    /// This does not necessarily mean that any data was written to the buffer.
    /// For example, an empty string has no data to be sent over the wire, but
    /// also is not null.
    No,
}

/// Wraps a buffer to be written by `ToSql` with additional backend specific
/// utilities.
pub struct Output<'a, 'b, DB>
where
    DB: Backend,
    DB::MetadataLookup: 'a,
{
    out: <crate::backend::BindCollector<'a, DB> as BindCollector<'a, DB>>::Buffer,
    metadata_lookup: Option<&'b mut DB::MetadataLookup>,
}

impl<'a, 'b, DB: Backend> Output<'a, 'b, DB> {
    /// Construct a new `Output`
    pub fn new(
        out: <crate::backend::BindCollector<'a, DB> as BindCollector<'a, DB>>::Buffer,
        metadata_lookup: &'b mut DB::MetadataLookup,
    ) -> Self {
        Output {
            out,
            metadata_lookup: Some(metadata_lookup),
        }
    }

    #[cfg(feature = "sqlite")]
    pub(crate) fn into_inner(
        self,
    ) -> <crate::backend::BindCollector<'a, DB> as BindCollector<'a, DB>>::Buffer {
        self.out
    }

    /// Returns the backend's mechanism for dynamically looking up type
    /// metadata at runtime, if relevant for the given backend.
    pub fn metadata_lookup(&mut self) -> &mut DB::MetadataLookup {
        *self.metadata_lookup.as_mut().expect("Lookup is there")
    }
}

#[cfg(feature = "sqlite")]
impl<'a, 'b> Output<'a, 'b, crate::sqlite::Sqlite> {
    pub(crate) fn set_small_int(&mut self, i: i16) {
        self.out = crate::sqlite::SqliteBindValue::I32(i as i32);
    }

    pub(crate) fn set_int(&mut self, i: i32) {
        self.out = crate::sqlite::SqliteBindValue::I32(i);
    }

    pub(crate) fn set_big_int(&mut self, i: i64) {
        self.out = crate::sqlite::SqliteBindValue::I64(i);
    }

    pub(crate) fn set_float(&mut self, i: f32) {
        self.out = crate::sqlite::SqliteBindValue::F64(i as f64);
    }

    pub(crate) fn set_double(&mut self, i: f64) {
        self.out = crate::sqlite::SqliteBindValue::F64(i);
    }

    pub(crate) fn set_borrowed_string(&mut self, s: &'a str) {
        self.out = crate::sqlite::SqliteBindValue::BorrowedString(s);
    }

    pub(crate) fn set_borrowed_binary(&mut self, s: &'a [u8]) {
        self.out = crate::sqlite::SqliteBindValue::BorrowedBinary(s);
    }

    // this can be unused depending on the enabled features
    #[allow(dead_code)]
    pub(crate) fn set_owned_string(&mut self, s: String) {
        self.out = crate::sqlite::SqliteBindValue::String(s.into_boxed_str());
    }

    // This can be unused depending on the enabled features
    #[allow(dead_code)]
    pub(crate) fn set_owned_binary(&mut self, b: Vec<u8>) {
        self.out = crate::sqlite::SqliteBindValue::Binary(b.into_boxed_slice());
    }
}

#[cfg(test)]
impl<'a, DB: Backend> Output<'a, 'static, DB> {
    /// Returns a `Output` suitable for testing `ToSql` implementations.
    /// Unsafe to use for testing types which perform dynamic metadata lookup.
    pub fn test(
        buffer: <crate::backend::BindCollector<'a, DB> as BindCollector<'a, DB>>::Buffer,
    ) -> Self {
        Self {
            out: buffer,
            metadata_lookup: None,
        }
    }
}

impl<'a, 'b, DB: Backend<BindCollector = RawBytesBindCollector<DB>>> Write for Output<'a, 'b, DB> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.out.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.out.flush()
    }

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.out.write_all(buf)
    }

    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
        self.out.write_fmt(fmt)
    }
}

impl<'a, 'b, DB: Backend<BindCollector = RawBytesBindCollector<DB>>> Output<'a, 'b, DB> {
    /// Call this method whenever you pass an instance of `Output<DB>` by value.
    ///
    /// Effectively copies `self`, with a narrower lifetime. When passing a
    /// reference or a mutable reference, this is normally done by rust
    /// implicitly. This is why you can pass `&mut Foo` to multiple functions,
    /// even though mutable references are not `Copy`. However, this is only
    /// done implicitly for references. For structs with lifetimes it must be
    /// done explicitly. This method matches the semantics of what Rust would do
    /// implicitly if you were passing a mutable reference
    pub fn reborrow<'c>(&'c mut self) -> Output<'c, 'c, DB>
    where
        'a: 'c,
    {
        Output {
            out: RawBytesBindCollector::<DB>::reborrow_buffer(self.out),
            metadata_lookup: match &mut self.metadata_lookup {
                None => None,
                Some(m) => Some(&mut **m),
            },
        }
    }
}

impl<'a, 'b, DB> fmt::Debug for Output<'a, 'b, DB>
where
    <<DB as HasBindCollector<'a>>::BindCollector as BindCollector<'a, DB>>::Buffer: fmt::Debug,
    DB: Backend,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.out.fmt(f)
    }
}

/// Serializes a single value to be sent to the database.
///
/// The output is sent as a bind parameter, and the data must be written in the
/// expected format for the given backend.
///
/// When possible, implementations of this trait should prefer using an existing
/// implementation, rather than writing to `out` directly. (For example, if you
/// are implementing this for an enum, which is represented as an integer in the
/// database, you should use `i32::to_sql(x, out)` instead of writing to `out`
/// yourself.)
///
/// Any types which implement this trait should also
/// [`#[derive(AsExpression)]`](derive@crate::AsExpression).
///
/// ### Backend specific details
///
/// - For PostgreSQL, the bytes will be sent using the binary protocol, not text.
/// - For SQLite, all implementations should be written in terms of an existing
///   `ToSql` implementation.
/// - For MySQL, the expected bytes will depend on the return value of
///   `type_metadata` for the given SQL type. See [`MysqlType`] for details.
/// - For third party backends, consult that backend's documentation.
///
/// [`MysqlType`]: ../mysql/enum.MysqlType.html
///
/// ### Examples
///
/// Most implementations of this trait will be defined in terms of an existing
/// implementation.
///
/// ```rust
/// # use diesel::backend::Backend;
/// # use diesel::expression::AsExpression;
/// # use diesel::sql_types::*;
/// # use diesel::serialize::{self, ToSql, Output};
/// # use std::io::Write;
/// #
/// #[repr(i32)]
/// #[derive(Debug, Clone, Copy, AsExpression)]
/// #[diesel(sql_type = Integer)]
/// pub enum MyEnum {
///     A = 1,
///     B = 2,
/// }
///
/// impl<DB> ToSql<Integer, DB> for MyEnum
/// where
///     DB: Backend,
///     i32: ToSql<Integer, DB>,
/// {
///     fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
///         match self {
///             MyEnum::A => 1.to_sql(out),
///             MyEnum::B => 2.to_sql(out),
///         }
///     }
/// }
/// ```
pub trait ToSql<A, DB: Backend>: fmt::Debug {
    /// See the trait documentation.
    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> Result;
}

impl<'a, A, T, DB> ToSql<A, DB> for &'a T
where
    DB: Backend,
    T: ToSql<A, DB> + ?Sized,
{
    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> Result {
        (*self).to_sql(out)
    }
}
<|endoftext|>