<commit_before>use std::fmt;
use std::mem::transmute;
use std::io::{Cursor, Read, Write};
use std::default::Default;
use std::iter::FromIterator;
use std::string::{String, FromUtf8Error};
use std::result::Result as StdResult;
use byteorder::{ByteOrder, NetworkEndian};
use bytes::BufMut;

use rand;

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

fn apply_mask(buf: &mut [u8], mask: &[u8; 4]) {
    for (i, byte) in buf.iter_mut().enumerate() {
        *byte ^= mask[i & 3];
    }
}

#[inline]
fn generate_mask() -> [u8; 4] {
    rand::random()
}

/// 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<(CloseCode, String)>> {
        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((code, text)))
            }
        }
    }

    /// 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<(CloseCode, &str)>) -> Frame {
        let payload = if let Some((code, reason)) = msg {
            let raw: [u8; 2] = unsafe {
                let u: u16 = code.into();
                transmute(u.to_be())
            };
            Vec::from_iter(
                raw[..].iter()
                       .chain(reason.as_bytes().iter())
                       .map(|&b| b))
        } 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 length == 126 {
            let mut length_bytes = [0u8; 2];
            if try!(cursor.read(&mut length_bytes)) != 2 {
                cursor.set_position(initial);
                return Ok(None)
            }

            length = unsafe {
                let mut wide: u16 = transmute(length_bytes);
                wide = u16::from_be(wide);
                wide
            } as u64;
            header_length += 2;
        } else if length == 127 {
            let mut length_bytes = [0u8; 8];
            if try!(cursor.read(&mut length_bytes)) != 8 {
                cursor.set_position(initial);
                return Ok(None)
            }

            unsafe { length = transmute(length_bytes); }
            length = u64::from_be(length);
            header_length += 8;
        }
        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
        };

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

        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 length_bytes: [u8; 2] = unsafe {
                let short = self.payload.len() as u16;
                transmute(short.to_be())
            };
            let headers = [one, two, length_bytes[0], length_bytes[1]];
            try!(w.write(&headers));
        } else {
            two |= 127;
            let length_bytes: [u8; 8] = unsafe {
                let long = self.payload.len() as u64;
                transmute(long.to_be())
            };
            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);
        view.contains("payload:");
    }
}
<commit_msg>Speed up apply_mask() - part 2<commit_after>use std::fmt;
use std::mem::transmute;
use std::io::{Cursor, Read, Write};
use std::default::Default;
use std::iter::FromIterator;
use std::string::{String, FromUtf8Error};
use std::result::Result as StdResult;
use byteorder::{ByteOrder, NetworkEndian};
use bytes::BufMut;

use rand;

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

fn apply_mask(buf: &mut [u8], mask: &[u8; 4]) {
    for (i, byte) in buf.iter_mut().enumerate() {
        *byte ^= mask[i & 3];
    }
}

/// Faster version of `apply_mask()` which operates on 4-byte blocks.
///
/// Safety: `buf` must be at least 4-bytes aligned.
unsafe fn apply_mask_aligned32(buf: &mut [u8], mask: &[u8; 4]) {
    debug_assert_eq!(buf.as_ptr() as usize % 4, 0);

    let mask_u32 = transmute(*mask);

    let mut ptr = buf.as_mut_ptr() as *mut u32;
    for _ in 0..(buf.len() / 4) {
        *ptr ^= mask_u32;
        ptr = ptr.offset(1);
    }

    // Possible last block with less than 4 bytes.
    let last_block_start = buf.len() & !3;
    let last_block = &mut buf[last_block_start..];
    apply_mask(last_block, mask);
}

#[inline]
fn generate_mask() -> [u8; 4] {
    rand::random()
}

/// 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| {
            // Assumes Vec's backing memory is at least 4-bytes aligned.
            unsafe {
                Some(apply_mask_aligned32(&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<(CloseCode, String)>> {
        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((code, text)))
            }
        }
    }

    /// 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<(CloseCode, &str)>) -> Frame {
        let payload = if let Some((code, reason)) = msg {
            let raw: [u8; 2] = unsafe {
                let u: u16 = code.into();
                transmute(u.to_be())
            };
            Vec::from_iter(
                raw[..].iter()
                       .chain(reason.as_bytes().iter())
                       .map(|&b| b))
        } 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 length == 126 {
            let mut length_bytes = [0u8; 2];
            if try!(cursor.read(&mut length_bytes)) != 2 {
                cursor.set_position(initial);
                return Ok(None)
            }

            length = unsafe {
                let mut wide: u16 = transmute(length_bytes);
                wide = u16::from_be(wide);
                wide
            } as u64;
            header_length += 2;
        } else if length == 127 {
            let mut length_bytes = [0u8; 8];
            if try!(cursor.read(&mut length_bytes)) != 8 {
                cursor.set_position(initial);
                return Ok(None)
            }

            unsafe { length = transmute(length_bytes); }
            length = u64::from_be(length);
            header_length += 8;
        }
        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
        };

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

        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 length_bytes: [u8; 2] = unsafe {
                let short = self.payload.len() as u16;
                transmute(short.to_be())
            };
            let headers = [one, two, length_bytes[0], length_bytes[1]];
            try!(w.write(&headers));
        } else {
            two |= 127;
            let length_bytes: [u8; 8] = unsafe {
                let long = self.payload.len() as u64;
                transmute(long.to_be())
            };
            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();
            // Assumes Vec's backing memory is at least 4-bytes aligned.
            unsafe {
                apply_mask_aligned32(&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 test_apply_mask() {
        let mask = [
            0x6d, 0xb6, 0xb2, 0x80,
        ];
        let unmasked = vec![
            0xf3, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x82, 0xff, 0xfe, 0x00,
        ];

        let mut masked = unmasked.clone();
        apply_mask(&mut masked, &mask);

        let mut masked_aligned = unmasked.clone();
        unsafe { apply_mask_aligned32(&mut masked_aligned, &mask) };

        assert_eq!(masked, masked_aligned);
    }

    #[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);
        view.contains("payload:");
    }
}
<|endoftext|>


<commit_before>use hir::{Adt, ModuleDef, Struct};
use ide_db::defs::{Definition, NameRefClass};
use syntax::{
    ast::{self, AstNode, GenericParamsOwner, VisibilityOwner},
    match_ast,
};

use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};

