<commit_before>use std::fmt;
use std::borrow::Cow;
use std::io::{Cursor, Read, Write, ErrorKind};
use std::default::Default;
use std::string::{String, FromUtf8Error};
use std::result::Result as StdResult;
use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt, NetworkEndian};
use bytes::BufMut;

use error::{Error, Result};
use super::coding::{OpCode, Control, Data, CloseCode};
use super::mask::{generate_mask, apply_mask};

/// A struct representing the close command.
#[derive(Debug, Clone)]
pub struct CloseFrame<'t> {
    /// The reason as a code.
    pub code: CloseCode,
    /// The reason as text string.
    pub reason: Cow<'t, str>,
}

impl<'t> CloseFrame<'t> {
    /// Convert into a owned string.
    pub fn into_owned(self) -> CloseFrame<'static> {
        CloseFrame {
            code: self.code,
            reason: self.reason.into_owned().into(),
        }
    }
}

impl<'t> fmt::Display for CloseFrame<'t> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} ({})", self.reason, self.code)
    }
}

/// A struct representing a WebSocket frame.
#[derive(Debug, Clone)]
pub struct Frame {
    finished: bool,
    rsv1: bool,
    rsv2: bool,
    rsv3: bool,
    opcode: OpCode,

    mask: Option<[u8; 4]>,

    payload: Vec<u8>,
}

impl Frame {

    /// Get the length of the frame.
    /// This is the length of the header + the length of the payload.
    #[inline]
    pub fn len(&self) -> usize {
        let mut header_length = 2;
        let payload_len = self.payload().len();
        if payload_len > 125 {
            if payload_len <= u16::max_value() as usize {
                header_length += 2;
            } else {
                header_length += 8;
            }
        }

        if self.is_masked() {
            header_length += 4;
        }

        header_length + payload_len
    }

    /// Test whether the frame is a final frame.
    #[inline]
    pub fn is_final(&self) -> bool {
        self.finished
    }

    /// Test whether the first reserved bit is set.
    #[inline]
    pub fn has_rsv1(&self) -> bool {
        self.rsv1
    }

    /// Test whether the second reserved bit is set.
    #[inline]
    pub fn has_rsv2(&self) -> bool {
        self.rsv2
    }

    /// Test whether the third reserved bit is set.
    #[inline]
    pub fn has_rsv3(&self) -> bool {
        self.rsv3
    }

    /// Get the OpCode of the frame.
    #[inline]
    pub fn opcode(&self) -> OpCode {
        self.opcode
    }

    /// Get a reference to the frame's payload.
    #[inline]
    pub fn payload(&self) -> &Vec<u8> {
        &self.payload
    }

    // Test whether the frame is masked.
    #[doc(hidden)]
    #[inline]
    pub fn is_masked(&self) -> bool {
        self.mask.is_some()
    }

    // Get an optional reference to the frame's mask.
    #[doc(hidden)]
    #[allow(dead_code)]
    #[inline]
    pub fn mask(&self) -> Option<&[u8; 4]> {
        self.mask.as_ref()
    }

    /// Make this frame a final frame.
    #[allow(dead_code)]
    #[inline]
    pub fn set_final(&mut self, is_final: bool) -> &mut Frame {
        self.finished = is_final;
        self
    }

    /// Set the first reserved bit.
    #[inline]
    pub fn set_rsv1(&mut self, has_rsv1: bool) -> &mut Frame {
        self.rsv1 = has_rsv1;
        self
    }

    /// Set the second reserved bit.
    #[inline]
    pub fn set_rsv2(&mut self, has_rsv2: bool) -> &mut Frame {
        self.rsv2 = has_rsv2;
        self
    }

    /// Set the third reserved bit.
    #[inline]
    pub fn set_rsv3(&mut self, has_rsv3: bool) -> &mut Frame {
        self.rsv3 = has_rsv3;
        self
    }

    /// Set the OpCode.
    #[allow(dead_code)]
    #[inline]
    pub fn set_opcode(&mut self, opcode: OpCode) -> &mut Frame {
        self.opcode = opcode;
        self
    }

    /// Edit the frame's payload.
    #[allow(dead_code)]
    #[inline]
    pub fn payload_mut(&mut self) -> &mut Vec<u8> {
        &mut self.payload
    }

    // Generate a new mask for this frame.
    //
    // This method simply generates and stores the mask. It does not change the payload data.
    // Instead, the payload data will be masked with the generated mask when the frame is sent
    // to the other endpoint.
    #[doc(hidden)]
    #[inline]
    pub fn set_mask(&mut self) -> &mut Frame {
        self.mask = Some(generate_mask());
        self
    }

    // This method unmasks the payload and should only be called on frames that are actually
    // masked. In other words, those frames that have just been received from a client endpoint.
    #[doc(hidden)]
    #[inline]
    pub fn remove_mask(&mut self) {
        self.mask.and_then(|mask| {
            Some(apply_mask(&mut self.payload, &mask))
        });
        self.mask = None;
    }

    /// Consume the frame into its payload as binary.
    #[inline]
    pub fn into_data(self) -> Vec<u8> {
        self.payload
    }

    /// Consume the frame into its payload as string.
    #[inline]
    pub fn into_string(self) -> StdResult<String, FromUtf8Error> {
        String::from_utf8(self.payload)
    }

     /// Consume the frame into a closing frame.
    #[inline]
    pub fn into_close(self) -> Result<Option<CloseFrame<'static>>> {
        match self.payload.len() {
            0 => Ok(None),
            1 => Err(Error::Protocol("Invalid close sequence".into())),
            _ => {
                let mut data = self.payload;
                let code = NetworkEndian::read_u16(&data[0..2]).into();
                data.drain(0..2);
                let text = String::from_utf8(data)?;
                Ok(Some(CloseFrame { code: code, reason: text.into() }))
            }
        }
    }

    /// Create a new data frame.
    #[inline]
    pub fn message(data: Vec<u8>, code: OpCode, finished: bool) -> Frame {
        debug_assert!(match code {
            OpCode::Data(_) => true,
            _ => false,
        }, "Invalid opcode for data frame.");

        Frame {
            finished: finished,
            opcode: code,
            payload: data,
            .. Frame::default()
        }
    }

    /// Create a new Pong control frame.
    #[inline]
    pub fn pong(data: Vec<u8>) -> Frame {
        Frame {
            opcode: OpCode::Control(Control::Pong),
            payload: data,
            .. Frame::default()
        }
    }

    /// Create a new Ping control frame.
    #[inline]
    pub fn ping(data: Vec<u8>) -> Frame {
        Frame {
            opcode: OpCode::Control(Control::Ping),
            payload: data,
            .. Frame::default()
        }
    }

    /// Create a new Close control frame.
    #[inline]
    pub fn close(msg: Option<CloseFrame>) -> Frame {
        let payload = if let Some(CloseFrame { code, reason }) = msg {
            let mut p = Vec::with_capacity(reason.as_bytes().len() + 2);
            p.write_u16::<NetworkEndian>(code.into()).unwrap(); // can't fail
            p.extend_from_slice(reason.as_bytes());
            p
        } else {
            Vec::new()
        };

        Frame {
            payload: payload,
            .. Frame::default()
        }
    }

    /// Parse the input stream into a frame.
    pub fn parse(cursor: &mut Cursor<Vec<u8>>) -> Result<Option<Frame>> {
        let size = cursor.get_ref().len() as u64 - cursor.position();
        let initial = cursor.position();
        trace!("Position in buffer {}", initial);

        let mut head = [0u8; 2];
        if try!(cursor.read(&mut head)) != 2 {
            cursor.set_position(initial);
            return Ok(None)
        }

        trace!("Parsed headers {:?}", head);

        let first = head[0];
        let second = head[1];
        trace!("First: {:b}", first);
        trace!("Second: {:b}", second);

        let finished = first & 0x80 != 0;

        let rsv1 = first & 0x40 != 0;
        let rsv2 = first & 0x20 != 0;
        let rsv3 = first & 0x10 != 0;

        let opcode = OpCode::from(first & 0x0F);
        trace!("Opcode: {:?}", opcode);

        let masked = second & 0x80 != 0;
        trace!("Masked: {:?}", masked);

        let mut header_length = 2;

        let mut length = (second & 0x7F) as u64;

        if let Some(length_nbytes) = match length {
            126 => Some(2),
            127 => Some(8),
            _ => None,
        } {
            match cursor.read_uint::<NetworkEndian>(length_nbytes) {
                Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => {
                    cursor.set_position(initial);
                    return Ok(None);
                }
                Err(err) => {
                    return Err(Error::from(err));
                }
                Ok(read) => {
                    length = read;
                }
            };
            header_length += length_nbytes as u64;
        }
        trace!("Payload length: {}", length);

        let mask = if masked {
            let mut mask_bytes = [0u8; 4];
            if try!(cursor.read(&mut mask_bytes)) != 4 {
                cursor.set_position(initial);
                return Ok(None)
            } else {
                header_length += 4;
                Some(mask_bytes)
            }
        } else {
            None
        };

        // Make sure `length` is not too big (fits into `usize`).
        if length > usize::max_value() as u64 {
            return Err(Error::Capacity(format!("Message length too big: {}", length).into()));
        }

        if size < header_length || size - header_length < length {
            cursor.set_position(initial);
            return Ok(None)
        }

        // Size is checked above, so it won't be truncated here.
        let mut data = Vec::with_capacity(length as usize);
        if length > 0 {
            unsafe {
                try!(cursor.read_exact(data.bytes_mut()));
                data.advance_mut(length as usize);
            }
        }

        // Disallow bad opcode
        match opcode {
            OpCode::Control(Control::Reserved(_)) | OpCode::Data(Data::Reserved(_)) => {
                return Err(Error::Protocol(format!("Encountered invalid opcode: {}", first & 0x0F).into()))
            }
            _ => ()
        }

        let frame = Frame {
            finished: finished,
            rsv1: rsv1,
            rsv2: rsv2,
            rsv3: rsv3,
            opcode: opcode,
            mask: mask,
            payload: data,
        };

        Ok(Some(frame))
    }

    /// Write a frame out to a buffer
    pub fn format<W>(mut self, w: &mut W) -> Result<()>
        where W: Write
    {
        let mut one = 0u8;
        let code: u8 = self.opcode.into();
        if self.is_final() {
            one |= 0x80;
        }
        if self.has_rsv1() {
            one |= 0x40;
        }
        if self.has_rsv2() {
            one |= 0x20;
        }
        if self.has_rsv3() {
            one |= 0x10;
        }
        one |= code;

        let mut two = 0u8;

        if self.is_masked() {
            two |= 0x80;
        }

        if self.payload.len() < 126 {
            two |= self.payload.len() as u8;
            let headers = [one, two];
            try!(w.write(&headers));
        } else if self.payload.len() <= 65535 {
            two |= 126;
            let mut length_bytes = [0u8; 2];
            NetworkEndian::write_u16(&mut length_bytes, self.payload.len() as u16);
            let headers = [one, two, length_bytes[0], length_bytes[1]];
            try!(w.write(&headers));
        } else {
            two |= 127;
            let mut length_bytes = [0u8; 8];
            NetworkEndian::write_u64(&mut length_bytes, self.payload.len() as u64);
            let headers = [
                one,
                two,
                length_bytes[0],
                length_bytes[1],
                length_bytes[2],
                length_bytes[3],
                length_bytes[4],
                length_bytes[5],
                length_bytes[6],
                length_bytes[7],
            ];
            try!(w.write(&headers));
        }

        if self.is_masked() {
            let mask = self.mask.take().unwrap();
            apply_mask(&mut self.payload, &mask);
            try!(w.write(&mask));
        }

        try!(w.write(&self.payload));
        Ok(())
    }
}

impl Default for Frame {
    fn default() -> Frame {
        Frame {
            finished: true,
            rsv1: false,
            rsv2: false,
            rsv3: false,
            opcode: OpCode::Control(Control::Close),
            mask: None,
            payload: Vec::new(),
        }
    }
}

