<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use debug_font_data;
use device::{Device, GpuMarker, Program, VAOId, TextureId, VertexDescriptor};
use device::{TextureFilter, VertexAttribute, VertexUsageHint, VertexAttributeKind, TextureTarget};
use euclid::{Transform3D, Point2D, Size2D, Rect};
use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, TextureSampler};
use internal_types::RenderTargetMode;
use std::f32;
use api::{ColorU, ImageFormat, DeviceUintSize};

const DESC_FONT: VertexDescriptor = VertexDescriptor {
    vertex_attributes: &[
        VertexAttribute { name: "aPosition", count: 2, kind: VertexAttributeKind::F32 },
        VertexAttribute { name: "aColor", count: 4, kind: VertexAttributeKind::U8Norm },
        VertexAttribute { name: "aColorTexCoord", count: 2, kind: VertexAttributeKind::F32 },
    ],
    instance_attributes: &[]
};

const DESC_COLOR: VertexDescriptor = VertexDescriptor {
    vertex_attributes: &[
        VertexAttribute { name: "aPosition", count: 2, kind: VertexAttributeKind::F32 },
        VertexAttribute { name: "aColor", count: 4, kind: VertexAttributeKind::U8Norm },
    ],
    instance_attributes: &[]
};

#[repr(C)]
pub struct DebugFontVertex {
    pub x: f32,
    pub y: f32,
    pub color: ColorU,
    pub u: f32,
    pub v: f32,
}

impl DebugFontVertex {
    pub fn new(x: f32, y: f32, u: f32, v: f32, color: ColorU) -> DebugFontVertex {
        DebugFontVertex {
            x,
            y,
            color,
            u,
            v,
        }
    }
}

#[repr(C)]
pub struct DebugColorVertex {
    pub x: f32,
    pub y: f32,
    pub color: ColorU,
}

impl DebugColorVertex {
    pub fn new(x: f32, y: f32, color: ColorU) -> DebugColorVertex {
        DebugColorVertex {
            x,
            y,
            color,
        }
    }
}

pub struct DebugRenderer {
    font_vertices: Vec<DebugFontVertex>,
    font_indices: Vec<u32>,
    font_program: Program,
    font_vao: VAOId,
    font_texture_id: TextureId,

    tri_vertices: Vec<DebugColorVertex>,
    tri_indices: Vec<u32>,
    tri_vao: VAOId,
    line_vertices: Vec<DebugColorVertex>,
    line_vao: VAOId,
    color_program: Program,
}

impl DebugRenderer {
    pub fn new(device: &mut Device) -> DebugRenderer {
        let font_program = device.create_program("debug_font", "shared_other", &DESC_FONT).unwrap();
        let color_program = device.create_program("debug_color", "shared_other", &DESC_COLOR).unwrap();

        let font_vao = device.create_vao(&DESC_FONT, 32);
        let line_vao = device.create_vao(&DESC_COLOR, 32);
        let tri_vao = device.create_vao(&DESC_COLOR, 32);

        let font_texture_id = device.create_texture_ids(1, TextureTarget::Default)[0];
        device.init_texture(font_texture_id,
                            debug_font_data::BMP_WIDTH,
                            debug_font_data::BMP_HEIGHT,
                            ImageFormat::A8,
                            TextureFilter::Linear,
                            RenderTargetMode::None,
                            Some(&debug_font_data::FONT_BITMAP));

        DebugRenderer {
            font_vertices: Vec::new(),
            font_indices: Vec::new(),
            line_vertices: Vec::new(),
            tri_vao,
            tri_vertices: Vec::new(),
            tri_indices: Vec::new(),
            font_program,
            color_program,
            font_vao,
            line_vao,
            font_texture_id,
        }
    }

    pub fn deinit(&mut self, device: &mut Device) {
        device.delete_program(&mut self.font_program);
        device.delete_program(&mut self.color_program);
    }

    pub fn line_height(&self) -> f32 {
        debug_font_data::FONT_SIZE as f32 * 1.1
    }

    pub fn add_text(&mut self,
                    x: f32,
                    y: f32,
                    text: &str,
                    color: ColorU) -> Rect<f32> {
        let mut x_start = x;
        let ipw = 1.0 / debug_font_data::BMP_WIDTH as f32;
        let iph = 1.0 / debug_font_data::BMP_HEIGHT as f32;

        let mut min_x = f32::MAX;
        let mut max_x = -f32::MAX;
        let mut min_y = f32::MAX;
        let mut max_y = -f32::MAX;

        for c in text.chars() {
            let c = c as usize - debug_font_data::FIRST_GLYPH_INDEX as usize;
            if c < debug_font_data::GLYPHS.len() {
                let glyph = &debug_font_data::GLYPHS[c];

                let x0 = (x_start + glyph.xo + 0.5).floor();
                let y0 = (y + glyph.yo + 0.5).floor();

                let x1 = x0 + glyph.x1 as f32 - glyph.x0 as f32;
                let y1 = y0 + glyph.y1 as f32 - glyph.y0 as f32;

                let s0 = glyph.x0 as f32 * ipw;
                let t0 = glyph.y0 as f32 * iph;
                let s1 = glyph.x1 as f32 * ipw;
                let t1 = glyph.y1 as f32 * iph;

                x_start += glyph.xa;

                let vertex_count = self.font_vertices.len() as u32;

                self.font_vertices.push(DebugFontVertex::new(x0, y0, s0, t0, color));
                self.font_vertices.push(DebugFontVertex::new(x1, y0, s1, t0, color));
                self.font_vertices.push(DebugFontVertex::new(x0, y1, s0, t1, color));
                self.font_vertices.push(DebugFontVertex::new(x1, y1, s1, t1, color));

                self.font_indices.push(vertex_count + 0);
                self.font_indices.push(vertex_count + 1);
                self.font_indices.push(vertex_count + 2);
                self.font_indices.push(vertex_count + 2);
                self.font_indices.push(vertex_count + 1);
                self.font_indices.push(vertex_count + 3);

                min_x = min_x.min(x0);
                max_x = max_x.max(x1);
                min_y = min_y.min(y0);
                max_y = max_y.max(y1);
            }
        }

        Rect::new(Point2D::new(min_x, min_y), Size2D::new(max_x-min_x, max_y-min_y))
    }

    pub fn add_quad(&mut self,
                    x0: f32,
                    y0: f32,
                    x1: f32,
                    y1: f32,
                    color_top: ColorU,
                    color_bottom: ColorU) {
        let vertex_count = self.tri_vertices.len() as u32;

        self.tri_vertices.push(DebugColorVertex::new(x0, y0, color_top));
        self.tri_vertices.push(DebugColorVertex::new(x1, y0, color_top));
        self.tri_vertices.push(DebugColorVertex::new(x0, y1, color_bottom));
        self.tri_vertices.push(DebugColorVertex::new(x1, y1, color_bottom));

        self.tri_indices.push(vertex_count + 0);
        self.tri_indices.push(vertex_count + 1);
        self.tri_indices.push(vertex_count + 2);
        self.tri_indices.push(vertex_count + 2);
        self.tri_indices.push(vertex_count + 1);
        self.tri_indices.push(vertex_count + 3);
    }

    #[allow(dead_code)]
    pub fn add_line(&mut self,
                    x0: i32,
                    y0: i32,
                    color0: ColorU,
                    x1: i32,
                    y1: i32,
                    color1: ColorU) {
        self.line_vertices.push(DebugColorVertex::new(x0 as f32, y0 as f32, color0));
        self.line_vertices.push(DebugColorVertex::new(x1 as f32, y1 as f32, color1));
    }

    pub fn render(&mut self,
                  device: &mut Device,
                  viewport_size: &DeviceUintSize) {
        let _gm = GpuMarker::new(device.rc_gl(), "debug");
        device.disable_depth();
        device.set_blend(true);
        device.set_blend_mode_alpha();

        let projection = Transform3D::ortho(0.0,
                                            viewport_size.width as f32,
                                            viewport_size.height as f32,
                                            0.0,
                                            ORTHO_NEAR_PLANE,
                                            ORTHO_FAR_PLANE);

        // Triangles
        if !self.tri_vertices.is_empty() {
            device.bind_program(&self.color_program);
            device.set_uniforms(&self.color_program, &projection);
            device.bind_vao(self.tri_vao);
            device.update_vao_indices(self.tri_vao,
                                      &self.tri_indices,
                                      VertexUsageHint::Dynamic);
            device.update_vao_main_vertices(self.tri_vao,
                                            &self.tri_vertices,
                                            VertexUsageHint::Dynamic);
            device.draw_triangles_u32(0, self.tri_indices.len() as i32);
        }

        // Lines
        if !self.line_vertices.is_empty() {
            device.bind_program(&self.color_program);
            device.set_uniforms(&self.color_program, &projection);
            device.bind_vao(self.line_vao);
            device.update_vao_main_vertices(self.line_vao,
                                            &self.line_vertices,
                                            VertexUsageHint::Dynamic);
            device.draw_nonindexed_lines(0, self.line_vertices.len() as i32);
        }

        // Glyph
        if !self.font_indices.is_empty() {
            device.bind_program(&self.font_program);
            device.set_uniforms(&self.font_program, &projection);
            device.bind_texture(TextureSampler::Color0, self.font_texture_id);
            device.bind_vao(self.font_vao);
            device.update_vao_indices(self.font_vao,
                                      &self.font_indices,
                                      VertexUsageHint::Dynamic);
            device.update_vao_main_vertices(self.font_vao,
                                            &self.font_vertices,
                                            VertexUsageHint::Dynamic);
            device.draw_triangles_u32(0, self.font_indices.len() as i32);
        }

        self.font_indices.clear();
        self.font_vertices.clear();
        self.line_vertices.clear();
        self.tri_vertices.clear();
        self.tri_indices.clear();
    }
}
<commit_msg>Switch debug renderer to use array textures.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use debug_font_data;
use device::{Device, GpuMarker, Program, VAOId, TextureId, VertexDescriptor};
use device::{TextureFilter, VertexAttribute, VertexUsageHint, VertexAttributeKind, TextureTarget};
use euclid::{Transform3D, Point2D, Size2D, Rect};
use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, TextureSampler};
use internal_types::RenderTargetMode;
use std::f32;
use api::{ColorU, ImageFormat, DeviceUintSize};