// Assist: convert_tuple_struct_to_named_struct
//
// Converts tuple struct to struct with named fields.
//
// ```
// struct Point$0(f32, f32);
//
// impl Point {
//     pub fn new(x: f32, y: f32) -> Self {
//         Point(x, y)
//     }
//
//     pub fn x(&self) -> f32 {
//         self.0
//     }
//
//     pub fn y(&self) -> f32 {
//         self.1
//     }
// }
// ```
// ->
// ```
// struct Point { field1: f32, field2: f32 }
//
// impl Point {
//     pub fn new(x: f32, y: f32) -> Self {
//         Point { field1: x, field2: y }
//     }
//
//     pub fn x(&self) -> f32 {
//         self.field1
//     }
//
//     pub fn y(&self) -> f32 {
//         self.field2
//     }
// }
// ```
pub(crate) fn convert_tuple_struct_to_named_struct(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
    let tuple_fields = match strukt.field_list()? {
        ast::FieldList::TupleFieldList(it) => it,
        ast::FieldList::RecordFieldList(_) => return None,
    };
    let strukt_def = ctx.sema.to_def(&strukt)?;

    let target = strukt.syntax().text_range();
    acc.add(
        AssistId("convert_tuple_struct_to_named_struct", AssistKind::RefactorRewrite),
        "Convert to named struct",
        target,
        |edit| {
            let names = generate_names(tuple_fields.fields());
            edit_field_references(ctx, edit, tuple_fields.fields(), &names);
            edit_struct_references(ctx, edit, strukt_def, &names);
            edit_struct_def(ctx, edit, &strukt, tuple_fields, names);
        },
    )
}

fn edit_struct_def(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    strukt: &ast::Struct,
    tuple_fields: ast::TupleFieldList,
    names: Vec<ast::Name>,
) {
    let record_fields = tuple_fields
        .fields()
        .zip(names)
        .filter_map(|(f, name)| Some(ast::make::record_field(f.visibility(), name, f.ty()?)));
    let record_fields = ast::make::record_field_list(record_fields);
    let tuple_fields_text_range = tuple_fields.syntax().text_range();

    edit.edit_file(ctx.frange.file_id);

    if let Some(w) = strukt.where_clause() {
        edit.delete(w.syntax().text_range());
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
        edit.insert(tuple_fields_text_range.start(), w.syntax().text());
        edit.insert(tuple_fields_text_range.start(), ",");
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
    } else {
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text());
    }

    edit.replace(tuple_fields_text_range, record_fields.to_string());
    strukt.semicolon_token().map(|t| edit.delete(t.text_range()));
}

fn edit_struct_references(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    strukt: Struct,
    names: &[ast::Name],
) {
    let strukt_def = Definition::ModuleDef(ModuleDef::Adt(Adt::Struct(strukt)));
    let usages = strukt_def.usages(&ctx.sema).include_self_kw_refs(true).all();

    for (file_id, refs) in usages {
        edit.edit_file(file_id);
        for r in refs {
            for node in r.name.syntax().ancestors() {
                match_ast! {
                    match node {
                        ast::TupleStructPat(tuple_struct_pat) => {
                            let path = match tuple_struct_pat.path() {
                                Some(it) => it,
                                None => continue,
                            };

                            edit.replace(
                                tuple_struct_pat.syntax().text_range(),
                                ast::make::record_pat_with_fields(
                                    path,
                                    ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
                                        |(pat, name)| {
                                            ast::make::record_pat_field(
                                                ast::make::name_ref(&name.to_string()),
                                                pat,
                                            )
                                        },
                                    )),
                                )
                                .to_string(),
                            );
                        },
                        // for tuple struct creations like Foo(42)
                        ast::CallExpr(call_expr) => {
                            let path = match call_expr.syntax().descendants().find_map(ast::PathExpr::cast).map(|expr| expr.path()) {
                                Some(Some(it)) => it,
                                _ => continue,
                            };

                            // this also includes method calls like Foo::new(42), we should skip them
                            if let Some(Some(name_ref)) = path.segment().map(|s| s.name_ref()) {
                                match NameRefClass::classify(&ctx.sema, &name_ref) {
                                    Some(NameRefClass::Definition(Definition::SelfType(_))) => {},
                                    Some(NameRefClass::Definition(def)) if def == strukt_def => {},
                                    _ => continue,
                                };
                            }

                            let arg_list = match call_expr.syntax().descendants().find_map(ast::ArgList::cast) {
                                Some(it) => it,
                                None => continue,
                            };

                            edit.replace(
                                call_expr.syntax().text_range(),
                                ast::make::record_expr(
                                    path,
                                    ast::make::record_expr_field_list(arg_list.args().zip(names).map(
                                        |(expr, name)| {
                                            ast::make::record_expr_field(
                                                ast::make::name_ref(&name.to_string()),
                                                Some(expr),
                                            )
                                        },
                                    )),
                                )
                                .to_string(),
                            );
                        },
                        _ => ()
                    }
                }
            }
        }
    }
}

fn edit_field_references(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    fields: impl Iterator<Item = ast::TupleField>,
    names: &[ast::Name],
) {
    for (field, name) in fields.zip(names) {
        let field = match ctx.sema.to_def(&field) {
            Some(it) => it,
            None => continue,
        };
        let def = Definition::Field(field);
        let usages = def.usages(&ctx.sema).all();
        for (file_id, refs) in usages {
            edit.edit_file(file_id);
            for r in refs {
                if let Some(name_ref) = r.name.as_name_ref() {
                    edit.replace(name_ref.syntax().text_range(), name.text());
                }
            }
        }
    }
}

fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Name> {
    fields.enumerate().map(|(i, _)| ast::make::name(&format!("field{}", i + 1))).collect()
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn not_applicable_other_than_tuple_struct() {
        check_assist_not_applicable(
            convert_tuple_struct_to_named_struct,
            r#"struct Foo$0 { bar: u32 };"#,
        );
        check_assist_not_applicable(convert_tuple_struct_to_named_struct, r#"struct Foo$0;"#);
    }

    #[test]
    fn convert_simple_struct() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn new(inner: Inner) -> A {
        A(inner)
    }

    fn new_with_default() -> A {
        A::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.0
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn new(inner: Inner) -> A {
        A { field1: inner }
    }

    fn new_with_default() -> A {
        A::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.field1
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_referenced_via_self_kw() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn new(inner: Inner) -> Self {
        Self(inner)
    }

    fn new_with_default() -> Self {
        Self::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.0
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn new(inner: Inner) -> Self {
        Self { field1: inner }
    }

    fn new_with_default() -> Self {
        Self::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.field1
    }
}"#,
        );
    }

    #[test]
    fn convert_destructured_struct() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn into_inner(self) -> Inner {
        let A(first) = self;
        first
    }

    fn into_inner_via_self(self) -> Inner {
        let Self(first) = self;
        first
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn into_inner(self) -> Inner {
        let A { field1: first } = self;
        first
    }

    fn into_inner_via_self(self) -> Inner {
        let Self { field1: first } = self;
        first
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_with_visibility() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct A$0(pub u32, pub(crate) u64);

impl A {
    fn new() -> A {
        A(42, 42)
    }

    fn into_first(self) -> u32 {
        self.0
    }

    fn into_second(self) -> u64 {
        self.1
    }
}"#,
            r#"
struct A { pub field1: u32, pub(crate) field2: u64 }

impl A {
    fn new() -> A {
        A { field1: 42, field2: 42 }
    }

    fn into_first(self) -> u32 {
        self.field1
    }

    fn into_second(self) -> u64 {
        self.field2
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_with_where_clause() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Wrap$0<T>(T)
where
    T: Display;
"#,
            r#"
struct Wrap<T>
where
    T: Display,
{ field1: T }

"#,
        );
    }
}
<commit_msg>Add multi file test for "Convert to named struct" assist<commit_after>use hir::{Adt, ModuleDef, Struct};
use ide_db::defs::{Definition, NameRefClass};
use syntax::{
    ast::{self, AstNode, GenericParamsOwner, VisibilityOwner},
    match_ast,
};

use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};

// Assist: convert_tuple_struct_to_named_struct
//
// Converts tuple struct to struct with named fields.
//
// ```
// struct Point$0(f32, f32);
//
// impl Point {
//     pub fn new(x: f32, y: f32) -> Self {
//         Point(x, y)
//     }
//
//     pub fn x(&self) -> f32 {
//         self.0
//     }
//
//     pub fn y(&self) -> f32 {
//         self.1
//     }
// }
// ```
// ->
// ```
// struct Point { field1: f32, field2: f32 }
//
// impl Point {
//     pub fn new(x: f32, y: f32) -> Self {
//         Point { field1: x, field2: y }
//     }
//
//     pub fn x(&self) -> f32 {
//         self.field1
//     }
//
//     pub fn y(&self) -> f32 {
//         self.field2
//     }
// }
// ```
pub(crate) fn convert_tuple_struct_to_named_struct(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
    let tuple_fields = match strukt.field_list()? {
        ast::FieldList::TupleFieldList(it) => it,
        ast::FieldList::RecordFieldList(_) => return None,
    };
    let strukt_def = ctx.sema.to_def(&strukt)?;

    let target = strukt.syntax().text_range();
    acc.add(
        AssistId("convert_tuple_struct_to_named_struct", AssistKind::RefactorRewrite),
        "Convert to named struct",
        target,
        |edit| {
            let names = generate_names(tuple_fields.fields());
            edit_field_references(ctx, edit, tuple_fields.fields(), &names);
            edit_struct_references(ctx, edit, strukt_def, &names);
            edit_struct_def(ctx, edit, &strukt, tuple_fields, names);
        },
    )
}

fn edit_struct_def(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    strukt: &ast::Struct,
    tuple_fields: ast::TupleFieldList,
    names: Vec<ast::Name>,
) {
    let record_fields = tuple_fields
        .fields()
        .zip(names)
        .filter_map(|(f, name)| Some(ast::make::record_field(f.visibility(), name, f.ty()?)));
    let record_fields = ast::make::record_field_list(record_fields);
    let tuple_fields_text_range = tuple_fields.syntax().text_range();

    edit.edit_file(ctx.frange.file_id);

    if let Some(w) = strukt.where_clause() {
        edit.delete(w.syntax().text_range());
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
        edit.insert(tuple_fields_text_range.start(), w.syntax().text());
        edit.insert(tuple_fields_text_range.start(), ",");
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
    } else {
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text());
    }

    edit.replace(tuple_fields_text_range, record_fields.to_string());
    strukt.semicolon_token().map(|t| edit.delete(t.text_range()));
}

fn edit_struct_references(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    strukt: Struct,
    names: &[ast::Name],
) {
    let strukt_def = Definition::ModuleDef(ModuleDef::Adt(Adt::Struct(strukt)));
    let usages = strukt_def.usages(&ctx.sema).include_self_kw_refs(true).all();

    for (file_id, refs) in usages {
        edit.edit_file(file_id);
        for r in refs {
            for node in r.name.syntax().ancestors() {
                match_ast! {
                    match node {
                        ast::TupleStructPat(tuple_struct_pat) => {
                            let path = match tuple_struct_pat.path() {
                                Some(it) => it,
                                None => continue,
                            };

                            edit.replace(
                                tuple_struct_pat.syntax().text_range(),
                                ast::make::record_pat_with_fields(
                                    path,
                                    ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
                                        |(pat, name)| {
                                            ast::make::record_pat_field(
                                                ast::make::name_ref(&name.to_string()),
                                                pat,
                                            )
                                        },
                                    )),
                                )
                                .to_string(),
                            );
                        },
                        // for tuple struct creations like Foo(42)
                        ast::CallExpr(call_expr) => {
                            let path = match call_expr.syntax().descendants().find_map(ast::PathExpr::cast).map(|expr| expr.path()) {
                                Some(Some(it)) => it,
                                _ => continue,
                            };

                            // this also includes method calls like Foo::new(42), we should skip them
                            if let Some(Some(name_ref)) = path.segment().map(|s| s.name_ref()) {
                                match NameRefClass::classify(&ctx.sema, &name_ref) {
                                    Some(NameRefClass::Definition(Definition::SelfType(_))) => {},
                                    Some(NameRefClass::Definition(def)) if def == strukt_def => {},
                                    _ => continue,
                                };
                            }

                            let arg_list = match call_expr.syntax().descendants().find_map(ast::ArgList::cast) {
                                Some(it) => it,
                                None => continue,
                            };

                            edit.replace(
                                call_expr.syntax().text_range(),
                                ast::make::record_expr(
                                    path,
                                    ast::make::record_expr_field_list(arg_list.args().zip(names).map(
                                        |(expr, name)| {
                                            ast::make::record_expr_field(
                                                ast::make::name_ref(&name.to_string()),
                                                Some(expr),
                                            )
                                        },
                                    )),
                                )
                                .to_string(),
                            );
                        },
                        _ => ()
                    }
                }
            }
        }
    }
}