impl fmt::Display for Frame {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
            "
<FRAME>
final: {}
reserved: {} {} {}
opcode: {}
length: {}
payload length: {}
payload: 0x{}
            ",
            self.finished,
            self.rsv1,
            self.rsv2,
            self.rsv3,
            self.opcode,
            // self.mask.map(|mask| format!("{:?}", mask)).unwrap_or("NONE".into()),
            self.len(),
            self.payload.len(),
            self.payload.iter().map(|byte| format!("{:x}", byte)).collect::<String>())
    }
}

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

    use super::super::coding::{OpCode, Data};
    use std::io::Cursor;

    #[test]
    fn parse() {
        let mut raw: Cursor<Vec<u8>> = Cursor::new(vec![
            0x82, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ]);
        let frame = Frame::parse(&mut raw).unwrap().unwrap();
        assert_eq!(frame.into_data(), vec![ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ]);
    }

    #[test]
    fn format() {
        let frame = Frame::ping(vec![0x01, 0x02]);
        let mut buf = Vec::with_capacity(frame.len());
        frame.format(&mut buf).unwrap();
        assert_eq!(buf, vec![0x89, 0x02, 0x01, 0x02]);
    }

    #[test]
    fn display() {
        let f = Frame::message("hi there".into(), OpCode::Data(Data::Text), true);
        let view = format!("{}", f);
        assert!(view.contains("payload:"));
    }

    #[test]
    fn parse_overflow() {
        let mut raw: Cursor<Vec<u8>> = Cursor::new(vec![
            0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
            0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
        ]);
        let _ = Frame::parse(&mut raw); // should not crash
    }
}
<commit_msg>frame: reject bad opcodes early<commit_after>use std::fmt;
use std::borrow::Cow;
use std::io::{Cursor, Read, Write, ErrorKind};
use std::default::Default;
use std::string::{String, FromUtf8Error};
use std::result::Result as StdResult;
use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt, NetworkEndian};
use bytes::BufMut;

use error::{Error, Result};
use super::coding::{OpCode, Control, Data, CloseCode};
use super::mask::{generate_mask, apply_mask};

/// A struct representing the close command.
#[derive(Debug, Clone)]
pub struct CloseFrame<'t> {
    /// The reason as a code.
    pub code: CloseCode,
    /// The reason as text string.
    pub reason: Cow<'t, str>,
}

impl<'t> CloseFrame<'t> {
    /// Convert into a owned string.
    pub fn into_owned(self) -> CloseFrame<'static> {
        CloseFrame {
            code: self.code,
            reason: self.reason.into_owned().into(),
        }
    }
}

impl<'t> fmt::Display for CloseFrame<'t> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} ({})", self.reason, self.code)
    }
}

/// A struct representing a WebSocket frame.
#[derive(Debug, Clone)]
pub struct Frame {
    finished: bool,
    rsv1: bool,
    rsv2: bool,
    rsv3: bool,
    opcode: OpCode,

    mask: Option<[u8; 4]>,

    payload: Vec<u8>,
}

impl Frame {

    /// Get the length of the frame.
    /// This is the length of the header + the length of the payload.
    #[inline]
    pub fn len(&self) -> usize {
        let mut header_length = 2;
        let payload_len = self.payload().len();
        if payload_len > 125 {
            if payload_len <= u16::max_value() as usize {
                header_length += 2;
            } else {
                header_length += 8;
            }
        }

        if self.is_masked() {
            header_length += 4;
        }

        header_length + payload_len
    }

    /// Test whether the frame is a final frame.
    #[inline]
    pub fn is_final(&self) -> bool {
        self.finished
    }

    /// Test whether the first reserved bit is set.
    #[inline]
    pub fn has_rsv1(&self) -> bool {
        self.rsv1
    }

    /// Test whether the second reserved bit is set.
    #[inline]
    pub fn has_rsv2(&self) -> bool {
        self.rsv2
    }

    /// Test whether the third reserved bit is set.
    #[inline]
    pub fn has_rsv3(&self) -> bool {
        self.rsv3
    }

    /// Get the OpCode of the frame.
    #[inline]
    pub fn opcode(&self) -> OpCode {
        self.opcode
    }

    /// Get a reference to the frame's payload.
    #[inline]
    pub fn payload(&self) -> &Vec<u8> {
        &self.payload
    }

    // Test whether the frame is masked.
    #[doc(hidden)]
    #[inline]
    pub fn is_masked(&self) -> bool {
        self.mask.is_some()
    }

    // Get an optional reference to the frame's mask.
    #[doc(hidden)]
    #[allow(dead_code)]
    #[inline]
    pub fn mask(&self) -> Option<&[u8; 4]> {
        self.mask.as_ref()
    }

    /// Make this frame a final frame.
    #[allow(dead_code)]
    #[inline]
    pub fn set_final(&mut self, is_final: bool) -> &mut Frame {
        self.finished = is_final;
        self
    }

    /// Set the first reserved bit.
    #[inline]
    pub fn set_rsv1(&mut self, has_rsv1: bool) -> &mut Frame {
        self.rsv1 = has_rsv1;
        self
    }

    /// Set the second reserved bit.
    #[inline]
    pub fn set_rsv2(&mut self, has_rsv2: bool) -> &mut Frame {
        self.rsv2 = has_rsv2;
        self
    }

    /// Set the third reserved bit.
    #[inline]
    pub fn set_rsv3(&mut self, has_rsv3: bool) -> &mut Frame {
        self.rsv3 = has_rsv3;
        self
    }

    /// Set the OpCode.
    #[allow(dead_code)]
    #[inline]
    pub fn set_opcode(&mut self, opcode: OpCode) -> &mut Frame {
        self.opcode = opcode;
        self
    }

    /// Edit the frame's payload.
    #[allow(dead_code)]
    #[inline]
    pub fn payload_mut(&mut self) -> &mut Vec<u8> {
        &mut self.payload
    }

    // Generate a new mask for this frame.
    //
    // This method simply generates and stores the mask. It does not change the payload data.
    // Instead, the payload data will be masked with the generated mask when the frame is sent
    // to the other endpoint.
    #[doc(hidden)]
    #[inline]
    pub fn set_mask(&mut self) -> &mut Frame {
        self.mask = Some(generate_mask());
        self
    }

    // This method unmasks the payload and should only be called on frames that are actually
    // masked. In other words, those frames that have just been received from a client endpoint.
    #[doc(hidden)]
    #[inline]
    pub fn remove_mask(&mut self) {
        self.mask.and_then(|mask| {
            Some(apply_mask(&mut self.payload, &mask))
        });
        self.mask = None;
    }

    /// Consume the frame into its payload as binary.
    #[inline]
    pub fn into_data(self) -> Vec<u8> {
        self.payload
    }

    /// Consume the frame into its payload as string.
    #[inline]
    pub fn into_string(self) -> StdResult<String, FromUtf8Error> {
        String::from_utf8(self.payload)
    }

     /// Consume the frame into a closing frame.
    #[inline]
    pub fn into_close(self) -> Result<Option<CloseFrame<'static>>> {
        match self.payload.len() {
            0 => Ok(None),
            1 => Err(Error::Protocol("Invalid close sequence".into())),
            _ => {
                let mut data = self.payload;
                let code = NetworkEndian::read_u16(&data[0..2]).into();
                data.drain(0..2);
                let text = String::from_utf8(data)?;
                Ok(Some(CloseFrame { code: code, reason: text.into() }))
            }
        }
    }

    /// Create a new data frame.
    #[inline]
    pub fn message(data: Vec<u8>, code: OpCode, finished: bool) -> Frame {
        debug_assert!(match code {
            OpCode::Data(_) => true,
            _ => false,
        }, "Invalid opcode for data frame.");

        Frame {
            finished: finished,
            opcode: code,
            payload: data,
            .. Frame::default()
        }
    }

    /// Create a new Pong control frame.
    #[inline]
    pub fn pong(data: Vec<u8>) -> Frame {
        Frame {
            opcode: OpCode::Control(Control::Pong),
            payload: data,
            .. Frame::default()
        }
    }

    /// Create a new Ping control frame.
    #[inline]
    pub fn ping(data: Vec<u8>) -> Frame {
        Frame {
            opcode: OpCode::Control(Control::Ping),
            payload: data,
            .. Frame::default()
        }
    }

    /// Create a new Close control frame.
    #[inline]
    pub fn close(msg: Option<CloseFrame>) -> Frame {
        let payload = if let Some(CloseFrame { code, reason }) = msg {
            let mut p = Vec::with_capacity(reason.as_bytes().len() + 2);
            p.write_u16::<NetworkEndian>(code.into()).unwrap(); // can't fail
            p.extend_from_slice(reason.as_bytes());
            p
        } else {
            Vec::new()
        };

        Frame {
            payload: payload,
            .. Frame::default()
        }
    }

    /// Parse the input stream into a frame.
    pub fn parse(cursor: &mut Cursor<Vec<u8>>) -> Result<Option<Frame>> {
        let size = cursor.get_ref().len() as u64 - cursor.position();
        let initial = cursor.position();
        trace!("Position in buffer {}", initial);

        let mut head = [0u8; 2];
        if try!(cursor.read(&mut head)) != 2 {
            cursor.set_position(initial);
            return Ok(None)
        }

        trace!("Parsed headers {:?}", head);

        let first = head[0];
        let second = head[1];
        trace!("First: {:b}", first);
        trace!("Second: {:b}", second);

        let finished = first & 0x80 != 0;

        let rsv1 = first & 0x40 != 0;
        let rsv2 = first & 0x20 != 0;
        let rsv3 = first & 0x10 != 0;

        let opcode = OpCode::from(first & 0x0F);
        trace!("Opcode: {:?}", opcode);

        let masked = second & 0x80 != 0;
        trace!("Masked: {:?}", masked);

        let mut header_length = 2;

        let mut length = (second & 0x7F) as u64;

        if let Some(length_nbytes) = match length {
            126 => Some(2),
            127 => Some(8),
            _ => None,
        } {
            match cursor.read_uint::<NetworkEndian>(length_nbytes) {
                Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => {
                    cursor.set_position(initial);
                    return Ok(None);
                }
                Err(err) => {
                    return Err(Error::from(err));
                }
                Ok(read) => {
                    length = read;
                }
            };
            header_length += length_nbytes as u64;
        }
        trace!("Payload length: {}", length);

        let mask = if masked {
            let mut mask_bytes = [0u8; 4];
            if try!(cursor.read(&mut mask_bytes)) != 4 {
                cursor.set_position(initial);
                return Ok(None)
            } else {
                header_length += 4;
                Some(mask_bytes)
            }
        } else {
            None
        };

        // Disallow bad opcode
        match opcode {
            OpCode::Control(Control::Reserved(_)) | OpCode::Data(Data::Reserved(_)) => {
                return Err(Error::Protocol(format!("Encountered invalid opcode: {}", first & 0x0F).into()))
            }
            _ => ()
        }

        // Make sure `length` is not too big (fits into `usize`).
        if length > usize::max_value() as u64 {
            return Err(Error::Capacity(format!("Message length too big: {}", length).into()));
        }

        if size < header_length || size - header_length < length {
            cursor.set_position(initial);
            return Ok(None)
        }

        // Size is checked above, so it won't be truncated here.
        let mut data = Vec::with_capacity(length as usize);
        if length > 0 {
            unsafe {
                try!(cursor.read_exact(data.bytes_mut()));
                data.advance_mut(length as usize);
            }
        }

        let frame = Frame {
            finished: finished,
            rsv1: rsv1,
            rsv2: rsv2,
            rsv3: rsv3,
            opcode: opcode,
            mask: mask,
            payload: data,
        };

        Ok(Some(frame))
    }

    /// Write a frame out to a buffer
    pub fn format<W>(mut self, w: &mut W) -> Result<()>
        where W: Write
    {
        let mut one = 0u8;
        let code: u8 = self.opcode.into();
        if self.is_final() {
            one |= 0x80;
        }
        if self.has_rsv1() {
            one |= 0x40;
        }
        if self.has_rsv2() {
            one |= 0x20;
        }
        if self.has_rsv3() {
            one |= 0x10;
        }
        one |= code;

        let mut two = 0u8;

        if self.is_masked() {
            two |= 0x80;
        }

        if self.payload.len() < 126 {
            two |= self.payload.len() as u8;
            let headers = [one, two];
            try!(w.write(&headers));
        } else if self.payload.len() <= 65535 {
            two |= 126;
            let mut length_bytes = [0u8; 2];
            NetworkEndian::write_u16(&mut length_bytes, self.payload.len() as u16);
            let headers = [one, two, length_bytes[0], length_bytes[1]];
            try!(w.write(&headers));
        } else {
            two |= 127;
            let mut length_bytes = [0u8; 8];
            NetworkEndian::write_u64(&mut length_bytes, self.payload.len() as u64);
            let headers = [
                one,
                two,
                length_bytes[0],
                length_bytes[1],
                length_bytes[2],
                length_bytes[3],
                length_bytes[4],
                length_bytes[5],
                length_bytes[6],
                length_bytes[7],
            ];
            try!(w.write(&headers));
        }

        if self.is_masked() {
            let mask = self.mask.take().unwrap();
            apply_mask(&mut self.payload, &mask);
            try!(w.write(&mask));
        }

        try!(w.write(&self.payload));
        Ok(())
    }
}