const DESC_FONT: VertexDescriptor = VertexDescriptor {
    vertex_attributes: &[
        VertexAttribute { name: "aPosition", count: 2, kind: VertexAttributeKind::F32 },
        VertexAttribute { name: "aColor", count: 4, kind: VertexAttributeKind::U8Norm },
        VertexAttribute { name: "aColorTexCoord", count: 2, kind: VertexAttributeKind::F32 },
    ],
    instance_attributes: &[]
};

const DESC_COLOR: VertexDescriptor = VertexDescriptor {
    vertex_attributes: &[
        VertexAttribute { name: "aPosition", count: 2, kind: VertexAttributeKind::F32 },
        VertexAttribute { name: "aColor", count: 4, kind: VertexAttributeKind::U8Norm },
    ],
    instance_attributes: &[]
};

#[repr(C)]
pub struct DebugFontVertex {
    pub x: f32,
    pub y: f32,
    pub color: ColorU,
    pub u: f32,
    pub v: f32,
}

impl DebugFontVertex {
    pub fn new(x: f32, y: f32, u: f32, v: f32, color: ColorU) -> DebugFontVertex {
        DebugFontVertex {
            x,
            y,
            color,
            u,
            v,
        }
    }
}

#[repr(C)]
pub struct DebugColorVertex {
    pub x: f32,
    pub y: f32,
    pub color: ColorU,
}

impl DebugColorVertex {
    pub fn new(x: f32, y: f32, color: ColorU) -> DebugColorVertex {
        DebugColorVertex {
            x,
            y,
            color,
        }
    }
}

pub struct DebugRenderer {
    font_vertices: Vec<DebugFontVertex>,
    font_indices: Vec<u32>,
    font_program: Program,
    font_vao: VAOId,
    font_texture_id: TextureId,

    tri_vertices: Vec<DebugColorVertex>,
    tri_indices: Vec<u32>,
    tri_vao: VAOId,
    line_vertices: Vec<DebugColorVertex>,
    line_vao: VAOId,
    color_program: Program,
}

impl DebugRenderer {
    pub fn new(device: &mut Device) -> DebugRenderer {
        let font_program = device.create_program("debug_font", "shared_other", &DESC_FONT).unwrap();
        let color_program = device.create_program("debug_color", "shared_other", &DESC_COLOR).unwrap();

        let font_vao = device.create_vao(&DESC_FONT, 32);
        let line_vao = device.create_vao(&DESC_COLOR, 32);
        let tri_vao = device.create_vao(&DESC_COLOR, 32);

        let font_texture_id = device.create_texture_ids(1, TextureTarget::Array)[0];
        device.init_texture(font_texture_id,
                            debug_font_data::BMP_WIDTH,
                            debug_font_data::BMP_HEIGHT,
                            ImageFormat::A8,
                            TextureFilter::Linear,
                            RenderTargetMode::None,
                            1,
                            Some(&debug_font_data::FONT_BITMAP));

        DebugRenderer {
            font_vertices: Vec::new(),
            font_indices: Vec::new(),
            line_vertices: Vec::new(),
            tri_vao,
            tri_vertices: Vec::new(),
            tri_indices: Vec::new(),
            font_program,
            color_program,
            font_vao,
            line_vao,
            font_texture_id,
        }
    }

    pub fn deinit(&mut self, device: &mut Device) {
        device.delete_program(&mut self.font_program);
        device.delete_program(&mut self.color_program);
    }

    pub fn line_height(&self) -> f32 {
        debug_font_data::FONT_SIZE as f32 * 1.1
    }

    pub fn add_text(&mut self,
                    x: f32,
                    y: f32,
                    text: &str,
                    color: ColorU) -> Rect<f32> {
        let mut x_start = x;
        let ipw = 1.0 / debug_font_data::BMP_WIDTH as f32;
        let iph = 1.0 / debug_font_data::BMP_HEIGHT as f32;

        let mut min_x = f32::MAX;
        let mut max_x = -f32::MAX;
        let mut min_y = f32::MAX;
        let mut max_y = -f32::MAX;

        for c in text.chars() {
            let c = c as usize - debug_font_data::FIRST_GLYPH_INDEX as usize;
            if c < debug_font_data::GLYPHS.len() {
                let glyph = &debug_font_data::GLYPHS[c];

                let x0 = (x_start + glyph.xo + 0.5).floor();
                let y0 = (y + glyph.yo + 0.5).floor();

                let x1 = x0 + glyph.x1 as f32 - glyph.x0 as f32;
                let y1 = y0 + glyph.y1 as f32 - glyph.y0 as f32;

                let s0 = glyph.x0 as f32 * ipw;
                let t0 = glyph.y0 as f32 * iph;
                let s1 = glyph.x1 as f32 * ipw;
                let t1 = glyph.y1 as f32 * iph;

                x_start += glyph.xa;

                let vertex_count = self.font_vertices.len() as u32;

                self.font_vertices.push(DebugFontVertex::new(x0, y0, s0, t0, color));
                self.font_vertices.push(DebugFontVertex::new(x1, y0, s1, t0, color));
                self.font_vertices.push(DebugFontVertex::new(x0, y1, s0, t1, color));
                self.font_vertices.push(DebugFontVertex::new(x1, y1, s1, t1, color));

                self.font_indices.push(vertex_count + 0);
                self.font_indices.push(vertex_count + 1);
                self.font_indices.push(vertex_count + 2);
                self.font_indices.push(vertex_count + 2);
                self.font_indices.push(vertex_count + 1);
                self.font_indices.push(vertex_count + 3);

                min_x = min_x.min(x0);
                max_x = max_x.max(x1);
                min_y = min_y.min(y0);
                max_y = max_y.max(y1);
            }
        }

        Rect::new(Point2D::new(min_x, min_y), Size2D::new(max_x-min_x, max_y-min_y))
    }

    pub fn add_quad(&mut self,
                    x0: f32,
                    y0: f32,
                    x1: f32,
                    y1: f32,
                    color_top: ColorU,
                    color_bottom: ColorU) {
        let vertex_count = self.tri_vertices.len() as u32;

        self.tri_vertices.push(DebugColorVertex::new(x0, y0, color_top));
        self.tri_vertices.push(DebugColorVertex::new(x1, y0, color_top));
        self.tri_vertices.push(DebugColorVertex::new(x0, y1, color_bottom));
        self.tri_vertices.push(DebugColorVertex::new(x1, y1, color_bottom));

        self.tri_indices.push(vertex_count + 0);
        self.tri_indices.push(vertex_count + 1);
        self.tri_indices.push(vertex_count + 2);
        self.tri_indices.push(vertex_count + 2);
        self.tri_indices.push(vertex_count + 1);
        self.tri_indices.push(vertex_count + 3);
    }

    #[allow(dead_code)]
    pub fn add_line(&mut self,
                    x0: i32,
                    y0: i32,
                    color0: ColorU,
                    x1: i32,
                    y1: i32,
                    color1: ColorU) {
        self.line_vertices.push(DebugColorVertex::new(x0 as f32, y0 as f32, color0));
        self.line_vertices.push(DebugColorVertex::new(x1 as f32, y1 as f32, color1));
    }

