<commit_before>use types::{OscPacket, OscType, Result, OscMessage, OscMidiMessage, OscColor, OscBundle};
use errors::OscError;
use utils;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> Result<OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.")),
    }
}

fn decode_message(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(OscError::BadBundle("Wrong bundle specifier!"));
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::new();
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle("Bundle shorter than expected!"));
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> Result<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> Result<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> Result<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            read_time_tag(cursor)
        }
        'b' => {
            read_blob(cursor)
        }
        'r' => {
            read_osc_color(cursor)
        }
        'T' => {
            Ok(OscType::Bool(true))
        }
        'F' => {
            Ok(OscType::Bool(false))
        }
        'N' => {
            Ok(OscType::Nil)
        }
        'I' => {
            Ok(OscType::Inf)
        }
        'c' => {
            read_char(cursor)
        }
        'm' => {
            read_midi_message(cursor)
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_char(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let opt_char = try!(cursor.read_u32::<BigEndian>()
                              .map(char::from_u32)
                              .map_err(OscError::ByteOrderError));
    match opt_char {
        Some(c) => Ok(OscType::Char(c)),
        None => Err(OscError::BadArg("Argument is not a char!".to_string())),
    }
}

fn read_blob(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut byte_buf: Vec<u8> = Vec::with_capacity(size);

    try!(cursor.take(size as u64)
               .read_to_end(&mut byte_buf)
               .map_err(OscError::ReadError));

    pad_cursor(cursor);

    Ok(OscType::Blob(byte_buf))
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let date = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));
    let frac = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));

    Ok(OscType::Time(date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn read_osc_color(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Color(OscColor {
        red: buf[0],
        green: buf[1],
        blue: buf[2],
        alpha: buf[3],
    }))
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<commit_msg>Set initial capacity<commit_after>use types::{OscPacket, OscType, Result, OscMessage, OscMidiMessage, OscColor, OscBundle};
use errors::OscError;
use utils;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> Result<OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.")),
    }
}