impl Default for Frame {
    fn default() -> Frame {
        Frame {
            finished: true,
            rsv1: false,
            rsv2: false,
            rsv3: false,
            opcode: OpCode::Control(Control::Close),
            mask: None,
            payload: Vec::new(),
        }
    }
}

impl fmt::Display for Frame {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
            "
<FRAME>
final: {}
reserved: {} {} {}
opcode: {}
length: {}
payload length: {}
payload: 0x{}
            ",
            self.finished,
            self.rsv1,
            self.rsv2,
            self.rsv3,
            self.opcode,
            // self.mask.map(|mask| format!("{:?}", mask)).unwrap_or("NONE".into()),
            self.len(),
            self.payload.len(),
            self.payload.iter().map(|byte| format!("{:x}", byte)).collect::<String>())
    }
}

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

    use super::super::coding::{OpCode, Data};
    use std::io::Cursor;

    #[test]
    fn parse() {
        let mut raw: Cursor<Vec<u8>> = Cursor::new(vec![
            0x82, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ]);
        let frame = Frame::parse(&mut raw).unwrap().unwrap();
        assert_eq!(frame.into_data(), vec![ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ]);
    }

    #[test]
    fn format() {
        let frame = Frame::ping(vec![0x01, 0x02]);
        let mut buf = Vec::with_capacity(frame.len());
        frame.format(&mut buf).unwrap();
        assert_eq!(buf, vec![0x89, 0x02, 0x01, 0x02]);
    }

    #[test]
    fn display() {
        let f = Frame::message("hi there".into(), OpCode::Data(Data::Text), true);
        let view = format!("{}", f);
        assert!(view.contains("payload:"));
    }

    #[test]
    fn parse_overflow() {
        let mut raw: Cursor<Vec<u8>> = Cursor::new(vec![
            0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
            0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
        ]);
        let _ = Frame::parse(&mut raw); // should not crash
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
use specs;
use specs::{ReadStorage, WriteStorage};
use game::constants::VIEW_DISTANCE;
use gfx_app::mouse_controls::MouseInputState;
use character::CharacterDrawable;

#[derive(Clone, Debug)]
pub struct CameraInputState {
  pub distance: f32,
  pub x_pos: f32,
  pub y_pos: f32,
}

impl CameraInputState {
  pub fn new() -> CameraInputState {
    CameraInputState {
      distance: VIEW_DISTANCE,
      x_pos: 0.0,
      y_pos: 0.0,
    }
  }
}

impl specs::Component for CameraInputState {
  type Storage = specs::HashMapStorage<CameraInputState>;
}

#[derive(Debug)]
pub enum CameraControl {
  ZoomOut,
  ZoomIn,
  ZoomStop,
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
}

#[derive(Debug)]
pub struct CameraControlSystem {
  queue: mpsc::Receiver<CameraControl>,
  zoom_level: Option<f32>,
  x_move: Option<f32>,
  y_move: Option<f32>,
}

impl CameraControlSystem {
  pub fn new() -> (CameraControlSystem, mpsc::Sender<CameraControl>) {
    let (tx, rx) = mpsc::channel();
    (CameraControlSystem {
      queue: rx,
      zoom_level: None,
      x_move: None,
      y_move: None,
    }, tx)
  }
}

impl<'a> specs::System<'a> for CameraControlSystem {
  type SystemData = (WriteStorage<'a, CameraInputState>, WriteStorage<'a, MouseInputState>, ReadStorage<'a, CharacterDrawable>);
  fn run(&mut self, (mut map_input, mut mouse_input, character): Self::SystemData) {
    use specs::Join;

    while let Ok(control) = self.queue.try_recv() {
      match control {
        CameraControl::ZoomIn => self.zoom_level = Some(2.0),
        CameraControl::ZoomOut => self.zoom_level = Some(-2.0),
        CameraControl::ZoomStop => self.zoom_level = None,
        CameraControl::Up => self.y_move = Some(-0.265),
        CameraControl::Down => self.y_move = Some(0.265),
        CameraControl::YMoveStop => self.y_move = None,
        CameraControl::Right => self.x_move = Some(0.265),
        CameraControl::Left => self.x_move = Some(-0.265),
        CameraControl::XMoveStop => self.x_move = None,
      }
    }
    if let Some(zoom) = self.zoom_level {
      for m in (&mut map_input).join() {
        if m.distance > 200.0 && zoom < 0.0 || m.distance < 1000.0 && zoom > 0.0 {
          m.distance += zoom;
        }
      }
    }
    if let Some(x) = self.x_move {
      if let Some(y) = self.y_move {
        for (map, mi, c) in (&mut map_input, &mut mouse_input, &character).join() {
          if mi.left_click_point.is_none() && !c.is_collision {
            map.x_pos += x;
            map.y_pos += y / 2.0;
          }
        }
      }
    }
    if let Some(x) = self.x_move {
      if self.y_move == None {
        for (map, mi, c) in (&mut map_input, &mut mouse_input, &character).join() {
          if mi.left_click_point.is_none() && !c.is_collision {
            map.x_pos += x;
          }
        }
      }
    }
    if let Some(y) = self.y_move {
      if self.x_move == None {
        for (map, mi, c) in (&mut map_input, &mut mouse_input, &character).join() {
          if mi.left_click_point.is_none() && !c.is_collision {
            map.y_pos += y;
          }
        }
      }
    }
  }
}
<commit_msg>Refactor character position update<commit_after>use std::sync::mpsc;
use specs;
use specs::{ReadStorage, WriteStorage};
use game::constants::VIEW_DISTANCE;
use gfx_app::mouse_controls::MouseInputState;
use character::CharacterDrawable;

#[derive(Clone, Debug)]
pub struct CameraInputState {
  pub distance: f32,
  pub x_pos: f32,
  pub y_pos: f32,
}

impl CameraInputState {
  pub fn new() -> CameraInputState {
    CameraInputState {
      distance: VIEW_DISTANCE,
      x_pos: 0.0,
      y_pos: 0.0,
    }
  }
}

impl specs::Component for CameraInputState {
  type Storage = specs::HashMapStorage<CameraInputState>;
}

#[derive(Debug)]
pub enum CameraControl {
  ZoomOut,
  ZoomIn,
  ZoomStop,
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
}

#[derive(Debug)]
pub struct CameraControlSystem {
  queue: mpsc::Receiver<CameraControl>,
  zoom_level: Option<f32>,
  x_move: Option<f32>,
  y_move: Option<f32>,
}

impl CameraControlSystem {
  pub fn new() -> (CameraControlSystem, mpsc::Sender<CameraControl>) {
    let (tx, rx) = mpsc::channel();
    (CameraControlSystem {
      queue: rx,
      zoom_level: None,
      x_move: None,
      y_move: None,
    }, tx)
  }
}

impl<'a> specs::System<'a> for CameraControlSystem {
  type SystemData = (WriteStorage<'a, CameraInputState>, WriteStorage<'a, MouseInputState>, ReadStorage<'a, CharacterDrawable>);
  fn run(&mut self, (mut map_input, mut mouse_input, character): Self::SystemData) {
    use specs::Join;

    while let Ok(control) = self.queue.try_recv() {
      match control {
        CameraControl::ZoomIn => self.zoom_level = Some(2.0),
        CameraControl::ZoomOut => self.zoom_level = Some(-2.0),
        CameraControl::ZoomStop => self.zoom_level = None,
        CameraControl::Up => self.y_move = Some(-0.265),
        CameraControl::Down => self.y_move = Some(0.265),
        CameraControl::YMoveStop => self.y_move = None,
        CameraControl::Right => self.x_move = Some(0.265),
        CameraControl::Left => self.x_move = Some(-0.265),
        CameraControl::XMoveStop => self.x_move = None,
      }
    }
    if let Some(zoom) = self.zoom_level {
      for m in (&mut map_input).join() {
        if m.distance > 200.0 && zoom < 0.0 || m.distance < 1000.0 && zoom > 0.0 {
          m.distance += zoom;
        }
      }
    }
    if let Some(x) = self.x_move {
      if self.y_move == None {
        for (map, mi, c) in (&mut map_input, &mut mouse_input, &character).join() {
          if mi.left_click_point.is_none() && !c.is_collision {
            map.x_pos += x;
          }
        }
      } else if let Some(y) = self.y_move {
        for (map, mi, c) in (&mut map_input, &mut mouse_input, &character).join() {
          if mi.left_click_point.is_none() && !c.is_collision {
            map.x_pos += x;
            map.y_pos += y / 2.0;
          }
        }
      }
    }
    if let Some(y) = self.y_move {
      if self.x_move == None {
        for (map, mi, c) in (&mut map_input, &mut mouse_input, &character).join() {
          if mi.left_click_point.is_none() && !c.is_collision {
            map.y_pos += y;
          }
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>use base::{AbstractCFType, AbstractCFTypeRef, CFAllocatorRef, CFIndex, CFRelease, CFTypeRef, kCFAllocatorDefault};
use cast::reinterpret_cast;
use dvec::DVec;
use libc::c_void;
use ptr::to_unsafe_ptr;
use vec::raw::to_ptr;

pub type CFDictionaryRetainCallBack = *u8;
pub type CFDictionaryReleaseCallBack = *u8;
pub type CFDictionaryCopyDescriptionCallBack = *u8;
pub type CFDictionaryEqualCallBack = *u8;
pub type CFDictionaryHashCallBack = *u8;

pub struct CFDictionaryKeyCallBacks {
    version: CFIndex,
    retain: CFDictionaryRetainCallBack,
    release: CFDictionaryReleaseCallBack,
    copyDescription: CFDictionaryCopyDescriptionCallBack,
    equal: CFDictionaryEqualCallBack,
    hash: CFDictionaryHashCallBack
}

pub struct CFDictionaryValueCallBacks {
    version: CFIndex,
    retain: CFDictionaryRetainCallBack,
    release: CFDictionaryReleaseCallBack,
    copyDescription: CFDictionaryCopyDescriptionCallBack,
    equal: CFDictionaryEqualCallBack
}

struct __CFDictionary { private: () }
pub type CFDictionaryRef = *__CFDictionary;

impl CFDictionaryRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
}

struct CFDictionary<KeyRefType   : AbstractCFTypeRef,
                    ValueRefType : AbstractCFTypeRef,
                    KeyType      : AbstractCFType<KeyRefType>,
                    ValueType    : AbstractCFType<ValueRefType>> {
    obj: CFDictionaryRef,

    drop {
        unsafe {
            CFRelease(reinterpret_cast(&self.obj));
        }
    }
}

pub impl<KeyRefType   : AbstractCFTypeRef,
         ValueRefType : AbstractCFTypeRef,
         KeyType      : AbstractCFType<KeyRefType>,
         ValueType    : AbstractCFType<ValueRefType>>
    CFDictionary<KeyRefType, ValueRefType, KeyType, ValueType> : AbstractCFType<CFDictionaryRef> {

    pure fn get_ref() -> CFDictionaryRef { self.obj }

    static fn wrap(obj: CFDictionaryRef) -> CFDictionary<KeyRefType, ValueRefType, KeyType, ValueType> {
        CFDictionary { obj: obj }
    }

    static fn unwrap(wrapper: CFDictionary<KeyRefType, ValueRefType, KeyType, ValueType>) -> CFDictionaryRef {
        wrapper.obj
    }
}

pub impl<KeyRefType   : AbstractCFTypeRef,
         ValueRefType : AbstractCFTypeRef,
         KeyType      : AbstractCFType<KeyRefType>,
         ValueType    : AbstractCFType<ValueRefType>>
    CFDictionary<KeyRefType, ValueRefType, KeyType, ValueType> {

    static fn new(pairs: &[(KeyType,ValueType)]) -> CFDictionary<KeyRefType, ValueRefType, KeyType, ValueType> {
        let (keys, values) = (DVec(), DVec());
        for pairs.each |pair| {
            // FIXME: "let" would be much nicer here, but that doesn't work yet.
            match *pair {
                (ref key, ref value) => {
                    // TODO: should be able to say key.get_type_ref(), but resolve isn't having any of it.
                    keys.push(key.get_ref().as_type_ref());
                    values.push(value.get_ref().as_type_ref());
                }
            }
        }

        assert keys.len() == values.len();
        let keys = dvec::unwrap(move keys);
        let values = dvec::unwrap(move values);

        let dictionary_ref : CFDictionaryRef;
        unsafe {
            dictionary_ref = CFDictionaryCreate(kCFAllocatorDefault,
                                                reinterpret_cast(&to_ptr(keys)),
                                                reinterpret_cast(&to_ptr(values)),
                                                keys.len() as CFIndex,
                                                to_unsafe_ptr(&kCFTypeDictionaryKeyCallBacks),
                                                to_unsafe_ptr(&kCFTypeDictionaryValueCallBacks));
        }

        return base::wrap(dictionary_ref);
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFDictionary.h
     */

    const kCFTypeDictionaryKeyCallBacks: CFDictionaryKeyCallBacks;
    const kCFTypeDictionaryValueCallBacks: CFDictionaryValueCallBacks;

    fn CFDictionaryCreate(allocator: CFAllocatorRef, keys: **c_void, values: **c_void,
                          numValues: CFIndex, keyCallBacks: *CFDictionaryKeyCallBacks,
                          valueCallBacks: *CFDictionaryValueCallBacks)
                       -> CFDictionaryRef;
}

<commit_msg>Add some more immutable methods to CFDictionary.<commit_after>use base::{
    AbstractCFType,
    AbstractCFTypeRef,
    Boolean,
    CFAllocatorRef,
    CFIndex,
    CFRelease,
    CFTypeID,
    CFTypeRef,
    kCFAllocatorDefault
};
use cast::reinterpret_cast;
use dvec::DVec;
use libc::c_void;
use ptr::to_unsafe_ptr;
use vec::raw::to_ptr;

pub type CFDictionaryApplierFunction = *u8;
pub type CFDictionaryCopyDescriptionCallBack = *u8;
pub type CFDictionaryEqualCallBack = *u8;
pub type CFDictionaryHashCallBack = *u8;
pub type CFDictionaryReleaseCallBack = *u8;
pub type CFDictionaryRetainCallBack = *u8;

pub struct CFDictionaryKeyCallBacks {
    version: CFIndex,
    retain: CFDictionaryRetainCallBack,
    release: CFDictionaryReleaseCallBack,
    copyDescription: CFDictionaryCopyDescriptionCallBack,
    equal: CFDictionaryEqualCallBack,
    hash: CFDictionaryHashCallBack
}

pub struct CFDictionaryValueCallBacks {
    version: CFIndex,
    retain: CFDictionaryRetainCallBack,
    release: CFDictionaryReleaseCallBack,
    copyDescription: CFDictionaryCopyDescriptionCallBack,
    equal: CFDictionaryEqualCallBack
}

struct __CFDictionary { private: () }
pub type CFDictionaryRef = *__CFDictionary;

impl CFDictionaryRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
}

struct CFDictionary<KeyRefType   : AbstractCFTypeRef,
                    ValueRefType : AbstractCFTypeRef,
                    KeyType      : AbstractCFType<KeyRefType>,
                    ValueType    : AbstractCFType<ValueRefType>> {
    obj: CFDictionaryRef,

    drop {
        unsafe {
            CFRelease(reinterpret_cast(&self.obj));
        }
    }
}

pub impl<KeyRefType   : AbstractCFTypeRef,
         ValueRefType : AbstractCFTypeRef,
         KeyType      : AbstractCFType<KeyRefType>,
         ValueType    : AbstractCFType<ValueRefType>>
    CFDictionary<KeyRefType, ValueRefType, KeyType, ValueType> : AbstractCFType<CFDictionaryRef> {

    pure fn get_ref() -> CFDictionaryRef { self.obj }

    static fn wrap(obj: CFDictionaryRef) -> CFDictionary<KeyRefType, ValueRefType, KeyType, ValueType> {
        CFDictionary { obj: obj }
    }

    static fn unwrap(wrapper: CFDictionary<KeyRefType, ValueRefType, KeyType, ValueType>) -> CFDictionaryRef {
        wrapper.obj
    }
}

pub impl<KeyRefType   : AbstractCFTypeRef,
         ValueRefType : AbstractCFTypeRef,
         KeyType      : AbstractCFType<KeyRefType>,
         ValueType    : AbstractCFType<ValueRefType>>
    CFDictionary<KeyRefType, ValueRefType, KeyType, ValueType> {

    static fn new(pairs: &[(KeyType,ValueType)]) -> CFDictionary<KeyRefType, ValueRefType, KeyType, ValueType> {
        let (keys, values) = (DVec(), DVec());
        for pairs.each |pair| {
            // FIXME: "let" would be much nicer here, but that doesn't work yet.
            match *pair {
                (ref key, ref value) => {
                    // TODO: should be able to say key.get_type_ref(), but resolve isn't having any of it.
                    keys.push(key.get_ref().as_type_ref());
                    values.push(value.get_ref().as_type_ref());
                }
            }
        }

        assert keys.len() == values.len();
        let keys = dvec::unwrap(move keys);
        let values = dvec::unwrap(move values);

        let dictionary_ref : CFDictionaryRef;
        unsafe {
            dictionary_ref = CFDictionaryCreate(kCFAllocatorDefault,
                                                reinterpret_cast(&to_ptr(keys)),
                                                reinterpret_cast(&to_ptr(values)),
                                                keys.len() as CFIndex,
                                                to_unsafe_ptr(&kCFTypeDictionaryKeyCallBacks),
                                                to_unsafe_ptr(&kCFTypeDictionaryValueCallBacks));
        }

        return base::wrap(dictionary_ref);
    }
}

trait DictionaryMethods {
    // TODO
}

pub impl<KeyRefType   : AbstractCFTypeRef Copy,
         ValueRefType : AbstractCFTypeRef Copy,
         KeyType      : AbstractCFType<KeyRefType>,
         ValueType    : AbstractCFType<ValueRefType>>
    CFDictionary<KeyRefType, ValueRefType, KeyType, ValueType> {
    pure fn len() -> uint unsafe {
        return CFDictionaryGetCount(self.obj) as uint;
    }

    pure fn is_empty() -> bool { self.len() == 0 }

    pure fn contains_key(key: &KeyType) -> bool unsafe {
        return CFDictionaryContainsKey(self.obj, cast::transmute(key.get_ref())) as bool;
    }

    pure fn find(key: &KeyType) -> Option<ValueType> unsafe {
        let value : *c_void = ptr::null();
        let did_find_value = CFDictionaryGetValueIfPresent(self.obj,
                                                           cast::transmute(key.get_ref()),
                                                           cast::transmute(&value)) as bool;

        // FIXME: this will not handle non-CF dictionary entries
        // or ptr::null() values correctly.
        return if did_find_value {
            Some(base::wrap(cast::transmute::<*c_void, ValueRefType>(value)))
        } else {
            None
        }
    }

    pure fn get(key: &KeyType) -> ValueType {
        let value = self.find(key);
        if value.is_none() {
            fail fmt!("No entry found for key: %?", key);
        }
        option::unwrap(move value)
    }

             fn each(blk: fn&(&KeyType, &ValueType) -> bool) unsafe {
                 let len = self.len();
                 let keys: ~[KeyRefType] = vec::from_elem(len, cast::transmute::<*c_void, KeyRefType>(ptr::null()));
                 let values: ~[ValueRefType] = vec::from_elem(len, cast::transmute::<*c_void, ValueRefType>(ptr::null()));

                 do uint::range(0,len) |i| {
                     let key = base::wrap(keys[i]);
                     let value = base::wrap(values[i]);
                     blk(&key, &value)
                 }
             }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFDictionary.h
     */

    const kCFTypeDictionaryKeyCallBacks: CFDictionaryKeyCallBacks;
    const kCFTypeDictionaryValueCallBacks: CFDictionaryValueCallBacks;

    fn CFDictionaryApplyFunction(theDict: CFDictionaryRef, applier: CFDictionaryApplierFunction,
                                 context: *c_void);
    fn CFDictionaryContainsKey(theDict: CFDictionaryRef, key: *c_void) -> Boolean;
    fn CFDictionaryContainsValue(theDict: CFDictionaryRef, value: *c_void) -> Boolean;
    fn CFDictionaryCreate(allocator: CFAllocatorRef, keys: **c_void, values: **c_void,
                          numValues: CFIndex, keyCallBacks: *CFDictionaryKeyCallBacks,
                          valueCallBacks: *CFDictionaryValueCallBacks)
                       -> CFDictionaryRef;
    fn CFDictionaryCreateCopy(allocator: CFAllocatorRef, theDict: CFDictionaryRef) -> CFDictionaryRef;
    fn CFDictionaryGetCount(theDict: CFDictionaryRef) -> CFIndex;
    fn CFDictionaryGetCountOfKey(theDict: CFDictionaryRef, key: *c_void) -> CFIndex;
    fn CFDictionaryGetCountOfValue(theDict: CFDictionaryRef, value: *c_void) -> CFIndex;
    fn CFDictionaryGetKeysAndValues(theDict: CFDictionaryRef, keys: **c_void, values: **c_void);
    fn CFDictionaryGetTypeID() -> CFTypeID;
    fn CFDictionaryGetValue(theDict: CFDictionaryRef, key: *c_void) -> *c_void;
    fn CFDictionaryGetValueIfPresent(theDict: CFDictionaryRef, key: *c_void, value: **c_void) -> Boolean;
}

<|endoftext|>


<commit_before>#![deny(deprecated, clippy::all, clippy::pedantic)]

use thiserror::Error;

#[derive(Error, Debug)]
pub enum Error {
    #[deprecated]
    #[error("...")]
    Deprecated,
}
<commit_msg>Delete broken #[deprecated] test<commit_after><|endoftext|>


<commit_before>#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
use std::iter::FromIterator;
use syn::parse::{Parse, ParseStream};
use syn::{DeriveInput, Result, Visibility};

#[derive(Debug)]
struct VisRest {
    vis: Visibility,
    rest: TokenStream,
}

impl Parse for VisRest {
    fn parse(input: ParseStream) -> Result<Self> {
        Ok(VisRest {
            vis: input.parse()?,
            rest: input.parse()?,
        })
    }
}

macro_rules! assert_vis_parse {
    ($input:expr, Ok($p:pat)) => {
        assert_vis_parse!($input, Ok($p) + "");
    };

    ($input:expr, Ok($p:pat) + $rest:expr) => {
        let expected = $rest.parse::<TokenStream>().unwrap();
        let parse: VisRest = syn::parse_str($input).unwrap();

        match parse.vis {
            $p => {}
            _ => panic!("Expected {}, got {:?}", stringify!($p), parse.vis),
        }

        // NOTE: Round-trips through `to_string` to avoid potential whitespace
        // diffs.
        assert_eq!(parse.rest.to_string(), expected.to_string());
    };

    ($input:expr, Err) => {
        syn::parse2::<VisRest>($input.parse().unwrap()).unwrap_err();
    };
}

#[test]
fn test_pub() {
    assert_vis_parse!("pub", Ok(Visibility::Public(_)));
}

#[test]
fn test_crate() {
    assert_vis_parse!("crate", Ok(Visibility::Crate(_)));
}

#[test]
fn test_inherited() {
    assert_vis_parse!("", Ok(Visibility::Inherited));
}

#[test]
fn test_in() {
    assert_vis_parse!("pub(in foo::bar)", Ok(Visibility::Restricted(_)));
}

#[test]
fn test_pub_crate() {
    assert_vis_parse!("pub(crate)", Ok(Visibility::Restricted(_)));
}

#[test]
fn test_pub_self() {
    assert_vis_parse!("pub(self)", Ok(Visibility::Restricted(_)));
}

#[test]
fn test_pub_super() {
    assert_vis_parse!("pub(super)", Ok(Visibility::Restricted(_)));
}

#[test]
fn test_missing_in() {
    assert_vis_parse!("pub(foo::bar)", Ok(Visibility::Public(_)) + "(foo::bar)");
}

#[test]
fn test_missing_in_path() {
    assert_vis_parse!("pub(in)", Err);
}

#[test]
fn test_crate_path() {
    assert_vis_parse!("pub(crate::A, crate::B)", Ok(Visibility::Public(_)) + "(crate::A, crate::B)");
}

#[test]
fn test_junk_after_in() {
    assert_vis_parse!("pub(in some::path @@garbage)", Err);
}

#[test]
fn test_empty_group_vis() {
    // mimics `struct S { $vis $field: () }` where $vis is empty
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Ident(Ident::new("struct", Span::call_site())),
        TokenTree::Ident(Ident::new("S", Span::call_site())),
        TokenTree::Group(Group::new(
            Delimiter::Brace,
            TokenStream::from_iter(vec![
                TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())),
                TokenTree::Group(Group::new(
                    Delimiter::None,
                    TokenStream::from_iter(vec![TokenTree::Ident(Ident::new(
                        "f",
                        Span::call_site(),
                    ))]),
                )),
                TokenTree::Punct(Punct::new(':', Spacing::Alone)),
                TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
            ]),
        )),
    ]);

    snapshot!(tokens as DeriveInput, @r###"
    DeriveInput {
        vis: Inherited,
        ident: "S",
        generics: Generics,
        data: Data::Struct {
            fields: Fields::Named {
                named: [
                    Field {
                        vis: Inherited,
                        ident: Some("f"),
                        colon_token: Some,
                        ty: Type::Tuple,
                    },
                ],
            },
        },
    }
    "###);
}
<commit_msg>Format with rustfmt 1.4.30-nightly<commit_after>#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
use std::iter::FromIterator;
use syn::parse::{Parse, ParseStream};
use syn::{DeriveInput, Result, Visibility};

#[derive(Debug)]
struct VisRest {
    vis: Visibility,
    rest: TokenStream,
}

impl Parse for VisRest {
    fn parse(input: ParseStream) -> Result<Self> {
        Ok(VisRest {
            vis: input.parse()?,
            rest: input.parse()?,
        })
    }
}

macro_rules! assert_vis_parse {
    ($input:expr, Ok($p:pat)) => {
        assert_vis_parse!($input, Ok($p) + "");
    };

    ($input:expr, Ok($p:pat) + $rest:expr) => {
        let expected = $rest.parse::<TokenStream>().unwrap();
        let parse: VisRest = syn::parse_str($input).unwrap();

        match parse.vis {
            $p => {}
            _ => panic!("Expected {}, got {:?}", stringify!($p), parse.vis),
        }

        // NOTE: Round-trips through `to_string` to avoid potential whitespace
        // diffs.
        assert_eq!(parse.rest.to_string(), expected.to_string());
    };

    ($input:expr, Err) => {
        syn::parse2::<VisRest>($input.parse().unwrap()).unwrap_err();
    };
}

#[test]
fn test_pub() {
    assert_vis_parse!("pub", Ok(Visibility::Public(_)));
}

#[test]
fn test_crate() {
    assert_vis_parse!("crate", Ok(Visibility::Crate(_)));
}

#[test]
fn test_inherited() {
    assert_vis_parse!("", Ok(Visibility::Inherited));
}

#[test]
fn test_in() {
    assert_vis_parse!("pub(in foo::bar)", Ok(Visibility::Restricted(_)));
}

#[test]
fn test_pub_crate() {
    assert_vis_parse!("pub(crate)", Ok(Visibility::Restricted(_)));
}

#[test]
fn test_pub_self() {
    assert_vis_parse!("pub(self)", Ok(Visibility::Restricted(_)));
}

#[test]
fn test_pub_super() {
    assert_vis_parse!("pub(super)", Ok(Visibility::Restricted(_)));
}

#[test]
fn test_missing_in() {
    assert_vis_parse!("pub(foo::bar)", Ok(Visibility::Public(_)) + "(foo::bar)");
}

#[test]
fn test_missing_in_path() {
    assert_vis_parse!("pub(in)", Err);
}

#[test]
fn test_crate_path() {
    assert_vis_parse!(
        "pub(crate::A, crate::B)",
        Ok(Visibility::Public(_)) + "(crate::A, crate::B)"
    );
}

#[test]
fn test_junk_after_in() {
    assert_vis_parse!("pub(in some::path @@garbage)", Err);
}

#[test]
fn test_empty_group_vis() {
    // mimics `struct S { $vis $field: () }` where $vis is empty
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Ident(Ident::new("struct", Span::call_site())),
        TokenTree::Ident(Ident::new("S", Span::call_site())),
        TokenTree::Group(Group::new(
            Delimiter::Brace,
            TokenStream::from_iter(vec![
                TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())),
                TokenTree::Group(Group::new(
                    Delimiter::None,
                    TokenStream::from_iter(vec![TokenTree::Ident(Ident::new(
                        "f",
                        Span::call_site(),
                    ))]),
                )),
                TokenTree::Punct(Punct::new(':', Spacing::Alone)),
                TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
            ]),
        )),
    ]);

    snapshot!(tokens as DeriveInput, @r###"
    DeriveInput {
        vis: Inherited,
        ident: "S",
        generics: Generics,
        data: Data::Struct {
            fields: Fields::Named {
                named: [
                    Field {
                        vis: Inherited,
                        ident: Some("f"),
                        colon_token: Some,
                        ty: Type::Tuple,
                    },
                ],
            },
        },
    }
    "###);
}
<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0<Paste>

use serde_json::{Map, Value};

use super::super::VmmAction;
use logger::{Metric, METRICS};
use request::{checked_id, Body, Error, ParsedRequest, StatusCode};
use vmm::vmm_config::drive::BlockDeviceConfig;

#[derive(Clone)]
pub struct PatchDrivePayload {
    // Leaving `fields` pub because ownership on it needs to be yielded to the
    // Request enum object. A getter couldn't move `fields` out of the borrowed
    // PatchDrivePayload object.
    pub fields: Value,
}

impl PatchDrivePayload {
    /// Checks that `field_key` exists and that the value has the type Value::String.
    fn check_field_is_string(map: &Map<String, Value>, field_key: &str) -> Result<(), String> {
        match map.get(field_key) {
            None => {
                return Err(format!(
                    "Required key {} not present in the json.",
                    field_key
                ));
            }
            Some(id) => {
                // Check that field is a string.
                if id.as_str().is_none() {
                    return Err(format!("Invalid type for key {}.", field_key));
                }
            }
        }
        Ok(())
    }

    /// Validates that only path_on_host and drive_id are present in the payload.
    fn validate(&self) -> Result<(), Error> {
        match self.fields.as_object() {
            Some(fields_map) => {
                // Check that field `drive_id` exists and its type is String.
                PatchDrivePayload::check_field_is_string(fields_map, "drive_id")
                    .map_err(|e| Error::Generic(StatusCode::BadRequest, e))?;
                // Check that field `drive_id` exists and its type is String.
                PatchDrivePayload::check_field_is_string(fields_map, "path_on_host")
                    .map_err(|e| Error::Generic(StatusCode::BadRequest, e))?;

                // Check that there are no other fields in the object.
                if fields_map.len() > 2 {
                    return Err(Error::Generic(
                        StatusCode::BadRequest,
                        "Invalid PATCH payload. Only updates on path_on_host are allowed."
                            .to_string(),
                    ));
                }
                Ok(())
            }
            _ => Err(Error::Generic(
                StatusCode::BadRequest,
                "Invalid json.".to_string(),
            )),
        }
    }

    /// Returns the field specified by `field_key` as a string. This is unsafe if validate
    /// is not called prior to calling this method.
    fn get_string_field_unchecked(&self, field_key: &str) -> String {
        self.fields
            .get(field_key)
            .unwrap()
            .as_str()
            .unwrap()
            .to_string()
    }
}

pub fn parse_put_drive(body: &Body, id_from_path: Option<&&str>) -> Result<ParsedRequest, Error> {
    METRICS.put_api_requests.drive_count.inc();
    let id = match id_from_path {
        Some(&id) => checked_id(id)?,
        None => {
            return Err(Error::EmptyID);
        }
    };

    let device_cfg = serde_json::from_slice::<BlockDeviceConfig>(body.raw()).map_err(|e| {
        METRICS.put_api_requests.drive_fails.inc();
        Error::SerdeJson(e)
    })?;

    if id != device_cfg.drive_id {
        METRICS.put_api_requests.drive_fails.inc();
        Err(Error::Generic(
            StatusCode::BadRequest,
            "The id from the path does not match the id from the body!".to_string(),
        ))
    } else {
        Ok(ParsedRequest::Sync(VmmAction::InsertBlockDevice(
            device_cfg,
        )))
    }
}

pub fn parse_patch_drive(body: &Body, id_from_path: Option<&&str>) -> Result<ParsedRequest, Error> {
    METRICS.patch_api_requests.drive_count.inc();
    let id = match id_from_path {
        Some(&id) => checked_id(id)?,
        None => {
            return Err(Error::EmptyID);
        }
    };

    METRICS.patch_api_requests.drive_count.inc();
    let patch_drive_payload = PatchDrivePayload {
        fields: serde_json::from_slice(body.raw()).map_err(|e| {
            METRICS.patch_api_requests.drive_fails.inc();
            Error::SerdeJson(e)
        })?,
    };

    patch_drive_payload.validate()?;
    let drive_id: String = patch_drive_payload.get_string_field_unchecked("drive_id");
    let path_on_host: String = patch_drive_payload.get_string_field_unchecked("path_on_host");

    if id != drive_id.as_str() {
        METRICS.patch_api_requests.drive_fails.inc();
        return Err(Error::Generic(
            StatusCode::BadRequest,
            String::from("The id from the path does not match the id from the body!"),
        ));
    }

    Ok(ParsedRequest::Sync(VmmAction::UpdateBlockDevicePath(
        drive_id,
        path_on_host,
    )))
}

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

    #[test]
    fn test_parse_patch_request() {
        assert!(parse_patch_drive(&Body::new("invalid_payload"), Some(&"id")).is_err());

        // PATCH with invalid fields.
        let body = r#"{
                "drive_id": "bar",
                "is_read_only": false
              }"#;
        assert!(parse_patch_drive(&Body::new(body), Some(&"2")).is_err());

        // PATCH with invalid types on fields. Adding a drive_id as number instead of string.
        let body = r#"{
                "drive_id": 1000,
                "path_on_host": "dummy"
              }"#;
        let res = parse_patch_drive(&Body::new(body), Some(&"1000"));
        assert!(res.is_err());

        // PATCH with invalid types on fields. Adding a path_on_host as bool instead of string.
        let body = r#"{
                "drive_id": 1000,
                "path_on_host": true
              }"#;
        let res = parse_patch_drive(&Body::new(body), Some(&"1000"));
        assert!(res.is_err());

        // PATCH with missing path_on_host field.
        let body = r#"{
                "drive_id": "dummy_id"
              }"#;
        let res = parse_patch_drive(&Body::new(body), Some(&"dummy_id"));
        assert!(res.is_err());

        // PATCH with missing drive_id field.
        let body = r#"{
                "path_on_host": true
              }"#;
        let res = parse_patch_drive(&Body::new(body), Some(&"1000"));
        assert!(res.is_err());

        // PATCH that tries to update something else other than path_on_host.
        let body = r#"{
                "drive_id": 1234,
                "path_on_host": "dummy",
                "is_read_only": false
              }"#;
        let res = parse_patch_drive(&Body::new(body), Some(&"1234"));
        assert!(res.is_err());

        // PATCH with payload that is not a json.
        let body = r#"{
                "fields": "dummy_field"
              }"#;
        assert!(parse_patch_drive(&Body::new(body), Some(&"1234")).is_err());

        let body = r#"{
                "drive_id": "foo",
                "path_on_host": "dummy"
              }"#;
        match parse_patch_drive(&Body::new(body), Some(&"foo")) {
            Ok(ParsedRequest::Sync(VmmAction::UpdateBlockDevicePath(a, b))) => {
                assert_eq!(a, "foo".to_string());
                assert_eq!(b, "dummy".to_string());
            }
            Err(_e) => panic!("Test failed."),
            _ => panic!("Test failed: Invalid parameters"),
        };

        let body = r#"{
                "drive_id": "foo",
                "path_on_host": "dummy"
              }"#;
        assert!(parse_patch_drive(&Body::new(body), Some(&"bar")).is_err());
    }

    #[test]
    fn test_parse_put_request() {
        assert!(parse_put_drive(&Body::new("invalid_payload"), Some(&"id")).is_err());

        // PATCH with invalid fields.
        let body = r#"{
                "drive_id": "bar",
                "is_read_only": false
              }"#;
        assert!(parse_put_drive(&Body::new(body), Some(&"2")).is_err());

        // PATCH with invalid types on fields. Adding a drive_id as number instead of string.
        let body = r#"{
                "drive_id": "1000",
                "path_on_host": "dummy",
                "is_root_device": true,
                "partuuid": "string",
                "is_read_only": true,
                "rate_limiter": {
                    "bandwidth": {
                        "size": 0,
                        "one_time_burst": 0,
                        "refill_time": 0
                    },
                    "ops": {
                    "size": 0,
                    "one_time_burst": 0,
                    "refill_time": 0
                    }
                }
            }"#;
        assert!(parse_put_drive(&Body::new(body), Some(&"1000")).is_ok());

        assert!(parse_put_drive(&Body::new(body), Some(&"foo")).is_err());
    }

    #[test]
    fn test_validate() {
        let pdp = PatchDrivePayload {
            fields: Value::Null,
        };
        assert!(pdp.validate().is_err());
    }
}
<commit_msg>api_server: incorrect metrics collecting for drive<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0<Paste>