    pub fn render(&mut self,
                  device: &mut Device,
                  viewport_size: &DeviceUintSize) {
        let _gm = GpuMarker::new(device.rc_gl(), "debug");
        device.disable_depth();
        device.set_blend(true);
        device.set_blend_mode_alpha();

        let projection = Transform3D::ortho(0.0,
                                            viewport_size.width as f32,
                                            viewport_size.height as f32,
                                            0.0,
                                            ORTHO_NEAR_PLANE,
                                            ORTHO_FAR_PLANE);

        // Triangles
        if !self.tri_vertices.is_empty() {
            device.bind_program(&self.color_program);
            device.set_uniforms(&self.color_program, &projection);
            device.bind_vao(self.tri_vao);
            device.update_vao_indices(self.tri_vao,
                                      &self.tri_indices,
                                      VertexUsageHint::Dynamic);
            device.update_vao_main_vertices(self.tri_vao,
                                            &self.tri_vertices,
                                            VertexUsageHint::Dynamic);
            device.draw_triangles_u32(0, self.tri_indices.len() as i32);
        }

        // Lines
        if !self.line_vertices.is_empty() {
            device.bind_program(&self.color_program);
            device.set_uniforms(&self.color_program, &projection);
            device.bind_vao(self.line_vao);
            device.update_vao_main_vertices(self.line_vao,
                                            &self.line_vertices,
                                            VertexUsageHint::Dynamic);
            device.draw_nonindexed_lines(0, self.line_vertices.len() as i32);
        }

        // Glyph
        if !self.font_indices.is_empty() {
            device.bind_program(&self.font_program);
            device.set_uniforms(&self.font_program, &projection);
            device.bind_texture(TextureSampler::Color0, self.font_texture_id);
            device.bind_vao(self.font_vao);
            device.update_vao_indices(self.font_vao,
                                      &self.font_indices,
                                      VertexUsageHint::Dynamic);
            device.update_vao_main_vertices(self.font_vao,
                                            &self.font_vertices,
                                            VertexUsageHint::Dynamic);
            device.draw_triangles_u32(0, self.font_indices.len() as i32);
        }

        self.font_indices.clear();
        self.font_vertices.clear();
        self.line_vertices.clear();
        self.tri_vertices.clear();
        self.tri_indices.clear();
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// this used to cause exponential code-size blowup during LLVM passes.

#![feature(test)]

extern crate test;

struct MayUnwind;

impl Drop for MayUnwind {
    fn drop(&mut self) {
        if test::black_box(false) {
            panic!()
        }
    }
}

struct DS<U> {
    may_unwind: MayUnwind,
    name: String,
    next: U,
}

fn add<U>(ds: DS<U>, name: String) -> DS<DS<U>> {
    DS {
        may_unwind: MayUnwind,
        name: "?".to_owned(),
        next: ds,
    }
}

fn main() {
    let deserializers = DS { may_unwind: MayUnwind, name: "?".to_owned(), next: () };
    let deserializers = add(deserializers, "?".to_owned());
    let deserializers = add(deserializers, "?".to_owned());
    let deserializers = add(deserializers, "?".to_owned());
    let deserializers = add(deserializers, "?".to_owned());
    let deserializers = add(deserializers, "?".to_owned());
    let deserializers = add(deserializers, "?".to_owned());
    let deserializers = add(deserializers, "?".to_owned()); // 0.7s
    let deserializers = add(deserializers, "?".to_owned()); // 1.3s
    let deserializers = add(deserializers, "?".to_owned()); // 2.4s
    let deserializers = add(deserializers, "?".to_owned()); // 6.7s
    let deserializers = add(deserializers, "?".to_owned()); // 26.0s
    let deserializers = add(deserializers, "?".to_owned()); // 114.0s
    let deserializers = add(deserializers, "?".to_owned()); // 228.0s
    let deserializers = add(deserializers, "?".to_owned()); // 400.0s
    let deserializers = add(deserializers, "?".to_owned()); // 800.0s
    let deserializers = add(deserializers, "?".to_owned()); // 1600.0s
    let deserializers = add(deserializers, "?".to_owned()); // 3200.0s
}
<commit_msg>add min-llvm-version<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// this used to cause exponential code-size blowup during LLVM passes.
// min-llvm-version 3.9

#![feature(test)]

extern crate test;

struct MayUnwind;

impl Drop for MayUnwind {
    fn drop(&mut self) {
        if test::black_box(false) {
            panic!()
        }
    }
}

struct DS<U> {
    may_unwind: MayUnwind,
    name: String,
    next: U,
}

fn add<U>(ds: DS<U>, name: String) -> DS<DS<U>> {
    DS {
        may_unwind: MayUnwind,
        name: "?".to_owned(),
        next: ds,
    }
}

fn main() {
    let deserializers = DS { may_unwind: MayUnwind, name: "?".to_owned(), next: () };
    let deserializers = add(deserializers, "?".to_owned());
    let deserializers = add(deserializers, "?".to_owned());
    let deserializers = add(deserializers, "?".to_owned());
    let deserializers = add(deserializers, "?".to_owned());
    let deserializers = add(deserializers, "?".to_owned());
    let deserializers = add(deserializers, "?".to_owned());
    let deserializers = add(deserializers, "?".to_owned()); // 0.7s
    let deserializers = add(deserializers, "?".to_owned()); // 1.3s
    let deserializers = add(deserializers, "?".to_owned()); // 2.4s
    let deserializers = add(deserializers, "?".to_owned()); // 6.7s
    let deserializers = add(deserializers, "?".to_owned()); // 26.0s
    let deserializers = add(deserializers, "?".to_owned()); // 114.0s
    let deserializers = add(deserializers, "?".to_owned()); // 228.0s
    let deserializers = add(deserializers, "?".to_owned()); // 400.0s
    let deserializers = add(deserializers, "?".to_owned()); // 800.0s
    let deserializers = add(deserializers, "?".to_owned()); // 1600.0s
    let deserializers = add(deserializers, "?".to_owned()); // 3200.0s
}
<|endoftext|>


<commit_before>use std::io::{Cursor, Error, ErrorKind};
use tokio_codec::{Encoder, Decoder};
use bytes::{Buf, BufMut, BytesMut};
use std::mem::size_of;
use serializer::*;

use blockchain::Properties;
use net::rpc::*;

// 5 MiB limit
const MAX_PAYLOAD_LEN: u32 = 5_242_880;

#[derive(Default)]
pub struct RpcCodec {
    msg_len: u32
}

impl RpcCodec {
    pub fn new() -> RpcCodec {
        RpcCodec::default()
    }
}

impl Encoder for RpcCodec {
    type Item = RpcPayload;
    type Error = Error;

    fn encode(&mut self, pl: Self::Item, buf: &mut BytesMut) -> Result<(), Error> {
        let mut payload = Vec::<u8>::with_capacity(1024);
        payload.push_u32(pl.id);
        if let Some(msg) = pl.msg {
            match msg {
                RpcMsg::Handshake(hs) => {
                    payload.push(RpcMsgType::HANDSHAKE as u8);
                    payload.push(hs.peer_type as u8);
                },
                RpcMsg::Properties(props) => {
                    payload.push(RpcMsgType::PROPERTIES as u8);
                    if let Some(props) = props {
                        payload.push_u64(props.height);
                    }
                }
            }
        }

        buf.reserve(4 + payload.len());
        buf.put_u32_be(4 + (payload.len() as u32));
        buf.put_slice(&payload);
        debug_assert!((buf.capacity() as u32) < MAX_PAYLOAD_LEN);
        let mut v = Vec::<u8>::with_capacity(buf.len());
        v.extend_from_slice(buf);
        Ok(())
    }
}

impl Decoder for RpcCodec {
    type Item = RpcPayload;
    type Error = Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Error> {
        if self.msg_len == 0 && buf.len() >= 4 {
            let buf = buf.split_to(4);
            self.msg_len = u32_from_buf!(buf);
            if self.msg_len <= 4 {
                return Err(Error::new(ErrorKind::Other, "payload must be >4 bytes"))
            } else if self.msg_len > MAX_PAYLOAD_LEN {
                return Err(Error::new(ErrorKind::Other, format!("payload must be <={} bytes", MAX_PAYLOAD_LEN)))
            }
            self.msg_len -= 4;
        }
        if self.msg_len != 0 && buf.len() >= self.msg_len as usize {
            let msg_len = self.msg_len;
            let mut cur = Cursor::new(buf.split_to(msg_len as usize));
            self.msg_len = 0;

            let id = cur.get_u32_be();
            if msg_len == 4 {
                return Ok(Some(RpcPayload {
                    id,
                    msg: None
                }))
            }

            let msg = match cur.get_u8() {
                t if t == RpcMsgType::HANDSHAKE as u8 => {
                    let peer_type = match cur.get_u8() {
                        t if t == PeerType::NODE as u8 => PeerType::NODE,
                        t if t == PeerType::WALLET as u8 => PeerType::WALLET,
                        _ => return Err(Error::new(ErrorKind::Other, "invalid client type"))
                    };
                    RpcMsg::Handshake(RpcMsgHandshake {
                        peer_type
                    })
                },
                t if t == RpcMsgType::PROPERTIES as u8 => {
                    if u64::from(msg_len) - cur.position() >= size_of::<u64>() as u64 {
                        let height = cur.get_u64_be();
                        RpcMsg::Properties(Some(Properties {
                            height
                        }))
                    } else {
                        RpcMsg::Properties(None)
                    }
                },
                //t if t == RpcMsgType::BROADCAST as u8 => RpcMsg::Broadcast,
                _ => return Err(Error::new(ErrorKind::Other, "invalid msg type"))
            };

            Ok(Some(RpcPayload {
                id,
                msg: Some(msg)
            }))
        } else {
            Ok(None)
        }
    }
}
<commit_msg>Change wording from "invalid client type" to "invalid peer type"<commit_after>use std::io::{Cursor, Error, ErrorKind};
use tokio_codec::{Encoder, Decoder};
use bytes::{Buf, BufMut, BytesMut};
use std::mem::size_of;
use serializer::*;

use blockchain::Properties;
use net::rpc::*;

// 5 MiB limit
const MAX_PAYLOAD_LEN: u32 = 5_242_880;

#[derive(Default)]
pub struct RpcCodec {
    msg_len: u32
}

impl RpcCodec {
    pub fn new() -> RpcCodec {
        RpcCodec::default()
    }
}

impl Encoder for RpcCodec {
    type Item = RpcPayload;
    type Error = Error;

    fn encode(&mut self, pl: Self::Item, buf: &mut BytesMut) -> Result<(), Error> {
        let mut payload = Vec::<u8>::with_capacity(1024);
        payload.push_u32(pl.id);
        if let Some(msg) = pl.msg {
            match msg {
                RpcMsg::Handshake(hs) => {
                    payload.push(RpcMsgType::HANDSHAKE as u8);
                    payload.push(hs.peer_type as u8);
                },
                RpcMsg::Properties(props) => {
                    payload.push(RpcMsgType::PROPERTIES as u8);
                    if let Some(props) = props {
                        payload.push_u64(props.height);
                    }
                }
            }
        }

        buf.reserve(4 + payload.len());
        buf.put_u32_be(4 + (payload.len() as u32));
        buf.put_slice(&payload);
        debug_assert!((buf.capacity() as u32) < MAX_PAYLOAD_LEN);
        let mut v = Vec::<u8>::with_capacity(buf.len());
        v.extend_from_slice(buf);
        Ok(())
    }
}

impl Decoder for RpcCodec {
    type Item = RpcPayload;
    type Error = Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Error> {
        if self.msg_len == 0 && buf.len() >= 4 {
            let buf = buf.split_to(4);
            self.msg_len = u32_from_buf!(buf);
            if self.msg_len <= 4 {
                return Err(Error::new(ErrorKind::Other, "payload must be >4 bytes"))
            } else if self.msg_len > MAX_PAYLOAD_LEN {
                return Err(Error::new(ErrorKind::Other, format!("payload must be <={} bytes", MAX_PAYLOAD_LEN)))
            }
            self.msg_len -= 4;
        }
        if self.msg_len != 0 && buf.len() >= self.msg_len as usize {
            let msg_len = self.msg_len;
            let mut cur = Cursor::new(buf.split_to(msg_len as usize));
            self.msg_len = 0;

            let id = cur.get_u32_be();
            if msg_len == 4 {
                return Ok(Some(RpcPayload {
                    id,
                    msg: None
                }))
            }

            let msg = match cur.get_u8() {
                t if t == RpcMsgType::HANDSHAKE as u8 => {
                    let peer_type = match cur.get_u8() {
                        t if t == PeerType::NODE as u8 => PeerType::NODE,
                        t if t == PeerType::WALLET as u8 => PeerType::WALLET,
                        _ => return Err(Error::new(ErrorKind::Other, "invalid peer type"))
                    };
                    RpcMsg::Handshake(RpcMsgHandshake {
                        peer_type
                    })
                },
                t if t == RpcMsgType::PROPERTIES as u8 => {
                    if u64::from(msg_len) - cur.position() >= size_of::<u64>() as u64 {
                        let height = cur.get_u64_be();
                        RpcMsg::Properties(Some(Properties {
                            height
                        }))
                    } else {
                        RpcMsg::Properties(None)
                    }
                },
                //t if t == RpcMsgType::BROADCAST as u8 => RpcMsg::Broadcast,
                _ => return Err(Error::new(ErrorKind::Other, "invalid msg type"))
            };

            Ok(Some(RpcPayload {
                id,
                msg: Some(msg)
            }))
        } else {
            Ok(None)
        }
    }
}
<|endoftext|>


<commit_before>extern crate serialize;

use std::io::process::Command;
use std::io::{File, TempDir};

fn main() {
    use std::io::fs;

    let (args, passthrough) = parse_arguments();

    // getting the path from the ANDROID_HOME env
    let sdk_path = std::os::env().move_iter().find(|&(ref k, _)| k.as_slice() == "ANDROID_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the ANDROID_HOME environment variable");

    // hardcoding ndk path
    let ndk_path = std::os::env().move_iter().find(|&(ref k, _)| k.as_slice() == "NDK_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the NDK_HOME environment variable");

    // hardcoding ndk path
    let standalone_path = std::os::env().move_iter().find(|&(ref k, _)| k.as_slice() == "NDK_STANDALONE")
        .map(|(_, v)| Path::new(v)).unwrap_or(Path::new("/opt/ndk_standalone"));

    // creating the build directory that will contain all the necessary files to create teh apk
    let directory = build_directory(&sdk_path, args.output.filestem_str().unwrap());

    // compiling android_native_app_glue.c
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .arg(ndk_path.join("sources").join("android").join("native_app_glue").join("android_native_app_glue.c"))
        .arg("-c")
        .arg("-o").arg(directory.path().join("android_native_app_glue.o"))
        .stdout(std::io::process::InheritFd(1)).stderr(std::io::process::InheritFd(2))
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling gcc to link to an executable
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .args(passthrough.as_slice())
        .arg(directory.path().join("android_native_app_glue.o"))
        .arg("-o").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .arg("-Wl,-E")
        .stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2))//.cwd(directory.path())
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling elfedit to turn our executable into a shared object
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-elfedit"))
        .arg("--output-type").arg("dyn")
        .arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2))
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing elfedit");
        std::os::set_exit_status(1);
        return;
    }

    // calling objdump to make sure that our object has `ANativeActivity_onCreate`
    {
        let mut process =
            Command::new(standalone_path.join("bin").join("arm-linux-androideabi-objdump"))
            .arg("-x").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
            .stderr(std::io::process::InheritFd(2))
            .spawn().unwrap();

        // TODO: use UFCS instead
        fn by_ref<'a, T: Reader>(r: &'a mut T) -> std::io::RefReader<'a, T> { r.by_ref() };

        let stdout = process.stdout.as_mut().unwrap();
        let mut stdout = std::io::BufferedReader::new(by_ref(stdout));

        if stdout.lines().filter_map(|l| l.ok())
            .find(|line| line.as_slice().contains("ANativeActivity_onCreate")).is_none()
        {
            println!("Error: the output file doesn't contain ANativeActivity_onCreate");
            std::os::set_exit_status(1);
            return;
        }
    }

    // executing ant
    if Command::new("ant").arg("debug").stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2)).cwd(directory.path())
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing ant debug");
        std::os::set_exit_status(1);
        return;
    }

    // copying apk file to the requested output
    fs::copy(&directory.path().join("bin").join("rust-android-debug.apk"),
        &args.output).unwrap();
}