fn decode_message(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(OscError::BadBundle("Wrong bundle specifier!"));
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::with_capacity(size);
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle("Bundle shorter than expected!"));
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> Result<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> Result<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> Result<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            read_time_tag(cursor)
        }
        'b' => {
            read_blob(cursor)
        }
        'r' => {
            read_osc_color(cursor)
        }
        'T' => {
            Ok(OscType::Bool(true))
        }
        'F' => {
            Ok(OscType::Bool(false))
        }
        'N' => {
            Ok(OscType::Nil)
        }
        'I' => {
            Ok(OscType::Inf)
        }
        'c' => {
            read_char(cursor)
        }
        'm' => {
            read_midi_message(cursor)
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_char(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let opt_char = try!(cursor.read_u32::<BigEndian>()
                              .map(char::from_u32)
                              .map_err(OscError::ByteOrderError));
    match opt_char {
        Some(c) => Ok(OscType::Char(c)),
        None => Err(OscError::BadArg("Argument is not a char!".to_string())),
    }
}

fn read_blob(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut byte_buf: Vec<u8> = Vec::with_capacity(size);

    try!(cursor.take(size as u64)
               .read_to_end(&mut byte_buf)
               .map_err(OscError::ReadError));

    pad_cursor(cursor);

    Ok(OscType::Blob(byte_buf))
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let date = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));
    let frac = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));

    Ok(OscType::Time(date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn read_osc_color(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Color(OscColor {
        red: buf[0],
        green: buf[1],
        blue: buf[2],
        alpha: buf[3],
    }))
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<|endoftext|>


<commit_before>#[derive(Debug)]
struct Clock {
    m : u16,
    t : u16
}

#[derive(Debug)]
struct Registers {
    // these registers are split into 8-bits for H/L
    a : u8, f : u8, // (a) accumulator and (f) flag registers
    b : u8, c : u8,
    d : u8, e : u8,
    h : u8, l : u8,

    // 16-bit
    pc : u16, // program counter
    sp : u16, // stack pointer

    // last instruction's timings (m/t)
    m : u16, t : u16
}

#[derive(Debug)]
pub struct CPU {
    c : Clock,
    r : Registers
}

impl CPU {
    pub fn new() -> CPU {
        let c = Clock{m:0, t:0};
        let r = Registers{a:0, b:0, c:0, d:0, e:0, h:0, l:0, f:0, pc:0, sp:0, m:0, t:0};
        CPU{c:c, r:r}
    }

    /// Returns bit 4 of the flag register (carry)
    pub fn carry_flag(&self) -> u8 {
        (self.r.f & 0x10) >> 4
    }

    /// add register specified to a
    pub fn add_r(&mut self, r : u8) {
        self.r.a = self.r.a.wrapping_add(r);
        self.r.f = 0;
        let overflow = self.r.a as u16 + r as u16 > 0xFF;
        // check overflow
        self.r.f |= if overflow {0x10} else {0};
        // check zero
        self.r.f |= if self.r.a == 0 {0x80} else {0};

        // ticks
        self.r.m = 1;
        self.r.t = 4;
    }

}

#[test]
fn cpu_new_reset() {
    let cpu = CPU::new();

    assert_eq!(cpu.c.m, 0);
    assert_eq!(cpu.r.pc, 0);
}

#[test]
fn carry_flag() {
    // extract bit 4
    let mut cpu = CPU::new();

    cpu.r.f = 0x10;
    let mut carry = cpu.carry_flag();
    assert_eq!(carry, 1);

    cpu.r.f = 0xF0;
    carry = cpu.carry_flag();
    assert_eq!(carry, 1);

    cpu.r.f = 0x80;
    carry = cpu.carry_flag();
    assert_eq!(carry, 0);
}

#[test]
fn add_to_acc() {
    let mut cpu = CPU::new();

    cpu.r.a = 200;
    cpu.r.e = 75;

    let e = cpu.r.e;

    cpu.add_r(e);
    assert_eq!(cpu.r.a, 19);
    assert_eq!(cpu.r.f, 0x10);
}
<commit_msg>fix add_r + cmp_r and tests<commit_after>#[derive(Debug)]
struct Clock {
    m : u16,
    t : u16
}

#[derive(Debug)]
struct Registers {
    // these registers are split into 8-bits for H/L
    a : u8, f : u8, // (a) accumulator and (f) flag registers
    b : u8, c : u8,
    d : u8, e : u8,
    h : u8, l : u8,

    // 16-bit
    pc : u16, // program counter
    sp : u16, // stack pointer

    // last instruction's timings (m/t)
    m : u16, t : u16
}

#[derive(Debug)]
pub struct CPU {
    c : Clock,
    r : Registers
}

impl CPU {
    pub fn new() -> CPU {
        let c = Clock{m:0, t:0};
        let r = Registers{a:0, b:0, c:0, d:0, e:0, h:0, l:0, f:0, pc:0, sp:0, m:0, t:0};
        CPU{c:c, r:r}
    }

    /// Returns bit 4 of the flag register (carry)
    pub fn carry_flag(&self) -> u8 {
        (self.r.f & 0x10) >> 4
    }

    /// add register specified to a
    pub fn add_r(&mut self, r : u8) {
        let overflow = self.r.a as u16 + r as u16 > 0xFF;
        self.r.a = self.r.a.wrapping_add(r);
        self.r.f = 0;

        // check overflow
        self.r.f |= if overflow {0x10} else {0};
        // check zero
        self.r.f |= if self.r.a == 0 {0x80} else {0};

        // ticks
        self.r.m = 1;
        self.r.t = 4;
    }

    /// compare register r to a
    pub fn cmp_r(&mut self, r : u8) {
        // copy of A to check underflow
        let mut tmp = self.r.a as i16;
        tmp -= r as i16;

        self.r.f |= 0x40;   //subtraction flag
        self.r.f |= if self.r.a == 0 {0x80} else {0}; // zero flag
        self.r.f |= if tmp < 0 {0x10} else {0}; // carry flag

        // ticks
        self.r.m = 1;
        self.r.t = 4;
    }

    /// NO-OP, only updates clock
    pub fn nop(&mut self) {
        // ticks
        self.r.m = 1;
        self.r.t = 4;
    }

}

#[test]
fn cpu_new_reset() {
    let cpu = CPU::new();

    assert_eq!(cpu.c.m, 0);
    assert_eq!(cpu.r.pc, 0);
}

#[test]
fn carry_flag() {
    // extract bit 4
    let mut cpu = CPU::new();

    cpu.r.f = 0x10;
    let mut carry = cpu.carry_flag();
    assert_eq!(carry, 1);

    cpu.r.f = 0xF0;
    carry = cpu.carry_flag();
    assert_eq!(carry, 1);

    cpu.r.f = 0x80;
    carry = cpu.carry_flag();
    assert_eq!(carry, 0);
}

#[test]
fn add_to_acc() {
    let mut cpu = CPU::new();

    cpu.r.a = 200;
    cpu.r.e = 75;

    let e = cpu.r.e;

    cpu.add_r(e);
    assert_eq!(cpu.r.a, 19);
    assert_eq!(cpu.r.f, 0x10);
}

#[test]
fn compare_to_acc() {
    let mut cpu = CPU::new();

    cpu.r.a = 10;
    cpu.r.e = 10;

    let e = cpu.r.e;

    cpu.cmp_r(e);
    assert_eq!(cpu.r.a, 10);
    assert_eq!(cpu.r.f, 0x40);
}
<|endoftext|>


<commit_before>use types::{Result, OscType, OscPacket, OscBundle, OscMessage};
use errors::OscError;
use utils;

use byteorder::{ByteOrder, BigEndian};
use std::iter;

pub fn encode_packet(packet: &OscPacket) -> Result<Vec<u8>> {
    match *packet {
        OscPacket::Message(ref msg) => encode_message(msg),
        OscPacket::Bundle(ref bundle) => encode_bundle(bundle),
    }
}

fn encode_message(msg: &OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(&msg.addr));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if msg.args.is_some() {
        let args = msg.args.as_ref().unwrap();
        // Possible optimization: write this as iterator
        for arg in args {
            let (bytes, tag): (Option<Vec<u8>>, char) = try!(encode(arg));

            type_tags.push(tag);
            if bytes.is_some() {
                arg_bytes.extend(bytes.unwrap());
            }
        }
    }

    msg_bytes.extend(encode_string(&type_tags.iter()
                                             .cloned()
                                             .collect::<String>()));
    if arg_bytes.len() > 0 {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

fn encode_bundle(bundle: &OscBundle) -> Result<Vec<u8>> {
    Err(OscError::Unimplemented)
}

fn encode(arg: &OscType) -> Result<(Option<Vec<u8>>, char)> {
    match arg {
        &OscType::Int(ref x) => {
            let mut bytes = Vec::with_capacity(4);
            BigEndian::write_i32(&mut bytes, *x);
            Ok((Some(bytes), 'i'))
        }
        &OscType::Long(ref x) => {
            let mut bytes = Vec::with_capacity(8);
            BigEndian::write_i64(&mut bytes, *x);
            Ok((Some(bytes), 'h'))
        }
        &OscType::Float(ref x) => {
            let mut bytes = Vec::with_capacity(4);
            BigEndian::write_f32(&mut bytes, *x);
            Ok((Some(bytes), 'f'))
        }
        &OscType::Double(ref x) => {
            let mut bytes = Vec::with_capacity(8);
            BigEndian::write_f64(&mut bytes, *x);
            Ok((Some(bytes), 'd'))
        }
        &OscType::Char(ref x) => {
            let mut bytes = Vec::with_capacity(4);
            BigEndian::write_u32(&mut bytes, *x as u32);
            Ok((Some(bytes), 'c'))
        }
        &OscType::String(ref x) => {
            Ok((Some(encode_string(&x)), 's'))
        }
        &OscType::Blob(ref x) => {
            let mut bytes = x.clone();
            pad_bytes(&mut bytes);
            Ok((Some(bytes), 'b'))
        }
        &OscType::Time(ref x, ref y) => {
            Ok((Some(encode_time_tag(*x, *y)), 't'))
        }
        &OscType::Midi(ref x) => {
            Ok((Some(vec![x.port, x.status, x.data1, x.data2]), 'm'))
        }
        &OscType::Bool(ref x) => {
            if *x {
                Ok((None, 'T'))
            } else {
                Ok((None, 'F'))
            }
        }
        &OscType::Nil => {
            Ok((None, 'N'))
        }
        &OscType::Inf => {
            Ok((None, 'I'))
        }
        _ => Err(OscError::Unimplemented),
    }
}

fn encode_string(s: &String) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.as_bytes()
                              .iter()
                              .cloned()
                              .chain(iter::once(0u8))
                              .collect();
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = utils::pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    let mut bytes = Vec::with_capacity(8);
    BigEndian::write_u32(&mut bytes[..3], sec);
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}
<commit_msg>Initialize byte buffers with zeros.<commit_after>use types::{Result, OscType, OscPacket, OscBundle, OscMessage};
use errors::OscError;
use utils;

use byteorder::{ByteOrder, BigEndian};
use std::iter;

pub fn encode_packet(packet: &OscPacket) -> Result<Vec<u8>> {
    match *packet {
        OscPacket::Message(ref msg) => encode_message(msg),
        OscPacket::Bundle(ref bundle) => encode_bundle(bundle),
    }
}

fn encode_message(msg: &OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(&msg.addr));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if msg.args.is_some() {
        let args = msg.args.as_ref().unwrap();
        // Possible optimization: write this as iterator
        for arg in args {
            let (bytes, tag): (Option<Vec<u8>>, char) = try!(encode(arg));

            type_tags.push(tag);
            if bytes.is_some() {
                arg_bytes.extend(bytes.unwrap());
            }
        }
    }

    msg_bytes.extend(encode_string(&type_tags.iter()
                                             .cloned()
                                             .collect::<String>()));
    if arg_bytes.len() > 0 {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

fn encode_bundle(bundle: &OscBundle) -> Result<Vec<u8>> {
    Err(OscError::Unimplemented)
}

fn encode(arg: &OscType) -> Result<(Option<Vec<u8>>, char)> {
    match arg {
        &OscType::Int(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_i32(&mut bytes, *x);
            Ok((Some(bytes), 'i'))
        }
        &OscType::Long(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_i64(&mut bytes, *x);
            Ok((Some(bytes), 'h'))
        }
        &OscType::Float(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_f32(&mut bytes, *x);
            Ok((Some(bytes), 'f'))
        }
        &OscType::Double(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_f64(&mut bytes, *x);
            Ok((Some(bytes), 'd'))
        }
        &OscType::Char(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_u32(&mut bytes, *x as u32);
            Ok((Some(bytes), 'c'))
        }
        &OscType::String(ref x) => {
            Ok((Some(encode_string(&x)), 's'))
        }
        &OscType::Blob(ref x) => {
            let mut bytes = x.clone();
            pad_bytes(&mut bytes);
            Ok((Some(bytes), 'b'))
        }
        &OscType::Time(ref x, ref y) => {
            Ok((Some(encode_time_tag(*x, *y)), 't'))
        }
        &OscType::Midi(ref x) => {
            Ok((Some(vec![x.port, x.status, x.data1, x.data2]), 'm'))
        }
        &OscType::Bool(ref x) => {
            if *x {
                Ok((None, 'T'))
            } else {
                Ok((None, 'F'))
            }
        }
        &OscType::Nil => {
            Ok((None, 'N'))
        }
        &OscType::Inf => {
            Ok((None, 'I'))
        }
        _ => Err(OscError::Unimplemented),
    }
}

fn encode_string(s: &String) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.as_bytes()
                              .iter()
                              .cloned()
                              .chain(iter::once(0u8))
                              .collect();
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = utils::pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    BigEndian::write_u32(&mut bytes[..3], sec);
    let mut bytes = vec![0u8; 8];
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! portaudio plateform specific extensions

// pub mod asio;
pub mod mac_core;<commit_msg>add config(macos) for mac_core<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! portaudio plateform specific extensions

// pub mod asio;

#[cfg(any(target_os="macos"))]
pub mod mac_core;<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

pub use self::lua::lua_Alloc;
pub use self::lua::lua_CFunction;
pub use self::lua::lua_Ctx;
pub use self::lua::lua_Debug;
pub use self::lua::lua_Hook;
pub use self::lua::lua_Integer;
pub use self::lua::lua_KFunction;
pub use self::lua::lua_Number;
pub use self::lua::lua_Reader;
pub use self::lua::lua_State;
pub use self::lua::lua_Unsigned;
pub use self::lua::lua_Writer;

pub use self::lua::lua_absindex;
pub use self::lua::lua_arith;
pub use self::lua::lua_atpanic;
pub use self::lua::lua_call;
pub use self::lua::lua_callk;
pub use self::lua::lua_checkstack;
pub use self::lua::lua_close;
pub use self::lua::lua_compare;
pub use self::lua::lua_concat;
pub use self::lua::lua_copy;
pub use self::lua::lua_createtable;
pub use self::lua::lua_dump;
pub use self::lua::lua_error;
pub use self::lua::lua_gc;
pub use self::lua::lua_getallocf;
pub use self::lua::lua_getextraspace;
pub use self::lua::lua_getfield;
pub use self::lua::lua_getglobal;
pub use self::lua::lua_gethook;
pub use self::lua::lua_gethookcount;
pub use self::lua::lua_gethookmask;
pub use self::lua::lua_getinfo;
pub use self::lua::lua_getlocal;
pub use self::lua::lua_getmetatable;
pub use self::lua::lua_getstack;
pub use self::lua::lua_gettable;
pub use self::lua::lua_gettop;
pub use self::lua::lua_getupvalue;
pub use self::lua::lua_getuservalue;
pub use self::lua::lua_insert;
pub use self::lua::lua_isboolean;
pub use self::lua::lua_iscfunction;
pub use self::lua::lua_isfunction;
pub use self::lua::lua_isinteger;
pub use self::lua::lua_islightuserdata;
pub use self::lua::lua_isnil;
pub use self::lua::lua_isnone;
pub use self::lua::lua_isnoneornil;
pub use self::lua::lua_isnumber;
pub use self::lua::lua_isstring;
pub use self::lua::lua_istable;
pub use self::lua::lua_isthread;
pub use self::lua::lua_isuserdata;
pub use self::lua::lua_isyieldable;
pub use self::lua::lua_len;
pub use self::lua::lua_load;
pub use self::lua::lua_newstate;
pub use self::lua::lua_newtable;
pub use self::lua::lua_newthread;
pub use self::lua::lua_newuserdata;
pub use self::lua::lua_next;
pub use self::luaconf::lua_numtointeger;
pub use self::lua::lua_pcall;
pub use self::lua::lua_pcallk;
pub use self::lua::lua_pop;
pub use self::lua::lua_pushboolean;
pub use self::lua::lua_pushcclosure;
pub use self::lua::lua_pushcfunction;
pub use self::lua::lua_pushfstring;
pub use self::lua::lua_pushglobaltable;
pub use self::lua::lua_pushinteger;
pub use self::lua::lua_pushlightuserdata;
pub use self::lua::lua_pushliteral;
pub use self::lua::lua_pushlstring;
pub use self::lua::lua_pushnil;
pub use self::lua::lua_pushnumber;
pub use self::lua::lua_pushstring;
pub use self::lua::lua_pushthread;
pub use self::lua::lua_pushvalue;
//pub use self::lua::lua_pushvfstring; -- not implemented
pub use self::lua::lua_rawequal;
pub use self::lua::lua_rawget;
pub use self::lua::lua_rawgeti;
pub use self::lua::lua_rawgetp;
pub use self::lua::lua_rawlen;
pub use self::lua::lua_rawset;
pub use self::lua::lua_rawseti;
pub use self::lua::lua_rawsetp;
pub use self::lua::lua_register;
pub use self::lua::lua_remove;
pub use self::lua::lua_replace;
pub use self::lua::lua_resume;
pub use self::lua::lua_rotate;
pub use self::lua::lua_setallocf;
pub use self::lua::lua_setfield;
pub use self::lua::lua_setglobal;
pub use self::lua::lua_sethook;
pub use self::lua::lua_setlocal;
pub use self::lua::lua_setmetatable;
pub use self::lua::lua_settable;
pub use self::lua::lua_settop;
pub use self::lua::lua_setupvalue;
pub use self::lua::lua_setuservalue;
pub use self::lua::lua_status;
pub use self::lua::lua_strtonum;
pub use self::lua::lua_toboolean;
pub use self::lua::lua_tocfunction;
pub use self::lua::lua_tointeger;
pub use self::lua::lua_tointegerx;
pub use self::lua::lua_tolstring;
pub use self::lua::lua_tonumber;
pub use self::lua::lua_tonumberx;
pub use self::lua::lua_topointer;
pub use self::lua::lua_tostring;
pub use self::lua::lua_tothread;
pub use self::lua::lua_touserdata;
pub use self::lua::lua_type;
pub use self::lua::lua_typename;
pub use self::lua::lua_upvalueid;
pub use self::lua::lua_upvalueindex;
pub use self::lua::lua_upvaluejoin;
pub use self::lua::lua_version;
pub use self::lua::lua_xmove;
pub use self::lua::lua_yield;
pub use self::lua::lua_yieldk;

pub use self::lauxlib::luaL_Buffer;
pub use self::lauxlib::luaL_Reg;
pub use self::lauxlib::luaL_Stream;

pub use self::lauxlib::luaL_addchar;
pub use self::lauxlib::luaL_addlstring;
pub use self::lauxlib::luaL_addsize;
pub use self::lauxlib::luaL_addstring;
pub use self::lauxlib::luaL_addvalue;
pub use self::lauxlib::luaL_argcheck;
pub use self::lauxlib::luaL_argerror;
pub use self::lauxlib::luaL_buffinit;
pub use self::lauxlib::luaL_buffinitsize;
pub use self::lauxlib::luaL_callmeta;
pub use self::lauxlib::luaL_checkany;
pub use self::lauxlib::luaL_checkint;
pub use self::lauxlib::luaL_checkinteger;
pub use self::lauxlib::luaL_checklong;
pub use self::lauxlib::luaL_checklstring;
pub use self::lauxlib::luaL_checknumber;
pub use self::lauxlib::luaL_checkoption;
pub use self::lauxlib::luaL_checkstack;
pub use self::lauxlib::luaL_checkstring;
pub use self::lauxlib::luaL_checktype;
pub use self::lauxlib::luaL_checkudata;
pub use self::lauxlib::luaL_checkversion;
pub use self::lauxlib::luaL_dofile;
pub use self::lauxlib::luaL_dostring;
pub use self::lauxlib::luaL_error;
pub use self::lauxlib::luaL_execresult;
pub use self::lauxlib::luaL_fileresult;
pub use self::lauxlib::luaL_getmetafield;
pub use self::lauxlib::luaL_getmetatable;
pub use self::lauxlib::luaL_getsubtable;
pub use self::lauxlib::luaL_gsub;
pub use self::lauxlib::luaL_len;
pub use self::lauxlib::luaL_loadbuffer;
pub use self::lauxlib::luaL_loadbufferx;
pub use self::lauxlib::luaL_loadfile;
pub use self::lauxlib::luaL_loadfilex;
pub use self::lauxlib::luaL_loadstring;
pub use self::lauxlib::luaL_newlib;
pub use self::lauxlib::luaL_newlibtable;
pub use self::lauxlib::luaL_newmetatable;
pub use self::lauxlib::luaL_newstate;
pub use self::lualib::luaL_openlibs;
pub use self::lauxlib::luaL_optint;
pub use self::lauxlib::luaL_optinteger;
pub use self::lauxlib::luaL_optlong;
pub use self::lauxlib::luaL_optlstring;
pub use self::lauxlib::luaL_optnumber;
pub use self::lauxlib::luaL_optstring;
pub use self::lauxlib::luaL_prepbuffer;
pub use self::lauxlib::luaL_prepbuffsize;
pub use self::lauxlib::luaL_pushresult;
pub use self::lauxlib::luaL_pushresultsize;
pub use self::lauxlib::luaL_ref;
pub use self::lauxlib::luaL_requiref;
pub use self::lauxlib::luaL_setfuncs;
pub use self::lauxlib::luaL_setmetatable;
pub use self::lauxlib::luaL_testudata;
pub use self::lauxlib::luaL_tolstring;
pub use self::lauxlib::luaL_traceback;
pub use self::lauxlib::luaL_typename;
pub use self::lauxlib::luaL_unref;
pub use self::lauxlib::luaL_where;

// commonly used constants from lua.h
pub use self::lua::{LUA_RIDX_MAINTHREAD, LUA_RIDX_GLOBALS};

pub use self::lua::{LUA_OPADD, LUA_OPSUB, LUA_OPMUL, LUA_OPDIV, LUA_OPIDIV};
pub use self::lua::{LUA_OPMOD, LUA_OPPOW, LUA_OPUNM};
pub use self::lua::{LUA_OPBNOT, LUA_OPBAND, LUA_OPBOR, LUA_OPBXOR, LUA_OPSHL, LUA_OPSHR};
pub use self::lua::{LUA_OPEQ, LUA_OPLT, LUA_OPLE};

pub use self::lua::{LUA_OK, LUA_ERRRUN, LUA_ERRMEM, LUA_ERRERR, LUA_ERRGCMM};

pub use self::lua::{LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE};
pub use self::lua::{LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, LUA_TLIGHTUSERDATA};

pub use self::lua::{LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKTAILCALL, LUA_HOOKLINE, LUA_HOOKCOUNT};

// constants from lauxlib.h
pub use self::lauxlib::{LUA_REFNIL, LUA_NOREF};

mod glue;
pub mod luaconf;
pub mod lua;
pub mod lauxlib;
pub mod lualib;

<commit_msg>Re-export LUA_MULTRET and LUA_REGISTRYINDEX<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

pub use self::lua::lua_Alloc;
pub use self::lua::lua_CFunction;
pub use self::lua::lua_Ctx;
pub use self::lua::lua_Debug;
pub use self::lua::lua_Hook;
pub use self::lua::lua_Integer;
pub use self::lua::lua_KFunction;
pub use self::lua::lua_Number;
pub use self::lua::lua_Reader;
pub use self::lua::lua_State;
pub use self::lua::lua_Unsigned;
pub use self::lua::lua_Writer;

pub use self::lua::lua_absindex;
pub use self::lua::lua_arith;
pub use self::lua::lua_atpanic;
pub use self::lua::lua_call;
pub use self::lua::lua_callk;
pub use self::lua::lua_checkstack;
pub use self::lua::lua_close;
pub use self::lua::lua_compare;
pub use self::lua::lua_concat;
pub use self::lua::lua_copy;
pub use self::lua::lua_createtable;
pub use self::lua::lua_dump;
pub use self::lua::lua_error;
pub use self::lua::lua_gc;
pub use self::lua::lua_getallocf;
pub use self::lua::lua_getextraspace;
pub use self::lua::lua_getfield;
pub use self::lua::lua_getglobal;
pub use self::lua::lua_gethook;
pub use self::lua::lua_gethookcount;
pub use self::lua::lua_gethookmask;
pub use self::lua::lua_getinfo;
pub use self::lua::lua_getlocal;
pub use self::lua::lua_getmetatable;
pub use self::lua::lua_getstack;
pub use self::lua::lua_gettable;
pub use self::lua::lua_gettop;
pub use self::lua::lua_getupvalue;
pub use self::lua::lua_getuservalue;
pub use self::lua::lua_insert;
pub use self::lua::lua_isboolean;
pub use self::lua::lua_iscfunction;
pub use self::lua::lua_isfunction;
pub use self::lua::lua_isinteger;
pub use self::lua::lua_islightuserdata;
pub use self::lua::lua_isnil;
pub use self::lua::lua_isnone;
pub use self::lua::lua_isnoneornil;
pub use self::lua::lua_isnumber;
pub use self::lua::lua_isstring;
pub use self::lua::lua_istable;
pub use self::lua::lua_isthread;
pub use self::lua::lua_isuserdata;
pub use self::lua::lua_isyieldable;
pub use self::lua::lua_len;
pub use self::lua::lua_load;
pub use self::lua::lua_newstate;
pub use self::lua::lua_newtable;
pub use self::lua::lua_newthread;
pub use self::lua::lua_newuserdata;
pub use self::lua::lua_next;
pub use self::luaconf::lua_numtointeger;
pub use self::lua::lua_pcall;
pub use self::lua::lua_pcallk;
pub use self::lua::lua_pop;
pub use self::lua::lua_pushboolean;
pub use self::lua::lua_pushcclosure;
pub use self::lua::lua_pushcfunction;
pub use self::lua::lua_pushfstring;
pub use self::lua::lua_pushglobaltable;
pub use self::lua::lua_pushinteger;
pub use self::lua::lua_pushlightuserdata;
pub use self::lua::lua_pushliteral;
pub use self::lua::lua_pushlstring;
pub use self::lua::lua_pushnil;
pub use self::lua::lua_pushnumber;
pub use self::lua::lua_pushstring;
pub use self::lua::lua_pushthread;
pub use self::lua::lua_pushvalue;
//pub use self::lua::lua_pushvfstring; -- not implemented
pub use self::lua::lua_rawequal;
pub use self::lua::lua_rawget;
pub use self::lua::lua_rawgeti;
pub use self::lua::lua_rawgetp;
pub use self::lua::lua_rawlen;
pub use self::lua::lua_rawset;
pub use self::lua::lua_rawseti;
pub use self::lua::lua_rawsetp;
pub use self::lua::lua_register;
pub use self::lua::lua_remove;
pub use self::lua::lua_replace;
pub use self::lua::lua_resume;
pub use self::lua::lua_rotate;
pub use self::lua::lua_setallocf;
pub use self::lua::lua_setfield;
pub use self::lua::lua_setglobal;
pub use self::lua::lua_sethook;
pub use self::lua::lua_setlocal;
pub use self::lua::lua_setmetatable;
pub use self::lua::lua_settable;
pub use self::lua::lua_settop;
pub use self::lua::lua_setupvalue;
pub use self::lua::lua_setuservalue;
pub use self::lua::lua_status;
pub use self::lua::lua_strtonum;
pub use self::lua::lua_toboolean;
pub use self::lua::lua_tocfunction;
pub use self::lua::lua_tointeger;
pub use self::lua::lua_tointegerx;
pub use self::lua::lua_tolstring;
pub use self::lua::lua_tonumber;
pub use self::lua::lua_tonumberx;
pub use self::lua::lua_topointer;
pub use self::lua::lua_tostring;
pub use self::lua::lua_tothread;
pub use self::lua::lua_touserdata;
pub use self::lua::lua_type;
pub use self::lua::lua_typename;
pub use self::lua::lua_upvalueid;
pub use self::lua::lua_upvalueindex;
pub use self::lua::lua_upvaluejoin;
pub use self::lua::lua_version;
pub use self::lua::lua_xmove;
pub use self::lua::lua_yield;
pub use self::lua::lua_yieldk;

pub use self::lauxlib::luaL_Buffer;
pub use self::lauxlib::luaL_Reg;
pub use self::lauxlib::luaL_Stream;

pub use self::lauxlib::luaL_addchar;
pub use self::lauxlib::luaL_addlstring;
pub use self::lauxlib::luaL_addsize;
pub use self::lauxlib::luaL_addstring;
pub use self::lauxlib::luaL_addvalue;
pub use self::lauxlib::luaL_argcheck;
pub use self::lauxlib::luaL_argerror;
pub use self::lauxlib::luaL_buffinit;
pub use self::lauxlib::luaL_buffinitsize;
pub use self::lauxlib::luaL_callmeta;
pub use self::lauxlib::luaL_checkany;
pub use self::lauxlib::luaL_checkint;
pub use self::lauxlib::luaL_checkinteger;
pub use self::lauxlib::luaL_checklong;
pub use self::lauxlib::luaL_checklstring;
pub use self::lauxlib::luaL_checknumber;
pub use self::lauxlib::luaL_checkoption;
pub use self::lauxlib::luaL_checkstack;
pub use self::lauxlib::luaL_checkstring;
pub use self::lauxlib::luaL_checktype;
pub use self::lauxlib::luaL_checkudata;
pub use self::lauxlib::luaL_checkversion;
pub use self::lauxlib::luaL_dofile;
pub use self::lauxlib::luaL_dostring;
pub use self::lauxlib::luaL_error;
pub use self::lauxlib::luaL_execresult;
pub use self::lauxlib::luaL_fileresult;
pub use self::lauxlib::luaL_getmetafield;
pub use self::lauxlib::luaL_getmetatable;
pub use self::lauxlib::luaL_getsubtable;
pub use self::lauxlib::luaL_gsub;
pub use self::lauxlib::luaL_len;
pub use self::lauxlib::luaL_loadbuffer;
pub use self::lauxlib::luaL_loadbufferx;
pub use self::lauxlib::luaL_loadfile;
pub use self::lauxlib::luaL_loadfilex;
pub use self::lauxlib::luaL_loadstring;
pub use self::lauxlib::luaL_newlib;
pub use self::lauxlib::luaL_newlibtable;
pub use self::lauxlib::luaL_newmetatable;
pub use self::lauxlib::luaL_newstate;
pub use self::lualib::luaL_openlibs;
pub use self::lauxlib::luaL_optint;
pub use self::lauxlib::luaL_optinteger;
pub use self::lauxlib::luaL_optlong;
pub use self::lauxlib::luaL_optlstring;
pub use self::lauxlib::luaL_optnumber;
pub use self::lauxlib::luaL_optstring;
pub use self::lauxlib::luaL_prepbuffer;
pub use self::lauxlib::luaL_prepbuffsize;
pub use self::lauxlib::luaL_pushresult;
pub use self::lauxlib::luaL_pushresultsize;
pub use self::lauxlib::luaL_ref;
pub use self::lauxlib::luaL_requiref;
pub use self::lauxlib::luaL_setfuncs;
pub use self::lauxlib::luaL_setmetatable;
pub use self::lauxlib::luaL_testudata;
pub use self::lauxlib::luaL_tolstring;
pub use self::lauxlib::luaL_traceback;
pub use self::lauxlib::luaL_typename;
pub use self::lauxlib::luaL_unref;
pub use self::lauxlib::luaL_where;

// commonly used constants from lua.h
pub use self::lua::LUA_MULTRET;
pub use self::lua::LUA_REGISTRYINDEX;

pub use self::lua::{LUA_RIDX_MAINTHREAD, LUA_RIDX_GLOBALS};

pub use self::lua::{LUA_OPADD, LUA_OPSUB, LUA_OPMUL, LUA_OPDIV, LUA_OPIDIV};
pub use self::lua::{LUA_OPMOD, LUA_OPPOW, LUA_OPUNM};
pub use self::lua::{LUA_OPBNOT, LUA_OPBAND, LUA_OPBOR, LUA_OPBXOR, LUA_OPSHL, LUA_OPSHR};
pub use self::lua::{LUA_OPEQ, LUA_OPLT, LUA_OPLE};

pub use self::lua::{LUA_OK, LUA_ERRRUN, LUA_ERRMEM, LUA_ERRERR, LUA_ERRGCMM};

pub use self::lua::{LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE};
pub use self::lua::{LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, LUA_TLIGHTUSERDATA};

pub use self::lua::{LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKTAILCALL, LUA_HOOKLINE, LUA_HOOKCOUNT};

// constants from lauxlib.h
pub use self::lauxlib::{LUA_REFNIL, LUA_NOREF};

mod glue;
pub mod luaconf;
pub mod lua;
pub mod lauxlib;
pub mod lualib;

<|endoftext|>


<commit_before>use crate::{
    buffer::Buffer, connection::Connection, connection_status::ConnectionState, Error,
    PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{error, trace};
use mio::{event::Source, Events, Interest, Poll, Token, Waker};
use std::{
    collections::VecDeque,
    io::{self, Read, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::{Duration, Instant},
};

pub(crate) const SOCKET: Token = Token(1);
const WAKER: Token = Token(2);

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    Setup,
    Stop,
}

pub struct IoLoop<T> {
    connection: Connection,
    socket: T,
    status: Status,
    poll: Poll,
    waker: Arc<Waker>,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    can_write: bool,
    can_read: bool,
    poll_timeout: Option<Duration>,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
    last_write: Instant,
}

impl<T: Source + Read + Write + Send + 'static> IoLoop<T> {
    pub(crate) fn new(
        connection: Connection,
        socket: T,
        poll: Option<(Poll, Token)>,
    ) -> Result<Self> {
        let (poll, registered) = poll
            .map(|t| Ok((t.0, true)))
            .unwrap_or_else(|| Poll::new().map(|poll| (poll, false)))?;
        let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
        let waker = Arc::new(Waker::new(poll.registry(), WAKER)?);
        let mut inner = Self {
            connection,
            socket,
            status: Status::Initial,
            poll,
            waker,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            can_write: false,
            can_read: false,
            poll_timeout: None,
            serialized_frames: VecDeque::default(),
            last_write: Instant::now(),
        };
        if registered {
            inner.poll.registry().reregister(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        } else {
            inner.poll.registry().register(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }
        Ok(inner)
    }

    fn ensure_setup(&mut self) -> Result<()> {
        if self.status != Status::Setup && self.connection.status().connected() {
            let frame_max = self.connection.configuration().frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.connection.configuration().heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat) * 500); // * 1000 (ms) / 2 (half the negociated timeout)
                self.poll_timeout = Some(heartbeat);
            }
            self.status = Status::Setup;
        }
        Ok(())
    }

    fn has_data(&self) -> bool {
        self.connection.has_pending_frames()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&self) -> bool {
        self.can_write && self.has_data() && !self.connection.status().blocked()
    }

    fn can_read(&self) -> bool {
        self.can_read
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        let connection_status = self.connection.status();
        (self.status == Status::Initial
            || connection_status.connected()
            || connection_status.closing())
            && self.status != Status::Stop
            && !connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.waker.clone();
        self.connection.clone().set_io_loop(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    let mut events = Events::with_capacity(1024);
                    while self.should_continue() {
                        if let Err(err) = self.run(&mut events) {
                            self.cancel_serilized_frames(err)?;
                        }
                    }
                    Ok(())
                })?,
            waker,
        )
    }

    fn cancel_serilized_frames(&self, error: Error) -> Result<()> {
        for (_, resolver) in self.serialized_frames.iter() {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn poll_timeout(&self) -> Option<Duration> {
        self.poll_timeout.map(|timeout| {
            timeout
                .checked_sub(self.last_write.elapsed())
                .unwrap_or_else(|| Duration::from_secs(0))
        })
    }

    fn poll(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop poll");
        self.poll.poll(events, self.poll_timeout())?;
        trace!("io_loop poll done");
        for event in events.iter() {
            if event.token() == SOCKET {
                trace!("Got mio event for socket: {:?}", event);
                if event.is_read_closed() || event.is_write_closed() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionReset).into())?;
                }
                if event.is_error() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionAborted).into())?;
                }
                // Due to a bug in epoll/mio, it doesn't seem like we can trust this, it's sometimes missing when it should be there
                /*
                if event.is_readable() {
                    self.can_read = true;
                }
                */
                self.can_read = true;
                if event.is_writable() {
                    self.can_write = true;
                }
            }
        }
        Ok(())
    }

    fn run(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop run");
        self.ensure_setup()?;
        self.poll(events)?;
        self.socket.flush()?;
        self.do_run()
    }

    fn do_run(&mut self) -> Result<()> {
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.can_read,
            self.can_write,
            self.has_data()
        );
        loop {
            self.write()?;
            if self.connection.status().closed() {
                self.status = Status::Stop;
            }
            if self.should_continue() {
                self.read()?;
            }
            self.parse()?;
            self.connection.poll_internal_promises()?;
            if self.should_heartbeat() {
                self.connection.send_heartbeat()?;
                // Update last_write so that if we cannot write yet to the socket, we don't enqueue countless heartbeats
                self.last_write = Instant::now();
            }
            if self.stop_looping() {
                self.maybe_continue()?;
                break;
            }
        }
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.can_read,
            self.can_write,
            self.has_data(),
            self.status
        );
        Ok(())
    }

    fn should_heartbeat(&self) -> bool {
        if let Some(heartbeat_timeout) = self.poll_timeout {
            self.last_write.elapsed() > heartbeat_timeout
        } else {
            false
        }
    }

    fn stop_looping(&self) -> bool {
        !self.can_read()
            || !self.can_write()
            || self.status == Status::Stop
            || self.connection.status().errored()
    }

    fn has_pending_operations(&self) -> bool {
        self.status != Status::Stop && (self.can_read() || self.can_parse() || self.can_write())
    }

    fn maybe_continue(&mut self) -> Result<()> {
        if self.has_pending_operations() {
            trace!(
                "io_loop send continue; can_read={}, can_write={}, has_data={}",
                self.can_read,
                self.can_write,
                self.has_data()
            );
            self.send_continue()?;
        }
        Ok(())
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let ConnectionState::SentProtocolHeader(resolver, ..) = self.connection.status().state()
        {
            resolver.swear(Err(error.clone()));
        }
        self.status = Status::Stop;
        self.connection.set_error(error.clone())?;
        Err(error)
    }

    fn write(&mut self) -> Result<()> {
        if self.can_write() {
            if let Err(e) = self.write_to_stream() {
                if e.wouldblock() {
                    self.can_write = false
                } else {
                    error!("error writing: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        Ok(())
    }

    fn read(&mut self) -> Result<()> {
        if self.can_read() {
            if let Err(e) = self.read_from_stream() {
                if e.wouldblock() {
                    self.can_read = false
                } else {
                    error!("error reading: {:?}", e);
                    self.critical_error(e)?;
                }
            }
            self.receive_buffer.shift_unless_available(self.frame_size);
        }
        Ok(())
    }

    fn send_continue(&mut self) -> Result<()> {
        self.waker.wake()?;
        Ok(())
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.socket)?;

        if sz > 0 {
            self.last_write = Instant::now();

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz, true);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        trace!("{} to write to complete this frame", to_write - written);
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    error!(
                        "We've written {} but didn't expect to write anything",
                        written
                    );
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                trace!("Still {} to write", self.send_buffer.available_data());
                self.send_continue()?;
            } else {
                self.socket.flush()?;
            }
        } else {
            error!("Socket was writable but we wrote 0, marking as wouldblock");
            self.can_write = false;
        }
        Ok(())
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection.status().state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer
                    .read_from(&mut self.socket, false)
                    .map(|sz| {
                        trace!("read {} bytes", sz);
                        self.receive_buffer.fill(sz, false);
                    })?;
                Ok(())
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        if let Some((next_msg, resolver)) = self.connection.next_frame() {
            // FIXME: having the body here is too verbose, impl Display on frame instead: trace!("will write to buffer: {:?}", next_msg);
            trace!("Will write to buffer");
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => {
                    self.serialized_frames.push_back((sz, resolver));
                    Ok(())
                }
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.connection.requeue_frame((next_msg, resolver))?;
                            Ok(())
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            let error = Error::SerialisationError(Arc::new(e));
                            self.connection.set_error(error.clone())?;
                            Err(error)
                        }
                    }
                }
            }
        } else {
            Ok(())
        }
    }

    fn parse(&mut self) -> Result<()> {
        if self.can_parse() {
            if let Some(frame) = self.do_parse()? {
                self.connection.handle_frame(frame)?;
            }
        }
        Ok(())
    }

    fn do_parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.data()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                self.receive_buffer.consume(consumed, false);
                Ok(Some(f))
            }
            Err(e) => {
                if e.is_incomplete() {
                    self.receive_buffer.shift();
                    Ok(None)
                } else {
                    error!("parse error: {:?}", e);
                    let error = Error::ParsingError(e);
                    self.connection.set_error(error.clone())?;
                    Err(error)
                }
            }
        }
    }
}
<commit_msg>IoLoop: fix cancelling serialized frames<commit_after>use crate::{
    buffer::Buffer, connection::Connection, connection_status::ConnectionState, Error,
    PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{error, trace};
use mio::{event::Source, Events, Interest, Poll, Token, Waker};
use std::{
    collections::VecDeque,
    io::{self, Read, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::{Duration, Instant},
};

pub(crate) const SOCKET: Token = Token(1);
const WAKER: Token = Token(2);

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    Setup,
    Stop,
}

pub struct IoLoop<T> {
    connection: Connection,
    socket: T,
    status: Status,
    poll: Poll,
    waker: Arc<Waker>,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    can_write: bool,
    can_read: bool,
    poll_timeout: Option<Duration>,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
    last_write: Instant,
}

impl<T: Source + Read + Write + Send + 'static> IoLoop<T> {
    pub(crate) fn new(
        connection: Connection,
        socket: T,
        poll: Option<(Poll, Token)>,
    ) -> Result<Self> {
        let (poll, registered) = poll
            .map(|t| Ok((t.0, true)))
            .unwrap_or_else(|| Poll::new().map(|poll| (poll, false)))?;
        let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
        let waker = Arc::new(Waker::new(poll.registry(), WAKER)?);
        let mut inner = Self {
            connection,
            socket,
            status: Status::Initial,
            poll,
            waker,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            can_write: false,
            can_read: false,
            poll_timeout: None,
            serialized_frames: VecDeque::default(),
            last_write: Instant::now(),
        };
        if registered {
            inner.poll.registry().reregister(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        } else {
            inner.poll.registry().register(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }
        Ok(inner)
    }

    fn ensure_setup(&mut self) -> Result<()> {
        if self.status != Status::Setup && self.connection.status().connected() {
            let frame_max = self.connection.configuration().frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.connection.configuration().heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat) * 500); // * 1000 (ms) / 2 (half the negociated timeout)
                self.poll_timeout = Some(heartbeat);
            }
            self.status = Status::Setup;
        }
        Ok(())
    }

    fn has_data(&self) -> bool {
        self.connection.has_pending_frames()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&self) -> bool {
        self.can_write && self.has_data() && !self.connection.status().blocked()
    }

    fn can_read(&self) -> bool {
        self.can_read
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        let connection_status = self.connection.status();
        (self.status == Status::Initial
            || connection_status.connected()
            || connection_status.closing())
            && self.status != Status::Stop
            && !connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.waker.clone();
        self.connection.clone().set_io_loop(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    let mut events = Events::with_capacity(1024);
                    while self.should_continue() {
                        if let Err(err) = self.run(&mut events) {
                            self.cancel_serilized_frames(err)?;
                        }
                    }
                    Ok(())
                })?,
            waker,
        )
    }

    fn cancel_serilized_frames(&mut self, error: Error) -> Result<()> {
        for (_, resolver) in std::mem::take(&mut self.serialized_frames) {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn poll_timeout(&self) -> Option<Duration> {
        self.poll_timeout.map(|timeout| {
            timeout
                .checked_sub(self.last_write.elapsed())
                .unwrap_or_else(|| Duration::from_secs(0))
        })
    }

    fn poll(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop poll");
        self.poll.poll(events, self.poll_timeout())?;
        trace!("io_loop poll done");
        for event in events.iter() {
            if event.token() == SOCKET {
                trace!("Got mio event for socket: {:?}", event);
                if event.is_read_closed() || event.is_write_closed() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionReset).into())?;
                }
                if event.is_error() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionAborted).into())?;
                }
                // Due to a bug in epoll/mio, it doesn't seem like we can trust this, it's sometimes missing when it should be there
                /*
                if event.is_readable() {
                    self.can_read = true;
                }
                */
                self.can_read = true;
                if event.is_writable() {
                    self.can_write = true;
                }
            }
        }
        Ok(())
    }

    fn run(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop run");
        self.ensure_setup()?;
        self.poll(events)?;
        self.socket.flush()?;
        self.do_run()
    }

    fn do_run(&mut self) -> Result<()> {
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.can_read,
            self.can_write,
            self.has_data()
        );
        loop {
            self.write()?;
            if self.connection.status().closed() {
                self.status = Status::Stop;
            }
            if self.should_continue() {
                self.read()?;
            }
            self.parse()?;
            self.connection.poll_internal_promises()?;
            if self.should_heartbeat() {
                self.connection.send_heartbeat()?;
                // Update last_write so that if we cannot write yet to the socket, we don't enqueue countless heartbeats
                self.last_write = Instant::now();
            }
            if self.stop_looping() {
                self.maybe_continue()?;
                break;
            }
        }
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.can_read,
            self.can_write,
            self.has_data(),
            self.status
        );
        Ok(())
    }

    fn should_heartbeat(&self) -> bool {
        if let Some(heartbeat_timeout) = self.poll_timeout {
            self.last_write.elapsed() > heartbeat_timeout
        } else {
            false
        }
    }

    fn stop_looping(&self) -> bool {
        !self.can_read()
            || !self.can_write()
            || self.status == Status::Stop
            || self.connection.status().errored()
    }

    fn has_pending_operations(&self) -> bool {
        self.status != Status::Stop && (self.can_read() || self.can_parse() || self.can_write())
    }

    fn maybe_continue(&mut self) -> Result<()> {
        if self.has_pending_operations() {
            trace!(
                "io_loop send continue; can_read={}, can_write={}, has_data={}",
                self.can_read,
                self.can_write,
                self.has_data()
            );
            self.send_continue()?;
        }
        Ok(())
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let ConnectionState::SentProtocolHeader(resolver, ..) = self.connection.status().state()
        {
            resolver.swear(Err(error.clone()));
        }
        self.status = Status::Stop;
        self.connection.set_error(error.clone())?;
        Err(error)
    }

    fn write(&mut self) -> Result<()> {
        if self.can_write() {
            if let Err(e) = self.write_to_stream() {
                if e.wouldblock() {
                    self.can_write = false
                } else {
                    error!("error writing: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        Ok(())
    }

    fn read(&mut self) -> Result<()> {
        if self.can_read() {
            if let Err(e) = self.read_from_stream() {
                if e.wouldblock() {
                    self.can_read = false
                } else {
                    error!("error reading: {:?}", e);
                    self.critical_error(e)?;
                }
            }
            self.receive_buffer.shift_unless_available(self.frame_size);
        }
        Ok(())
    }

    fn send_continue(&mut self) -> Result<()> {
        self.waker.wake()?;
        Ok(())
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.socket)?;

        if sz > 0 {
            self.last_write = Instant::now();

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz, true);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        trace!("{} to write to complete this frame", to_write - written);
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    error!(
                        "We've written {} but didn't expect to write anything",
                        written
                    );
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                trace!("Still {} to write", self.send_buffer.available_data());
                self.send_continue()?;
            } else {
                self.socket.flush()?;
            }
        } else {
            error!("Socket was writable but we wrote 0, marking as wouldblock");
            self.can_write = false;
        }
        Ok(())
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection.status().state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer
                    .read_from(&mut self.socket, false)
                    .map(|sz| {
                        trace!("read {} bytes", sz);
                        self.receive_buffer.fill(sz, false);
                    })?;
                Ok(())
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        if let Some((next_msg, resolver)) = self.connection.next_frame() {
            // FIXME: having the body here is too verbose, impl Display on frame instead: trace!("will write to buffer: {:?}", next_msg);
            trace!("Will write to buffer");
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => {
                    self.serialized_frames.push_back((sz, resolver));
                    Ok(())
                }
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.connection.requeue_frame((next_msg, resolver))?;
                            Ok(())
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            let error = Error::SerialisationError(Arc::new(e));
                            self.connection.set_error(error.clone())?;
                            Err(error)
                        }
                    }
                }
            }
        } else {
            Ok(())
        }
    }

    fn parse(&mut self) -> Result<()> {
        if self.can_parse() {
            if let Some(frame) = self.do_parse()? {
                self.connection.handle_frame(frame)?;
            }
        }
        Ok(())
    }

    fn do_parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.data()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                self.receive_buffer.consume(consumed, false);
                Ok(Some(f))
            }
            Err(e) => {
                if e.is_incomplete() {
                    self.receive_buffer.shift();
                    Ok(None)
                } else {
                    error!("parse error: {:?}", e);
                    let error = Error::ParsingError(e);
                    self.connection.set_error(error.clone())?;
                    Err(error)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::mem::swap;
use std::ptr;

use ctxt::Context;
use gc::root::IndirectObj;
use mem;
use object::Obj;
use os;
use timer::{in_ms, Timer};

pub struct SemiSpace {
    start: *const u8,
    end: *const u8,

    scan: *const u8,
    next: *const u8,
}

impl SemiSpace {
    pub fn new(size: usize) -> SemiSpace {
        let size = mem::align_usize(size, os::page_size() as usize);
        let ptr = os::mmap(size, os::Writable);

        if ptr.is_null() {
            panic!("could not allocate semi space of size {} bytes", size);
        }

        SemiSpace {
            start: ptr,
            end: unsafe { ptr.offset(size as isize) },
            scan: ptr,
            next: ptr,
        }
    }

    pub fn allocate(&mut self, size: usize) -> *const u8 {
        if self.end as usize - self.next as usize > size {
            let next = unsafe { self.next.offset(size as isize) };
            let addr = self.next;
            self.next = next;

            addr

        } else {
            ptr::null()
        }
    }

    pub fn includes(&self, ptr: *const u8) -> bool {
        self.start <= ptr && ptr < self.end
    }

    pub fn reset(&mut self) {
        self.scan = self.start;
        self.next = self.start;
    }

    pub fn size(&self) -> usize {
        self.end as usize - self.start as usize
    }
}

impl Drop for SemiSpace {
    fn drop(&mut self) {
        let size = self.end as usize - self.start as usize;
        os::munmap(self.start, size);
    }
}

pub fn minor_collect(ctxt: &Context,
                     from_space: &mut SemiSpace,
                     to_space: &mut SemiSpace,
                     rootset: Vec<IndirectObj>) {
    let mut timer = Timer::new(ctxt.args.flag_gc_events);
    swap(from_space, to_space);

    // empty to-space
    to_space.reset();

    for &root in &rootset {
        let root_ptr = root.get();

        if from_space.includes(root_ptr as *const u8) {
            root.set(copy(root_ptr, to_space));
        }
    }

    while to_space.scan < to_space.next {
        let object = unsafe { &mut *(to_space.scan as *mut Obj) };

        object.visit_reference_fields(|child| {
            let child_ptr = child.get();

            if from_space.includes(child_ptr as *const u8) {
                child.set(copy(child_ptr, to_space));
            }
        });

        to_space.scan = unsafe { to_space.scan.offset(object.size() as isize) };
    }

    if cfg!(debug_assertions) {
        unsafe {
            ptr::write_bytes(from_space.start as *mut u8, 0xcc, from_space.size());
        }
    }

    timer.stop_with(|dur| {
        // self.collect_duration += dur;

        if ctxt.args.flag_gc_events {
            println!("GC minor: collect garbage ({} ms)", in_ms(dur));
        }
    });
}

pub fn copy(obj: *mut Obj, to_space: &mut SemiSpace) -> *mut Obj {
    let obj = unsafe { &mut *obj };
    let addr = get_forwarding_address(obj);

    if is_forwarding_address(addr) {
        unmark_forwarding_address(addr) as *mut Obj

    } else {
        let addr = to_space.next;
        let obj_size = obj.size();

        unsafe {
            ptr::copy_nonoverlapping(obj as *const Obj as *const u8, addr as *mut u8, obj_size);
            to_space.next = to_space.next.offset(obj_size as isize);
        }

        set_forwarding_address(obj, addr);

        addr as *mut Obj
    }
}

pub fn is_forwarding_address(obj: *const u8) -> bool {
    (obj as usize) & 1 == 1
}

pub fn mark_forwarding_address(obj: *const u8) -> *const u8 {
    ((obj as usize) | 1) as *const u8
}

pub fn unmark_forwarding_address(obj: *const u8) -> *const u8 {
    ((obj as usize) & !1) as *const u8
}

pub fn get_forwarding_address(obj: &Obj) -> *const u8 {
    unsafe { *(obj as *const Obj as *const *const u8) }
}

pub fn set_forwarding_address(obj: &mut Obj, addr: *const u8) {
    unsafe {
        *(obj as *mut Obj as *mut *const u8) = mark_forwarding_address(addr);
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_mark_forwarding_address() {
        assert_eq!(9 as *const u8, mark_forwarding_address(8 as *const u8));
        assert_eq!(13 as *const u8, mark_forwarding_address(12 as *const u8));
    }

    #[test]
    fn test_unmark_forwarding_address() {
        assert_eq!(8 as *const u8, unmark_forwarding_address(9 as *const u8));
        assert_eq!(12 as *const u8, unmark_forwarding_address(13 as *const u8));
    }

    #[test]
    fn test_is_forwarding_address() {
        assert_eq!(false, is_forwarding_address(8 as *const u8));
        assert_eq!(true, is_forwarding_address(9 as *const u8));
        assert_eq!(false, is_forwarding_address(12 as *const u8));
        assert_eq!(true, is_forwarding_address(13 as *const u8));
    }
}<commit_msg>gc: zero allocation in copy collector<commit_after>use std::mem::swap;
use std::ptr;

use ctxt::Context;
use gc::root::IndirectObj;
use mem;
use object::Obj;
use os;
use timer::{in_ms, Timer};

pub struct SemiSpace {
    start: *const u8,
    end: *const u8,

    scan: *const u8,
    next: *const u8,
}

impl SemiSpace {
    pub fn new(size: usize) -> SemiSpace {
        let size = mem::align_usize(size, os::page_size() as usize);
        let ptr = os::mmap(size, os::Writable);

        if ptr.is_null() {
            panic!("could not allocate semi space of size {} bytes", size);
        }

        SemiSpace {
            start: ptr,
            end: unsafe { ptr.offset(size as isize) },
            scan: ptr,
            next: ptr,
        }
    }

    pub fn allocate(&mut self, size: usize) -> *const u8 {
        if self.end as usize - self.next as usize > size {
            let next = unsafe { self.next.offset(size as isize) };

            let addr = self.next;
            unsafe { ptr::write_bytes(addr as *mut u8, 0, size); }

            self.next = next;

            addr

        } else {
            ptr::null()
        }
    }

    pub fn includes(&self, ptr: *const u8) -> bool {
        self.start <= ptr && ptr < self.end
    }

    pub fn reset(&mut self) {
        self.scan = self.start;
        self.next = self.start;
    }

    pub fn size(&self) -> usize {
        self.end as usize - self.start as usize
    }
}

impl Drop for SemiSpace {
    fn drop(&mut self) {
        let size = self.end as usize - self.start as usize;
        os::munmap(self.start, size);
    }
}

pub fn minor_collect(ctxt: &Context,
                     from_space: &mut SemiSpace,
                     to_space: &mut SemiSpace,
                     rootset: Vec<IndirectObj>) {
    let mut timer = Timer::new(ctxt.args.flag_gc_events);
    swap(from_space, to_space);

    // empty to-space
    to_space.reset();

    for &root in &rootset {
        let root_ptr = root.get();

        if from_space.includes(root_ptr as *const u8) {
            root.set(copy(root_ptr, to_space));
        }
    }

    while to_space.scan < to_space.next {
        let object = unsafe { &mut *(to_space.scan as *mut Obj) };

        object.visit_reference_fields(|child| {
            let child_ptr = child.get();

            if from_space.includes(child_ptr as *const u8) {
                child.set(copy(child_ptr, to_space));
            }
        });

        to_space.scan = unsafe { to_space.scan.offset(object.size() as isize) };
    }

    if cfg!(debug_assertions) {
        unsafe {
            ptr::write_bytes(from_space.start as *mut u8, 0xcc, from_space.size());
        }
    }

    timer.stop_with(|dur| {
        // self.collect_duration += dur;

        if ctxt.args.flag_gc_events {
            println!("GC minor: collect garbage ({} ms)", in_ms(dur));
        }
    });
}

pub fn copy(obj: *mut Obj, to_space: &mut SemiSpace) -> *mut Obj {
    let obj = unsafe { &mut *obj };
    let addr = get_forwarding_address(obj);

    if is_forwarding_address(addr) {
        unmark_forwarding_address(addr) as *mut Obj

    } else {
        let addr = to_space.next;
        let obj_size = obj.size();

        unsafe {
            ptr::copy_nonoverlapping(obj as *const Obj as *const u8, addr as *mut u8, obj_size);
            to_space.next = to_space.next.offset(obj_size as isize);
        }

        set_forwarding_address(obj, addr);

        addr as *mut Obj
    }
}

pub fn is_forwarding_address(obj: *const u8) -> bool {
    (obj as usize) & 1 == 1
}

pub fn mark_forwarding_address(obj: *const u8) -> *const u8 {
    ((obj as usize) | 1) as *const u8
}

pub fn unmark_forwarding_address(obj: *const u8) -> *const u8 {
    ((obj as usize) & !1) as *const u8
}

pub fn get_forwarding_address(obj: &Obj) -> *const u8 {
    unsafe { *(obj as *const Obj as *const *const u8) }
}

pub fn set_forwarding_address(obj: &mut Obj, addr: *const u8) {
    unsafe {
        *(obj as *mut Obj as *mut *const u8) = mark_forwarding_address(addr);
    }
}

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

    #[test]
    fn test_mark_forwarding_address() {
        assert_eq!(9 as *const u8, mark_forwarding_address(8 as *const u8));
        assert_eq!(13 as *const u8, mark_forwarding_address(12 as *const u8));
    }

    #[test]
    fn test_unmark_forwarding_address() {
        assert_eq!(8 as *const u8, unmark_forwarding_address(9 as *const u8));
        assert_eq!(12 as *const u8, unmark_forwarding_address(13 as *const u8));
    }

    #[test]
    fn test_is_forwarding_address() {
        assert_eq!(false, is_forwarding_address(8 as *const u8));
        assert_eq!(true, is_forwarding_address(9 as *const u8));
        assert_eq!(false, is_forwarding_address(12 as *const u8));
        assert_eq!(true, is_forwarding_address(13 as *const u8));
    }
}<|endoftext|>


<commit_before>use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};

use actix_http::{Error, Response};
use actix_service::{Service, ServiceFactory};
use futures_util::future::{ready, Ready};
use futures_util::ready;
use pin_project::pin_project;

use crate::extract::FromRequest;
use crate::request::HttpRequest;
use crate::responder::Responder;
use crate::service::{ServiceRequest, ServiceResponse};

///  A request handler is an async function that accepts zero or more parameters that can be
///  extracted from a request (ie, [`impl FromRequest`](crate::FromRequest)) and returns a type that can be converted into
///  an [`HttpResponse`](crate::HttpResponse) (ie, [`impl Responder`](crate::Responder)).
///
/// If you got the error `the trait Handler<_, _, _> is not implemented`, then your function is not
/// a valid handler. See [Request Handlers](https://actix.rs/docs/handlers/) for more information.
pub trait Handler<T, R>: Clone + 'static
where
    R: Future,
    R::Output: Responder,
{
    fn call(&self, param: T) -> R;
}

impl<F, R> Handler<(), R> for F
where
    F: Fn() -> R + Clone + 'static,
    R: Future,
    R::Output: Responder,
{
    fn call(&self, _: ()) -> R {
        (self)()
    }
}

#[doc(hidden)]
/// Extract arguments from request, run factory function and make response.
pub struct HandlerService<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    hnd: F,
    _t: PhantomData<(T, R)>,
}