fn edit_field_references(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    fields: impl Iterator<Item = ast::TupleField>,
    names: &[ast::Name],
) {
    for (field, name) in fields.zip(names) {
        let field = match ctx.sema.to_def(&field) {
            Some(it) => it,
            None => continue,
        };
        let def = Definition::Field(field);
        let usages = def.usages(&ctx.sema).all();
        for (file_id, refs) in usages {
            edit.edit_file(file_id);
            for r in refs {
                if let Some(name_ref) = r.name.as_name_ref() {
                    edit.replace(name_ref.syntax().text_range(), name.text());
                }
            }
        }
    }
}

fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Name> {
    fields.enumerate().map(|(i, _)| ast::make::name(&format!("field{}", i + 1))).collect()
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn not_applicable_other_than_tuple_struct() {
        check_assist_not_applicable(
            convert_tuple_struct_to_named_struct,
            r#"struct Foo$0 { bar: u32 };"#,
        );
        check_assist_not_applicable(convert_tuple_struct_to_named_struct, r#"struct Foo$0;"#);
    }

    #[test]
    fn convert_simple_struct() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn new(inner: Inner) -> A {
        A(inner)
    }

    fn new_with_default() -> A {
        A::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.0
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn new(inner: Inner) -> A {
        A { field1: inner }
    }

    fn new_with_default() -> A {
        A::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.field1
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_referenced_via_self_kw() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn new(inner: Inner) -> Self {
        Self(inner)
    }

    fn new_with_default() -> Self {
        Self::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.0
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn new(inner: Inner) -> Self {
        Self { field1: inner }
    }

    fn new_with_default() -> Self {
        Self::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.field1
    }
}"#,
        );
    }

    #[test]
    fn convert_destructured_struct() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn into_inner(self) -> Inner {
        let A(first) = self;
        first
    }

    fn into_inner_via_self(self) -> Inner {
        let Self(first) = self;
        first
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn into_inner(self) -> Inner {
        let A { field1: first } = self;
        first
    }

    fn into_inner_via_self(self) -> Inner {
        let Self { field1: first } = self;
        first
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_with_visibility() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct A$0(pub u32, pub(crate) u64);

impl A {
    fn new() -> A {
        A(42, 42)
    }

    fn into_first(self) -> u32 {
        self.0
    }

    fn into_second(self) -> u64 {
        self.1
    }
}"#,
            r#"
struct A { pub field1: u32, pub(crate) field2: u64 }

impl A {
    fn new() -> A {
        A { field1: 42, field2: 42 }
    }

    fn into_first(self) -> u32 {
        self.field1
    }

    fn into_second(self) -> u64 {
        self.field2
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_with_multi_file_references() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
//- /main.rs
struct Inner;
struct A$0(Inner);

mod foo;

//- /foo.rs
use crate::{A, Inner};
fn f() {
    let a = A(Inner);
}
"#,
            r#"
//- /main.rs
struct Inner;
struct A { field1: Inner }

mod foo;

//- /foo.rs
use crate::{A, Inner};
fn f() {
    let a = A { field1: Inner };
}
"#,
        );
    }

    #[test]
    fn convert_struct_with_where_clause() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Wrap$0<T>(T)
where
    T: Display;
"#,
            r#"
struct Wrap<T>
where
    T: Display,
{ field1: T }

"#,
        );
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use error::{Result, Error, ErrorKind};
use reader::FbxEvent;
use super::{CommonState, PropertyValue};

#[derive(Debug, Clone)]
pub struct BinaryParser {
    version: u32,
    end_offset_stack: Vec<u32>,
}

impl BinaryParser {
    pub fn new(version: u32) -> Self {
        BinaryParser {
            version: version,
            end_offset_stack: vec![],
        }
    }

    pub fn next<R: Read>(&mut self, reader: &mut R, common: &mut CommonState) -> Result<FbxEvent> {
        // Read a node record header.
        let node_record_header = try!(NodeRecordHeader::load(reader, &mut common.pos));
        if node_record_header.is_null_record() {
            // End of a node.
            return if let Some(expected_pos) = self.end_offset_stack.pop() {
                if common.pos == expected_pos as u64 {
                    Ok(FbxEvent::EndFbx)
                } else {
                    // Data is collapsed (the node doesn't end at expected position).
                    Err(Error::new(common.pos, ErrorKind::DataError("Node does not end at expected position".to_string())))
                }
            } else {
                // Data is collapsed (an extra node end marker found).
                Err(Error::new(common.pos, ErrorKind::DataError("An extra node end marker found".to_string())))
            };
        } else {
            // Start of a node.
            self.end_offset_stack.push(node_record_header.end_offset);
        }

        // Read properties.
        let mut properties = Vec::<PropertyValue>::with_capacity(node_record_header.num_properties as usize);
        for _ in 0..node_record_header.num_properties {
            let prop = try!(self.read_property(reader, common));
            properties.push(prop);
        }

        Err(Error::new(common.pos, ErrorKind::Unimplemented("Parser for Binary FBX format is not implemented yet".to_string())))
    }

    fn read_property<R: Read>(&mut self, reader: &mut R, common: &mut CommonState) -> Result<PropertyValue> {
        Err(Error::new(common.pos, ErrorKind::Unimplemented("Parser for FBX node property is not implemented yet".to_string())))
    }
}

#[derive(Debug, Copy, Clone)]
struct NodeRecordHeader {
    end_offset: u32,
    num_properties: u32,
    property_list_len: u32,
    name_len: u8,
}

impl NodeRecordHeader {
    pub fn load<R: Read>(reader: &mut R, pos: &mut u64) -> Result<Self> {
        let end_offset = try_read_le_u32!(*pos, reader);
        let num_properties = try_read_le_u32!(*pos, reader);
        let property_list_len = try_read_le_u32!(*pos, reader);
        let name_len = try_read_le_u8!(*pos, reader);
        Ok(NodeRecordHeader {
            end_offset: end_offset,
            num_properties: num_properties,
            property_list_len: property_list_len,
            name_len: name_len,
        })
    }

    /// Check whether the header indicates there are no more children.
    pub fn is_null_record(&self) -> bool {
        self.end_offset == 0
            && self.num_properties == 0
            && self.property_list_len == 0
            && self.name_len == 0
    }
}
<commit_msg>Fix `BinaryParser` skipping reading a node name<commit_after>use std::io::Read;
use error::{Result, Error, ErrorKind};
use reader::FbxEvent;
use super::{CommonState, PropertyValue};

#[derive(Debug, Clone)]
pub struct BinaryParser {
    version: u32,
    end_offset_stack: Vec<u32>,
}

impl BinaryParser {
    pub fn new(version: u32) -> Self {
        BinaryParser {
            version: version,
            end_offset_stack: vec![],
        }
    }

    pub fn next<R: Read>(&mut self, reader: &mut R, common: &mut CommonState) -> Result<FbxEvent> {
        // Read a node record header.
        let node_record_header = try!(NodeRecordHeader::load(reader, &mut common.pos));
        if node_record_header.is_null_record() {
            // End of a node.
            return if let Some(expected_pos) = self.end_offset_stack.pop() {
                if common.pos == expected_pos as u64 {
                    Ok(FbxEvent::EndFbx)
                } else {
                    // Data is collapsed (the node doesn't end at expected position).
                    Err(Error::new(common.pos, ErrorKind::DataError("Node does not end at expected position".to_string())))
                }
            } else {
                // Data is collapsed (an extra node end marker found).
                Err(Error::new(common.pos, ErrorKind::DataError("An extra node end marker found".to_string())))
            };
        } else {
            // Start of a node.
            self.end_offset_stack.push(node_record_header.end_offset);
        }

        // Read a node name.
        let name = try_read_fixstr!(common.pos, reader, node_record_header.name_len);

        // Read properties.
        let mut properties = Vec::<PropertyValue>::with_capacity(node_record_header.num_properties as usize);
        for _ in 0..node_record_header.num_properties {
            let prop = try!(self.read_property(reader, common));
            properties.push(prop);
        }

        Err(Error::new(common.pos, ErrorKind::Unimplemented("Parser for Binary FBX format is not implemented yet".to_string())))
    }

    fn read_property<R: Read>(&mut self, reader: &mut R, common: &mut CommonState) -> Result<PropertyValue> {
        Err(Error::new(common.pos, ErrorKind::Unimplemented("Parser for FBX node property is not implemented yet".to_string())))
    }
}

#[derive(Debug, Copy, Clone)]
struct NodeRecordHeader {
    end_offset: u32,
    num_properties: u32,
    property_list_len: u32,
    name_len: u8,
}

impl NodeRecordHeader {
    pub fn load<R: Read>(reader: &mut R, pos: &mut u64) -> Result<Self> {
        let end_offset = try_read_le_u32!(*pos, reader);
        let num_properties = try_read_le_u32!(*pos, reader);
        let property_list_len = try_read_le_u32!(*pos, reader);
        let name_len = try_read_le_u8!(*pos, reader);
        Ok(NodeRecordHeader {
            end_offset: end_offset,
            num_properties: num_properties,
            property_list_len: property_list_len,
            name_len: name_len,
        })
    }

    /// Check whether the header indicates there are no more children.
    pub fn is_null_record(&self) -> bool {
        self.end_offset == 0
            && self.num_properties == 0
            && self.property_list_len == 0
            && self.name_len == 0
    }
}
<|endoftext|>


<commit_before>use screen::*;
use piston_window;

pub struct BattleScreen {
    // TODO: FIXME.
    _fixme: i32,
//    player: object::Object,
}

impl BattleScreen {
    pub fn new() -> BattleScreen {
        BattleScreen{ _fixme: 42 }
    }
}

impl Screen for BattleScreen {
    fn on_input(&mut self, input: &piston_window::Input) -> InputResults {
        let result = Vec::new();
        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
    }
}
<commit_msg>Battle screen - work in progress<commit_after>use screen::*;
use piston_window;

pub struct BattleScreen {
    // TODO: FIXME.
    _fixme: i32,
//    player: object::Object,
}

impl BattleScreen {
    pub fn new() -> BattleScreen {
        BattleScreen{ _fixme: 42 }
    }
}

impl Screen for BattleScreen {
    fn on_input(&mut self, input: &piston_window::Input) -> InputResults {
        use piston_window::{Input, Button, Key};

        let result = Vec::new();

        match input {
            &Input::Press(button) => {
                match button {
//                    Button::Keyboard(Key::Up) => { self.up = true; }
//                    Button::Keyboard(Key::Down) => { self.down = true; }
//                    Button::Keyboard(Key::Left) => { self.left = true; }
//                    Button::Keyboard(Key::Right) => { self.right = true; }
                    _ => {}
                }
            }
            &Input::Release(button) => {
                match button {
//                    Button::Keyboard(Key::Up) => { self.up = false; }
//                    Button::Keyboard(Key::Down) => { self.down = false; }
//                    Button::Keyboard(Key::Left) => { self.left = false; }
//                    Button::Keyboard(Key::Right) => { self.right = false; }
                    _ => {}
                }
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::fmt::{self, Display, Formatter};
use ffi::{self, GtkCssProvider};
use glib::translate::{ToGlibPtr, from_glib_full};
use glib::{self, GlibContainer};

#[repr(C)]
pub struct CssProvider {
    pointer: *mut GtkCssProvider
}

impl ::StyleProviderTrait for CssProvider {}

impl CssProvider {
    pub fn new() -> Self {
        assert_initialized_main_thread!();
        unsafe { CssProvider { pointer: ffi::gtk_css_provider_new() } }
    }

    pub fn get_default() -> Self {
        assert_initialized_main_thread!();
        unsafe { CssProvider { pointer: ffi::gtk_css_provider_get_default() } }
    }

    pub fn get_named(name: &str, variant: &str) -> Self {
        assert_initialized_main_thread!();
        unsafe {
            CssProvider { pointer: ffi::gtk_css_provider_get_named(name.to_glib_none().0,
                                                                   variant.to_glib_none().0) }
        }
    }

    pub fn load_from_path(path: &str) -> Result<CssProvider, glib::Error> {
        assert_initialized_main_thread!();
        unsafe {
            let pointer = ffi::gtk_css_provider_new();
            let mut error = ::std::ptr::null_mut();
            ffi::gtk_css_provider_load_from_path(pointer, path.to_glib_none().0, &mut error);
            if error.is_null() {
                Ok(CssProvider { pointer: pointer })
            } else {
                Err(glib::Error::wrap(error))
            }

        }
    }
}

impl Display for CssProvider {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let tmp: String = unsafe { from_glib_full(ffi::gtk_css_provider_to_string(self.pointer)) };
        write!(f, "{}", tmp)
    }
}

impl_GObjectFunctions!(CssProvider, GtkCssProvider);
impl_TraitObject!(CssProvider, GtkCssProvider);
<commit_msg>Adds load_from_data function to CssProvider and removes empty lines<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::fmt::{self, Display, Formatter};
use ffi::{self, GtkCssProvider};
use glib::translate::{ToGlibPtr, from_glib_full};
use glib::{self, GlibContainer};
use libc::ssize_t;

#[repr(C)]
pub struct CssProvider {
    pointer: *mut GtkCssProvider
}

impl ::StyleProviderTrait for CssProvider {}

impl CssProvider {
    pub fn new() -> Self {
        assert_initialized_main_thread!();
        unsafe { CssProvider { pointer: ffi::gtk_css_provider_new() } }
    }

    pub fn get_default() -> Self {
        assert_initialized_main_thread!();
        unsafe { CssProvider { pointer: ffi::gtk_css_provider_get_default() } }
    }

    pub fn get_named(name: &str, variant: &str) -> Self {
        assert_initialized_main_thread!();
        unsafe {
            CssProvider { pointer: ffi::gtk_css_provider_get_named(name.to_glib_none().0,
                                                                   variant.to_glib_none().0) }
        }
    }

    pub fn load_from_data(data: &str) -> Result<CssProvider, glib::Error> {
        assert_initialized_main_thread!();
        unsafe {
            let pointer = ffi::gtk_css_provider_new();
            let mut error = ::std::ptr::null_mut();
            ffi::gtk_css_provider_load_from_data(pointer, data.as_ptr() as *mut u8, data.len() as ssize_t, &mut error);
            if error.is_null() {
                Ok(CssProvider { pointer: pointer })
            } else {
                Err(glib::Error::wrap(error))
            }
        }
    }

    pub fn load_from_path(path: &str) -> Result<CssProvider, glib::Error> {
        assert_initialized_main_thread!();
        unsafe {
            let pointer = ffi::gtk_css_provider_new();
            let mut error = ::std::ptr::null_mut();
            ffi::gtk_css_provider_load_from_path(pointer, path.to_glib_none().0, &mut error);
            if error.is_null() {
                Ok(CssProvider { pointer: pointer })
            } else {
                Err(glib::Error::wrap(error))
            }
        }
    }
}

impl Display for CssProvider {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let tmp: String = unsafe { from_glib_full(ffi::gtk_css_provider_to_string(self.pointer)) };
        write!(f, "{}", tmp)
    }
}

impl_GObjectFunctions!(CssProvider, GtkCssProvider);
impl_TraitObject!(CssProvider, GtkCssProvider);
<|endoftext|>


<commit_before>// Regression test for issue #26083
// Test that span for public struct fields start at `pub` instead of the identifier

struct Foo {
    pub bar: u8,

    pub
    //~^ error: field `bar` is already declared [E0124]
    bar: u8,

    pub bar:
    //~^ error: field `bar` is already declared [E0124]
    u8,

    bar:
    //~^ error: field `bar` is already declared [E0124]
    u8,
}

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

// Regression test for issue #26083
// Test that span for public struct fields start at `pub` instead of the identifier

struct Foo {
    pub bar: u8,

    pub
    //~^ error: field `bar` is already declared [E0124]
    bar: u8,

    pub bar:
    //~^ error: field `bar` is already declared [E0124]
    u8,

    bar:
    //~^ error: field `bar` is already declared [E0124]
    u8,
}

fn main() { }
<|endoftext|>


<commit_before>use inkwell::context::Context;
use inkwell::debug_info::{
    AsDIScope, DIFlags, DISubprogram, DWARFEmissionKind, DWARFSourceLanguage, DebugInfoBuilder,
};
use inkwell::module::FlagBehavior;

#[test]
fn test_smoke() {
    let context = Context::create();
    let module = context.create_module("bin");

    let debug_metadata_version = context.i32_type().const_int(3, false);
    module.add_basic_value_flag(
        "Debug Info Version",
        FlagBehavior::Warning,
        debug_metadata_version,
    );
    let builder = context.create_builder();
    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    let ditype = dibuilder
        .create_basic_type(
            "type_name",
            0_u64,
            0x00,
            #[cfg(not(all(feature = "llvm7-0")))]
            DIFlags::Public,
        )
        .unwrap();
    let subroutine_type = dibuilder.create_subroutine_type(
        compile_unit.get_file(),
        Some(ditype.as_type()),
        &[],
        DIFlags::Public,
    );
    let func_scope: DISubprogram<'_> = dibuilder.create_function(
        compile_unit.as_debug_info_scope(),
        "main",
        None,
        compile_unit.get_file(),
        0,
        subroutine_type,
        true,
        true,
        0,
        DIFlags::Public,
        false,
    );

    let fn_type = context.i64_type().fn_type(&[], false);
    let fn_val = module.add_function("fn_name_str", fn_type, None);
    fn_val.set_subprogram(func_scope);

    let basic_block = context.append_basic_block(fn_val, "entry");
    builder.position_at_end(basic_block);
    builder.build_return(Some(&context.i64_type().const_zero()));

    let lexical_block = dibuilder.create_lexical_block(
        func_scope.as_debug_info_scope(),
        compile_unit.get_file(),
        0,
        0,
    );

    let loc =
        dibuilder.create_debug_location(&context, 0, 0, lexical_block.as_debug_info_scope(), None);
    builder.set_current_debug_location(&context, loc);

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_struct_with_placeholders() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    // Some byte aligned integer types.
    let i32ty = dibuilder
        .create_basic_type(
            "i32",
            32,
            0x07,
            #[cfg(not(all(feature = "llvm7-0")))]
            DIFlags::Public,
        )
        .unwrap();
    let i64ty = dibuilder
        .create_basic_type(
            "i64",
            64,
            0x07,
            #[cfg(not(all(feature = "llvm7-0")))]
            DIFlags::Public,
        )
        .unwrap();
    let f32ty = dibuilder
        .create_basic_type(
            "f32",
            32,
            0x04,
            #[cfg(not(all(feature = "llvm7-0")))]
            DIFlags::Public,
        )
        .unwrap();
    let f64ty = dibuilder
        .create_basic_type(
            "f64",
            64,
            0x04,
            #[cfg(not(all(feature = "llvm7-0")))]
            DIFlags::Public,
        )
        .unwrap();

    let member_sizes = vec![32, 64, 32, 64];
    let member_types = vec![i32ty, i64ty, f32ty, f64ty];
    let member_placeholders = member_types
        .iter()
        .map(|ty| unsafe { dibuilder.create_placeholder_derived_type(&context) })
        .collect::<Vec<_>>();
    let member_placeholders_as_ditype = member_types
        .iter()
        .map(|ty| ty.as_type())
        .collect::<Vec<_>>();

    let structty = dibuilder.create_struct_type(
        compile_unit.get_file().as_debug_info_scope(),
        "",
        compile_unit.get_file(),
        0,
        192,
        8,
        DIFlags::Public,
        None,
        member_placeholders_as_ditype.as_slice(),
        0,
        None,
        "",
    );

    let mut offset = 0;
    for ((placeholder, ty), size) in member_placeholders
        .iter()
        .zip(member_types.iter())
        .zip(member_sizes.iter())
    {
        let member = dibuilder.create_member_type(
            structty.as_debug_info_scope(),
            "",
            compile_unit.get_file(),
            0,
            *size,
            8,
            offset,
            DIFlags::Public,
            ty.as_type(),
        );
        unsafe {
            dibuilder.replace_placeholder_derived_type(*placeholder, member);
        }
        offset += size;
    }

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_no_explicit_finalize() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, _compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    drop(dibuilder);

    assert!(module.verify().is_ok());
}

#[test]
#[llvm_versions(8.0..=latest)]
fn test_replacing_placeholder_with_placeholder() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    let i32ty = dibuilder
        .create_basic_type("i32", 32, 0x07, DIFlags::Public)
        .unwrap();
    let typedefty = dibuilder.create_typedef(
        i32ty.as_type(),
        "",
        compile_unit.get_file(),
        0,
        compile_unit.get_file().as_debug_info_scope(),
        #[cfg(not(all(feature = "llvm8-0", feature = "llvm9-0")))]
        32,
    );

    unsafe {
        let ph1 = dibuilder.create_placeholder_derived_type(&context);
        let ph2 = dibuilder.create_placeholder_derived_type(&context);

        dibuilder.replace_placeholder_derived_type(ph2, ph1);
        dibuilder.replace_placeholder_derived_type(ph1, typedefty);
    }
}

#[test]
#[llvm_versions(7.0..=latest)]
fn test_anonymous_basic_type() {
    let context = Context::create();
    let module = context.create_module("bin");

    let (dibuilder, _compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    assert_eq!(
        dibuilder.create_basic_type(
            "",
            0_u64,
            0x00,
            #[cfg(not(all(feature = "llvm7-0")))]
            DIFlags::Zero
        ),
        Err("basic types must have names")
    );
}
<commit_msg>This entire test module is llvm7.0+. Remove redundant #[llvm_versions].<commit_after>use inkwell::context::Context;
use inkwell::debug_info::{
    AsDIScope, DIFlags, DISubprogram, DWARFEmissionKind, DWARFSourceLanguage, DebugInfoBuilder,
};
use inkwell::module::FlagBehavior;

#[test]
fn test_smoke() {
    let context = Context::create();
    let module = context.create_module("bin");

    let debug_metadata_version = context.i32_type().const_int(3, false);
    module.add_basic_value_flag(
        "Debug Info Version",
        FlagBehavior::Warning,
        debug_metadata_version,
    );
    let builder = context.create_builder();
    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    let ditype = dibuilder
        .create_basic_type(
            "type_name",
            0_u64,
            0x00,
            #[cfg(not(all(feature = "llvm7-0")))]
            DIFlags::Public,
        )
        .unwrap();
    let subroutine_type = dibuilder.create_subroutine_type(
        compile_unit.get_file(),
        Some(ditype.as_type()),
        &[],
        DIFlags::Public,
    );
    let func_scope: DISubprogram<'_> = dibuilder.create_function(
        compile_unit.as_debug_info_scope(),
        "main",
        None,
        compile_unit.get_file(),
        0,
        subroutine_type,
        true,
        true,
        0,
        DIFlags::Public,
        false,
    );

    let fn_type = context.i64_type().fn_type(&[], false);
    let fn_val = module.add_function("fn_name_str", fn_type, None);
    fn_val.set_subprogram(func_scope);

    let basic_block = context.append_basic_block(fn_val, "entry");
    builder.position_at_end(basic_block);
    builder.build_return(Some(&context.i64_type().const_zero()));

    let lexical_block = dibuilder.create_lexical_block(
        func_scope.as_debug_info_scope(),
        compile_unit.get_file(),
        0,
        0,
    );

    let loc =
        dibuilder.create_debug_location(&context, 0, 0, lexical_block.as_debug_info_scope(), None);
    builder.set_current_debug_location(&context, loc);

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_struct_with_placeholders() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    // Some byte aligned integer types.
    let i32ty = dibuilder
        .create_basic_type(
            "i32",
            32,
            0x07,
            #[cfg(not(all(feature = "llvm7-0")))]
            DIFlags::Public,
        )
        .unwrap();
    let i64ty = dibuilder
        .create_basic_type(
            "i64",
            64,
            0x07,
            #[cfg(not(all(feature = "llvm7-0")))]
            DIFlags::Public,
        )
        .unwrap();
    let f32ty = dibuilder
        .create_basic_type(
            "f32",
            32,
            0x04,
            #[cfg(not(all(feature = "llvm7-0")))]
            DIFlags::Public,
        )
        .unwrap();
    let f64ty = dibuilder
        .create_basic_type(
            "f64",
            64,
            0x04,
            #[cfg(not(all(feature = "llvm7-0")))]
            DIFlags::Public,
        )
        .unwrap();

    let member_sizes = vec![32, 64, 32, 64];
    let member_types = vec![i32ty, i64ty, f32ty, f64ty];
    let member_placeholders = member_types
        .iter()
        .map(|ty| unsafe { dibuilder.create_placeholder_derived_type(&context) })
        .collect::<Vec<_>>();
    let member_placeholders_as_ditype = member_types
        .iter()
        .map(|ty| ty.as_type())
        .collect::<Vec<_>>();

    let structty = dibuilder.create_struct_type(
        compile_unit.get_file().as_debug_info_scope(),
        "",
        compile_unit.get_file(),
        0,
        192,
        8,
        DIFlags::Public,
        None,
        member_placeholders_as_ditype.as_slice(),
        0,
        None,
        "",
    );

    let mut offset = 0;
    for ((placeholder, ty), size) in member_placeholders
        .iter()
        .zip(member_types.iter())
        .zip(member_sizes.iter())
    {
        let member = dibuilder.create_member_type(
            structty.as_debug_info_scope(),
            "",
            compile_unit.get_file(),
            0,
            *size,
            8,
            offset,
            DIFlags::Public,
            ty.as_type(),
        );
        unsafe {
            dibuilder.replace_placeholder_derived_type(*placeholder, member);
        }
        offset += size;
    }

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_no_explicit_finalize() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, _compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    drop(dibuilder);

    assert!(module.verify().is_ok());
}

#[test]
#[llvm_versions(8.0..=latest)]
fn test_replacing_placeholder_with_placeholder() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    let i32ty = dibuilder
        .create_basic_type("i32", 32, 0x07, DIFlags::Public)
        .unwrap();
    let typedefty = dibuilder.create_typedef(
        i32ty.as_type(),
        "",
        compile_unit.get_file(),
        0,
        compile_unit.get_file().as_debug_info_scope(),
        #[cfg(not(all(feature = "llvm8-0", feature = "llvm9-0")))]
        32,
    );

    unsafe {
        let ph1 = dibuilder.create_placeholder_derived_type(&context);
        let ph2 = dibuilder.create_placeholder_derived_type(&context);

        dibuilder.replace_placeholder_derived_type(ph2, ph1);
        dibuilder.replace_placeholder_derived_type(ph1, typedefty);
    }
}

#[test]
fn test_anonymous_basic_type() {
    let context = Context::create();
    let module = context.create_module("bin");

    let (dibuilder, _compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    assert_eq!(
        dibuilder.create_basic_type(
            "",
            0_u64,
            0x00,
            #[cfg(not(all(feature = "llvm7-0")))]
            DIFlags::Zero
        ),
        Err("basic types must have names")
    );
}
<|endoftext|>