struct Args {
    output: Path,
}

fn parse_arguments() -> (Args, Vec<String>) {
    let mut result_output = None;
    let mut result_passthrough = Vec::new();

    let args = std::os::args();
    let mut args = args.move_iter().skip(1);

    loop {
        let arg = match args.next() {
            None => return (
                Args {
                    output: result_output.expect("Could not find -o argument")
                },
                result_passthrough
            ),
            Some(arg) => arg
        };

        match arg.as_slice() {
            "-o" => {
                result_output = Some(Path::new(args.next().expect("-o must be followed by the output name")));
            },
            _ => result_passthrough.push(arg)
        };
    }
}

fn build_directory(sdk_dir: &Path, crate_name: &str) -> TempDir {
    use std::io::fs;

    let build_directory = TempDir::new("android-rs-glue-rust-to-apk")
        .ok().expect("Could not create temporary build directory");

    File::create(&build_directory.path().join("AndroidManifest.xml")).unwrap()
        .write_str(build_manifest(crate_name).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("build.xml")).unwrap()
        .write_str(build_build_xml().as_slice())
        .unwrap();

    File::create(&build_directory.path().join("local.properties")).unwrap()
        .write_str(build_local_properties(sdk_dir).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("project.properties")).unwrap()
        .write_str(build_project_properties().as_slice())
        .unwrap();

    {
        let src_path = build_directory.path().join("src").join("com").join("example")
            .join("native_activity");
        fs::mkdir_recursive(&src_path, std::io::UserRWX).unwrap();
        File::create(&src_path.join("MyNativeActivity.java")).unwrap()
            .write_str(build_java_class().as_slice())
            .unwrap();
    }

    {
        let libs_path = build_directory.path().join("libs").join("armeabi");
        fs::mkdir_recursive(&libs_path, std::io::UserRWX).unwrap();
    }

    build_directory
}

