<commit_before>extern crate combine;

mod combinators;
pub mod file;

#[derive(Debug, Clone)]
pub enum CwValue {
    String(String),
    Table(CwTable),
    Array(Vec<CwValue>)
}

impl CwValue {
    pub fn from_str<S: Into<String>>(value: S) -> Self {
        CwValue::String(value.into())
    }

    pub fn from_color(r: u8, g: u8, b: u8) -> Self {
        CwValue::Array(vec![
            CwValue::String(r.to_string()),
            CwValue::String(g.to_string()),
            CwValue::String(b.to_string())
        ])
    }

    pub fn as_string(&self) -> Option<&String> {
        if let &CwValue::String(ref val) = self {
            Some(val)
        } else {
            None
        }
    }

    pub fn as_table(&self) -> Option<&CwTable> {
        if let &CwValue::Table(ref val) = self {
            Some(val)
        } else {
            None
        }
    }

    pub fn as_table_mut(&mut self) -> Option<&mut CwTable> {
        if let &mut CwValue::Table(ref mut val) = self {
            Some(val)
        } else {
            None
        }
    }
}

impl From<String> for CwValue {
    fn from(value: String) -> Self {
        CwValue::from_str(value)
    }
}

impl<'a> From<&'a String> for CwValue {
    fn from(value: &'a String) -> Self {
        CwValue::from_str(value.clone())
    }
}

#[derive(Debug, Clone)]
pub struct CwKeyValue {
    pub key: String,
    pub value: CwValue,
}

#[derive(Debug, Clone)]
pub struct CwTable {
    pub values: Vec<CwKeyValue>,
}

impl CwTable {
    pub fn new() -> Self {
        CwTable {
            values: Vec::new()
        }
    }

    pub fn parse(text: &str) -> CwTable {
        combinators::parse(text)
    }

    pub fn serialize(&self) -> String {
        let mut target = String::new();

        for key_value in &self.values {
            // Serialize the key if we have one
            if key_value.key != "" {
                target.push_str(&escape_str_if_needed(&key_value.key));
                target.push_str(" = ");
            }

            // Serialize the value
            key_value.value.serialize_to(&mut target);
        }

        target
    }

    pub fn get(&self, key: &str) -> Option<&CwValue> {
        self.values.iter().find(|v| v.key == key).map(|v| &v.value)
    }

    pub fn get_mut(&mut self, key: &str) -> Option<&mut CwValue> {
        self.values.iter_mut().find(|v| v.key == key).map(|v| &mut v.value)
    }

    pub fn set(&mut self, key: &str, value: CwValue) {
        // Check if a value already exists with this key
        if let Some(ref mut entry) = self.values.iter_mut().find(|v| v.key == key) {
            // It does, overwrite it
            entry.value = value;
            return; // < Can't use else, borrow checking complains
        }

        // It doesn't, add it
        self.values.push(CwKeyValue { key: key.into(), value: value });
    }

    pub fn add(&mut self, key: &str, value: CwValue) {
        self.values.push(CwKeyValue { key: key.into(), value: value });
    }
}

impl CwValue {
    fn serialize_to(&self, target: &mut String) {
        match self {
            &CwValue::String(ref v) => {
                target.push_str(&escape_str_if_needed(v));
                target.push('\n');
            },
            &CwValue::Table(ref t) => {
                target.push_str("{\n");
                target.push_str(&t.serialize());
                target.push_str("}\n");
            },
            &CwValue::Array(ref a) => {
                target.push_str("{\n");
                for val in a {
                    val.serialize_to(target);
                }
                target.push_str("}\n");
            }
        }
    }
}

fn escape_str(text: &str) -> String {
    let mut target = String::new();

    target.push('\"');
    for c in text.chars() {
        match c {
            '\\' => target.push_str("\\\\"),
            _ => target.push(c)
        };
    }
    target.push('\"');

    target
}

fn escape_str_if_needed(text: &str) -> String {
    if text.len() == 0 || text.chars().any(|c| c == '\\' || c == ' ') {
        escape_str(text)
    } else {
        text.into()
    }
}

#[cfg(test)]
mod tests {
    use super::{CwTable, CwValue, CwKeyValue};

    #[test]
    fn parse_value() {
        let data = CwTable::parse("foo=bar");
        assert_eq!(data.values.len(), 1);
        assert_eq!(data.values[0].key, "foo");
        assert_eq!(data.values[0].value.as_string(), Some("bar"));
    }

    #[test]
    fn parse_values() {
        let data = CwTable::parse("foo=bar\nbar=foo");
        assert_eq!(data.values.len(), 2);
        assert_eq!(data.values[0].key, "foo");
        assert_eq!(data.values[0].value.as_string(), Some("bar"));
        assert_eq!(data.values[1].key, "bar");
        assert_eq!(data.values[1].value.as_string(), Some("foo"));
    }

    #[test]
    fn parse_values_inline() {
        let data = CwTable::parse("foo=bar bar=foo");
        assert_eq!(data.values.len(), 2);
        assert_eq!(data.values[0].key, "foo");
        assert_eq!(data.values[0].value.as_string(), Some("bar"));
        assert_eq!(data.values[1].key, "bar");
        assert_eq!(data.values[1].value.as_string(), Some("foo"));
    }

    #[test]
    fn parse_whitespace() {
        let data = CwTable::parse(" foo  = bar  ");
        assert_eq!(data.values.len(), 1);
        assert_eq!(data.values[0].key, "foo");
        assert_eq!(data.values[0].value.as_string(), Some("bar"));
    }

    #[test]
    fn parse_comments() {
        let data = CwTable::parse("foo=bar #things\nbar=foo");
        assert_eq!(data.values.len(), 2);
        assert_eq!(data.values[0].key, "foo");
        assert_eq!(data.values[0].value.as_string(), Some("bar"));
        assert_eq!(data.values[1].key, "bar");
        assert_eq!(data.values[1].value.as_string(), Some("foo"));
    }

    #[test]
    fn parse_quoted() {
        let data = CwTable::parse("foo=\"I'm a little teapot\"");
        assert_eq!(data.values.len(), 1);
        assert_eq!(data.values[0].key, "foo");
        assert_eq!(data.values[0].value.as_string(), Some("I'm a little teapot"));

        let data = CwTable::parse(r#"foo="I'm a little teapot \"short and stout\"""#);
        assert_eq!(data.values.len(), 1);
        assert_eq!(data.values[0].key, "foo");
        assert_eq!(data.values[0].value.as_string(), Some("I'm a little teapot \"short and stout\""));
    }

    #[test]
    fn parse_nested() {
        let data = CwTable::parse("foo={bar=chickens foobar=frogs}\ncheeze=unfrogged");
        assert_eq!(data.values.len(), 2);
        assert_eq!(data.values[1].key, "cheeze");
        assert_eq!(data.values[1].value.as_string(), Some("unfrogged"));

        if let &CwValue::Table(ref table) = &data.values[0].value {
            assert_eq!(table.values.len(), 2);
            assert_eq!(table.values[0].key, "bar");
            assert_eq!(table.values[0].value.as_string(), Some("chickens"));
            assert_eq!(table.values[1].key, "foobar");
            assert_eq!(table.values[1].value.as_string(), Some("frogs"));
        } else {
            assert!(false, "Wrong value type!");
        }
    }

    #[test]
    fn parse_annoying_nested() {
        let data = CwTable::parse("foo={bar=chickens foobar=frogs}cheeze=unfrogged");
        assert_eq!(data.values.len(), 2);
        assert_keystr(data.values[1], "cheeze", "unfrogged");

        if let &CwValue::Table(ref table) = &data.values[0].value {
            assert_eq!(table.values.len(), 2);
            assert_keystr(table.values[0], "bar", "chickens");
            assert_keystr(table.values[1], "foobar", "frogs");
        } else {
            assert!(false, "Wrong value type!");
        }
    }

    #[test]
    fn parse_array() {
        let data = CwTable::parse("foo={why \"does this\" exist}");
        assert_eq!(data.values.len(), 1);
        assert_eq!(data.values[0].key, "foo");

        if let &CwValue::Array(ref array) = &data.values[0].value {
            assert_eq!(array.len(), 3);
            assert_valuestr(array[0], "why");
            assert_valuestr(array[1], "does this");
            assert_valuestr(array[2], "exist");
        }
    }

    fn assert_keystr(cw_value: &CwKeyValue, key: &str, value: &str) {
        assert_eq!(cw_value.key, key);
        assert_valuestr(cw_value.value, value);
    }

    fn assert_valuestr(cw_value: &CwValue, value: &str) {
        assert_eq!(cw_value.value.as_string(), Some(&String::from(value)));
    }
}
<commit_msg>Fix unit tests.<commit_after>extern crate combine;

mod combinators;
pub mod file;

#[derive(Debug, Clone)]
pub enum CwValue {
    String(String),
    Table(CwTable),
    Array(Vec<CwValue>)
}

impl CwValue {
    pub fn from_str<S: Into<String>>(value: S) -> Self {
        CwValue::String(value.into())
    }

    pub fn from_color(r: u8, g: u8, b: u8) -> Self {
        CwValue::Array(vec![
            CwValue::String(r.to_string()),
            CwValue::String(g.to_string()),
            CwValue::String(b.to_string())
        ])
    }

    pub fn as_string(&self) -> Option<&String> {
        if let &CwValue::String(ref val) = self {
            Some(val)
        } else {
            None
        }
    }