use serde_json::{Map, Value};

use super::super::VmmAction;
use logger::{Metric, METRICS};
use request::{checked_id, Body, Error, ParsedRequest, StatusCode};
use vmm::vmm_config::drive::BlockDeviceConfig;

struct PatchDrivePayload {
    // Leaving `fields` pub because ownership on it needs to be yielded to the
    // Request enum object. A getter couldn't move `fields` out of the borrowed
    // PatchDrivePayload object.
    pub fields: Value,
}

impl PatchDrivePayload {
    /// Checks that `field_key` exists and that the value has the type Value::String.
    fn check_field_is_string(map: &Map<String, Value>, field_key: &str) -> Result<(), String> {
        match map.get(field_key) {
            None => {
                return Err(format!(
                    "Required key {} not present in the json.",
                    field_key
                ));
            }
            Some(id) => {
                // Check that field is a string.
                if id.as_str().is_none() {
                    return Err(format!("Invalid type for key {}.", field_key));
                }
            }
        }
        Ok(())
    }

    /// Validates that only path_on_host and drive_id are present in the payload.
    fn validate(&self) -> Result<(), Error> {
        match self.fields.as_object() {
            Some(fields_map) => {
                // Check that field `drive_id` exists and its type is String.
                PatchDrivePayload::check_field_is_string(fields_map, "drive_id")
                    .map_err(|e| Error::Generic(StatusCode::BadRequest, e))?;
                // Check that field `path_on_host` exists and its type is String.
                PatchDrivePayload::check_field_is_string(fields_map, "path_on_host")
                    .map_err(|e| Error::Generic(StatusCode::BadRequest, e))?;

                // Check that there are no other fields in the object.
                if fields_map.len() > 2 {
                    return Err(Error::Generic(
                        StatusCode::BadRequest,
                        "Invalid PATCH payload. Only updates on path_on_host are allowed."
                            .to_string(),
                    ));
                }
                Ok(())
            }
            _ => Err(Error::Generic(
                StatusCode::BadRequest,
                "Invalid json.".to_string(),
            )),
        }
    }