fn build_manifest(crate_name: &str) -> String {
    format!(r#"<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.native_activity"
        android:versionCode="1"
        android:versionName="1.0">

    <uses-sdk android:minSdkVersion="18" />

    <application android:label="{0}" android:hasCode="true">
        <activity android:name="com.example.native_activity.MyNativeActivity"
                android:label="{0}"
                android:configChanges="orientation|keyboardHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
<!-- END_INCLUDE(manifest) -->
"#, crate_name)
}

fn build_build_xml() -> String {
    format!(r#"<?xml version="1.0" encoding="UTF-8"?>
<project name="rust-android" default="help">
    <property file="local.properties" />
    <loadproperties srcFile="project.properties" />
    <import file="custom_rules.xml" optional="true" />
    <import file="${{sdk.dir}}/tools/ant/build.xml" />
</project>
"#)
}

fn build_local_properties(sdk_dir: &Path) -> String {
    use std::os;
    format!(r"sdk.dir={}", os::make_absolute(sdk_dir).display())
}

fn build_project_properties() -> String {
    format!(r"target=android-18")
}

fn build_java_class() -> String {
    format!(r#"
package com.example.native_activity;

import android.app.NativeActivity;
import android.util.Log;

public class MyNativeActivity extends NativeActivity {{
  static {{
    System.loadLibrary("main");
  }}

  private static String TAG = "MyNativeActivity";

  public MyNativeActivity() {{
    super();
    Log.v(TAG, "Creating MyNativeActivity");
  }}
}}"#)
}
<commit_msg>Disabling symbol checker in apk-builder for now<commit_after>extern crate serialize;

use std::io::process::Command;
use std::io::{File, TempDir};

fn main() {
    use std::io::fs;

    let (args, passthrough) = parse_arguments();

    // getting the path from the ANDROID_HOME env
    let sdk_path = std::os::env().move_iter().find(|&(ref k, _)| k.as_slice() == "ANDROID_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the ANDROID_HOME environment variable");

    // hardcoding ndk path
    let ndk_path = std::os::env().move_iter().find(|&(ref k, _)| k.as_slice() == "NDK_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the NDK_HOME environment variable");

    // hardcoding ndk path
    let standalone_path = std::os::env().move_iter().find(|&(ref k, _)| k.as_slice() == "NDK_STANDALONE")
        .map(|(_, v)| Path::new(v)).unwrap_or(Path::new("/opt/ndk_standalone"));

    // creating the build directory that will contain all the necessary files to create teh apk
    let directory = build_directory(&sdk_path, args.output.filestem_str().unwrap());

    // compiling android_native_app_glue.c
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .arg(ndk_path.join("sources").join("android").join("native_app_glue").join("android_native_app_glue.c"))
        .arg("-c")
        .arg("-o").arg(directory.path().join("android_native_app_glue.o"))
        .stdout(std::io::process::InheritFd(1)).stderr(std::io::process::InheritFd(2))
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling gcc to link to an executable
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .args(passthrough.as_slice())
        .arg(directory.path().join("android_native_app_glue.o"))
        .arg("-o").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .arg("-Wl,-E")
        .stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2))//.cwd(directory.path())
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling elfedit to turn our executable into a shared object
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-elfedit"))
        .arg("--output-type").arg("dyn")
        .arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2))
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing elfedit");
        std::os::set_exit_status(1);
        return;
    }

    // calling objdump to make sure that our object has `ANativeActivity_onCreate`
    // TODO: not working
    /*{
        let mut process =
            Command::new(standalone_path.join("bin").join("arm-linux-androideabi-objdump"))
            .arg("-x").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
            .stderr(std::io::process::InheritFd(2))
            .spawn().unwrap();

        // TODO: use UFCS instead
        fn by_ref<'a, T: Reader>(r: &'a mut T) -> std::io::RefReader<'a, T> { r.by_ref() };

        let stdout = process.stdout.as_mut().unwrap();
        let mut stdout = std::io::BufferedReader::new(by_ref(stdout));

        if stdout.lines().filter_map(|l| l.ok())
            .find(|line| line.as_slice().contains("ANativeActivity_onCreate")).is_none()
        {
            println!("Error: the output file doesn't contain ANativeActivity_onCreate");
            std::os::set_exit_status(1);
            return;
        }
    }*/

    // executing ant
    if Command::new("ant").arg("debug").stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2)).cwd(directory.path())
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing ant debug");
        std::os::set_exit_status(1);
        return;
    }

    // copying apk file to the requested output
    fs::copy(&directory.path().join("bin").join("rust-android-debug.apk"),
        &args.output).unwrap();
}

struct Args {
    output: Path,
}

fn parse_arguments() -> (Args, Vec<String>) {
    let mut result_output = None;
    let mut result_passthrough = Vec::new();

    let args = std::os::args();
    let mut args = args.move_iter().skip(1);

    loop {
        let arg = match args.next() {
            None => return (
                Args {
                    output: result_output.expect("Could not find -o argument")
                },
                result_passthrough
            ),
            Some(arg) => arg
        };

        match arg.as_slice() {
            "-o" => {
                result_output = Some(Path::new(args.next().expect("-o must be followed by the output name")));
            },
            _ => result_passthrough.push(arg)
        };
    }
}

fn build_directory(sdk_dir: &Path, crate_name: &str) -> TempDir {
    use std::io::fs;

    let build_directory = TempDir::new("android-rs-glue-rust-to-apk")
        .ok().expect("Could not create temporary build directory");

    File::create(&build_directory.path().join("AndroidManifest.xml")).unwrap()
        .write_str(build_manifest(crate_name).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("build.xml")).unwrap()
        .write_str(build_build_xml().as_slice())
        .unwrap();

    File::create(&build_directory.path().join("local.properties")).unwrap()
        .write_str(build_local_properties(sdk_dir).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("project.properties")).unwrap()
        .write_str(build_project_properties().as_slice())
        .unwrap();

    {
        let src_path = build_directory.path().join("src").join("com").join("example")
            .join("native_activity");
        fs::mkdir_recursive(&src_path, std::io::UserRWX).unwrap();
        File::create(&src_path.join("MyNativeActivity.java")).unwrap()
            .write_str(build_java_class().as_slice())
            .unwrap();
    }

    {
        let libs_path = build_directory.path().join("libs").join("armeabi");
        fs::mkdir_recursive(&libs_path, std::io::UserRWX).unwrap();
    }

    build_directory
}