    pub fn as_table(&self) -> Option<&CwTable> {
        if let &CwValue::Table(ref val) = self {
            Some(val)
        } else {
            None
        }
    }

    pub fn as_table_mut(&mut self) -> Option<&mut CwTable> {
        if let &mut CwValue::Table(ref mut val) = self {
            Some(val)
        } else {
            None
        }
    }
}

impl From<String> for CwValue {
    fn from(value: String) -> Self {
        CwValue::from_str(value)
    }
}

impl<'a> From<&'a String> for CwValue {
    fn from(value: &'a String) -> Self {
        CwValue::from_str(value.clone())
    }
}

#[derive(Debug, Clone)]
pub struct CwKeyValue {
    pub key: String,
    pub value: CwValue,
}

#[derive(Debug, Clone)]
pub struct CwTable {
    pub values: Vec<CwKeyValue>,
}

impl CwTable {
    pub fn new() -> Self {
        CwTable {
            values: Vec::new()
        }
    }

    pub fn parse(text: &str) -> CwTable {
        combinators::parse(text)
    }

    pub fn serialize(&self) -> String {
        let mut target = String::new();

        for key_value in &self.values {
            // Serialize the key if we have one
            if key_value.key != "" {
                target.push_str(&escape_str_if_needed(&key_value.key));
                target.push_str(" = ");
            }

            // Serialize the value
            key_value.value.serialize_to(&mut target);
        }

        target
    }

    pub fn get(&self, key: &str) -> Option<&CwValue> {
        self.values.iter().find(|v| v.key == key).map(|v| &v.value)
    }

    pub fn get_mut(&mut self, key: &str) -> Option<&mut CwValue> {
        self.values.iter_mut().find(|v| v.key == key).map(|v| &mut v.value)
    }

    pub fn set(&mut self, key: &str, value: CwValue) {
        // Check if a value already exists with this key
        if let Some(ref mut entry) = self.values.iter_mut().find(|v| v.key == key) {
            // It does, overwrite it
            entry.value = value;
            return; // < Can't use else, borrow checking complains
        }

        // It doesn't, add it
        self.values.push(CwKeyValue { key: key.into(), value: value });
    }

    pub fn add(&mut self, key: &str, value: CwValue) {
        self.values.push(CwKeyValue { key: key.into(), value: value });
    }
}

impl CwValue {
    fn serialize_to(&self, target: &mut String) {
        match self {
            &CwValue::String(ref v) => {
                target.push_str(&escape_str_if_needed(v));
                target.push('\n');
            },
            &CwValue::Table(ref t) => {
                target.push_str("{\n");
                target.push_str(&t.serialize());
                target.push_str("}\n");
            },
            &CwValue::Array(ref a) => {
                target.push_str("{\n");
                for val in a {
                    val.serialize_to(target);
                }
                target.push_str("}\n");
            }
        }
    }
}

fn escape_str(text: &str) -> String {
    let mut target = String::new();

    target.push('\"');
    for c in text.chars() {
        match c {
            '\\' => target.push_str("\\\\"),
            _ => target.push(c)
        };
    }
    target.push('\"');

    target
}

fn escape_str_if_needed(text: &str) -> String {
    if text.len() == 0 || text.chars().any(|c| c == '\\' || c == ' ') {
        escape_str(text)
    } else {
        text.into()
    }
}

#[cfg(test)]
mod tests {
    use super::{CwTable, CwValue, CwKeyValue};

    #[test]
    fn parse_value() {
        let data = CwTable::parse("foo=bar");
        assert_eq!(data.values.len(), 1);
        assert_keystr(&data.values[0], "foo", "bar");
    }

    #[test]
    fn parse_values() {
        let data = CwTable::parse("foo=bar\nbar=foo");
        assert_eq!(data.values.len(), 2);
        assert_keystr(&data.values[0], "foo", "bar");
        assert_keystr(&data.values[1], "bar", "foo");
    }

    #[test]
    fn parse_values_inline() {
        let data = CwTable::parse("foo=bar bar=foo");
        assert_eq!(data.values.len(), 2);
        assert_keystr(&data.values[0], "foo", "bar");
        assert_keystr(&data.values[1], "bar", "foo");
    }

    #[test]
    fn parse_whitespace() {
        let data = CwTable::parse(" foo  = bar  ");
        assert_eq!(data.values.len(), 1);
        assert_keystr(&data.values[0], "foo", "bar");
    }

    #[test]
    fn parse_comments() {
        let data = CwTable::parse("foo=bar #things\nbar=foo");
        assert_eq!(data.values.len(), 2);
        assert_keystr(&data.values[0], "foo", "bar");
        assert_keystr(&data.values[1], "bar", "foo");
    }

    #[test]
    fn parse_quoted() {
        let data = CwTable::parse("foo=\"I'm a little teapot\"");
        assert_eq!(data.values.len(), 1);
        assert_keystr(&data.values[0], "foo", "I'm a little teapot");

        let data = CwTable::parse(r#"foo="I'm a little teapot \"short and stout\"""#);
        assert_eq!(data.values.len(), 1);
        assert_keystr(&data.values[0], "foo", "I'm a little teapot \"short and stout\"");
    }

    #[test]
    fn parse_nested() {
        let data = CwTable::parse("foo={bar=chickens foobar=frogs}\ncheeze=unfrogged");
        assert_eq!(data.values.len(), 2);
        assert_keystr(&data.values[1], "cheeze", "unfrogged");

        if let &CwValue::Table(ref table) = &data.values[0].value {
            assert_eq!(table.values.len(), 2);
            assert_keystr(&table.values[0], "bar", "chickens");
            assert_keystr(&table.values[1], "foobar", "frogs");
        } else {
            assert!(false, "Wrong value type!");
        }
    }

    #[test]
    fn parse_annoying_nested() {
        let data = CwTable::parse("foo={bar=chickens foobar=frogs}cheeze=unfrogged");
        assert_eq!(data.values.len(), 2);
        assert_keystr(&data.values[1], "cheeze", "unfrogged");

        if let &CwValue::Table(ref table) = &data.values[0].value {
            assert_eq!(table.values.len(), 2);
            assert_keystr(&table.values[0], "bar", "chickens");
            assert_keystr(&table.values[1], "foobar", "frogs");
        } else {
            assert!(false, "Wrong value type!");
        }
    }

    #[test]
    fn parse_array() {
        let data = CwTable::parse("foo={why \"does this\" exist}");
        assert_eq!(data.values.len(), 1);
        assert_eq!(data.values[0].key, "foo");

        if let &CwValue::Array(ref array) = &data.values[0].value {
            assert_eq!(array.len(), 3);
            assert_valuestr(&array[0], "why");
            assert_valuestr(&array[1], "does this");
            assert_valuestr(&array[2], "exist");
        }
    }

    fn assert_keystr(cw_value: &CwKeyValue, key: &str, value: &str) {
        assert_eq!(cw_value.key, key);
        assert_valuestr(&cw_value.value, value);
    }

    fn assert_valuestr(cw_value: &CwValue, value: &str) {
        assert_eq!(cw_value.as_string(), Some(&String::from(value)));
    }
}
<|endoftext|>


<commit_before>use actions::Action;
use notify::Event;
use std::io::{self, Write};
use std::process::{Command, Stdio};

pub struct CommandAction {
    command_line: String
}

impl CommandAction {
    pub fn new(command_line: String) -> CommandAction {
        CommandAction {
            command_line: command_line
        }
    }
}

impl Action for CommandAction {
    fn handle_change(&self, event: &Event) {
        let path = match event.path {
            None => "",
            Some(ref path) => path.to_str().unwrap_or("")
        };

        let cmd_line_with_path = self.command_line.replace("{:p}", path);

        let mut cmd_pieces = cmd_line_with_path.split(" ");
        let mut command = Command::new(cmd_pieces.next().unwrap());
        for piece in cmd_pieces {
            command.arg(piece);
        }

        let command_result = command
            .stdin(Stdio::inherit())
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .output();

        if command_result.is_err() {
            println!("Could not execute command: {:?}", self.command_line);
            return;
        }

        let output = command_result.unwrap();
        println!("{}", String::from_utf8_lossy(&output.stdout));

        if !output.stderr.is_empty() {
            let write_result = writeln!(
                &mut io::stderr(),
                "{}",
                String::from_utf8_lossy(&output.stderr)
            );
            match write_result {
                Err(x) => println!("Error: Unable to write to stderr: {}", x),
                Ok(_) => {}
            }
        }

    }
}
<commit_msg>Refactor CommandAction.handle_change()<commit_after>use actions::Action;
use notify::Event;
use std::io::{self, Write};
use std::process::{Command, Stdio};

pub struct CommandAction {
    command_line: String
}

impl CommandAction {
    pub fn new(command_line: String) -> CommandAction {
        CommandAction {
            command_line: command_line
        }
    }

    pub fn get_command_line(&self, event: &Event) -> String {
        let path = match event.path {
            None => "",
            Some(ref path) => path.to_str().unwrap_or("")
        };

        self.command_line.replace("{:p}", path)
    }