    /// Returns the field specified by `field_key` as a string. This is unsafe if validate
    /// is not called prior to calling this method.
    fn get_string_field_unchecked(&self, field_key: &str) -> String {
        self.fields
            .get(field_key)
            .unwrap()
            .as_str()
            .unwrap()
            .to_string()
    }
}

pub fn parse_put_drive(body: &Body, id_from_path: Option<&&str>) -> Result<ParsedRequest, Error> {
    METRICS.put_api_requests.drive_count.inc();
    let id = if let Some(id) = id_from_path {
        checked_id(id)?
    } else {
        METRICS.put_api_requests.drive_fails.inc();
        return Err(Error::EmptyID);
    };

    let device_cfg = serde_json::from_slice::<BlockDeviceConfig>(body.raw()).map_err(|e| {
        METRICS.put_api_requests.drive_fails.inc();
        Error::SerdeJson(e)
    })?;

    if id != device_cfg.drive_id {
        METRICS.put_api_requests.drive_fails.inc();
        Err(Error::Generic(
            StatusCode::BadRequest,
            "The id from the path does not match the id from the body!".to_string(),
        ))
    } else {
        Ok(ParsedRequest::Sync(VmmAction::InsertBlockDevice(
            device_cfg,
        )))
    }
}

pub fn parse_patch_drive(body: &Body, id_from_path: Option<&&str>) -> Result<ParsedRequest, Error> {
    METRICS.patch_api_requests.drive_count.inc();
    let id = if let Some(id) = id_from_path {
        checked_id(id)?
    } else {
        METRICS.patch_api_requests.drive_fails.inc();
        return Err(Error::EmptyID);
    };

    let patch_drive_payload = PatchDrivePayload {
        fields: serde_json::from_slice(body.raw()).map_err(|e| {
            METRICS.patch_api_requests.drive_fails.inc();
            Error::SerdeJson(e)
        })?,
    };

    patch_drive_payload.validate()?;
    let drive_id: String = patch_drive_payload.get_string_field_unchecked("drive_id");
    let path_on_host: String = patch_drive_payload.get_string_field_unchecked("path_on_host");

    if id != drive_id.as_str() {
        METRICS.patch_api_requests.drive_fails.inc();
        return Err(Error::Generic(
            StatusCode::BadRequest,
            String::from("The id from the path does not match the id from the body!"),
        ));
    }

    Ok(ParsedRequest::Sync(VmmAction::UpdateBlockDevicePath(
        drive_id,
        path_on_host,
    )))
}

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

    #[test]
    fn test_parse_patch_request() {
        assert!(parse_patch_drive(&Body::new("invalid_payload"), None).is_err());
        assert!(parse_patch_drive(&Body::new("invalid_payload"), Some(&"id")).is_err());

        // PATCH with invalid fields.
        let body = r#"{
                "drive_id": "bar",
                "is_read_only": false
              }"#;
        assert!(parse_patch_drive(&Body::new(body), Some(&"2")).is_err());

        // PATCH with invalid types on fields. Adding a drive_id as number instead of string.
        let body = r#"{
                "drive_id": 1000,
                "path_on_host": "dummy"
              }"#;
        let res = parse_patch_drive(&Body::new(body), Some(&"1000"));
        assert!(res.is_err());

        // PATCH with invalid types on fields. Adding a path_on_host as bool instead of string.
        let body = r#"{
                "drive_id": 1000,
                "path_on_host": true
              }"#;
        let res = parse_patch_drive(&Body::new(body), Some(&"1000"));
        assert!(res.is_err());

        // PATCH with missing path_on_host field.
        let body = r#"{
                "drive_id": "dummy_id"
              }"#;
        let res = parse_patch_drive(&Body::new(body), Some(&"dummy_id"));
        assert!(res.is_err());

        // PATCH with missing drive_id field.
        let body = r#"{
                "path_on_host": true
              }"#;
        let res = parse_patch_drive(&Body::new(body), Some(&"1000"));
        assert!(res.is_err());

        // PATCH that tries to update something else other than path_on_host.
        let body = r#"{
                "drive_id": "dummy_id",
                "path_on_host": "dummy_host",
                "is_read_only": false
              }"#;
        let res = parse_patch_drive(&Body::new(body), Some(&"1234"));
        assert!(res.is_err());

        // PATCH with payload that is not a json.
        let body = r#"{
                "fields": "dummy_field"
              }"#;
        assert!(parse_patch_drive(&Body::new(body), Some(&"1234")).is_err());

        let body = r#"{
                "drive_id": "foo",
                "path_on_host": "dummy"
              }"#;
        match parse_patch_drive(&Body::new(body), Some(&"foo")) {
            Ok(ParsedRequest::Sync(VmmAction::UpdateBlockDevicePath(a, b))) => {
                assert_eq!(a, "foo".to_string());
                assert_eq!(b, "dummy".to_string());
            }
            Err(_e) => panic!("Test failed."),
            _ => panic!("Test failed: Invalid parameters"),
        };

        let body = r#"{
                "drive_id": "foo",
                "path_on_host": "dummy"
              }"#;
        assert!(parse_patch_drive(&Body::new(body), Some(&"bar")).is_err());
    }

    #[test]
    fn test_parse_put_request() {
        assert!(parse_put_drive(&Body::new("invalid_payload"), None).is_err());
        assert!(parse_put_drive(&Body::new("invalid_payload"), Some(&"id")).is_err());

        // PATCH with invalid fields.
        let body = r#"{
                "drive_id": "bar",
                "is_read_only": false
              }"#;
        assert!(parse_put_drive(&Body::new(body), Some(&"2")).is_err());

        // PATCH with invalid types on fields. Adding a drive_id as number instead of string.
        let body = r#"{
                "drive_id": "1000",
                "path_on_host": "dummy",
                "is_root_device": true,
                "partuuid": "string",
                "is_read_only": true,
                "rate_limiter": {
                    "bandwidth": {
                        "size": 0,
                        "one_time_burst": 0,
                        "refill_time": 0
                    },
                    "ops": {
                    "size": 0,
                    "one_time_burst": 0,
                    "refill_time": 0
                    }
                }
            }"#;
        assert!(parse_put_drive(&Body::new(body), Some(&"1000")).is_ok());

        assert!(parse_put_drive(&Body::new(body), Some(&"foo")).is_err());
    }

    #[test]
    fn test_validate() {
        let pdp = PatchDrivePayload {
            fields: Value::Null,
        };
        assert!(pdp.validate().is_err());
    }
}
<|endoftext|>