impl<F, T, R> HandlerService<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    pub fn new(hnd: F) -> Self {
        Self {
            hnd,
            _t: PhantomData,
        }
    }
}

impl<F, T, R> Clone for HandlerService<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    fn clone(&self) -> Self {
        Self {
            hnd: self.hnd.clone(),
            _t: PhantomData,
        }
    }
}

impl<F, T, R> ServiceFactory for HandlerService<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse;
    type Error = Error;
    type Config = ();
    type Service = Self;
    type InitError = ();
    type Future = Ready<Result<Self::Service, ()>>;

    fn new_service(&self, _: ()) -> Self::Future {
        ready(Ok(self.clone()))
    }
}

// Handler is both it's ServiceHandler and Service Type.
impl<F, T, R> Service for HandlerService<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse;
    type Error = Error;
    type Future = HandlerServiceFuture<F, T, R>;

    fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: Self::Request) -> Self::Future {
        let (req, mut payload) = req.into_parts();
        let fut = T::from_request(&req, &mut payload);
        HandlerServiceFuture::Extract(fut, Some(req), self.hnd.clone())
    }
}

#[doc(hidden)]
#[pin_project(project = HandlerProj)]
pub enum HandlerServiceFuture<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    Extract(#[pin] T::Future, Option<HttpRequest>, F),
    Handle(#[pin] R, Option<HttpRequest>),
    Respond(#[pin] <R::Output as Responder>::Future, Option<HttpRequest>),
}

impl<F, T, R> Future for HandlerServiceFuture<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    // Error type in this future is a placeholder type.
    // all instances of error must be converted to ServiceResponse and return in Ok.
    type Output = Result<ServiceResponse, Error>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        loop {
            match self.as_mut().project() {
                HandlerProj::Extract(fut, req, handle) => {
                    match ready!(fut.poll(cx)) {
                        Ok(item) => {
                            let fut = handle.call(item);
                            let state = HandlerServiceFuture::Handle(fut, req.take());
                            self.as_mut().set(state);
                        }
                        Err(e) => {
                            let res: Response = e.into().into();
                            let req = req.take().unwrap();
                            return Poll::Ready(Ok(ServiceResponse::new(req, res)));
                        }
                    };
                }
                HandlerProj::Handle(fut, req) => {
                    let res = ready!(fut.poll(cx));
                    let fut = res.respond_to(req.as_ref().unwrap());
                    let state = HandlerServiceFuture::Respond(fut, req.take());
                    self.as_mut().set(state);
                }
                HandlerProj::Respond(fut, req) => {
                    let res = ready!(fut.poll(cx)).unwrap_or_else(|e| e.into().into());
                    let req = req.take().unwrap();
                    return Poll::Ready(Ok(ServiceResponse::new(req, res)));
                }
            }
        }
    }
}