fn build_manifest(crate_name: &str) -> String {
    format!(r#"<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.native_activity"
        android:versionCode="1"
        android:versionName="1.0">

    <uses-sdk android:minSdkVersion="18" />

    <application android:label="{0}" android:hasCode="true">
        <activity android:name="com.example.native_activity.MyNativeActivity"
                android:label="{0}"
                android:configChanges="orientation|keyboardHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
<!-- END_INCLUDE(manifest) -->
"#, crate_name)
}

fn build_build_xml() -> String {
    format!(r#"<?xml version="1.0" encoding="UTF-8"?>
<project name="rust-android" default="help">
    <property file="local.properties" />
    <loadproperties srcFile="project.properties" />
    <import file="custom_rules.xml" optional="true" />
    <import file="${{sdk.dir}}/tools/ant/build.xml" />
</project>
"#)
}

fn build_local_properties(sdk_dir: &Path) -> String {
    use std::os;
    format!(r"sdk.dir={}", os::make_absolute(sdk_dir).display())
}

fn build_project_properties() -> String {
    format!(r"target=android-18")
}

fn build_java_class() -> String {
    format!(r#"
package com.example.native_activity;

import android.app.NativeActivity;
import android.util.Log;

public class MyNativeActivity extends NativeActivity {{
  static {{
    System.loadLibrary("main");
  }}

  private static String TAG = "MyNativeActivity";

  public MyNativeActivity() {{
    super();
    Log.v(TAG, "Creating MyNativeActivity");
  }}
}}"#)
}
<|endoftext|>


<commit_before><commit_msg>expand on tests for count and max<commit_after><|endoftext|>


<commit_before>use std::time::Duration;
use std::{fmt, io};

use actix_net::connector::TcpConnector;
use actix_net::resolver::Resolver;
use actix_net::service::{Service, ServiceExt};
use actix_net::timeout::{TimeoutError, TimeoutService};
use futures::future::Either;
use futures::Poll;
use tokio_io::{AsyncRead, AsyncWrite};
use trust_dns_resolver::config::{ResolverConfig, ResolverOpts};

use super::connect::Connect;
use super::connection::{Connection, IoConnection};
use super::error::ConnectorError;
use super::pool::ConnectionPool;

#[cfg(feature = "ssl")]
use actix_net::ssl::OpensslConnector;
#[cfg(feature = "ssl")]
use openssl::ssl::{SslConnector, SslMethod};

#[cfg(not(feature = "ssl"))]
type SslConnector = ();

/// Http client connector builde instance.
/// `Connector` type uses builder-like pattern for connector service construction.
pub struct Connector {
    resolver: Resolver<Connect>,
    timeout: Duration,
    conn_lifetime: Duration,
    conn_keep_alive: Duration,
    disconnect_timeout: Duration,
    limit: usize,
    #[allow(dead_code)]
    connector: SslConnector,
}

impl Default for Connector {
    fn default() -> Connector {
        let connector = {
            #[cfg(feature = "ssl")]
            {
                SslConnector::builder(SslMethod::tls()).unwrap().build()
            }
            #[cfg(not(feature = "ssl"))]
            {
                ()
            }
        };

        Connector {
            connector,
            resolver: Resolver::default(),
            timeout: Duration::from_secs(1),
            conn_lifetime: Duration::from_secs(75),
            conn_keep_alive: Duration::from_secs(15),
            disconnect_timeout: Duration::from_millis(3000),
            limit: 100,
        }
    }
}

impl Connector {
    /// Use custom resolver.
    pub fn resolver(mut self, resolver: Resolver<Connect>) -> Self {
        self.resolver = resolver;;
        self
    }

    /// Use custom resolver configuration.
    pub fn resolver_config(mut self, cfg: ResolverConfig, opts: ResolverOpts) -> Self {
        self.resolver = Resolver::new(cfg, opts);
        self
    }

    /// Connection timeout, i.e. max time to connect to remote host including dns name resolution.
    /// Set to 1 second by default.
    pub fn timeout(mut self, timeout: Duration) -> Self {
        self.timeout = timeout;
        self
    }

    #[cfg(feature = "ssl")]
    /// Use custom `SslConnector` instance.
    pub fn ssl(mut self, connector: SslConnector) -> Self {
        self.connector = connector;
        self
    }

    /// Set total number of simultaneous connections per type of scheme.
    ///
    /// If limit is 0, the connector has no limit.
    /// The default limit size is 100.
    pub fn limit(mut self, limit: usize) -> Self {
        self.limit = limit;
        self
    }

    /// Set keep-alive period for opened connection.
    ///
    /// Keep-alive period is the period between connection usage. If
    /// the delay between repeated usages of the same connection
    /// exceeds this period, the connection is closed.
    /// Default keep-alive period is 15 seconds.
    pub fn conn_keep_alive(mut self, dur: Duration) -> Self {
        self.conn_keep_alive = dur;
        self
    }

    /// Set max lifetime period for connection.
    ///
    /// Connection lifetime is max lifetime of any opened connection
    /// until it is closed regardless of keep-alive period.
    /// Default lifetime period is 75 seconds.
    pub fn conn_lifetime(mut self, dur: Duration) -> Self {
        self.conn_lifetime = dur;
        self
    }

    /// Set server connection disconnect timeout in milliseconds.
    ///
    /// Defines a timeout for disconnect connection. If a disconnect procedure does not complete
    /// within this time, the socket get dropped. This timeout affects only secure connections.
    ///
    /// To disable timeout set value to 0.
    ///
    /// By default disconnect timeout is set to 3000 milliseconds.
    pub fn disconnect_timeout(mut self, dur: Duration) -> Self {
        self.disconnect_timeout = dur;
        self
    }

    /// Finish configuration process and create connector service.
    pub fn service(
        self,
    ) -> impl Service<Connect, Response = impl Connection, Error = ConnectorError> + Clone
    {
        #[cfg(not(feature = "ssl"))]
        {
            let connector = TimeoutService::new(
                self.timeout,
                self.resolver
                    .map_err(ConnectorError::from)
                    .and_then(TcpConnector::default().from_err()),
            ).map_err(|e| match e {
                TimeoutError::Service(e) => e,
                TimeoutError::Timeout => ConnectorError::Timeout,
            });

            connect_impl::InnerConnector {
                tcp_pool: ConnectionPool::new(
                    connector,
                    self.conn_lifetime,
                    self.conn_keep_alive,
                    None,
                    self.limit,
                ),
            }
        }
        #[cfg(feature = "ssl")]
        {
            let ssl_service = TimeoutService::new(
                self.timeout,
                self.resolver
                    .clone()
                    .map_err(ConnectorError::from)
                    .and_then(TcpConnector::default().from_err())
                    .and_then(
                        OpensslConnector::service(self.connector)
                            .map_err(ConnectorError::SslError),
                    ),
            ).map_err(|e| match e {
                TimeoutError::Service(e) => e,
                TimeoutError::Timeout => ConnectorError::Timeout,
            });

            let tcp_service = TimeoutService::new(
                self.timeout,
                self.resolver
                    .map_err(ConnectorError::from)
                    .and_then(TcpConnector::default().from_err()),
            ).map_err(|e| match e {
                TimeoutError::Service(e) => e,
                TimeoutError::Timeout => ConnectorError::Timeout,
            });

            connect_impl::InnerConnector {
                tcp_pool: ConnectionPool::new(
                    tcp_service,
                    self.conn_lifetime,
                    self.conn_keep_alive,
                    None,
                    self.limit,
                ),
                ssl_pool: ConnectionPool::new(
                    ssl_service,
                    self.conn_lifetime,
                    self.conn_keep_alive,
                    Some(self.disconnect_timeout),
                    self.limit,
                ),
            }
        }
    }
}

#[cfg(not(feature = "ssl"))]
mod connect_impl {
    use super::*;
    use futures::future::{err, FutureResult};

    pub(crate) struct InnerConnector<T, Io>
    where
        Io: AsyncRead + AsyncWrite + 'static,
        T: Service<Connect, Response = (Connect, Io), Error = ConnectorError>,
    {
        pub(crate) tcp_pool: ConnectionPool<T, Io>,
    }

    impl<T, Io> Clone for InnerConnector<T, Io>
    where
        Io: AsyncRead + AsyncWrite + 'static,
        T: Service<Connect, Response = (Connect, Io), Error = ConnectorError> + Clone,
    {
        fn clone(&self) -> Self {
            InnerConnector {
                tcp_pool: self.tcp_pool.clone(),
            }
        }
    }

    impl<T, Io> Service<Connect> for InnerConnector<T, Io>
    where
        Io: AsyncRead + AsyncWrite + 'static,
        T: Service<Connect, Response = (Connect, Io), Error = ConnectorError>,
    {
        type Response = IoConnection<Io>;
        type Error = ConnectorError;
        type Future = Either<
            <ConnectionPool<T, Io> as Service<Connect>>::Future,
            FutureResult<IoConnection<Io>, ConnectorError>,
        >;

        fn poll_ready(&mut self) -> Poll<(), Self::Error> {
            self.tcp_pool.poll_ready()
        }

        fn call(&mut self, req: Connect) -> Self::Future {
            if req.is_secure() {
                Either::B(err(ConnectorError::SslIsNotSupported))
            } else if let Err(e) = req.validate() {
                Either::B(err(e))
            } else {
                Either::A(self.tcp_pool.call(req))
            }
        }
    }
}

#[cfg(feature = "ssl")]
mod connect_impl {
    use std::marker::PhantomData;

    use futures::future::{err, FutureResult};
    use futures::{Async, Future, Poll};

    use super::*;

    pub(crate) struct InnerConnector<T1, T2, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
        T1: Service<
            Request = Connect,
            Response = (Connect, Io1),
            Error = ConnectorError,
        >,
        T2: Service<
            Request = Connect,
            Response = (Connect, Io2),
            Error = ConnectorError,
        >,
    {
        pub(crate) tcp_pool: ConnectionPool<T1, Io1>,
        pub(crate) ssl_pool: ConnectionPool<T2, Io2>,
    }

    impl<T1, T2, Io1, Io2> Clone for InnerConnector<T1, T2, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
        T1: Service<Connect, Response = (Connect, Io1), Error = ConnectorError> + Clone,
        T2: Service<Connect, Response = (Connect, Io2), Error = ConnectorError> + Clone,
    {
        fn clone(&self) -> Self {
            InnerConnector {
                tcp_pool: self.tcp_pool.clone(),
                ssl_pool: self.ssl_pool.clone(),
            }
        }
    }

    impl<T1, T2, Io1, Io2> Service for InnerConnector<T1, T2, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
        T1: Service<Connect, Response = (Connect, Io1), Error = ConnectorError>,
        T2: Service<Connect, Response = (Connect, Io2), Error = ConnectorError>,
    {
        type Response = IoEither<IoConnection<Io1>, IoConnection<Io2>>;
        type Error = ConnectorError;
        type Future = Either<
            FutureResult<Self::Response, Self::Error>,
            Either<
                InnerConnectorResponseA<T1, Io1, Io2>,
                InnerConnectorResponseB<T2, Io1, Io2>,
            >,
        >;

        fn poll_ready(&mut self) -> Poll<(), Self::Error> {
            self.tcp_pool.poll_ready()
        }

        fn call(&mut self, req: Connect) -> Self::Future {
            if let Err(e) = req.validate() {
                Either::A(err(e))
            } else if req.is_secure() {
                Either::B(Either::B(InnerConnectorResponseB {
                    fut: self.ssl_pool.call(req),
                    _t: PhantomData,
                }))
            } else {
                Either::B(Either::A(InnerConnectorResponseA {
                    fut: self.tcp_pool.call(req),
                    _t: PhantomData,
                }))
            }
        }
    }

    pub(crate) struct InnerConnectorResponseA<T, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        T: Service<Connect, Response = (Connect, Io1), Error = ConnectorError>,
    {
        fut: <ConnectionPool<T, Io1> as Service>::Future,
        _t: PhantomData<Io2>,
    }

    impl<T, Io1, Io2> Future for InnerConnectorResponseA<T, Io1, Io2>
    where
        T: Service<Connect, Response = (Connect, Io1), Error = ConnectorError>,
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
    {
        type Item = IoEither<IoConnection<Io1>, IoConnection<Io2>>;
        type Error = ConnectorError;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            match self.fut.poll()? {
                Async::NotReady => Ok(Async::NotReady),
                Async::Ready(res) => Ok(Async::Ready(IoEither::A(res))),
            }
        }
    }

    pub(crate) struct InnerConnectorResponseB<T, Io1, Io2>
    where
        Io2: AsyncRead + AsyncWrite + 'static,
        T: Service<Connect, Response = (Connect, Io2), Error = ConnectorError>,
    {
        fut: <ConnectionPool<T, Io2> as Service>::Future,
        _t: PhantomData<Io1>,
    }

    impl<T, Io1, Io2> Future for InnerConnectorResponseB<T, Io1, Io2>
    where
        T: Service<Connect, Response = (Connect, Io2), Error = ConnectorError>,
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
    {
        type Item = IoEither<IoConnection<Io1>, IoConnection<Io2>>;
        type Error = ConnectorError;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            match self.fut.poll()? {
                Async::NotReady => Ok(Async::NotReady),
                Async::Ready(res) => Ok(Async::Ready(IoEither::B(res))),
            }
        }
    }
}

pub(crate) enum IoEither<Io1, Io2> {
    A(Io1),
    B(Io2),
}

impl<Io1, Io2> Connection for IoEither<Io1, Io2>
where
    Io1: Connection,
    Io2: Connection,
{
    fn close(&mut self) {
        match self {
            IoEither::A(ref mut io) => io.close(),
            IoEither::B(ref mut io) => io.close(),
        }
    }

    fn release(&mut self) {
        match self {
            IoEither::A(ref mut io) => io.release(),
            IoEither::B(ref mut io) => io.release(),
        }
    }
}

impl<Io1, Io2> io::Read for IoEither<Io1, Io2>
where
    Io1: Connection,
    Io2: Connection,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match self {
            IoEither::A(ref mut io) => io.read(buf),
            IoEither::B(ref mut io) => io.read(buf),
        }
    }
}