<commit_before>use caption_strategy::MethodCaptionStrategy;
use cpp_data::{CppData, CppVisibility};
use cpp_ffi_data::{CppAndFfiMethod, c_base_name};
use cpp_method::{CppMethod, CppMethodKind};
use errors::{Result, ChainErr, unexpected};
use log;
use utils::add_to_multihash;
use config::CppFfiGeneratorFilterFn;

use std::collections::{HashSet, HashMap};

struct CGenerator<'a> {
  cpp_data: &'a CppData,
  c_lib_name: String,
  filters: Vec<&'a Box<CppFfiGeneratorFilterFn>>,
}

#[derive(Debug, Clone)]
pub struct CppFfiHeaderData {
  pub include_file: String,
  pub include_file_base_name: String,
  pub methods: Vec<CppAndFfiMethod>,
}

pub struct CppAndFfiData {
  pub cpp_data: CppData,
  pub cpp_ffi_headers: Vec<CppFfiHeaderData>,
}

/// Runs FFI generator
pub fn run(cpp_data: &CppData,
           c_lib_name: String,
           filters: Vec<&Box<CppFfiGeneratorFilterFn>>)
           -> Result<Vec<CppFfiHeaderData>> {
  let generator = CGenerator {
    cpp_data: cpp_data,
    c_lib_name: c_lib_name,
    filters: filters,
  };

  let mut c_headers = Vec::new();
  let mut include_name_list: Vec<_> =
    try!(generator.cpp_data.all_include_files()).into_iter().collect();
  include_name_list.sort();

  for include_file in &include_name_list {
    let mut include_file_base_name = include_file.clone();

    if let Some(index) = include_file_base_name.find('.') {
      include_file_base_name = include_file_base_name[0..index].to_string();
    }
    let methods = try!(generator.process_methods(include_file,
                                                 &include_file_base_name,
                                                 generator.cpp_data
                                                   .methods
                                                   .iter()
                                                   .filter(|x| &x.include_file == include_file)));
    if methods.is_empty() {
      log::info(format!("Skipping empty include file {}", include_file));
    } else {
      c_headers.push(CppFfiHeaderData {
        include_file: include_file.clone(),
        include_file_base_name: include_file_base_name,
        methods: methods,
      });
    }
  }
  if c_headers.is_empty() {
    return Err("No FFI headers generated".into());
  }
  Ok(c_headers)
}