/// FromRequest trait impl for tuples
macro_rules! factory_tuple ({ $(($n:tt, $T:ident)),+} => {
    impl<Func, $($T,)+ Res> Handler<($($T,)+), Res> for Func
    where Func: Fn($($T,)+) -> Res + Clone + 'static,
          Res: Future,
          Res::Output: Responder,
    {
        fn call(&self, param: ($($T,)+)) -> Res {
            (self)($(param.$n,)+)
        }
    }
});

#[rustfmt::skip]
mod m {
    use super::*;

factory_tuple!((0, A));
factory_tuple!((0, A), (1, B));
factory_tuple!((0, A), (1, B), (2, C));
factory_tuple!((0, A), (1, B), (2, C), (3, D));
factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E));
factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F));
factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G));
factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H));
factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I));
factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J));
}
<commit_msg>format factory_tuple macro invocations (#1859)<commit_after>use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};

use actix_http::{Error, Response};
use actix_service::{Service, ServiceFactory};
use futures_util::future::{ready, Ready};
use futures_util::ready;
use pin_project::pin_project;

use crate::extract::FromRequest;
use crate::request::HttpRequest;
use crate::responder::Responder;
use crate::service::{ServiceRequest, ServiceResponse};

///  A request handler is an async function that accepts zero or more parameters that can be
///  extracted from a request (ie, [`impl FromRequest`](crate::FromRequest)) and returns a type that can be converted into
///  an [`HttpResponse`](crate::HttpResponse) (ie, [`impl Responder`](crate::Responder)).
///
/// If you got the error `the trait Handler<_, _, _> is not implemented`, then your function is not
/// a valid handler. See [Request Handlers](https://actix.rs/docs/handlers/) for more information.
pub trait Handler<T, R>: Clone + 'static
where
    R: Future,
    R::Output: Responder,
{
    fn call(&self, param: T) -> R;
}

impl<F, R> Handler<(), R> for F
where
    F: Fn() -> R + Clone + 'static,
    R: Future,
    R::Output: Responder,
{
    fn call(&self, _: ()) -> R {
        (self)()
    }
}

#[doc(hidden)]
/// Extract arguments from request, run factory function and make response.
pub struct HandlerService<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    hnd: F,
    _t: PhantomData<(T, R)>,
}