    pub fn get_command(&self, event: &Event) -> Command {
        let command_line = self.get_command_line(event);
        let mut cmd_pieces = command_line.split(" ");
        let mut command = Command::new(cmd_pieces.next().unwrap());
        for piece in cmd_pieces {
            command.arg(piece);
        }

        command
    }
}

impl Action for CommandAction {
    fn handle_change(&self, event: &Event) {
        let mut command = self.get_command(event);
        let command_result = command
            .stdin(Stdio::inherit())
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .output();

        if command_result.is_err() {
            println!("Could not execute command: {:?}", self.command_line);
            return;
        }

        let output = command_result.unwrap();
        println!("{}", String::from_utf8_lossy(&output.stdout));

        if !output.stderr.is_empty() {
            let write_result = writeln!(
                &mut io::stderr(),
                "{}",
                String::from_utf8_lossy(&output.stderr)
            );
            match write_result {
                Err(x) => println!("Error: Unable to write to stderr: {}", x),
                Ok(_) => {}
            }
        }
    }
}
<|endoftext|>


<commit_before>use super::byteorder::{BigEndian, ByteOrder};
use super::amiga_hunk_parser::{HunkParser, Hunk, HunkType};
use super::musashi::Musashi;
use std::io;

// Memory layout of the 'Amiga'
// 0 - 512K is reserved for the "rom"
// 512 - 4MB - Executable has the range of 16MB
// 4MB - 16MB - 16MB -> Heap, bss, etc

static mut AMIGA_MEMORY: [u8; 16 * 1024 * 1024] = [0; 16 * 1024 * 1024];

const EXE_START: usize = 512 * 1024;

pub struct Amiga {
    pub dummy: i32,
}

impl Amiga {
    pub fn new() -> Amiga {
        Amiga { dummy: 0 }
    }

    pub fn parse_executable(&self, filename: &str) -> Result<Vec<Hunk>, io::Error> {
        HunkParser::parse_file(filename)
    }

    fn copy_data<'a>(src: &'a [u8], dest: &'a mut [u8], size: usize) {
        for i in 0..size {
            dest[i] = src[i];
        }
    }

    fn load_to_memory(hunks: Vec<Hunk>) {
        let mut exe_pos = EXE_START;
        let mut total_code_size = 0u32;

        for hunk in &hunks {
            if hunk.hunk_type == HunkType::Code {
                hunk.code_data
                    .as_ref()
                    .map(|data| {
                        unsafe {
                            Self::copy_data(&data, &mut AMIGA_MEMORY[exe_pos..], hunk.data_size);
                        }
                        exe_pos += hunk.data_size;
                        total_code_size += hunk.data_size as u32;
                    });
            }
        }

        let mut pc = EXE_START as u32;

        println!("total code size {}", total_code_size);

        while pc < EXE_START as u32 + total_code_size {
            pc += Musashi::disassemble(pc);
        }
    }

    pub fn load_executable_to_memory(&self, filename: &str) -> io::Result<()> {
        let hunks = try!(Self::parse_executable(self, filename));

        /*
        for hunk in &hunks {
           println!("type {:?} - size {} - alloc_size {}", hunk.hunk_type, hunk.data_size, hunk.alloc_size);
        }
        */

        Self::load_to_memory(hunks);

        Ok(())
    }
}

//
// This is kinda ugly but this is the way Musashi works. When we have
// our own 68k emulator this should be cleaned up and not be global
//

#[no_mangle]
pub extern "C" fn m68k_read_memory_32(address: u32) -> u32 {
    unsafe { BigEndian::read_u32(&AMIGA_MEMORY[address as usize..]) }
}

#[no_mangle]
pub extern "C" fn m68k_read_memory_16(address: u32) -> u16 {
    unsafe { BigEndian::read_u16(&AMIGA_MEMORY[address as usize..]) as u16 }
}

#[no_mangle]
pub extern "C" fn m68k_read_memory_8(address: u32) -> u32 {
    unsafe { AMIGA_MEMORY[address as usize] as u32 }
}

#[no_mangle]
pub extern "C" fn m68k_write_memory_8(address: u32, value: u32) {
    unsafe { AMIGA_MEMORY[address as usize] = value as u8 }
}

#[no_mangle]
pub extern "C" fn m68k_write_memory_16(address: u32, value: u32) {
    unsafe { BigEndian::write_u16(&mut AMIGA_MEMORY[address as usize..], value as u16) }
}

#[no_mangle]
pub extern "C" fn m68k_write_memory_32(address: u32, value: u32) {
    unsafe { BigEndian::write_u32(&mut AMIGA_MEMORY[address as usize..], value) }
}

#[no_mangle]
pub extern "C" fn m68k_read_disassembler_32(address: u32) -> u32 {
    m68k_read_memory_32(address)
}

#[no_mangle]
pub extern "C" fn m68k_read_disassembler_16(address: u32) -> u32 {
    m68k_read_memory_16(address) as u32
}

#[no_mangle]
pub extern "C" fn m68k_read_disassembler_8(address: u32) -> u32 {
    m68k_read_memory_8(address)
}
<commit_msg>Load code to memory and update memory location<commit_after>use super::byteorder::{BigEndian, ByteOrder};
use super::amiga_hunk_parser::{HunkParser, Hunk, HunkType};
use super::musashi::Musashi;
use std::io;

// Memory layout of the 'Amiga'
// 0 - 512K is reserved for the "rom"
// 512 - 4MB - Executable has the range of 16MB
// 4MB - 16MB - 16MB -> Heap, bss, etc

static mut AMIGA_MEMORY: [u8; 16 * 1024 * 1024] = [0; 16 * 1024 * 1024];

const EXE_START: usize = 512 * 1024;

pub struct Amiga {
    pub dummy: i32,
}

impl Amiga {
    pub fn new() -> Amiga {
        Amiga { dummy: 0 }
    }

    pub fn parse_executable(&self, filename: &str) -> Result<Vec<Hunk>, io::Error> {
        HunkParser::parse_file(filename)
    }

    fn copy_data<'a>(src: &'a [u8], dest: &'a mut [u8], size: usize) {
        for i in 0..size {
            dest[i] = src[i];
        }
    }

    fn clear_memory<'a>(dest: &'a mut [u8], size: usize) {
        for i in 0..size {
            dest[i] = 0;
        }
    }

    pub fn load_code_data(hunks: &mut Vec<Hunk>, hunk_type: HunkType, offset: usize) -> usize {
        let mut curr_offset = offset;

        for hunk in hunks.iter_mut() {
            if hunk.hunk_type == hunk_type {
                hunk.memory_offset = curr_offset;
                hunk.code_data.as_ref().map(|data| {
                    unsafe {
                        // Needs to be unsafe because Musashi callbacks doesn't provide userdata
                        // thus the Amiga memory needs to be global
                        Self::copy_data(&data, &mut AMIGA_MEMORY[curr_offset..], hunk.data_size);
                    }

                    curr_offset += hunk.data_size;
                });
            }
        }

        curr_offset
    }

    fn init_bss_sections(hunks: &mut Vec<Hunk>, offset: usize) -> usize {
        let mut curr_offset = offset;

        for hunk in hunks.iter_mut() {
            if hunk.hunk_type == HunkType::Bss {
                hunk.memory_offset = curr_offset;
                hunk.code_data.as_ref().map(|_| {
                    unsafe {
                        // Needs to be unsafe because Musashi callbacks doesn't provide userdata
                        // thus the Amiga memory needs to be global
                        Self::clear_memory(&mut AMIGA_MEMORY[curr_offset..], hunk.data_size);
                    }

                    curr_offset += hunk.data_size;
                });
            }
        }

        curr_offset
    }

    fn load_to_memory(hunks: &mut Vec<Hunk>) {
        let code_end = Self::load_code_data(hunks, HunkType::Code, EXE_START);
        let data_end = Self::load_code_data(hunks, HunkType::Data, code_end);
        let bss_end = Self::init_bss_sections(hunks, data_end);

        println!("code end: {} data end: {} bss end: {}", code_end, data_end, bss_end);

        let mut pc = EXE_START as u32;

        while pc < code_end as u32 {
            pc += Musashi::disassemble(pc);
        }
    }

    pub fn load_executable_to_memory(&self, filename: &str) -> io::Result<()> {
        let mut hunks = Self::parse_executable(self, filename)?;

        /*
        for hunk in &hunks {
           println!("type {:?} - size {} - alloc_size {}", hunk.hunk_type, hunk.data_size, hunk.alloc_size);
        }
        */

        Self::load_to_memory(&mut hunks);

        for hunk in &hunks {
            println!("type {:?} - {:?}", hunk.hunk_type, hunk);
        }

        Ok(())
    }
}

//
// This is kinda ugly but this is the way Musashi works. When we have
// our own 68k emulator this should be cleaned up and not be global
//

#[no_mangle]
pub extern "C" fn m68k_read_memory_32(address: u32) -> u32 {
    unsafe { BigEndian::read_u32(&AMIGA_MEMORY[address as usize..]) }
}

#[no_mangle]
pub extern "C" fn m68k_read_memory_16(address: u32) -> u16 {
    unsafe { BigEndian::read_u16(&AMIGA_MEMORY[address as usize..]) as u16 }
}

#[no_mangle]
pub extern "C" fn m68k_read_memory_8(address: u32) -> u32 {
    unsafe { AMIGA_MEMORY[address as usize] as u32 }
}

#[no_mangle]
pub extern "C" fn m68k_write_memory_8(address: u32, value: u32) {
    unsafe { AMIGA_MEMORY[address as usize] = value as u8 }
}

#[no_mangle]
pub extern "C" fn m68k_write_memory_16(address: u32, value: u32) {
    unsafe { BigEndian::write_u16(&mut AMIGA_MEMORY[address as usize..], value as u16) }
}