impl<'a> CGenerator<'a> {
  /// Returns false if the method is excluded from processing
  /// for some reason
  fn should_process_method(&self, method: &CppMethod) -> Result<bool> {
    let class_name = method.class_name().unwrap_or(&String::new()).clone();
    for filter in &self.filters {
      let allowed = try!(filter(method).chain_err(|| "cpp_ffi_generator_filter failed"));
      if !allowed {
        log::info(format!("Skipping blacklisted method: \n{}\n", method.short_text()));
        return Ok(false);
      }
    }
    if class_name == "QFlags" {
      return Ok(false);
    }
    if let Some(ref membership) = method.class_membership {
      if membership.kind == CppMethodKind::Constructor &&
         self.cpp_data.has_pure_virtual_methods(&class_name) {
        log::noisy(format!("Method is skipped:\n{}\nConstructors are not allowed for abstract \
                            classes.\n",
                           method.short_text()));
        return Ok(false);
      }
      if membership.visibility == CppVisibility::Private {
        return Ok(false);
      }
      if membership.visibility == CppVisibility::Protected {
        log::noisy(format!("Skipping protected method: \n{}\n", method.short_text()));
        return Ok(false);
      }
      if membership.is_signal {
        log::warning(format!("Skipping signal: \n{}\n", method.short_text()));
        return Ok(false);
      }
    }
    if method.template_arguments.is_some() {
      log::noisy(format!("Skipping template method: \n{}\n", method.short_text()));
      return Ok(false);
    }
    if method.template_arguments_values.is_some() {
      // TODO: re-enable after template test compilation (#24) is implemented
      log::noisy(format!("Skipping template method: \n{}\n", method.short_text()));
      return Ok(false);
    }
    if method.all_involved_types()
      .iter()
      .any(|x| x.base.is_or_contains_template_parameter()) {
      log::noisy(format!("Skipping method containing template parameters: \n{}\n",
                         method.short_text()));
      return Ok(false);
    }
    Ok(true)
  }

  /// Generates FFI wrappers for all specified methods,
  /// resolving all name conflicts using additional method captions.
  fn process_methods<'b, I: Iterator<Item = &'b CppMethod>>(&self,
                                                            include_file: &str,
                                                            include_file_base_name: &str,
                                                            methods: I)
                                                            -> Result<Vec<CppAndFfiMethod>> {
    log::info(format!("Generating C++ FFI methods for header: {}", include_file));
    let mut hash_name_to_methods: HashMap<String, Vec<_>> = HashMap::new();
    for method in methods {
      if !try!(self.should_process_method(method)) {
        continue;
      }
      match method.to_ffi_signatures() {
        Err(msg) => {
          log::warning(format!("Unable to produce C function for method:\n{}\nError:{}\n",
                               method.short_text(),
                               msg));
        }
        Ok(results) => {
          for result in results {
            match c_base_name(&result.cpp_method,
                              &result.allocation_place,
                              include_file_base_name) {
              Err(msg) => {
                log::warning(format!("Unable to produce C function for method:\n{}\nError:{}\n",
                                     method.short_text(),
                                     msg));
              }
              Ok(name) => {

                add_to_multihash(&mut hash_name_to_methods,
                                 format!("{}_{}", &self.c_lib_name, name),
                                 result);
              }
            }
          }
        }
      }
    }

    let mut processed_methods = Vec::new();
    for (key, mut values) in hash_name_to_methods {
      if values.len() == 1 {
        processed_methods.push(CppAndFfiMethod::new(values.remove(0), key.clone()));
        continue;
      }
      let mut found_strategy = None;
      for strategy in MethodCaptionStrategy::all() {
        let mut type_captions = HashSet::new();
        let mut ok = true;
        for value in &values {
          let caption = try!(value.c_signature.caption(strategy.clone()));
          if type_captions.contains(&caption) {
            ok = false;
            break;
          }
          type_captions.insert(caption);
        }
        if ok {
          found_strategy = Some(strategy);
          break;
        }
      }
      if let Some(strategy) = found_strategy {
        for x in values {
          let caption = try!(x.c_signature.caption(strategy.clone()));
          let final_name = if caption.is_empty() {
            key.clone()
          } else {
            format!("{}_{}", key, caption)
          };
          processed_methods.push(CppAndFfiMethod::new(x, final_name));
        }
      } else {
        log::error(format!("values dump: {:?}\n", values));
        log::error("All type caption strategies have failed! Involved functions:");
        for value in values {
          log::error(format!("  {}", value.cpp_method.short_text()));
        }
        return Err(unexpected("all type caption strategies have failed").into());
      }
    }
    processed_methods.sort_by(|a, b| a.c_name.cmp(&b.c_name));
    Ok(processed_methods)
  }
}
<commit_msg>detect possible signal argument types<commit_after>use caption_strategy::MethodCaptionStrategy;
use cpp_data::{CppData, CppVisibility};
use cpp_ffi_data::{CppAndFfiMethod, c_base_name};
use cpp_method::{CppMethod, CppMethodKind};
use errors::{Result, ChainErr, unexpected};
use log;
use utils::add_to_multihash;
use config::CppFfiGeneratorFilterFn;
use string_utils::JoinWithString;

use std::collections::{HashSet, HashMap};

struct CGenerator<'a> {
  cpp_data: &'a CppData,
  c_lib_name: String,
  filters: Vec<&'a Box<CppFfiGeneratorFilterFn>>,
}

#[derive(Debug, Clone)]
pub struct CppFfiHeaderData {
  pub include_file: String,
  pub include_file_base_name: String,
  pub methods: Vec<CppAndFfiMethod>,
}

pub struct CppAndFfiData {
  pub cpp_data: CppData,
  pub cpp_ffi_headers: Vec<CppFfiHeaderData>,
}

/// Runs FFI generator
pub fn run(cpp_data: &CppData,
           c_lib_name: String,
           filters: Vec<&Box<CppFfiGeneratorFilterFn>>)
           -> Result<Vec<CppFfiHeaderData>> {
  let generator = CGenerator {
    cpp_data: cpp_data,
    c_lib_name: c_lib_name,
    filters: filters,
  };

  let mut c_headers = Vec::new();
  let mut include_name_list: Vec<_> =
    try!(generator.cpp_data.all_include_files()).into_iter().collect();
  include_name_list.sort();

  for include_file in &include_name_list {
    let mut include_file_base_name = include_file.clone();

    if let Some(index) = include_file_base_name.find('.') {
      include_file_base_name = include_file_base_name[0..index].to_string();
    }
    let methods = try!(generator.process_methods(include_file,
                                                 &include_file_base_name,
                                                 generator.cpp_data
                                                   .methods
                                                   .iter()
                                                   .filter(|x| &x.include_file == include_file)));
    if methods.is_empty() {
      log::info(format!("Skipping empty include file {}", include_file));
    } else {
      c_headers.push(CppFfiHeaderData {
        include_file: include_file.clone(),
        include_file_base_name: include_file_base_name,
        methods: methods,
      });
    }
  }
  try!(generator.generate_slot_wrappers());
  if c_headers.is_empty() {
    return Err("No FFI headers generated".into());
  }
  Ok(c_headers)
}

impl<'a> CGenerator<'a> {
  /// Returns false if the method is excluded from processing
  /// for some reason
  fn should_process_method(&self, method: &CppMethod) -> Result<bool> {
    let class_name = method.class_name().unwrap_or(&String::new()).clone();
    for filter in &self.filters {
      let allowed = try!(filter(method).chain_err(|| "cpp_ffi_generator_filter failed"));
      if !allowed {
        log::info(format!("Skipping blacklisted method: \n{}\n", method.short_text()));
        return Ok(false);
      }
    }
    if class_name == "QFlags" {
      return Ok(false);
    }
    if let Some(ref membership) = method.class_membership {
      if membership.kind == CppMethodKind::Constructor &&
         self.cpp_data.has_pure_virtual_methods(&class_name) {
        log::noisy(format!("Method is skipped:\n{}\nConstructors are not allowed for abstract \
                            classes.\n",
                           method.short_text()));
        return Ok(false);
      }
      if membership.visibility == CppVisibility::Private {
        return Ok(false);
      }
      if membership.visibility == CppVisibility::Protected {
        log::noisy(format!("Skipping protected method: \n{}\n", method.short_text()));
        return Ok(false);
      }
      if membership.is_signal {
        log::warning(format!("Skipping signal: \n{}\n", method.short_text()));
        return Ok(false);
      }
    }
    if method.template_arguments.is_some() {
      log::noisy(format!("Skipping template method: \n{}\n", method.short_text()));
      return Ok(false);
    }
    if method.template_arguments_values.is_some() {
      // TODO: re-enable after template test compilation (#24) is implemented
      log::noisy(format!("Skipping template method: \n{}\n", method.short_text()));
      return Ok(false);
    }
    if method.all_involved_types()
      .iter()
      .any(|x| x.base.is_or_contains_template_parameter()) {
      log::noisy(format!("Skipping method containing template parameters: \n{}\n",
                         method.short_text()));
      return Ok(false);
    }
    Ok(true)
  }