impl<Io1, Io2> AsyncRead for IoEither<Io1, Io2>
where
    Io1: Connection,
    Io2: Connection,
{
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        match self {
            IoEither::A(ref io) => io.prepare_uninitialized_buffer(buf),
            IoEither::B(ref io) => io.prepare_uninitialized_buffer(buf),
        }
    }
}

impl<Io1, Io2> AsyncWrite for IoEither<Io1, Io2>
where
    Io1: Connection,
    Io2: Connection,
{
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        match self {
            IoEither::A(ref mut io) => io.shutdown(),
            IoEither::B(ref mut io) => io.shutdown(),
        }
    }

    fn poll_write(&mut self, buf: &[u8]) -> Poll<usize, io::Error> {
        match self {
            IoEither::A(ref mut io) => io.poll_write(buf),
            IoEither::B(ref mut io) => io.poll_write(buf),
        }
    }

    fn poll_flush(&mut self) -> Poll<(), io::Error> {
        match self {
            IoEither::A(ref mut io) => io.poll_flush(),
            IoEither::B(ref mut io) => io.poll_flush(),
        }
    }
}

impl<Io1, Io2> io::Write for IoEither<Io1, Io2>
where
    Io1: Connection,
    Io2: Connection,
{
    fn flush(&mut self) -> io::Result<()> {
        match self {
            IoEither::A(ref mut io) => io.flush(),
            IoEither::B(ref mut io) => io.flush(),
        }
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match self {
            IoEither::A(ref mut io) => io.write(buf),
            IoEither::B(ref mut io) => io.write(buf),
        }
    }
}

impl<Io1, Io2> fmt::Debug for IoEither<Io1, Io2>
where
    Io1: fmt::Debug,
    Io2: fmt::Debug,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            IoEither::A(ref io) => io.fmt(fmt),
            IoEither::B(ref io) => io.fmt(fmt),
        }
    }
}
<commit_msg>fix ssl support<commit_after>use std::time::Duration;
use std::{fmt, io};

use actix_net::connector::TcpConnector;
use actix_net::resolver::Resolver;
use actix_net::service::{Service, ServiceExt};
use actix_net::timeout::{TimeoutError, TimeoutService};
use futures::future::Either;
use futures::Poll;
use tokio_io::{AsyncRead, AsyncWrite};
use trust_dns_resolver::config::{ResolverConfig, ResolverOpts};

use super::connect::Connect;
use super::connection::{Connection, IoConnection};
use super::error::ConnectorError;
use super::pool::ConnectionPool;

#[cfg(feature = "ssl")]
use actix_net::ssl::OpensslConnector;
#[cfg(feature = "ssl")]
use openssl::ssl::{SslConnector, SslMethod};

#[cfg(not(feature = "ssl"))]
type SslConnector = ();

/// Http client connector builde instance.
/// `Connector` type uses builder-like pattern for connector service construction.
pub struct Connector {
    resolver: Resolver<Connect>,
    timeout: Duration,
    conn_lifetime: Duration,
    conn_keep_alive: Duration,
    disconnect_timeout: Duration,
    limit: usize,
    #[allow(dead_code)]
    connector: SslConnector,
}

impl Default for Connector {
    fn default() -> Connector {
        let connector = {
            #[cfg(feature = "ssl")]
            {
                SslConnector::builder(SslMethod::tls()).unwrap().build()
            }
            #[cfg(not(feature = "ssl"))]
            {
                ()
            }
        };

        Connector {
            connector,
            resolver: Resolver::default(),
            timeout: Duration::from_secs(1),
            conn_lifetime: Duration::from_secs(75),
            conn_keep_alive: Duration::from_secs(15),
            disconnect_timeout: Duration::from_millis(3000),
            limit: 100,
        }
    }
}

impl Connector {
    /// Use custom resolver.
    pub fn resolver(mut self, resolver: Resolver<Connect>) -> Self {
        self.resolver = resolver;;
        self
    }

    /// Use custom resolver configuration.
    pub fn resolver_config(mut self, cfg: ResolverConfig, opts: ResolverOpts) -> Self {
        self.resolver = Resolver::new(cfg, opts);
        self
    }

    /// Connection timeout, i.e. max time to connect to remote host including dns name resolution.
    /// Set to 1 second by default.
    pub fn timeout(mut self, timeout: Duration) -> Self {
        self.timeout = timeout;
        self
    }

    #[cfg(feature = "ssl")]
    /// Use custom `SslConnector` instance.
    pub fn ssl(mut self, connector: SslConnector) -> Self {
        self.connector = connector;
        self
    }

    /// Set total number of simultaneous connections per type of scheme.
    ///
    /// If limit is 0, the connector has no limit.
    /// The default limit size is 100.
    pub fn limit(mut self, limit: usize) -> Self {
        self.limit = limit;
        self
    }

    /// Set keep-alive period for opened connection.
    ///
    /// Keep-alive period is the period between connection usage. If
    /// the delay between repeated usages of the same connection
    /// exceeds this period, the connection is closed.
    /// Default keep-alive period is 15 seconds.
    pub fn conn_keep_alive(mut self, dur: Duration) -> Self {
        self.conn_keep_alive = dur;
        self
    }

    /// Set max lifetime period for connection.
    ///
    /// Connection lifetime is max lifetime of any opened connection
    /// until it is closed regardless of keep-alive period.
    /// Default lifetime period is 75 seconds.
    pub fn conn_lifetime(mut self, dur: Duration) -> Self {
        self.conn_lifetime = dur;
        self
    }

    /// Set server connection disconnect timeout in milliseconds.
    ///
    /// Defines a timeout for disconnect connection. If a disconnect procedure does not complete
    /// within this time, the socket get dropped. This timeout affects only secure connections.
    ///
    /// To disable timeout set value to 0.
    ///
    /// By default disconnect timeout is set to 3000 milliseconds.
    pub fn disconnect_timeout(mut self, dur: Duration) -> Self {
        self.disconnect_timeout = dur;
        self
    }

    /// Finish configuration process and create connector service.
    pub fn service(
        self,
    ) -> impl Service<Connect, Response = impl Connection, Error = ConnectorError> + Clone
    {
        #[cfg(not(feature = "ssl"))]
        {
            let connector = TimeoutService::new(
                self.timeout,
                self.resolver
                    .map_err(ConnectorError::from)
                    .and_then(TcpConnector::default().from_err()),
            ).map_err(|e| match e {
                TimeoutError::Service(e) => e,
                TimeoutError::Timeout => ConnectorError::Timeout,
            });

            connect_impl::InnerConnector {
                tcp_pool: ConnectionPool::new(
                    connector,
                    self.conn_lifetime,
                    self.conn_keep_alive,
                    None,
                    self.limit,
                ),
            }
        }
        #[cfg(feature = "ssl")]
        {
            let ssl_service = TimeoutService::new(
                self.timeout,
                self.resolver
                    .clone()
                    .map_err(ConnectorError::from)
                    .and_then(TcpConnector::default().from_err())
                    .and_then(
                        OpensslConnector::service(self.connector)
                            .map_err(ConnectorError::SslError),
                    ),
            ).map_err(|e| match e {
                TimeoutError::Service(e) => e,
                TimeoutError::Timeout => ConnectorError::Timeout,
            });

            let tcp_service = TimeoutService::new(
                self.timeout,
                self.resolver
                    .map_err(ConnectorError::from)
                    .and_then(TcpConnector::default().from_err()),
            ).map_err(|e| match e {
                TimeoutError::Service(e) => e,
                TimeoutError::Timeout => ConnectorError::Timeout,
            });

            connect_impl::InnerConnector {
                tcp_pool: ConnectionPool::new(
                    tcp_service,
                    self.conn_lifetime,
                    self.conn_keep_alive,
                    None,
                    self.limit,
                ),
                ssl_pool: ConnectionPool::new(
                    ssl_service,
                    self.conn_lifetime,
                    self.conn_keep_alive,
                    Some(self.disconnect_timeout),
                    self.limit,
                ),
            }
        }
    }
}