#[no_mangle]
pub extern "C" fn m68k_write_memory_32(address: u32, value: u32) {
    unsafe { BigEndian::write_u32(&mut AMIGA_MEMORY[address as usize..], value) }
}

#[no_mangle]
pub extern "C" fn m68k_read_disassembler_32(address: u32) -> u32 {
    m68k_read_memory_32(address)
}

#[no_mangle]
pub extern "C" fn m68k_read_disassembler_16(address: u32) -> u32 {
    m68k_read_memory_16(address) as u32
}

#[no_mangle]
pub extern "C" fn m68k_read_disassembler_8(address: u32) -> u32 {
    m68k_read_memory_8(address)
}
<|endoftext|>


<commit_before>use std::ops::Deref;

use config::gobjects::GObject;
use env::Env;
use library;
use nameutil::*;
use super::*;
use super::child_properties::ChildProperties;
use super::imports::Imports;
use super::info_base::InfoBase;
use super::signatures::Signatures;
use traits::*;

#[derive(Default)]
pub struct Info {
    pub base: InfoBase,
    pub c_type: String,
    pub get_type: String,
    pub supertypes: Vec<general::StatusedTypeId>,
    pub generate_trait: bool,
    pub trait_name: String,
    pub has_constructors: bool,
    pub has_methods: bool,
    pub has_functions: bool,
    pub signals: Vec<signals::Info>,
    pub notify_signals: Vec<signals::Info>,
    pub trampolines: trampolines::Trampolines,
    pub properties: Vec<properties::Property>,
    pub child_properties: ChildProperties,
    pub signatures: Signatures,
}

impl Info {
    pub fn has_signals(&self) -> bool {
        self.signals.iter().any(|s| s.trampoline_name.is_ok()) ||
        self.notify_signals.iter().any(|s| s.trampoline_name.is_ok())
    }
}

impl Deref for Info {
    type Target = InfoBase;

    fn deref(&self) -> &InfoBase {
        &self.base
    }
}

pub fn has_known_subtypes(env: &Env, class_tid: library::TypeId) -> bool {
    for child_tid in env.class_hierarchy.subtypes(class_tid) {
        let child_name = child_tid.full_name(&env.library);
        let status = env.config
            .objects
            .get(&child_name)
            .map(|o| o.status)
            .unwrap_or_default();
        if status.normal() {
            return true;
        }
    }

    false
}

pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info> {
    info!("Analyzing class {}", obj.name);
    let full_name = obj.name.clone();

    let class_tid = match env.library.find_type(0, &full_name) {
        Some(tid) => tid,
        None => return None,
    };

    let type_ = env.type_(class_tid);

    let name: String = split_namespace_name(&full_name).1.into();

    let klass: &library::Class = match type_.maybe_ref() {
        Some(klass) => klass,
        None => return None,
    };

    let mut imports = Imports::new();
    imports.add("glib::translate::*", None);
    imports.add("ffi", None);
    imports.add("glib_ffi", None);
    imports.add("gobject_ffi", None);
    imports.add("std::mem", None);
    imports.add("std::ptr", None);

    let supertypes = supertypes::analyze(env, class_tid, &mut imports);

    let mut generate_trait = obj.generate_trait;
    let trait_name = obj.trait_name
        .as_ref()
        .cloned()
        .unwrap_or_else(|| format!("{}Ext", name));

    // Sanity check the user's configuration. It's unlikely that not generating
    // a trait is wanted if there are subtypes in this very crate
    if !generate_trait && has_known_subtypes(env, class_tid) {
        error!(
            "Not generating trait for {} although subtypes exist",
            full_name
        );
    }

    let mut trampolines =
        trampolines::Trampolines::with_capacity(klass.signals.len() + klass.properties.len());
    let mut signatures = Signatures::with_capacity(klass.functions.len());

    let mut functions = functions::analyze(
        env,
        &klass.functions,
        class_tid,
        obj,
        &mut imports,
        Some(&mut signatures),
        Some(deps),
    );
    let specials = special_functions::extract(&mut functions);
    // `copy` will duplicate an object while `clone` just adds a reference
    special_functions::unhide(&mut functions, &specials, special_functions::Type::Copy);
    special_functions::analyze_imports(&specials, &mut imports);

    let signals = signals::analyze(
        env,
        &klass.signals,
        class_tid,
        generate_trait,
        &mut trampolines,
        obj,
        &mut imports,
    );
    let (properties, notify_signals) = properties::analyze(
        env,
        &klass.properties,
        class_tid,
        generate_trait,
        &mut trampolines,
        obj,
        &mut imports,
        &signatures,
        deps,
    );

    let (version, deprecated_version) = info_base::versions(
        env,
        obj,
        &functions,
        klass.version,
        klass.deprecated_version,
    );

    let child_properties =
        child_properties::analyze(env, obj.child_properties.as_ref(), class_tid, &mut imports);

    let has_methods = functions
        .iter()
        .any(|f| f.kind == library::FunctionKind::Method);
    let has_signals = signals.iter().any(|s| s.trampoline_name.is_ok()) ||
                      notify_signals.iter().any(|s| s.trampoline_name.is_ok());

    // There's no point in generating a trait if there are no signals, methods, properties
    // and child properties: it would be empty
    if generate_trait && !has_signals && !has_methods && properties.is_empty() &&
        child_properties.is_empty()
    {
        generate_trait = false;
    }

    if generate_trait && (!properties.is_empty() || has_signals) {
        imports.add("glib", None);
    }
    if generate_trait &&
        (has_methods || !properties.is_empty() || !child_properties.is_empty() || has_signals)
    {
        imports.add("glib::object::IsA", None);
    }

    //don't `use` yourself
    imports.remove(&name);

    imports.clean_glib(env);

    let base = InfoBase {
        full_name: full_name,
        type_id: class_tid,
        name: name,
        functions: functions,
        specials: specials,
        imports: imports,
        version: version,
        deprecated_version: deprecated_version,
        cfg_condition: obj.cfg_condition.clone(),
        concurrency: obj.concurrency,
    };

    // patch up trait methods in the symbol table
    if generate_trait {
        let mut symbols = env.symbols.borrow_mut();
        for func in base.methods() {
            if let Some(symbol) = symbols.by_c_name_mut(&func.glib_name) {
                symbol.make_trait_method(&trait_name);
            }
        }
    }

    let has_constructors = !base.constructors().is_empty();
    let has_functions = !base.functions().is_empty();

    let info = Info {
        base: base,
        c_type: klass.c_type.clone(),
        get_type: klass.glib_get_type.clone(),
        supertypes: supertypes,
        generate_trait: generate_trait,
        trait_name: trait_name,
        has_constructors: has_constructors,
        has_methods: has_methods,
        has_functions: has_functions,
        signals: signals,
        notify_signals: notify_signals,
        trampolines: trampolines,
        properties: properties,
        child_properties: child_properties,
        signatures: signatures,
    };

    Some(info)
}

pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info> {
    info!("Analyzing interface {}", obj.name);
    let full_name = obj.name.clone();

    let iface_tid = match env.library.find_type(0, &full_name) {
        Some(tid) => tid,
        None => return None,
    };

    let type_ = env.type_(iface_tid);

    let name: String = split_namespace_name(&full_name).1.into();

    let iface: &library::Interface = match type_.maybe_ref() {
        Some(iface) => iface,
        None => return None,
    };

    let mut imports = Imports::new();
    imports.add("glib::translate::*", None);
    imports.add("ffi", None);
    imports.add("glib::object::IsA", None);
    imports.add("glib_ffi", None);
    imports.add("gobject_ffi", None);
    imports.add("std::mem", None);
    imports.add("std::ptr", None);

    let supertypes = supertypes::analyze(env, iface_tid, &mut imports);

    let trait_name = obj.trait_name
        .as_ref()
        .cloned()
        .unwrap_or_else(|| format!("{}Ext", name));

    let mut trampolines = trampolines::Trampolines::with_capacity(iface.signals.len());
    let mut signatures = Signatures::with_capacity(iface.functions.len());

    let functions = functions::analyze(
        env,
        &iface.functions,
        iface_tid,
        obj,
        &mut imports,
        Some(&mut signatures),
        Some(deps),
    );

    let signals = signals::analyze(
        env,
        &iface.signals,
        iface_tid,
        true,
        &mut trampolines,
        obj,
        &mut imports,
    );
    let (properties, notify_signals) = properties::analyze(
        env,
        &iface.properties,
        iface_tid,
        true,
        &mut trampolines,
        obj,
        &mut imports,
        &signatures,
        deps,
    );

    let (version, deprecated_version) = info_base::versions(
        env,
        obj,
        &functions,
        iface.version,
        iface.deprecated_version,
    );

    if !properties.is_empty() {
        imports.add("glib", None);
    }

    //don't `use` yourself
    imports.remove(&name);

    imports.clean_glib(env);

    let base = InfoBase {
        full_name: full_name,
        type_id: iface_tid,
        name: name,
        functions: functions,
        specials: Default::default(),
        imports: imports,
        version: version,
        deprecated_version: deprecated_version,
        cfg_condition: obj.cfg_condition.clone(),
        concurrency: obj.concurrency,
    };

    let has_methods = !base.methods().is_empty();
    let has_functions = !base.functions().is_empty();

    let info = Info {
        base: base,
        c_type: iface.c_type.clone(),
        get_type: iface.glib_get_type.clone(),
        supertypes: supertypes,
        generate_trait: true,
        trait_name: trait_name,
        has_methods: has_methods,
        has_functions: has_functions,
        signals: signals,
        notify_signals: notify_signals,
        trampolines: trampolines,
        properties: properties,
        signatures: signatures,
        ..Default::default()
    };

    Some(info)
}
<commit_msg>Store the c_class_type for classes and interfaces in the analysis phase<commit_after>use std::ops::Deref;