  /// Generates FFI wrappers for all specified methods,
  /// resolving all name conflicts using additional method captions.
  fn process_methods<'b, I: Iterator<Item = &'b CppMethod>>(&self,
                                                            include_file: &str,
                                                            include_file_base_name: &str,
                                                            methods: I)
                                                            -> Result<Vec<CppAndFfiMethod>> {
    log::info(format!("Generating C++ FFI methods for header: {}", include_file));
    let mut hash_name_to_methods: HashMap<String, Vec<_>> = HashMap::new();
    for method in methods {
      if !try!(self.should_process_method(method)) {
        continue;
      }
      match method.to_ffi_signatures() {
        Err(msg) => {
          log::warning(format!("Unable to produce C function for method:\n{}\nError:{}\n",
                               method.short_text(),
                               msg));
        }
        Ok(results) => {
          for result in results {
            match c_base_name(&result.cpp_method,
                              &result.allocation_place,
                              include_file_base_name) {
              Err(msg) => {
                log::warning(format!("Unable to produce C function for method:\n{}\nError:{}\n",
                                     method.short_text(),
                                     msg));
              }
              Ok(name) => {

                add_to_multihash(&mut hash_name_to_methods,
                                 format!("{}_{}", &self.c_lib_name, name),
                                 result);
              }
            }
          }
        }
      }
    }

    let mut processed_methods = Vec::new();
    for (key, mut values) in hash_name_to_methods {
      if values.len() == 1 {
        processed_methods.push(CppAndFfiMethod::new(values.remove(0), key.clone()));
        continue;
      }
      let mut found_strategy = None;
      for strategy in MethodCaptionStrategy::all() {
        let mut type_captions = HashSet::new();
        let mut ok = true;
        for value in &values {
          let caption = try!(value.c_signature.caption(strategy.clone()));
          if type_captions.contains(&caption) {
            ok = false;
            break;
          }
          type_captions.insert(caption);
        }
        if ok {
          found_strategy = Some(strategy);
          break;
        }
      }
      if let Some(strategy) = found_strategy {
        for x in values {
          let caption = try!(x.c_signature.caption(strategy.clone()));
          let final_name = if caption.is_empty() {
            key.clone()
          } else {
            format!("{}_{}", key, caption)
          };
          processed_methods.push(CppAndFfiMethod::new(x, final_name));
        }
      } else {
        log::error(format!("values dump: {:?}\n", values));
        log::error("All type caption strategies have failed! Involved functions:");
        for value in values {
          log::error(format!("  {}", value.cpp_method.short_text()));
        }
        return Err(unexpected("all type caption strategies have failed").into());
      }
    }
    processed_methods.sort_by(|a, b| a.c_name.cmp(&b.c_name));
    Ok(processed_methods)
  }

  fn generate_slot_wrappers(&'a self) -> Result<()> {
    let mut all_types = HashSet::new();
    for method in &self.cpp_data.methods {
      if let Some(ref info) = method.class_membership {
        if info.is_signal {
          let types: Vec<_> = method.arguments.iter().map(|x| x.argument_type.clone()).collect();
          if !all_types.contains(&types) {
            all_types.insert(types);
          }
        }
      }
    }
    let mut types_with_omitted_args = HashSet::new();
    for t in &all_types {
      let mut types = t.clone();
      while let Some(_) = types.pop() {
        if !types_with_omitted_args.contains(&types) {
          types_with_omitted_args.insert(types.clone());
        }
      }
    }
    all_types.extend(types_with_omitted_args.into_iter());

//    if all_types.is_empty() {
//      return Ok(());
//    }
    println!("generate_slot_wrappers:");
    for t in all_types {
      println!("  ({})", t.iter().map(|x| x.to_cpp_pseudo_code()).join(", "));
    }
    unimplemented!();
    Ok(())
  }

}
<|endoftext|>


<commit_before>use rusqlite::Connection;

#[derive(Debug)]
pub struct JobDepend {
    pub id: i32,
    pub fk_job: i32,
    pub fk_variable: i32,
    pub sq_order: i32,
}

pub fn table_create_job_depend(conn: &Connection) -> &Connection {
    conn.execute(
        "CREATE TABLE JOBDEPEND (
                  id                INTEGER PRIMARY KEY ASC,
                  fk_job            INTEGER NOT NULL,
                  fk_variable       INTEGER NOT NULL,
                  sq_order          INTEGER NOT NULL,
                  UNIQUE (fk_job, fk_variable) ON CONFLICT REPLACE
                  FOREIGN KEY(fk_job) REFERENCES JOB(id) ON UPDATE CASCADE
                  FOREIGN KEY(fk_variable) REFERENCES VARIABLE_NAME(id) ON UPDATE CASCADE
                  )",
        &[],
    ).unwrap();
    return conn;
}

pub fn insert_job_depend(
    conn: &Connection,
    job: &i32,
    provider: &i32,
    sq_order: &i32,
) -> Result<i32, &'static str> {
    let me = JobDepend {
        id: 0,
        fk_job: *job,
        fk_variable: *provider,
        sq_order: *sq_order,
    };
    let job_depend_instance = conn.execute(
        "INSERT INTO JOBDEPEND (fk_job, fk_variable, sq_order)
                  VALUES (?1, ?2, ?3)",
        &[&me.fk_job, &me.fk_variable, &me.sq_order],
    );
    if job_depend_instance.is_err() {
        return Err("Failed trying to INSERT INTO JOBDEPEND");
    }
    job_depend_instance.unwrap();
    return Ok(0);
}

pub fn list_job_depend(conn: &Connection) -> Vec<JobDepend> {
    let mut stmt = conn.prepare("SELECT id, fk_job, fk_variable, sq_order  FROM JOBDEPEND")
        .unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        JobDepend {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable: row.get(2),
            sq_order: row.get(3),
        }
    });
    let mut items = Vec::<JobDepend>::new();
    if wraped_fs_file_iter.is_err() {
        return items;

    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {

        items.push(person.unwrap());
    }
    return items;
}

pub fn job_depend_list(conn: &Connection) {
    let mut stmt = conn.prepare("SELECT id, fk_job, fk_variable, sq_order FROM JOBDEPEND")
        .unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        JobDepend {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable: row.get(2),
            sq_order: row.get(3),
        }
    }).unwrap();

    for person in person_iter {
        info!("Found job_depend {:?}", person.unwrap());
    }
}

pub fn pk_job_depend_by_all(
    conn: &Connection,
    fk_job: &i32,
    provider: &i32,
    sq_order: &i32,
) -> Result<i32, &'static str> {
    let mut output = 0;
    let mut stmt = conn.prepare("SELECT JOBDEPEND.id, JOBDEPEND.fk_job, JOBDEPEND.fk_variable, JOBDEPEND.sq_order  FROM JOBDEPEND WHERE JOBDEPEND.fk_job = ?1 AND JOBDEPEND.fk_variable=?2 AND JOBDEPEND.sq_order=?3 ").unwrap();
    let job_depend_iter = stmt.query_map(&[fk_job, provider, sq_order], |row| {
        JobDepend {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable: row.get(2),
            sq_order: row.get(3),
        }
    });
    if job_depend_iter.is_err() {
        return Err("Insert failed");
    }
    let result = job_depend_iter.unwrap();
    let mut found = 0;
    for person in result {
        let bill = person.unwrap();
        output = bill.id;
        found = 1;
    }
    if found != 0 {
        return Ok(output);
    }
    return Err("None found");
}

pub fn job_depend_count(conn: &Connection, fk_job: &i32) -> Result<i32, &'static str> {
    let count_prep_rc = conn.prepare(
        "SELECT JOBDEPEND.id FROM JOBDEPEND WHERE JOBDEPEND.fk_job = ?1",
    );
    match count_prep_rc {
        Ok(mut result) => {
            let result_row = result.query(&[fk_job]);
            let mut rox = result_row.unwrap();
            let mut counter = 0;
            while let Some(_) = rox.next() {
                counter += 1;
            }
            return Ok(counter);
        }
        Err(_) => {
            return Err("Failed");
        }
    }
}
<commit_msg>Apply rustfmt<commit_after>use rusqlite::Connection;

#[derive(Debug)]
pub struct JobDepend {
    pub id: i32,
    pub fk_job: i32,
    pub fk_variable: i32,
    pub sq_order: i32,
}

pub fn table_create_job_depend(conn: &Connection) -> &Connection {
    conn.execute(
        "CREATE TABLE JOBDEPEND (
                  id                INTEGER PRIMARY KEY ASC,
                  fk_job            INTEGER NOT NULL,
                  fk_variable       INTEGER NOT NULL,
                  sq_order          INTEGER NOT NULL,
                  UNIQUE (fk_job, fk_variable) ON CONFLICT REPLACE
                  FOREIGN KEY(fk_job) REFERENCES JOB(id) ON UPDATE CASCADE
                  FOREIGN KEY(fk_variable) REFERENCES VARIABLE_NAME(id) ON UPDATE CASCADE
                  )",
        &[],
    ).unwrap();
    return conn;
}

pub fn insert_job_depend(
    conn: &Connection,
    job: &i32,
    provider: &i32,
    sq_order: &i32,
) -> Result<i32, &'static str> {
    let me = JobDepend {
        id: 0,
        fk_job: *job,
        fk_variable: *provider,
        sq_order: *sq_order,
    };
    let job_depend_instance = conn.execute(
        "INSERT INTO JOBDEPEND (fk_job, fk_variable, sq_order)
                  VALUES (?1, ?2, ?3)",
        &[&me.fk_job, &me.fk_variable, &me.sq_order],
    );
    if job_depend_instance.is_err() {
        return Err("Failed trying to INSERT INTO JOBDEPEND");
    }
    job_depend_instance.unwrap();
    return Ok(0);
}

pub fn list_job_depend(conn: &Connection) -> Vec<JobDepend> {
    let mut stmt = conn.prepare("SELECT id, fk_job, fk_variable, sq_order  FROM JOBDEPEND")
        .unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| JobDepend {
        id: row.get(0),
        fk_job: row.get(1),
        fk_variable: row.get(2),
        sq_order: row.get(3),
    });
    let mut items = Vec::<JobDepend>::new();
    if wraped_fs_file_iter.is_err() {
        return items;
    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {
        items.push(person.unwrap());
    }
    return items;
}

pub fn job_depend_list(conn: &Connection) {
    let mut stmt = conn.prepare("SELECT id, fk_job, fk_variable, sq_order FROM JOBDEPEND")
        .unwrap();
    let person_iter = stmt.query_map(&[], |row| JobDepend {
        id: row.get(0),
        fk_job: row.get(1),
        fk_variable: row.get(2),
        sq_order: row.get(3),
    }).unwrap();

    for person in person_iter {
        info!("Found job_depend {:?}", person.unwrap());
    }
}

pub fn pk_job_depend_by_all(
    conn: &Connection,
    fk_job: &i32,
    provider: &i32,
    sq_order: &i32,
) -> Result<i32, &'static str> {
    let mut output = 0;
    let mut stmt = conn.prepare("SELECT JOBDEPEND.id, JOBDEPEND.fk_job, JOBDEPEND.fk_variable, JOBDEPEND.sq_order  FROM JOBDEPEND WHERE JOBDEPEND.fk_job = ?1 AND JOBDEPEND.fk_variable=?2 AND JOBDEPEND.sq_order=?3 ").unwrap();
    let job_depend_iter = stmt.query_map(&[fk_job, provider, sq_order], |row| JobDepend {
        id: row.get(0),
        fk_job: row.get(1),
        fk_variable: row.get(2),
        sq_order: row.get(3),
    });
    if job_depend_iter.is_err() {
        return Err("Insert failed");
    }
    let result = job_depend_iter.unwrap();
    let mut found = 0;
    for person in result {
        let bill = person.unwrap();
        output = bill.id;
        found = 1;
    }
    if found != 0 {
        return Ok(output);
    }
    return Err("None found");
}

pub fn job_depend_count(conn: &Connection, fk_job: &i32) -> Result<i32, &'static str> {
    let count_prep_rc =
        conn.prepare("SELECT JOBDEPEND.id FROM JOBDEPEND WHERE JOBDEPEND.fk_job = ?1");
    match count_prep_rc {
        Ok(mut result) => {
            let result_row = result.query(&[fk_job]);
            let mut rox = result_row.unwrap();
            let mut counter = 0;
            while let Some(_) = rox.next() {
                counter += 1;
            }
            return Ok(counter);
        }
        Err(_) => {
            return Err("Failed");
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>feat: add error type for config parsing<commit_after><|endoftext|>