#[cfg(not(feature = "ssl"))]
mod connect_impl {
    use super::*;
    use futures::future::{err, FutureResult};

    pub(crate) struct InnerConnector<T, Io>
    where
        Io: AsyncRead + AsyncWrite + 'static,
        T: Service<Connect, Response = (Connect, Io), Error = ConnectorError>,
    {
        pub(crate) tcp_pool: ConnectionPool<T, Io>,
    }

    impl<T, Io> Clone for InnerConnector<T, Io>
    where
        Io: AsyncRead + AsyncWrite + 'static,
        T: Service<Connect, Response = (Connect, Io), Error = ConnectorError> + Clone,
    {
        fn clone(&self) -> Self {
            InnerConnector {
                tcp_pool: self.tcp_pool.clone(),
            }
        }
    }

    impl<T, Io> Service<Connect> for InnerConnector<T, Io>
    where
        Io: AsyncRead + AsyncWrite + 'static,
        T: Service<Connect, Response = (Connect, Io), Error = ConnectorError>,
    {
        type Response = IoConnection<Io>;
        type Error = ConnectorError;
        type Future = Either<
            <ConnectionPool<T, Io> as Service<Connect>>::Future,
            FutureResult<IoConnection<Io>, ConnectorError>,
        >;

        fn poll_ready(&mut self) -> Poll<(), Self::Error> {
            self.tcp_pool.poll_ready()
        }

        fn call(&mut self, req: Connect) -> Self::Future {
            if req.is_secure() {
                Either::B(err(ConnectorError::SslIsNotSupported))
            } else if let Err(e) = req.validate() {
                Either::B(err(e))
            } else {
                Either::A(self.tcp_pool.call(req))
            }
        }
    }
}

#[cfg(feature = "ssl")]
mod connect_impl {
    use std::marker::PhantomData;

    use futures::future::{err, FutureResult};
    use futures::{Async, Future, Poll};

    use super::*;

    pub(crate) struct InnerConnector<T1, T2, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
        T1: Service<
            Connect,
            Response = (Connect, Io1),
            Error = ConnectorError,
        >,
        T2: Service<
            Connect,
            Response = (Connect, Io2),
            Error = ConnectorError,
        >,
    {
        pub(crate) tcp_pool: ConnectionPool<T1, Io1>,
        pub(crate) ssl_pool: ConnectionPool<T2, Io2>,
    }

    impl<T1, T2, Io1, Io2> Clone for InnerConnector<T1, T2, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
        T1: Service<Connect, Response = (Connect, Io1), Error = ConnectorError> + Clone,
        T2: Service<Connect, Response = (Connect, Io2), Error = ConnectorError> + Clone,
    {
        fn clone(&self) -> Self {
            InnerConnector {
                tcp_pool: self.tcp_pool.clone(),
                ssl_pool: self.ssl_pool.clone(),
            }
        }
    }

    impl<T1, T2, Io1, Io2> Service<Connect> for InnerConnector<T1, T2, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
        T1: Service<Connect, Response = (Connect, Io1), Error = ConnectorError>,
        T2: Service<Connect, Response = (Connect, Io2), Error = ConnectorError>,
    {
        type Response = IoEither<IoConnection<Io1>, IoConnection<Io2>>;
        type Error = ConnectorError;
        type Future = Either<
            FutureResult<Self::Response, Self::Error>,
            Either<
                InnerConnectorResponseA<T1, Io1, Io2>,
                InnerConnectorResponseB<T2, Io1, Io2>,
            >,
        >;

        fn poll_ready(&mut self) -> Poll<(), Self::Error> {
            self.tcp_pool.poll_ready()
        }

        fn call(&mut self, req: Connect) -> Self::Future {
            if let Err(e) = req.validate() {
                Either::A(err(e))
            } else if req.is_secure() {
                Either::B(Either::B(InnerConnectorResponseB {
                    fut: self.ssl_pool.call(req),
                    _t: PhantomData,
                }))
            } else {
                Either::B(Either::A(InnerConnectorResponseA {
                    fut: self.tcp_pool.call(req),
                    _t: PhantomData,
                }))
            }
        }
    }

    pub(crate) struct InnerConnectorResponseA<T, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        T: Service<Connect, Response = (Connect, Io1), Error = ConnectorError>,
    {
        fut: <ConnectionPool<T, Io1> as Service<Connect>>::Future,
        _t: PhantomData<Io2>,
    }

    impl<T, Io1, Io2> Future for InnerConnectorResponseA<T, Io1, Io2>
    where
        T: Service<Connect, Response = (Connect, Io1), Error = ConnectorError>,
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
    {
        type Item = IoEither<IoConnection<Io1>, IoConnection<Io2>>;
        type Error = ConnectorError;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            match self.fut.poll()? {
                Async::NotReady => Ok(Async::NotReady),
                Async::Ready(res) => Ok(Async::Ready(IoEither::A(res))),
            }
        }
    }

    pub(crate) struct InnerConnectorResponseB<T, Io1, Io2>
    where
        Io2: AsyncRead + AsyncWrite + 'static,
        T: Service<Connect, Response = (Connect, Io2), Error = ConnectorError>,
    {
        fut: <ConnectionPool<T, Io2> as Service<Connect>>::Future,
        _t: PhantomData<Io1>,
    }

    impl<T, Io1, Io2> Future for InnerConnectorResponseB<T, Io1, Io2>
    where
        T: Service<Connect, Response = (Connect, Io2), Error = ConnectorError>,
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
    {
        type Item = IoEither<IoConnection<Io1>, IoConnection<Io2>>;
        type Error = ConnectorError;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            match self.fut.poll()? {
                Async::NotReady => Ok(Async::NotReady),
                Async::Ready(res) => Ok(Async::Ready(IoEither::B(res))),
            }
        }
    }
}

pub(crate) enum IoEither<Io1, Io2> {
    A(Io1),
    B(Io2),
}

impl<Io1, Io2> Connection for IoEither<Io1, Io2>
where
    Io1: Connection,
    Io2: Connection,
{
    fn close(&mut self) {
        match self {
            IoEither::A(ref mut io) => io.close(),
            IoEither::B(ref mut io) => io.close(),
        }
    }

    fn release(&mut self) {
        match self {
            IoEither::A(ref mut io) => io.release(),
            IoEither::B(ref mut io) => io.release(),
        }
    }
}

impl<Io1, Io2> io::Read for IoEither<Io1, Io2>
where
    Io1: Connection,
    Io2: Connection,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match self {
            IoEither::A(ref mut io) => io.read(buf),
            IoEither::B(ref mut io) => io.read(buf),
        }
    }
}

impl<Io1, Io2> AsyncRead for IoEither<Io1, Io2>
where
    Io1: Connection,
    Io2: Connection,
{
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        match self {
            IoEither::A(ref io) => io.prepare_uninitialized_buffer(buf),
            IoEither::B(ref io) => io.prepare_uninitialized_buffer(buf),
        }
    }
}

impl<Io1, Io2> AsyncWrite for IoEither<Io1, Io2>
where
    Io1: Connection,
    Io2: Connection,
{
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        match self {
            IoEither::A(ref mut io) => io.shutdown(),
            IoEither::B(ref mut io) => io.shutdown(),
        }
    }

    fn poll_write(&mut self, buf: &[u8]) -> Poll<usize, io::Error> {
        match self {
            IoEither::A(ref mut io) => io.poll_write(buf),
            IoEither::B(ref mut io) => io.poll_write(buf),
        }
    }

    fn poll_flush(&mut self) -> Poll<(), io::Error> {
        match self {
            IoEither::A(ref mut io) => io.poll_flush(),
            IoEither::B(ref mut io) => io.poll_flush(),
        }
    }
}

impl<Io1, Io2> io::Write for IoEither<Io1, Io2>
where
    Io1: Connection,
    Io2: Connection,
{
    fn flush(&mut self) -> io::Result<()> {
        match self {
            IoEither::A(ref mut io) => io.flush(),
            IoEither::B(ref mut io) => io.flush(),
        }
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match self {
            IoEither::A(ref mut io) => io.write(buf),
            IoEither::B(ref mut io) => io.write(buf),
        }
    }
}

impl<Io1, Io2> fmt::Debug for IoEither<Io1, Io2>
where
    Io1: fmt::Debug,
    Io2: fmt::Debug,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            IoEither::A(ref io) => io.fmt(fmt),
            IoEither::B(ref io) => io.fmt(fmt),
        }
    }
}
<|endoftext|>