use config::gobjects::GObject;
use env::Env;
use library;
use nameutil::*;
use super::*;
use super::child_properties::ChildProperties;
use super::imports::Imports;
use super::info_base::InfoBase;
use super::signatures::Signatures;
use traits::*;

#[derive(Default)]
pub struct Info {
    pub base: InfoBase,
    pub c_type: String,
    pub c_class_type: Option<String>,
    pub get_type: String,
    pub supertypes: Vec<general::StatusedTypeId>,
    pub generate_trait: bool,
    pub trait_name: String,
    pub has_constructors: bool,
    pub has_methods: bool,
    pub has_functions: bool,
    pub signals: Vec<signals::Info>,
    pub notify_signals: Vec<signals::Info>,
    pub trampolines: trampolines::Trampolines,
    pub properties: Vec<properties::Property>,
    pub child_properties: ChildProperties,
    pub signatures: Signatures,
}

impl Info {
    pub fn has_signals(&self) -> bool {
        self.signals.iter().any(|s| s.trampoline_name.is_ok()) ||
        self.notify_signals.iter().any(|s| s.trampoline_name.is_ok())
    }
}

impl Deref for Info {
    type Target = InfoBase;

    fn deref(&self) -> &InfoBase {
        &self.base
    }
}

pub fn has_known_subtypes(env: &Env, class_tid: library::TypeId) -> bool {
    for child_tid in env.class_hierarchy.subtypes(class_tid) {
        let child_name = child_tid.full_name(&env.library);
        let status = env.config
            .objects
            .get(&child_name)
            .map(|o| o.status)
            .unwrap_or_default();
        if status.normal() {
            return true;
        }
    }

    false
}