impl<F, T, R> HandlerService<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    pub fn new(hnd: F) -> Self {
        Self {
            hnd,
            _t: PhantomData,
        }
    }
}

impl<F, T, R> Clone for HandlerService<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    fn clone(&self) -> Self {
        Self {
            hnd: self.hnd.clone(),
            _t: PhantomData,
        }
    }
}

impl<F, T, R> ServiceFactory for HandlerService<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse;
    type Error = Error;
    type Config = ();
    type Service = Self;
    type InitError = ();
    type Future = Ready<Result<Self::Service, ()>>;

    fn new_service(&self, _: ()) -> Self::Future {
        ready(Ok(self.clone()))
    }
}

// Handler is both it's ServiceHandler and Service Type.
impl<F, T, R> Service for HandlerService<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse;
    type Error = Error;
    type Future = HandlerServiceFuture<F, T, R>;

    fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: Self::Request) -> Self::Future {
        let (req, mut payload) = req.into_parts();
        let fut = T::from_request(&req, &mut payload);
        HandlerServiceFuture::Extract(fut, Some(req), self.hnd.clone())
    }
}

#[doc(hidden)]
#[pin_project(project = HandlerProj)]
pub enum HandlerServiceFuture<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    Extract(#[pin] T::Future, Option<HttpRequest>, F),
    Handle(#[pin] R, Option<HttpRequest>),
    Respond(#[pin] <R::Output as Responder>::Future, Option<HttpRequest>),
}

impl<F, T, R> Future for HandlerServiceFuture<F, T, R>
where
    F: Handler<T, R>,
    T: FromRequest,
    R: Future,
    R::Output: Responder,
{
    // Error type in this future is a placeholder type.
    // all instances of error must be converted to ServiceResponse and return in Ok.
    type Output = Result<ServiceResponse, Error>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        loop {
            match self.as_mut().project() {
                HandlerProj::Extract(fut, req, handle) => {
                    match ready!(fut.poll(cx)) {
                        Ok(item) => {
                            let fut = handle.call(item);
                            let state = HandlerServiceFuture::Handle(fut, req.take());
                            self.as_mut().set(state);
                        }
                        Err(e) => {
                            let res: Response = e.into().into();
                            let req = req.take().unwrap();
                            return Poll::Ready(Ok(ServiceResponse::new(req, res)));
                        }
                    };
                }
                HandlerProj::Handle(fut, req) => {
                    let res = ready!(fut.poll(cx));
                    let fut = res.respond_to(req.as_ref().unwrap());
                    let state = HandlerServiceFuture::Respond(fut, req.take());
                    self.as_mut().set(state);
                }
                HandlerProj::Respond(fut, req) => {
                    let res = ready!(fut.poll(cx)).unwrap_or_else(|e| e.into().into());
                    let req = req.take().unwrap();
                    return Poll::Ready(Ok(ServiceResponse::new(req, res)));
                }
            }
        }
    }
}

/// FromRequest trait impl for tuples
macro_rules! factory_tuple ({ $(($n:tt, $T:ident)),+} => {
    impl<Func, $($T,)+ Res> Handler<($($T,)+), Res> for Func
    where Func: Fn($($T,)+) -> Res + Clone + 'static,
          Res: Future,
          Res::Output: Responder,
    {
        fn call(&self, param: ($($T,)+)) -> Res {
            (self)($(param.$n,)+)
        }
    }
});

#[rustfmt::skip]
mod m {
    use super::*;

    factory_tuple!((0, A));
    factory_tuple!((0, A), (1, B));
    factory_tuple!((0, A), (1, B), (2, C));
    factory_tuple!((0, A), (1, B), (2, C), (3, D));
    factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E));
    factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F));
    factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G));
    factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H));
    factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I));
    factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J));
}
<|endoftext|>