pub fn class(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info> {
    info!("Analyzing class {}", obj.name);
    let full_name = obj.name.clone();

    let class_tid = match env.library.find_type(0, &full_name) {
        Some(tid) => tid,
        None => return None,
    };

    let type_ = env.type_(class_tid);

    let name: String = split_namespace_name(&full_name).1.into();

    let klass: &library::Class = match type_.maybe_ref() {
        Some(klass) => klass,
        None => return None,
    };

    let mut imports = Imports::new();
    imports.add("glib::translate::*", None);
    imports.add("ffi", None);
    imports.add("glib_ffi", None);
    imports.add("gobject_ffi", None);
    imports.add("std::mem", None);
    imports.add("std::ptr", None);

    let supertypes = supertypes::analyze(env, class_tid, &mut imports);

    let mut generate_trait = obj.generate_trait;
    let trait_name = obj.trait_name
        .as_ref()
        .cloned()
        .unwrap_or_else(|| format!("{}Ext", name));

    // Sanity check the user's configuration. It's unlikely that not generating
    // a trait is wanted if there are subtypes in this very crate
    if !generate_trait && has_known_subtypes(env, class_tid) {
        error!(
            "Not generating trait for {} although subtypes exist",
            full_name
        );
    }

    let mut trampolines =
        trampolines::Trampolines::with_capacity(klass.signals.len() + klass.properties.len());
    let mut signatures = Signatures::with_capacity(klass.functions.len());

    let mut functions = functions::analyze(
        env,
        &klass.functions,
        class_tid,
        obj,
        &mut imports,
        Some(&mut signatures),
        Some(deps),
    );
    let specials = special_functions::extract(&mut functions);
    // `copy` will duplicate an object while `clone` just adds a reference
    special_functions::unhide(&mut functions, &specials, special_functions::Type::Copy);
    special_functions::analyze_imports(&specials, &mut imports);

    let signals = signals::analyze(
        env,
        &klass.signals,
        class_tid,
        generate_trait,
        &mut trampolines,
        obj,
        &mut imports,
    );
    let (properties, notify_signals) = properties::analyze(
        env,
        &klass.properties,
        class_tid,
        generate_trait,
        &mut trampolines,
        obj,
        &mut imports,
        &signatures,
        deps,
    );

    let (version, deprecated_version) = info_base::versions(
        env,
        obj,
        &functions,
        klass.version,
        klass.deprecated_version,
    );

    let child_properties =
        child_properties::analyze(env, obj.child_properties.as_ref(), class_tid, &mut imports);

    let has_methods = functions
        .iter()
        .any(|f| f.kind == library::FunctionKind::Method);
    let has_signals = signals.iter().any(|s| s.trampoline_name.is_ok()) ||
                      notify_signals.iter().any(|s| s.trampoline_name.is_ok());

    // There's no point in generating a trait if there are no signals, methods, properties
    // and child properties: it would be empty
    if generate_trait && !has_signals && !has_methods && properties.is_empty() &&
        child_properties.is_empty()
    {
        generate_trait = false;
    }

    if generate_trait && (!properties.is_empty() || has_signals) {
        imports.add("glib", None);
    }
    if generate_trait &&
        (has_methods || !properties.is_empty() || !child_properties.is_empty() || has_signals)
    {
        imports.add("glib::object::IsA", None);
    }

    //don't `use` yourself
    imports.remove(&name);

    imports.clean_glib(env);

    let base = InfoBase {
        full_name: full_name,
        type_id: class_tid,
        name: name,
        functions: functions,
        specials: specials,
        imports: imports,
        version: version,
        deprecated_version: deprecated_version,
        cfg_condition: obj.cfg_condition.clone(),
        concurrency: obj.concurrency,
    };

    // patch up trait methods in the symbol table
    if generate_trait {
        let mut symbols = env.symbols.borrow_mut();
        for func in base.methods() {
            if let Some(symbol) = symbols.by_c_name_mut(&func.glib_name) {
                symbol.make_trait_method(&trait_name);
            }
        }
    }

    let has_constructors = !base.constructors().is_empty();
    let has_functions = !base.functions().is_empty();

    let info = Info {
        base: base,
        c_type: klass.c_type.clone(),
        c_class_type: klass.c_class_type.clone(),
        get_type: klass.glib_get_type.clone(),
        supertypes: supertypes,
        generate_trait: generate_trait,
        trait_name: trait_name,
        has_constructors: has_constructors,
        has_methods: has_methods,
        has_functions: has_functions,
        signals: signals,
        notify_signals: notify_signals,
        trampolines: trampolines,
        properties: properties,
        child_properties: child_properties,
        signatures: signatures,
    };

    Some(info)
}

pub fn interface(env: &Env, obj: &GObject, deps: &[library::TypeId]) -> Option<Info> {
    info!("Analyzing interface {}", obj.name);
    let full_name = obj.name.clone();

    let iface_tid = match env.library.find_type(0, &full_name) {
        Some(tid) => tid,
        None => return None,
    };

    let type_ = env.type_(iface_tid);

    let name: String = split_namespace_name(&full_name).1.into();

    let iface: &library::Interface = match type_.maybe_ref() {
        Some(iface) => iface,
        None => return None,
    };

    let mut imports = Imports::new();
    imports.add("glib::translate::*", None);
    imports.add("ffi", None);
    imports.add("glib::object::IsA", None);
    imports.add("glib_ffi", None);
    imports.add("gobject_ffi", None);
    imports.add("std::mem", None);
    imports.add("std::ptr", None);

    let supertypes = supertypes::analyze(env, iface_tid, &mut imports);

    let trait_name = obj.trait_name
        .as_ref()
        .cloned()
        .unwrap_or_else(|| format!("{}Ext", name));

    let mut trampolines = trampolines::Trampolines::with_capacity(iface.signals.len());
    let mut signatures = Signatures::with_capacity(iface.functions.len());

    let functions = functions::analyze(
        env,
        &iface.functions,
        iface_tid,
        obj,
        &mut imports,
        Some(&mut signatures),
        Some(deps),
    );

    let signals = signals::analyze(
        env,
        &iface.signals,
        iface_tid,
        true,
        &mut trampolines,
        obj,
        &mut imports,
    );
    let (properties, notify_signals) = properties::analyze(
        env,
        &iface.properties,
        iface_tid,
        true,
        &mut trampolines,
        obj,
        &mut imports,
        &signatures,
        deps,
    );

    let (version, deprecated_version) = info_base::versions(
        env,
        obj,
        &functions,
        iface.version,
        iface.deprecated_version,
    );

    if !properties.is_empty() {
        imports.add("glib", None);
    }

    //don't `use` yourself
    imports.remove(&name);

    imports.clean_glib(env);

    let base = InfoBase {
        full_name: full_name,
        type_id: iface_tid,
        name: name,
        functions: functions,
        specials: Default::default(),
        imports: imports,
        version: version,
        deprecated_version: deprecated_version,
        cfg_condition: obj.cfg_condition.clone(),
        concurrency: obj.concurrency,
    };

    let has_methods = !base.methods().is_empty();
    let has_functions = !base.functions().is_empty();

    let info = Info {
        base: base,
        c_type: iface.c_type.clone(),
        c_class_type: iface.c_class_type.clone(),
        get_type: iface.glib_get_type.clone(),
        supertypes: supertypes,
        generate_trait: true,
        trait_name: trait_name,
        has_methods: has_methods,
        has_functions: has_functions,
        signals: signals,
        notify_signals: notify_signals,
        trampolines: trampolines,
        properties: properties,
        signatures: signatures,
        ..Default::default()
    };

    Some(info)
}
<|endoftext|>


<commit_before>use bytes::{Bytes, BytesMut};
use futures::sync::oneshot;
use futures::{Async, Future, Poll};
use http::header::CONTENT_ENCODING;
use std::time::{Duration, Instant};
use std::{io, mem};
use tokio_timer::Delay;

use actix::{Addr, Request, SystemService};

use super::{
    ClientConnector, ClientConnectorError, ClientRequest, ClientResponse, Connect,
    Connection, HttpClientWriter, HttpResponseParser, HttpResponseParserError,
};
use body::{Body, BodyStream};
use context::{ActorHttpContext, Frame};
use error::Error;
use error::PayloadError;
use header::ContentEncoding;
use httpmessage::HttpMessage;
use server::encoding::PayloadStream;
use server::WriterState;

/// A set of errors that can occur during request sending and response reading
#[derive(Fail, Debug)]
pub enum SendRequestError {
    /// Response took too long
    #[fail(display = "Timeout while waiting for response")]
    Timeout,
    /// Failed to connect to host
    #[fail(display = "Failed to connect to host: {}", _0)]
    Connector(#[cause] ClientConnectorError),
    /// Error parsing response
    #[fail(display = "{}", _0)]
    ParseError(#[cause] HttpResponseParserError),
    /// Error reading response payload
    #[fail(display = "Error reading response payload: {}", _0)]
    Io(#[cause] io::Error),
}

impl From<io::Error> for SendRequestError {
    fn from(err: io::Error) -> SendRequestError {
        SendRequestError::Io(err)
    }
}

impl From<ClientConnectorError> for SendRequestError {
    fn from(err: ClientConnectorError) -> SendRequestError {
        match err {
            ClientConnectorError::Timeout => SendRequestError::Timeout,
            _ => SendRequestError::Connector(err),
        }
    }
}

enum State {
    New,
    Connect(Request<ClientConnector, Connect>),
    Connection(Connection),
    Send(Box<Pipeline>),
    None,
}

/// `SendRequest` is a `Future` which represents an asynchronous
/// request sending process.
#[must_use = "SendRequest does nothing unless polled"]
pub struct SendRequest {
    req: ClientRequest,
    state: State,
    conn: Option<Addr<ClientConnector>>,
    conn_timeout: Duration,
    wait_timeout: Duration,
    timeout: Option<Delay>,
}

impl SendRequest {
    pub(crate) fn new(req: ClientRequest) -> SendRequest {
        SendRequest {
            req,
            conn: None,
            state: State::New,
            timeout: None,
            wait_timeout: Duration::from_secs(5),
            conn_timeout: Duration::from_secs(1),
        }
    }

    pub(crate) fn with_connector(
        req: ClientRequest, conn: Addr<ClientConnector>,
    ) -> SendRequest {
        SendRequest {
            req,
            conn: Some(conn),
            state: State::New,
            timeout: None,
            wait_timeout: Duration::from_secs(5),
            conn_timeout: Duration::from_secs(1),
        }
    }

    pub(crate) fn with_connection(req: ClientRequest, conn: Connection) -> SendRequest {
        SendRequest {
            req,
            state: State::Connection(conn),
            conn: None,
            timeout: None,
            wait_timeout: Duration::from_secs(5),
            conn_timeout: Duration::from_secs(1),
        }
    }

    /// Set request timeout
    ///
    /// Request timeout is the total time before a response must be received.
    /// Default value is 5 seconds.
    pub fn timeout(mut self, timeout: Duration) -> Self {
        self.timeout = Some(Delay::new(Instant::now() + timeout));
        self
    }

    /// Set connection timeout
    ///
    /// Connection timeout includes resolving hostname and actual connection to
    /// the host.
    /// Default value is 1 second.
    pub fn conn_timeout(mut self, timeout: Duration) -> Self {
        self.conn_timeout = timeout;
        self
    }

    /// Set wait timeout
    ///
    /// If connections pool limits are enabled, wait time indicates max time
    /// to wait for available connection. Default value is 5 seconds.
    pub fn wait_timeout(mut self, timeout: Duration) -> Self {
        self.wait_timeout = timeout;
        self
    }
}

impl Future for SendRequest {
    type Item = ClientResponse;
    type Error = SendRequestError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            let state = mem::replace(&mut self.state, State::None);

            match state {
                State::New => {
                    let conn = if let Some(conn) = self.conn.take() {
                        conn
                    } else {
                        ClientConnector::from_registry()
                    };
                    self.state = State::Connect(conn.send(Connect {
                        uri: self.req.uri().clone(),
                        wait_timeout: self.wait_timeout,
                        conn_timeout: self.conn_timeout,
                    }))
                }
                State::Connect(mut conn) => match conn.poll() {
                    Ok(Async::NotReady) => {
                        self.state = State::Connect(conn);
                        return Ok(Async::NotReady);
                    }
                    Ok(Async::Ready(result)) => match result {
                        Ok(stream) => self.state = State::Connection(stream),
                        Err(err) => return Err(err.into()),
                    },
                    Err(_) => {
                        return Err(SendRequestError::Connector(
                            ClientConnectorError::Disconnected,
                        ));
                    }
                },
                State::Connection(conn) => {
                    let mut writer = HttpClientWriter::new();
                    writer.start(&mut self.req)?;

                    let body = match self.req.replace_body(Body::Empty) {
                        Body::Streaming(stream) => IoBody::Payload(stream),
                        Body::Actor(ctx) => IoBody::Actor(ctx),
                        _ => IoBody::Done,
                    };

                    let timeout = self.timeout.take().unwrap_or_else(|| {
                        Delay::new(Instant::now() + Duration::from_secs(5))
                    });

                    let pl = Box::new(Pipeline {
                        body,
                        writer,
                        conn: Some(conn),
                        parser: Some(HttpResponseParser::default()),
                        parser_buf: BytesMut::new(),
                        disconnected: false,
                        body_completed: false,
                        drain: None,
                        decompress: None,
                        should_decompress: self.req.response_decompress(),
                        write_state: RunningState::Running,
                        timeout: Some(timeout),
                    });
                    self.state = State::Send(pl);
                }
                State::Send(mut pl) => {
                    pl.poll_timeout()?;
                    pl.poll_write().map_err(|e| {
                        io::Error::new(io::ErrorKind::Other, format!("{}", e).as_str())
                    })?;

                    match pl.parse() {
                        Ok(Async::Ready(mut resp)) => {
                            resp.set_pipeline(pl);
                            return Ok(Async::Ready(resp));
                        }
                        Ok(Async::NotReady) => {
                            self.state = State::Send(pl);
                            return Ok(Async::NotReady);
                        }
                        Err(err) => {
                            return Err(SendRequestError::ParseError(err));
                        }
                    }
                }
                State::None => unreachable!(),
            }
        }
    }
}

pub(crate) struct Pipeline {
    body: IoBody,
    body_completed: bool,
    conn: Option<Connection>,
    writer: HttpClientWriter,
    parser: Option<HttpResponseParser>,
    parser_buf: BytesMut,
    disconnected: bool,
    drain: Option<oneshot::Sender<()>>,
    decompress: Option<PayloadStream>,
    should_decompress: bool,
    write_state: RunningState,
    timeout: Option<Delay>,
}

enum IoBody {
    Payload(BodyStream),
    Actor(Box<ActorHttpContext>),
    Done,
}

#[derive(Debug, PartialEq)]
enum RunningState {
    Running,
    Paused,
    Done,
}

impl RunningState {
    #[inline]
    fn pause(&mut self) {
        if *self != RunningState::Done {
            *self = RunningState::Paused
        }
    }
    #[inline]
    fn resume(&mut self) {
        if *self != RunningState::Done {
            *self = RunningState::Running
        }
    }
}

impl Pipeline {
    fn release_conn(&mut self) {
        if let Some(conn) = self.conn.take() {
            conn.release()
        }
    }

    #[inline]
    fn parse(&mut self) -> Poll<ClientResponse, HttpResponseParserError> {
        if let Some(ref mut conn) = self.conn {
            match self
                .parser
                .as_mut()
                .unwrap()
                .parse(conn, &mut self.parser_buf)
            {
                Ok(Async::Ready(resp)) => {
                    // check content-encoding
                    if self.should_decompress {
                        if let Some(enc) = resp.headers().get(CONTENT_ENCODING) {
                            if let Ok(enc) = enc.to_str() {
                                match ContentEncoding::from(enc) {
                                    ContentEncoding::Auto
                                    | ContentEncoding::Identity => (),
                                    enc => {
                                        self.decompress = Some(PayloadStream::new(enc))
                                    }
                                }
                            }
                        }
                    }

                    Ok(Async::Ready(resp))
                }
                val => val,
            }
        } else {
            Ok(Async::NotReady)
        }
    }

    #[inline]
    pub fn poll(&mut self) -> Poll<Option<Bytes>, PayloadError> {
        if self.conn.is_none() {
            return Ok(Async::Ready(None));
        }
        let mut need_run = false;

        // need write?
        match self
            .poll_write()
            .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{}", e)))?
        {
            Async::NotReady => need_run = true,
            Async::Ready(_) => {
                self.poll_timeout().map_err(|e| {
                    io::Error::new(io::ErrorKind::Other, format!("{}", e))
                })?;
            }
        }

        // need read?
        if self.parser.is_some() {
            let conn: &mut Connection = self.conn.as_mut().unwrap();

            loop {
                match self
                    .parser
                    .as_mut()
                    .unwrap()
                    .parse_payload(conn, &mut self.parser_buf)?
                {
                    Async::Ready(Some(b)) => {
                        if let Some(ref mut decompress) = self.decompress {
                            match decompress.feed_data(b) {
                                Ok(Some(b)) => return Ok(Async::Ready(Some(b))),
                                Ok(None) => return Ok(Async::NotReady),
                                Err(ref err)
                                    if err.kind() == io::ErrorKind::WouldBlock =>
                                {
                                    continue
                                }
                                Err(err) => return Err(err.into()),
                            }
                        } else {
                            return Ok(Async::Ready(Some(b)));
                        }
                    }
                    Async::Ready(None) => {
                        let _ = self.parser.take();
                        break;
                    }
                    Async::NotReady => return Ok(Async::NotReady),
                }
            }
        }

        // eof
        if let Some(mut decompress) = self.decompress.take() {
            let res = decompress.feed_eof();
            if let Some(b) = res? {
                self.release_conn();
                return Ok(Async::Ready(Some(b)));
            }
        }

        if need_run {
            Ok(Async::NotReady)
        } else {
            self.release_conn();
            Ok(Async::Ready(None))
        }
    }

    fn poll_timeout(&mut self) -> Result<(), SendRequestError> {
        if self.timeout.is_some() {
            match self.timeout.as_mut().unwrap().poll() {
                Ok(Async::Ready(())) => return Err(SendRequestError::Timeout),
                Ok(Async::NotReady) => (),
                Err(e) => return Err(e.into()),
            }
        }
        Ok(())
    }

    #[inline]
    fn poll_write(&mut self) -> Poll<(), Error> {
        if self.write_state == RunningState::Done || self.conn.is_none() {
            return Ok(Async::Ready(()));
        }

        let mut done = false;
        if self.drain.is_none() && self.write_state != RunningState::Paused {
            'outter: loop {
                let result = match mem::replace(&mut self.body, IoBody::Done) {
                    IoBody::Payload(mut body) => match body.poll()? {
                        Async::Ready(None) => {
                            self.writer.write_eof()?;
                            self.body_completed = true;
                            break;
                        }
                        Async::Ready(Some(chunk)) => {
                            self.body = IoBody::Payload(body);
                            self.writer.write(chunk.as_ref())?
                        }
                        Async::NotReady => {
                            done = true;
                            self.body = IoBody::Payload(body);
                            break;
                        }
                    },
                    IoBody::Actor(mut ctx) => {
                        if self.disconnected {
                            ctx.disconnected();
                        }
                        match ctx.poll()? {
                            Async::Ready(Some(vec)) => {
                                if vec.is_empty() {
                                    self.body = IoBody::Actor(ctx);
                                    break;
                                }
                                let mut res = None;
                                for frame in vec {
                                    match frame {
                                        Frame::Chunk(None) => {
                                            self.body_completed = true;
                                            self.writer.write_eof()?;
                                            break 'outter;
                                        }
                                        Frame::Chunk(Some(chunk)) => {
                                            res =
                                                Some(self.writer.write(chunk.as_ref())?)
                                        }
                                        Frame::Drain(fut) => self.drain = Some(fut),
                                    }
                                }
                                self.body = IoBody::Actor(ctx);
                                if self.drain.is_some() {
                                    self.write_state.resume();
                                    break;
                                }
                                res.unwrap()
                            }
                            Async::Ready(None) => {
                                done = true;
                                break;
                            }
                            Async::NotReady => {
                                done = true;
                                self.body = IoBody::Actor(ctx);
                                break;
                            }
                        }
                    }
                    IoBody::Done => {
                        self.body_completed = true;
                        done = true;
                        break;
                    }
                };

                match result {
                    WriterState::Pause => {
                        self.write_state.pause();
                        break;
                    }
                    WriterState::Done => self.write_state.resume(),
                }
            }
        }

        // flush io but only if we need to
        match self
            .writer
            .poll_completed(self.conn.as_mut().unwrap(), false)
        {
            Ok(Async::Ready(_)) => {
                if self.disconnected
                    || (self.body_completed && self.writer.is_completed())
                {
                    self.write_state = RunningState::Done;
                } else {
                    self.write_state.resume();
                }

                // resolve drain futures
                if let Some(tx) = self.drain.take() {
                    let _ = tx.send(());
                }
                // restart io processing
                if !done || self.write_state == RunningState::Done {
                    self.poll_write()
                } else {
                    Ok(Async::NotReady)
                }
            }
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(err) => Err(err.into()),
        }
    }
}

impl Drop for Pipeline {
    fn drop(&mut self) {
        if let Some(conn) = self.conn.take() {
            conn.close()
        }
    }
}
<commit_msg>convert timer error to io error<commit_after>use bytes::{Bytes, BytesMut};
use futures::sync::oneshot;
use futures::{Async, Future, Poll};
use http::header::CONTENT_ENCODING;
use std::time::{Duration, Instant};
use std::{io, mem};
use tokio_timer::Delay;

use actix::{Addr, Request, SystemService};

use super::{
    ClientConnector, ClientConnectorError, ClientRequest, ClientResponse, Connect,
    Connection, HttpClientWriter, HttpResponseParser, HttpResponseParserError,
};
use body::{Body, BodyStream};
use context::{ActorHttpContext, Frame};
use error::Error;
use error::PayloadError;
use header::ContentEncoding;
use httpmessage::HttpMessage;
use server::encoding::PayloadStream;
use server::WriterState;

/// A set of errors that can occur during request sending and response reading
#[derive(Fail, Debug)]
pub enum SendRequestError {
    /// Response took too long
    #[fail(display = "Timeout while waiting for response")]
    Timeout,
    /// Failed to connect to host
    #[fail(display = "Failed to connect to host: {}", _0)]
    Connector(#[cause] ClientConnectorError),
    /// Error parsing response
    #[fail(display = "{}", _0)]
    ParseError(#[cause] HttpResponseParserError),
    /// Error reading response payload
    #[fail(display = "Error reading response payload: {}", _0)]
    Io(#[cause] io::Error),
}

impl From<io::Error> for SendRequestError {
    fn from(err: io::Error) -> SendRequestError {
        SendRequestError::Io(err)
    }
}

impl From<ClientConnectorError> for SendRequestError {
    fn from(err: ClientConnectorError) -> SendRequestError {
        match err {
            ClientConnectorError::Timeout => SendRequestError::Timeout,
            _ => SendRequestError::Connector(err),
        }
    }
}

enum State {
    New,
    Connect(Request<ClientConnector, Connect>),
    Connection(Connection),
    Send(Box<Pipeline>),
    None,
}

/// `SendRequest` is a `Future` which represents an asynchronous
/// request sending process.
#[must_use = "SendRequest does nothing unless polled"]
pub struct SendRequest {
    req: ClientRequest,
    state: State,
    conn: Option<Addr<ClientConnector>>,
    conn_timeout: Duration,
    wait_timeout: Duration,
    timeout: Option<Delay>,
}

impl SendRequest {
    pub(crate) fn new(req: ClientRequest) -> SendRequest {
        SendRequest {
            req,
            conn: None,
            state: State::New,
            timeout: None,
            wait_timeout: Duration::from_secs(5),
            conn_timeout: Duration::from_secs(1),
        }
    }

    pub(crate) fn with_connector(
        req: ClientRequest, conn: Addr<ClientConnector>,
    ) -> SendRequest {
        SendRequest {
            req,
            conn: Some(conn),
            state: State::New,
            timeout: None,
            wait_timeout: Duration::from_secs(5),
            conn_timeout: Duration::from_secs(1),
        }
    }

    pub(crate) fn with_connection(req: ClientRequest, conn: Connection) -> SendRequest {
        SendRequest {
            req,
            state: State::Connection(conn),
            conn: None,
            timeout: None,
            wait_timeout: Duration::from_secs(5),
            conn_timeout: Duration::from_secs(1),
        }
    }

    /// Set request timeout
    ///
    /// Request timeout is the total time before a response must be received.
    /// Default value is 5 seconds.
    pub fn timeout(mut self, timeout: Duration) -> Self {
        self.timeout = Some(Delay::new(Instant::now() + timeout));
        self
    }

    /// Set connection timeout
    ///
    /// Connection timeout includes resolving hostname and actual connection to
    /// the host.
    /// Default value is 1 second.
    pub fn conn_timeout(mut self, timeout: Duration) -> Self {
        self.conn_timeout = timeout;
        self
    }

    /// Set wait timeout
    ///
    /// If connections pool limits are enabled, wait time indicates max time
    /// to wait for available connection. Default value is 5 seconds.
    pub fn wait_timeout(mut self, timeout: Duration) -> Self {
        self.wait_timeout = timeout;
        self
    }
}

impl Future for SendRequest {
    type Item = ClientResponse;
    type Error = SendRequestError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            let state = mem::replace(&mut self.state, State::None);

            match state {
                State::New => {
                    let conn = if let Some(conn) = self.conn.take() {
                        conn
                    } else {
                        ClientConnector::from_registry()
                    };
                    self.state = State::Connect(conn.send(Connect {
                        uri: self.req.uri().clone(),
                        wait_timeout: self.wait_timeout,
                        conn_timeout: self.conn_timeout,
                    }))
                }
                State::Connect(mut conn) => match conn.poll() {
                    Ok(Async::NotReady) => {
                        self.state = State::Connect(conn);
                        return Ok(Async::NotReady);
                    }
                    Ok(Async::Ready(result)) => match result {
                        Ok(stream) => self.state = State::Connection(stream),
                        Err(err) => return Err(err.into()),
                    },
                    Err(_) => {
                        return Err(SendRequestError::Connector(
                            ClientConnectorError::Disconnected,
                        ));
                    }
                },
                State::Connection(conn) => {
                    let mut writer = HttpClientWriter::new();
                    writer.start(&mut self.req)?;

                    let body = match self.req.replace_body(Body::Empty) {
                        Body::Streaming(stream) => IoBody::Payload(stream),
                        Body::Actor(ctx) => IoBody::Actor(ctx),
                        _ => IoBody::Done,
                    };

                    let timeout = self.timeout.take().unwrap_or_else(|| {
                        Delay::new(Instant::now() + Duration::from_secs(5))
                    });

                    let pl = Box::new(Pipeline {
                        body,
                        writer,
                        conn: Some(conn),
                        parser: Some(HttpResponseParser::default()),
                        parser_buf: BytesMut::new(),
                        disconnected: false,
                        body_completed: false,
                        drain: None,
                        decompress: None,
                        should_decompress: self.req.response_decompress(),
                        write_state: RunningState::Running,
                        timeout: Some(timeout),
                    });
                    self.state = State::Send(pl);
                }
                State::Send(mut pl) => {
                    pl.poll_timeout()?;
                    pl.poll_write().map_err(|e| {
                        io::Error::new(io::ErrorKind::Other, format!("{}", e).as_str())
                    })?;

                    match pl.parse() {
                        Ok(Async::Ready(mut resp)) => {
                            resp.set_pipeline(pl);
                            return Ok(Async::Ready(resp));
                        }
                        Ok(Async::NotReady) => {
                            self.state = State::Send(pl);
                            return Ok(Async::NotReady);
                        }
                        Err(err) => {
                            return Err(SendRequestError::ParseError(err));
                        }
                    }
                }
                State::None => unreachable!(),
            }
        }
    }
}

pub(crate) struct Pipeline {
    body: IoBody,
    body_completed: bool,
    conn: Option<Connection>,
    writer: HttpClientWriter,
    parser: Option<HttpResponseParser>,
    parser_buf: BytesMut,
    disconnected: bool,
    drain: Option<oneshot::Sender<()>>,
    decompress: Option<PayloadStream>,
    should_decompress: bool,
    write_state: RunningState,
    timeout: Option<Delay>,
}

enum IoBody {
    Payload(BodyStream),
    Actor(Box<ActorHttpContext>),
    Done,
}

#[derive(Debug, PartialEq)]
enum RunningState {
    Running,
    Paused,
    Done,
}

impl RunningState {
    #[inline]
    fn pause(&mut self) {
        if *self != RunningState::Done {
            *self = RunningState::Paused
        }
    }
    #[inline]
    fn resume(&mut self) {
        if *self != RunningState::Done {
            *self = RunningState::Running
        }
    }
}

impl Pipeline {
    fn release_conn(&mut self) {
        if let Some(conn) = self.conn.take() {
            conn.release()
        }
    }

    #[inline]
    fn parse(&mut self) -> Poll<ClientResponse, HttpResponseParserError> {
        if let Some(ref mut conn) = self.conn {
            match self
                .parser
                .as_mut()
                .unwrap()
                .parse(conn, &mut self.parser_buf)
            {
                Ok(Async::Ready(resp)) => {
                    // check content-encoding
                    if self.should_decompress {
                        if let Some(enc) = resp.headers().get(CONTENT_ENCODING) {
                            if let Ok(enc) = enc.to_str() {
                                match ContentEncoding::from(enc) {
                                    ContentEncoding::Auto
                                    | ContentEncoding::Identity => (),
                                    enc => {
                                        self.decompress = Some(PayloadStream::new(enc))
                                    }
                                }
                            }
                        }
                    }

                    Ok(Async::Ready(resp))
                }
                val => val,
            }
        } else {
            Ok(Async::NotReady)
        }
    }

    #[inline]
    pub fn poll(&mut self) -> Poll<Option<Bytes>, PayloadError> {
        if self.conn.is_none() {
            return Ok(Async::Ready(None));
        }
        let mut need_run = false;

        // need write?
        match self
            .poll_write()
            .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{}", e)))?
        {
            Async::NotReady => need_run = true,
            Async::Ready(_) => {
                self.poll_timeout().map_err(|e| {
                    io::Error::new(io::ErrorKind::Other, format!("{}", e))
                })?;
            }
        }

        // need read?
        if self.parser.is_some() {
            let conn: &mut Connection = self.conn.as_mut().unwrap();

            loop {
                match self
                    .parser
                    .as_mut()
                    .unwrap()
                    .parse_payload(conn, &mut self.parser_buf)?
                {
                    Async::Ready(Some(b)) => {
                        if let Some(ref mut decompress) = self.decompress {
                            match decompress.feed_data(b) {
                                Ok(Some(b)) => return Ok(Async::Ready(Some(b))),
                                Ok(None) => return Ok(Async::NotReady),
                                Err(ref err)
                                    if err.kind() == io::ErrorKind::WouldBlock =>
                                {
                                    continue
                                }
                                Err(err) => return Err(err.into()),
                            }
                        } else {
                            return Ok(Async::Ready(Some(b)));
                        }
                    }
                    Async::Ready(None) => {
                        let _ = self.parser.take();
                        break;
                    }
                    Async::NotReady => return Ok(Async::NotReady),
                }
            }
        }

        // eof
        if let Some(mut decompress) = self.decompress.take() {
            let res = decompress.feed_eof();
            if let Some(b) = res? {
                self.release_conn();
                return Ok(Async::Ready(Some(b)));
            }
        }

        if need_run {
            Ok(Async::NotReady)
        } else {
            self.release_conn();
            Ok(Async::Ready(None))
        }
    }

    fn poll_timeout(&mut self) -> Result<(), SendRequestError> {
        if self.timeout.is_some() {
            match self.timeout.as_mut().unwrap().poll() {
                Ok(Async::Ready(())) => return Err(SendRequestError::Timeout),
                Ok(Async::NotReady) => (),
                Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e).into()),
            }
        }
        Ok(())
    }

    #[inline]
    fn poll_write(&mut self) -> Poll<(), Error> {
        if self.write_state == RunningState::Done || self.conn.is_none() {
            return Ok(Async::Ready(()));
        }

        let mut done = false;
        if self.drain.is_none() && self.write_state != RunningState::Paused {
            'outter: loop {
                let result = match mem::replace(&mut self.body, IoBody::Done) {
                    IoBody::Payload(mut body) => match body.poll()? {
                        Async::Ready(None) => {
                            self.writer.write_eof()?;
                            self.body_completed = true;
                            break;
                        }
                        Async::Ready(Some(chunk)) => {
                            self.body = IoBody::Payload(body);
                            self.writer.write(chunk.as_ref())?
                        }
                        Async::NotReady => {
                            done = true;
                            self.body = IoBody::Payload(body);
                            break;
                        }
                    },
                    IoBody::Actor(mut ctx) => {
                        if self.disconnected {
                            ctx.disconnected();
                        }
                        match ctx.poll()? {
                            Async::Ready(Some(vec)) => {
                                if vec.is_empty() {
                                    self.body = IoBody::Actor(ctx);
                                    break;
                                }
                                let mut res = None;
                                for frame in vec {
                                    match frame {
                                        Frame::Chunk(None) => {
                                            self.body_completed = true;
                                            self.writer.write_eof()?;
                                            break 'outter;
                                        }
                                        Frame::Chunk(Some(chunk)) => {
                                            res =
                                                Some(self.writer.write(chunk.as_ref())?)
                                        }
                                        Frame::Drain(fut) => self.drain = Some(fut),
                                    }
                                }
                                self.body = IoBody::Actor(ctx);
                                if self.drain.is_some() {
                                    self.write_state.resume();
                                    break;
                                }
                                res.unwrap()
                            }
                            Async::Ready(None) => {
                                done = true;
                                break;
                            }
                            Async::NotReady => {
                                done = true;
                                self.body = IoBody::Actor(ctx);
                                break;
                            }
                        }
                    }
                    IoBody::Done => {
                        self.body_completed = true;
                        done = true;
                        break;
                    }
                };

                match result {
                    WriterState::Pause => {
                        self.write_state.pause();
                        break;
                    }
                    WriterState::Done => self.write_state.resume(),
                }
            }
        }

        // flush io but only if we need to
        match self
            .writer
            .poll_completed(self.conn.as_mut().unwrap(), false)
        {
            Ok(Async::Ready(_)) => {
                if self.disconnected
                    || (self.body_completed && self.writer.is_completed())
                {
                    self.write_state = RunningState::Done;
                } else {
                    self.write_state.resume();
                }

                // resolve drain futures
                if let Some(tx) = self.drain.take() {
                    let _ = tx.send(());
                }
                // restart io processing
                if !done || self.write_state == RunningState::Done {
                    self.poll_write()
                } else {
                    Ok(Async::NotReady)
                }
            }
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(err) => Err(err.into()),
        }
    }
}

impl Drop for Pipeline {
    fn drop(&mut self) {
        if let Some(conn) = self.conn.take() {
            conn.close()
        }
    }
}
<|endoftext|>