<commit_before>//! Utilities to work with raw WebSocket frames.

pub mod coding;

#[allow(clippy::module_inception)]
mod frame;
mod mask;

pub use self::frame::CloseFrame;
pub use self::frame::{Frame, FrameHeader};

use crate::error::{Error, Result};
use input_buffer::{InputBuffer, MIN_READ};
use log::*;
use std::io::{Read, Write};

/// A reader and writer for WebSocket frames.
#[derive(Debug)]
pub struct FrameSocket<Stream> {
    /// The underlying network stream.
    stream: Stream,
    /// Codec for reading/writing frames.
    codec: FrameCodec,
}

impl<Stream> FrameSocket<Stream> {
    /// Create a new frame socket.
    pub fn new(stream: Stream) -> Self {
        FrameSocket {
            stream,
            codec: FrameCodec::new(),
        }
    }

    /// Create a new frame socket from partially read data.
    pub fn from_partially_read(stream: Stream, part: Vec<u8>) -> Self {
        FrameSocket {
            stream,
            codec: FrameCodec::from_partially_read(part),
        }
    }

    /// Extract a stream from the socket.
    pub fn into_inner(self) -> (Stream, Vec<u8>) {
        (self.stream, self.codec.in_buffer.into_vec())
    }

    /// Returns a shared reference to the inner stream.
    pub fn get_ref(&self) -> &Stream {
        &self.stream
    }

    /// Returns a mutable reference to the inner stream.
    pub fn get_mut(&mut self) -> &mut Stream {
        &mut self.stream
    }
}

impl<Stream> FrameSocket<Stream>
where
    Stream: Read,
{
    /// Read a frame from stream.
    pub fn read_frame(&mut self, max_size: Option<usize>) -> Result<Option<Frame>> {
        self.codec.read_frame(&mut self.stream, max_size)
    }
}

impl<Stream> FrameSocket<Stream>
where
    Stream: Write,
{
    /// Write a frame to stream.
    ///
    /// This function guarantees that the frame is queued regardless of any errors.
    /// There is no need to resend the frame. In order to handle WouldBlock or Incomplete,
    /// call write_pending() afterwards.
    pub fn write_frame(&mut self, frame: Frame) -> Result<()> {
        self.codec.write_frame(&mut self.stream, frame)
    }

    /// Complete pending write, if any.
    pub fn write_pending(&mut self) -> Result<()> {
        self.codec.write_pending(&mut self.stream)
    }
}

/// A codec for WebSocket frames.
#[derive(Debug)]
pub(super) struct FrameCodec {
    /// Buffer to read data from the stream.
    in_buffer: InputBuffer,
    /// Buffer to send packets to the network.
    out_buffer: Vec<u8>,
    /// Header and remaining size of the incoming packet being processed.
    header: Option<(FrameHeader, u64)>,
}

impl FrameCodec {
    /// Create a new frame codec.
    pub(super) fn new() -> Self {
        Self {
            in_buffer: InputBuffer::with_capacity(MIN_READ),
            out_buffer: Vec::new(),
            header: None,
        }
    }

    /// Create a new frame codec from partially read data.
    pub(super) fn from_partially_read(part: Vec<u8>) -> Self {
        Self {
            in_buffer: InputBuffer::from_partially_read(part),
            out_buffer: Vec::new(),
            header: None,
        }
    }

    /// Read a frame from the provided stream.
    pub(super) fn read_frame<Stream>(
        &mut self,
        stream: &mut Stream,
        max_size: Option<usize>,
    ) -> Result<Option<Frame>>
    where
        Stream: Read,
    {
        let max_size = max_size.unwrap_or_else(usize::max_value);

        let payload = loop {
            {
                let cursor = self.in_buffer.as_cursor_mut();

                if self.header.is_none() {
                    self.header = FrameHeader::parse(cursor)?;
                }

                if let Some((_, ref length)) = self.header {
                    let length = *length;

                    // Enforce frame size limit early and make sure `length`
                    // is not too big (fits into `usize`).
                    if length > max_size as u64 {
                        return Err(Error::Capacity(
                            format!("Message length too big: {} > {}", length, max_size).into(),
                        ));
                    }

                    let input_size = cursor.get_ref().len() as u64 - cursor.position();
                    if length <= input_size {
                        // No truncation here since `length` is checked above
                        let mut payload = Vec::with_capacity(length as usize);
                        if length > 0 {
                            cursor.take(length).read_to_end(&mut payload)?;
                        }
                        break payload;
                    }
                }
            }

            // Not enough data in buffer.
            let size = self
                .in_buffer
                .prepare_reserve(MIN_READ)
                .with_limit(usize::max_value())
                .map_err(|_| Error::Capacity("Incoming TCP buffer is full".into()))?
                .read_from(stream)?;
            if size == 0 {
                trace!("no frame received");
                return Ok(None);
            }
        };

        let (header, length) = self.header.take().expect("Bug: no frame header");
        debug_assert_eq!(payload.len() as u64, length);
        let frame = Frame::from_payload(header, payload);
        trace!("received frame {}", frame);
        Ok(Some(frame))
    }

    /// Write a frame to the provided stream.
    pub(super) fn write_frame<Stream>(&mut self, stream: &mut Stream, frame: Frame) -> Result<()>
    where
        Stream: Write,
    {
        trace!("writing frame {}", frame);
        self.out_buffer.reserve(frame.len());
        frame
            .format(&mut self.out_buffer)
            .expect("Bug: can't write to vector");
        self.write_pending(stream)
    }

    /// Complete pending write, if any.
    pub(super) fn write_pending<Stream>(&mut self, stream: &mut Stream) -> Result<()>
    where
        Stream: Write,
    {
        while !self.out_buffer.is_empty() {
            let len = stream.write(&self.out_buffer)?;
            self.out_buffer.drain(0..len);
        }
        stream.flush()?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {

    use super::{Frame, FrameSocket};

    use std::io::Cursor;

    #[test]
    fn read_frames() {
        let raw = Cursor::new(vec![
            0x82, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x82, 0x03, 0x03, 0x02, 0x01,
            0x99,
        ]);
        let mut sock = FrameSocket::new(raw);

        assert_eq!(
            sock.read_frame(None).unwrap().unwrap().into_data(),
            vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]
        );
        assert_eq!(
            sock.read_frame(None).unwrap().unwrap().into_data(),
            vec![0x03, 0x02, 0x01]
        );
        assert!(sock.read_frame(None).unwrap().is_none());

        let (_, rest) = sock.into_inner();
        assert_eq!(rest, vec![0x99]);
    }

    #[test]
    fn from_partially_read() {
        let raw = Cursor::new(vec![0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
        let mut sock = FrameSocket::from_partially_read(raw, vec![0x82, 0x07, 0x01]);
        assert_eq!(
            sock.read_frame(None).unwrap().unwrap().into_data(),
            vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]
        );
    }

    #[test]
    fn write_frames() {
        let mut sock = FrameSocket::new(Vec::new());

        let frame = Frame::ping(vec![0x04, 0x05]);
        sock.write_frame(frame).unwrap();

        let frame = Frame::pong(vec![0x01]);
        sock.write_frame(frame).unwrap();

        let (buf, _) = sock.into_inner();
        assert_eq!(buf, vec![0x89, 0x02, 0x04, 0x05, 0x8a, 0x01, 0x01]);
    }

    #[test]
    fn parse_overflow() {
        let raw = Cursor::new(vec![
            0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
        ]);
        let mut sock = FrameSocket::new(raw);
        let _ = sock.read_frame(None); // should not crash
    }

    #[test]
    fn size_limit_hit() {
        let raw = Cursor::new(vec![0x82, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
        let mut sock = FrameSocket::new(raw);
        assert_eq!(
            sock.read_frame(Some(5)).unwrap_err().to_string(),
            "Space limit exceeded: Message length too big: 7 > 5"
        );
    }
}
<commit_msg>frame: correct possible infinite loop on sending<commit_after>//! Utilities to work with raw WebSocket frames.

pub mod coding;

#[allow(clippy::module_inception)]
mod frame;
mod mask;

pub use self::frame::CloseFrame;
pub use self::frame::{Frame, FrameHeader};

use crate::error::{Error, Result};
use input_buffer::{InputBuffer, MIN_READ};
use log::*;
use std::io::{Read, Write, Error as IoError, ErrorKind as IoErrorKind};

/// A reader and writer for WebSocket frames.
#[derive(Debug)]
pub struct FrameSocket<Stream> {
    /// The underlying network stream.
    stream: Stream,
    /// Codec for reading/writing frames.
    codec: FrameCodec,
}

impl<Stream> FrameSocket<Stream> {
    /// Create a new frame socket.
    pub fn new(stream: Stream) -> Self {
        FrameSocket {
            stream,
            codec: FrameCodec::new(),
        }
    }

    /// Create a new frame socket from partially read data.
    pub fn from_partially_read(stream: Stream, part: Vec<u8>) -> Self {
        FrameSocket {
            stream,
            codec: FrameCodec::from_partially_read(part),
        }
    }

    /// Extract a stream from the socket.
    pub fn into_inner(self) -> (Stream, Vec<u8>) {
        (self.stream, self.codec.in_buffer.into_vec())
    }

    /// Returns a shared reference to the inner stream.
    pub fn get_ref(&self) -> &Stream {
        &self.stream
    }

    /// Returns a mutable reference to the inner stream.
    pub fn get_mut(&mut self) -> &mut Stream {
        &mut self.stream
    }
}

impl<Stream> FrameSocket<Stream>
where
    Stream: Read,
{
    /// Read a frame from stream.
    pub fn read_frame(&mut self, max_size: Option<usize>) -> Result<Option<Frame>> {
        self.codec.read_frame(&mut self.stream, max_size)
    }
}

impl<Stream> FrameSocket<Stream>
where
    Stream: Write,
{
    /// Write a frame to stream.
    ///
    /// This function guarantees that the frame is queued regardless of any errors.
    /// There is no need to resend the frame. In order to handle WouldBlock or Incomplete,
    /// call write_pending() afterwards.
    pub fn write_frame(&mut self, frame: Frame) -> Result<()> {
        self.codec.write_frame(&mut self.stream, frame)
    }

    /// Complete pending write, if any.
    pub fn write_pending(&mut self) -> Result<()> {
        self.codec.write_pending(&mut self.stream)
    }
}

/// A codec for WebSocket frames.
#[derive(Debug)]
pub(super) struct FrameCodec {
    /// Buffer to read data from the stream.
    in_buffer: InputBuffer,
    /// Buffer to send packets to the network.
    out_buffer: Vec<u8>,
    /// Header and remaining size of the incoming packet being processed.
    header: Option<(FrameHeader, u64)>,
}

impl FrameCodec {
    /// Create a new frame codec.
    pub(super) fn new() -> Self {
        Self {
            in_buffer: InputBuffer::with_capacity(MIN_READ),
            out_buffer: Vec::new(),
            header: None,
        }
    }

    /// Create a new frame codec from partially read data.
    pub(super) fn from_partially_read(part: Vec<u8>) -> Self {
        Self {
            in_buffer: InputBuffer::from_partially_read(part),
            out_buffer: Vec::new(),
            header: None,
        }
    }

    /// Read a frame from the provided stream.
    pub(super) fn read_frame<Stream>(
        &mut self,
        stream: &mut Stream,
        max_size: Option<usize>,
    ) -> Result<Option<Frame>>
    where
        Stream: Read,
    {
        let max_size = max_size.unwrap_or_else(usize::max_value);

        let payload = loop {
            {
                let cursor = self.in_buffer.as_cursor_mut();

                if self.header.is_none() {
                    self.header = FrameHeader::parse(cursor)?;
                }

                if let Some((_, ref length)) = self.header {
                    let length = *length;

                    // Enforce frame size limit early and make sure `length`
                    // is not too big (fits into `usize`).
                    if length > max_size as u64 {
                        return Err(Error::Capacity(
                            format!("Message length too big: {} > {}", length, max_size).into(),
                        ));
                    }

                    let input_size = cursor.get_ref().len() as u64 - cursor.position();
                    if length <= input_size {
                        // No truncation here since `length` is checked above
                        let mut payload = Vec::with_capacity(length as usize);
                        if length > 0 {
                            cursor.take(length).read_to_end(&mut payload)?;
                        }
                        break payload;
                    }
                }
            }

            // Not enough data in buffer.
            let size = self
                .in_buffer
                .prepare_reserve(MIN_READ)
                .with_limit(usize::max_value())
                .map_err(|_| Error::Capacity("Incoming TCP buffer is full".into()))?
                .read_from(stream)?;
            if size == 0 {
                trace!("no frame received");
                return Ok(None);
            }
        };

        let (header, length) = self.header.take().expect("Bug: no frame header");
        debug_assert_eq!(payload.len() as u64, length);
        let frame = Frame::from_payload(header, payload);
        trace!("received frame {}", frame);
        Ok(Some(frame))
    }

    /// Write a frame to the provided stream.
    pub(super) fn write_frame<Stream>(&mut self, stream: &mut Stream, frame: Frame) -> Result<()>
    where
        Stream: Write,
    {
        trace!("writing frame {}", frame);
        self.out_buffer.reserve(frame.len());
        frame
            .format(&mut self.out_buffer)
            .expect("Bug: can't write to vector");
        self.write_pending(stream)
    }

    /// Complete pending write, if any.
    pub(super) fn write_pending<Stream>(&mut self, stream: &mut Stream) -> Result<()>
    where
        Stream: Write,
    {
        while !self.out_buffer.is_empty() {
            let len = stream.write(&self.out_buffer)?;
            if len == 0 {
                // This is the same as "Connection reset by peer"
                return Err(IoError::new(IoErrorKind::ConnectionReset, "Connection reset while sending").into())
            }
            self.out_buffer.drain(0..len);
        }
        stream.flush()?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {

    use super::{Frame, FrameSocket};

    use std::io::Cursor;

    #[test]
    fn read_frames() {
        let raw = Cursor::new(vec![
            0x82, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x82, 0x03, 0x03, 0x02, 0x01,
            0x99,
        ]);
        let mut sock = FrameSocket::new(raw);

        assert_eq!(
            sock.read_frame(None).unwrap().unwrap().into_data(),
            vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]
        );
        assert_eq!(
            sock.read_frame(None).unwrap().unwrap().into_data(),
            vec![0x03, 0x02, 0x01]
        );
        assert!(sock.read_frame(None).unwrap().is_none());

        let (_, rest) = sock.into_inner();
        assert_eq!(rest, vec![0x99]);
    }

    #[test]
    fn from_partially_read() {
        let raw = Cursor::new(vec![0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
        let mut sock = FrameSocket::from_partially_read(raw, vec![0x82, 0x07, 0x01]);
        assert_eq!(
            sock.read_frame(None).unwrap().unwrap().into_data(),
            vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]
        );
    }

    #[test]
    fn write_frames() {
        let mut sock = FrameSocket::new(Vec::new());

        let frame = Frame::ping(vec![0x04, 0x05]);
        sock.write_frame(frame).unwrap();

        let frame = Frame::pong(vec![0x01]);
        sock.write_frame(frame).unwrap();

        let (buf, _) = sock.into_inner();
        assert_eq!(buf, vec![0x89, 0x02, 0x04, 0x05, 0x8a, 0x01, 0x01]);
    }

    #[test]
    fn parse_overflow() {
        let raw = Cursor::new(vec![
            0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
        ]);
        let mut sock = FrameSocket::new(raw);
        let _ = sock.read_frame(None); // should not crash
    }

    #[test]
    fn size_limit_hit() {
        let raw = Cursor::new(vec![0x82, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
        let mut sock = FrameSocket::new(raw);
        assert_eq!(
            sock.read_frame(Some(5)).unwrap_err().to_string(),
            "Space limit exceeded: Message length too big: 7 > 5"
        );
    }
}
<|endoftext|>


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

use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;

use std::num::{NumCast, One, Zero};

#[deriving(Clone,Eq)]
pub struct Au(i32);

impl Add<Au,Au> for Au {
    fn add(&self, other: &Au) -> Au { Au(**self + **other) }
}

impl Sub<Au,Au> for Au {
    fn sub(&self, other: &Au) -> Au { Au(**self - **other) }
}

impl Mul<Au,Au> for Au {
    fn mul(&self, other: &Au) -> Au { Au(**self * **other) }
}

impl Div<Au,Au> for Au {
    fn div(&self, other: &Au) -> Au { Au(**self / **other) }
}

impl Rem<Au,Au> for Au {
    fn rem(&self, other: &Au) -> Au { Au(**self % **other) }
}

impl Neg<Au> for Au {
    fn neg(&self) -> Au { Au(-**self) }
}

impl Ord for Au {
    fn lt(&self, other: &Au) -> bool { **self <  **other }
    fn le(&self, other: &Au) -> bool { **self <= **other }
    fn ge(&self, other: &Au) -> bool { **self >= **other }
    fn gt(&self, other: &Au) -> bool { **self >  **other }
}

impl One for Au {
    fn one() -> Au { Au(1) }
}

impl Zero for Au {
    fn zero() -> Au { Au(0) }
    fn is_zero(&self) -> bool { **self == 0 }
}

impl Num for Au {}

pub fn min(x: Au, y: Au) -> Au { if x < y { x } else { y } }
pub fn max(x: Au, y: Au) -> Au { if x > y { x } else { y } }

impl NumCast for Au {
    fn from<T:NumCast>(n: T) -> Au { Au(n.to_i32()) }

    fn to_u8(&self) -> u8       { (**self).to_u8() }
    fn to_u16(&self) -> u16     { (**self).to_u16() }
    fn to_u32(&self) -> u32     { (**self).to_u32() }
    fn to_u64(&self) -> u64     { (**self).to_u64() }
    fn to_uint(&self) -> uint   { (**self).to_uint() }

    fn to_i8(&self) -> i8       { (**self).to_i8() }
    fn to_i16(&self) -> i16     { (**self).to_i16() }
    fn to_i32(&self) -> i32     { (**self).to_i32() }
    fn to_i64(&self) -> i64     { (**self).to_i64() }
    fn to_int(&self) -> int     { (**self).to_int() }

    fn to_f32(&self) -> f32     { (**self).to_f32() }
    fn to_f64(&self) -> f64     { (**self).to_f64() }
    fn to_float(&self) -> float { (**self).to_float() }
}

pub fn box<T:Clone + Ord + Add<T,T> + Sub<T,T>>(x: T, y: T, w: T, h: T) -> Rect<T> {
    Rect(Point2D(x, y), Size2D(w, h))
}

impl Au {
    pub fn scale_by(self, factor: float) -> Au {
        Au(((*self as float) * factor) as i32)
    }

    pub fn from_px(i: int) -> Au {
        NumCast::from(i * 60)
    }

    pub fn to_px(&self) -> int {
        (**self / 60) as int
    }

    pub fn to_snapped(&self) -> Au {
        let res = **self % 60i32;
        return if res >= 30i32 { return Au(**self - res + 60i32) }
                       else { return Au(**self - res) };
    }

    pub fn zero_point() -> Point2D<Au> {
        Point2D(Au(0), Au(0))
    }

    pub fn zero_rect() -> Rect<Au> {
        let z = Au(0);
        Rect(Point2D(z, z), Size2D(z, z))
    }

    pub fn from_pt(f: float) -> Au {
        from_px(pt_to_px(f) as int)
    }

    pub fn from_frac_px(f: float) -> Au {
        Au((f * 60f) as i32)
    }

    pub fn min(x: Au, y: Au) -> Au { if *x < *y { x } else { y } }
    pub fn max(x: Au, y: Au) -> Au { if *x > *y { x } else { y } }
}

// assumes 72 points per inch, and 96 px per inch
pub fn pt_to_px(f: float) -> float {
    f / 72f * 96f
}

// assumes 72 points per inch, and 96 px per inch
pub fn px_to_pt(f: float) -> float {
    f / 96f * 72f
}

pub fn zero_rect() -> Rect<Au> {
    let z = Au(0);
    Rect(Point2D(z, z), Size2D(z, z))
}

pub fn zero_point() -> Point2D<Au> {
    Point2D(Au(0), Au(0))
}

pub fn zero_size() -> Size2D<Au> {
    Size2D(Au(0), Au(0))
}

pub fn from_frac_px(f: float) -> Au {
    Au((f * 60f) as i32)
}

pub fn from_px(i: int) -> Au {
    NumCast::from(i * 60)
}

pub fn to_px(au: Au) -> int {
    (*au / 60) as int
}

pub fn to_frac_px(au: Au) -> float {
    (*au as float) / 60f
}

// assumes 72 points per inch, and 96 px per inch
pub fn from_pt(f: float) -> Au {
    from_px((f / 72f * 96f) as int)
}
<commit_msg>Rename geomerty argument`s name<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;

use std::num::{NumCast, One, Zero};

#[deriving(Clone,Eq)]
pub struct Au(i32);

impl Add<Au,Au> for Au {
    fn add(&self, other: &Au) -> Au { Au(**self + **other) }
}

impl Sub<Au,Au> for Au {
    fn sub(&self, other: &Au) -> Au { Au(**self - **other) }
}

impl Mul<Au,Au> for Au {
    fn mul(&self, other: &Au) -> Au { Au(**self * **other) }
}

impl Div<Au,Au> for Au {
    fn div(&self, other: &Au) -> Au { Au(**self / **other) }
}

impl Rem<Au,Au> for Au {
    fn rem(&self, other: &Au) -> Au { Au(**self % **other) }
}

impl Neg<Au> for Au {
    fn neg(&self) -> Au { Au(-**self) }
}

impl Ord for Au {
    fn lt(&self, other: &Au) -> bool { **self <  **other }
    fn le(&self, other: &Au) -> bool { **self <= **other }
    fn ge(&self, other: &Au) -> bool { **self >= **other }
    fn gt(&self, other: &Au) -> bool { **self >  **other }
}

impl One for Au {
    fn one() -> Au { Au(1) }
}

impl Zero for Au {
    fn zero() -> Au { Au(0) }
    fn is_zero(&self) -> bool { **self == 0 }
}

impl Num for Au {}

pub fn min(x: Au, y: Au) -> Au { if x < y { x } else { y } }
pub fn max(x: Au, y: Au) -> Au { if x > y { x } else { y } }

impl NumCast for Au {
    fn from<T:NumCast>(n: T) -> Au { Au(n.to_i32()) }

    fn to_u8(&self) -> u8       { (**self).to_u8() }
    fn to_u16(&self) -> u16     { (**self).to_u16() }
    fn to_u32(&self) -> u32     { (**self).to_u32() }
    fn to_u64(&self) -> u64     { (**self).to_u64() }
    fn to_uint(&self) -> uint   { (**self).to_uint() }

    fn to_i8(&self) -> i8       { (**self).to_i8() }
    fn to_i16(&self) -> i16     { (**self).to_i16() }
    fn to_i32(&self) -> i32     { (**self).to_i32() }
    fn to_i64(&self) -> i64     { (**self).to_i64() }
    fn to_int(&self) -> int     { (**self).to_int() }

    fn to_f32(&self) -> f32     { (**self).to_f32() }
    fn to_f64(&self) -> f64     { (**self).to_f64() }
    fn to_float(&self) -> float { (**self).to_float() }
}

pub fn box<T:Clone + Ord + Add<T,T> + Sub<T,T>>(x: T, y: T, w: T, h: T) -> Rect<T> {
    Rect(Point2D(x, y), Size2D(w, h))
}

impl Au {
    pub fn scale_by(self, factor: float) -> Au {
        Au(((*self as float) * factor) as i32)
    }

    pub fn from_px(px: int) -> Au {
        NumCast::from(px * 60)
    }

    pub fn to_px(&self) -> int {
        (**self / 60) as int
    }

    pub fn to_snapped(&self) -> Au {
        let res = **self % 60i32;
        return if res >= 30i32 { return Au(**self - res + 60i32) }
                       else { return Au(**self - res) };
    }

    pub fn zero_point() -> Point2D<Au> {
        Point2D(Au(0), Au(0))
    }

    pub fn zero_rect() -> Rect<Au> {
        let z = Au(0);
        Rect(Point2D(z, z), Size2D(z, z))
    }

    pub fn from_pt(pt: float) -> Au {
        from_px(pt_to_px(pt) as int)
    }

    pub fn from_frac_px(px: float) -> Au {
        Au((px * 60f) as i32)
    }

    pub fn min(x: Au, y: Au) -> Au { if *x < *y { x } else { y } }
    pub fn max(x: Au, y: Au) -> Au { if *x > *y { x } else { y } }
}

// assumes 72 points per inch, and 96 px per inch
pub fn pt_to_px(pt: float) -> float {
    pt / 72f * 96f
}

// assumes 72 points per inch, and 96 px per inch
pub fn px_to_pt(px: float) -> float {
    px / 96f * 72f
}

pub fn zero_rect() -> Rect<Au> {
    let z = Au(0);
    Rect(Point2D(z, z), Size2D(z, z))
}

pub fn zero_point() -> Point2D<Au> {
    Point2D(Au(0), Au(0))
}

pub fn zero_size() -> Size2D<Au> {
    Size2D(Au(0), Au(0))
}

pub fn from_frac_px(px: float) -> Au {
    Au((px * 60f) as i32)
}

pub fn from_px(px: int) -> Au {
    NumCast::from(px * 60)
}

pub fn to_px(au: Au) -> int {
    (*au / 60) as int
}

pub fn to_frac_px(au: Au) -> float {
    (*au as float) / 60f
}

// assumes 72 points per inch, and 96 px per inch
pub fn from_pt(pt: float) -> Au {
    from_px((pt / 72f * 96f) as int)
}
<|endoftext|>


<commit_before>#![allow(clippy::redundant_clone)]
#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]

use std::thread;
use tokio::runtime::Runtime;
use tokio::sync::mpsc;
use tokio::sync::mpsc::error::{TryRecvError, TrySendError};
use tokio_test::task;
use tokio_test::{
    assert_err, assert_ok, assert_pending, assert_ready, assert_ready_err, assert_ready_ok,
};

use std::sync::Arc;

trait AssertSend: Send {}
impl AssertSend for mpsc::Sender<i32> {}
impl AssertSend for mpsc::Receiver<i32> {}

#[tokio::test]
async fn send_recv_with_buffer() {
    let (tx, mut rx) = mpsc::channel::<i32>(16);

    // Using poll_ready / try_send
    // let permit assert_ready_ok!(tx.reserve());
    let permit = tx.reserve().await.unwrap();
    permit.send(1);

    // Without poll_ready
    tx.try_send(2).unwrap();

    drop(tx);

    let val = rx.recv().await;
    assert_eq!(val, Some(1));

    let val = rx.recv().await;
    assert_eq!(val, Some(2));

    let val = rx.recv().await;
    assert!(val.is_none());
}

#[tokio::test]
async fn reserve_disarm() {
    let (tx, mut rx) = mpsc::channel::<i32>(2);
    let tx1 = tx.clone();
    let tx2 = tx.clone();
    let tx3 = tx.clone();
    let tx4 = tx;

    // We should be able to `poll_ready` two handles without problem
    let permit1 = assert_ok!(tx1.reserve().await);
    let permit2 = assert_ok!(tx2.reserve().await);

    // But a third should not be ready
    let mut r3 = task::spawn(tx3.reserve());
    assert_pending!(r3.poll());

    let mut r4 = task::spawn(tx4.reserve());
    assert_pending!(r4.poll());

    // Using one of the reserved slots should allow a new handle to become ready
    permit1.send(1);

    // We also need to receive for the slot to be free
    assert!(!r3.is_woken());
    rx.recv().await.unwrap();
    // Now there's a free slot!
    assert!(r3.is_woken());
    assert!(!r4.is_woken());

    // Dropping a permit should also open up a slot
    drop(permit2);
    assert!(r4.is_woken());

    let mut r1 = task::spawn(tx1.reserve());
    assert_pending!(r1.poll());
}

#[tokio::test]
async fn send_recv_stream_with_buffer() {
    use tokio::stream::StreamExt;

    let (tx, mut rx) = mpsc::channel::<i32>(16);

    tokio::spawn(async move {
        assert_ok!(tx.send(1).await);
        assert_ok!(tx.send(2).await);
    });

    assert_eq!(Some(1), rx.next().await);
    assert_eq!(Some(2), rx.next().await);
    assert_eq!(None, rx.next().await);
}

#[tokio::test]
async fn async_send_recv_with_buffer() {
    let (tx, mut rx) = mpsc::channel(16);

    tokio::spawn(async move {
        assert_ok!(tx.send(1).await);
        assert_ok!(tx.send(2).await);
    });

    assert_eq!(Some(1), rx.recv().await);
    assert_eq!(Some(2), rx.recv().await);
    assert_eq!(None, rx.recv().await);
}

#[tokio::test]
async fn start_send_past_cap() {
    use std::future::Future;

    let mut t1 = task::spawn(());

    let (tx1, mut rx) = mpsc::channel(1);
    let tx2 = tx1.clone();

    assert_ok!(tx1.try_send(()));

    let mut r1 = Box::pin(tx1.reserve());
    t1.enter(|cx, _| assert_pending!(r1.as_mut().poll(cx)));

    {
        let mut r2 = task::spawn(tx2.reserve());
        assert_pending!(r2.poll());

        drop(r1);

        assert!(rx.recv().await.is_some());

        assert!(r2.is_woken());
        assert!(!t1.is_woken());
    }

    drop(tx1);
    drop(tx2);

    assert!(rx.recv().await.is_none());
}

#[test]
#[should_panic]
fn buffer_gteq_one() {
    mpsc::channel::<i32>(0);
}

#[tokio::test]
async fn send_recv_unbounded() {
    let (tx, mut rx) = mpsc::unbounded_channel::<i32>();

    // Using `try_send`
    assert_ok!(tx.send(1));
    assert_ok!(tx.send(2));

    assert_eq!(rx.recv().await, Some(1));
    assert_eq!(rx.recv().await, Some(2));

    drop(tx);

    assert!(rx.recv().await.is_none());
}

#[tokio::test]
async fn async_send_recv_unbounded() {
    let (tx, mut rx) = mpsc::unbounded_channel();

    tokio::spawn(async move {
        assert_ok!(tx.send(1));
        assert_ok!(tx.send(2));
    });

    assert_eq!(Some(1), rx.recv().await);
    assert_eq!(Some(2), rx.recv().await);
    assert_eq!(None, rx.recv().await);
}

#[tokio::test]
async fn send_recv_stream_unbounded() {
    use tokio::stream::StreamExt;

    let (tx, mut rx) = mpsc::unbounded_channel::<i32>();

    tokio::spawn(async move {
        assert_ok!(tx.send(1));
        assert_ok!(tx.send(2));
    });

    assert_eq!(Some(1), rx.next().await);
    assert_eq!(Some(2), rx.next().await);
    assert_eq!(None, rx.next().await);
}

#[tokio::test]
async fn no_t_bounds_buffer() {
    struct NoImpls;

    let (tx, mut rx) = mpsc::channel(100);

    // sender should be Debug even though T isn't Debug
    println!("{:?}", tx);
    // same with Receiver
    println!("{:?}", rx);
    // and sender should be Clone even though T isn't Clone
    assert!(tx.clone().try_send(NoImpls).is_ok());

    assert!(rx.recv().await.is_some());
}

#[tokio::test]
async fn no_t_bounds_unbounded() {
    struct NoImpls;

    let (tx, mut rx) = mpsc::unbounded_channel();

    // sender should be Debug even though T isn't Debug
    println!("{:?}", tx);
    // same with Receiver
    println!("{:?}", rx);
    // and sender should be Clone even though T isn't Clone
    assert!(tx.clone().send(NoImpls).is_ok());

    assert!(rx.recv().await.is_some());
}

#[tokio::test]
async fn send_recv_buffer_limited() {
    let (tx, mut rx) = mpsc::channel::<i32>(1);

    // Reserve capacity
    let p1 = assert_ok!(tx.reserve().await);

    // Send first message
    p1.send(1);

    // Not ready
    let mut p2 = task::spawn(tx.reserve());
    assert_pending!(p2.poll());

    // Take the value
    assert!(rx.recv().await.is_some());

    // Notified
    assert!(p2.is_woken());

    // Trying to send fails
    assert_err!(tx.try_send(1337));

    // Send second
    let permit = assert_ready_ok!(p2.poll());
    permit.send(2);

    assert!(rx.recv().await.is_some());
}

#[tokio::test]
async fn recv_close_gets_none_idle() {
    let (tx, mut rx) = mpsc::channel::<i32>(10);

    rx.close();

    assert!(rx.recv().await.is_none());

    assert_err!(tx.send(1).await);
}

#[tokio::test]
async fn recv_close_gets_none_reserved() {
    let (tx1, mut rx) = mpsc::channel::<i32>(1);
    let tx2 = tx1.clone();

    let permit1 = assert_ok!(tx1.reserve().await);
    let mut permit2 = task::spawn(tx2.reserve());
    assert_pending!(permit2.poll());

    rx.close();

    assert!(permit2.is_woken());
    assert_ready_err!(permit2.poll());

    {
        let mut recv = task::spawn(rx.recv());
        assert_pending!(recv.poll());

        permit1.send(123);
        assert!(recv.is_woken());

        let v = assert_ready!(recv.poll());
        assert_eq!(v, Some(123));
    }

    assert!(rx.recv().await.is_none());
}

#[tokio::test]
async fn tx_close_gets_none() {
    let (_, mut rx) = mpsc::channel::<i32>(10);
    assert!(rx.recv().await.is_none());
}

#[tokio::test]
async fn try_send_fail() {
    let (tx, mut rx) = mpsc::channel(1);

    tx.try_send("hello").unwrap();

    // This should fail
    match assert_err!(tx.try_send("fail")) {
        TrySendError::Full(..) => {}
        _ => panic!(),
    }

    assert_eq!(rx.recv().await, Some("hello"));

    assert_ok!(tx.try_send("goodbye"));
    drop(tx);

    assert_eq!(rx.recv().await, Some("goodbye"));
    assert!(rx.recv().await.is_none());
}

#[tokio::test]
async fn drop_permit_releases_permit() {
    // poll_ready reserves capacity, ensure that the capacity is released if tx
    // is dropped w/o sending a value.
    let (tx1, _rx) = mpsc::channel::<i32>(1);
    let tx2 = tx1.clone();

    let permit = assert_ok!(tx1.reserve().await);

    let mut reserve2 = task::spawn(tx2.reserve());
    assert_pending!(reserve2.poll());

    drop(permit);

    assert!(reserve2.is_woken());
    assert_ready_ok!(reserve2.poll());
}

#[tokio::test]
async fn dropping_rx_closes_channel() {
    let (tx, rx) = mpsc::channel(100);

    let msg = Arc::new(());
    assert_ok!(tx.try_send(msg.clone()));

    drop(rx);
    assert_err!(tx.reserve().await);
    assert_eq!(1, Arc::strong_count(&msg));
}

#[test]
fn dropping_rx_closes_channel_for_try() {
    let (tx, rx) = mpsc::channel(100);

    let msg = Arc::new(());
    tx.try_send(msg.clone()).unwrap();

    drop(rx);

    {
        let err = assert_err!(tx.try_send(msg.clone()));
        match err {
            TrySendError::Closed(..) => {}
            _ => panic!(),
        }
    }

    assert_eq!(1, Arc::strong_count(&msg));
}

#[test]
fn unconsumed_messages_are_dropped() {
    let msg = Arc::new(());

    let (tx, rx) = mpsc::channel(100);

    tx.try_send(msg.clone()).unwrap();

    assert_eq!(2, Arc::strong_count(&msg));

    drop((tx, rx));

    assert_eq!(1, Arc::strong_count(&msg));
}

#[test]
fn try_recv() {
    let (tx, mut rx) = mpsc::channel(1);
    match rx.try_recv() {
        Err(TryRecvError::Empty) => {}
        _ => panic!(),
    }
    tx.try_send(42).unwrap();
    match rx.try_recv() {
        Ok(42) => {}
        _ => panic!(),
    }
    drop(tx);
    match rx.try_recv() {
        Err(TryRecvError::Closed) => {}
        _ => panic!(),
    }
}

#[test]
fn try_recv_unbounded() {
    let (tx, mut rx) = mpsc::unbounded_channel();
    match rx.try_recv() {
        Err(TryRecvError::Empty) => {}
        _ => panic!(),
    }
    tx.send(42).unwrap();
    match rx.try_recv() {
        Ok(42) => {}
        _ => panic!(),
    }
    drop(tx);
    match rx.try_recv() {
        Err(TryRecvError::Closed) => {}
        _ => panic!(),
    }
}

#[test]
fn blocking_recv() {
    let (tx, mut rx) = mpsc::channel::<u8>(1);

    let sync_code = thread::spawn(move || {
        assert_eq!(Some(10), rx.blocking_recv());
    });

    Runtime::new().unwrap().block_on(async move {
        let _ = tx.send(10).await;
    });
    sync_code.join().unwrap()
}

#[tokio::test]
#[should_panic]
async fn blocking_recv_async() {
    let (_tx, mut rx) = mpsc::channel::<()>(1);
    let _ = rx.blocking_recv();
}

#[test]
fn blocking_send() {
    let (tx, mut rx) = mpsc::channel::<u8>(1);

    let sync_code = thread::spawn(move || {
        tx.blocking_send(10).unwrap();
    });

    Runtime::new().unwrap().block_on(async move {
        assert_eq!(Some(10), rx.recv().await);
    });
    sync_code.join().unwrap()
}

#[tokio::test]
#[should_panic]
async fn blocking_send_async() {
    let (tx, _rx) = mpsc::channel::<()>(1);
    let _ = tx.blocking_send(());
}

#[tokio::test]
async fn ready_close_cancel_bounded() {
    let (tx, mut rx) = mpsc::channel::<()>(100);
    let _tx2 = tx.clone();

    let permit = assert_ok!(tx.reserve().await);

    rx.close();

    let mut recv = task::spawn(rx.recv());
    assert_pending!(recv.poll());

    drop(permit);

    assert!(recv.is_woken());
    let val = assert_ready!(recv.poll());
    assert!(val.is_none());
}
<commit_msg>sync: forward port 0.2 mpsc test (#3225)<commit_after>#![allow(clippy::redundant_clone)]
#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]

use std::thread;
use tokio::runtime::Runtime;
use tokio::sync::mpsc;
use tokio::sync::mpsc::error::{TryRecvError, TrySendError};
use tokio_test::task;
use tokio_test::{
    assert_err, assert_ok, assert_pending, assert_ready, assert_ready_err, assert_ready_ok,
};

use std::sync::Arc;

trait AssertSend: Send {}
impl AssertSend for mpsc::Sender<i32> {}
impl AssertSend for mpsc::Receiver<i32> {}

#[tokio::test]
async fn send_recv_with_buffer() {
    let (tx, mut rx) = mpsc::channel::<i32>(16);

    // Using poll_ready / try_send
    // let permit assert_ready_ok!(tx.reserve());
    let permit = tx.reserve().await.unwrap();
    permit.send(1);

    // Without poll_ready
    tx.try_send(2).unwrap();

    drop(tx);

    let val = rx.recv().await;
    assert_eq!(val, Some(1));

    let val = rx.recv().await;
    assert_eq!(val, Some(2));

    let val = rx.recv().await;
    assert!(val.is_none());
}

#[tokio::test]
async fn reserve_disarm() {
    let (tx, mut rx) = mpsc::channel::<i32>(2);
    let tx1 = tx.clone();
    let tx2 = tx.clone();
    let tx3 = tx.clone();
    let tx4 = tx;

    // We should be able to `poll_ready` two handles without problem
    let permit1 = assert_ok!(tx1.reserve().await);
    let permit2 = assert_ok!(tx2.reserve().await);

    // But a third should not be ready
    let mut r3 = task::spawn(tx3.reserve());
    assert_pending!(r3.poll());

    let mut r4 = task::spawn(tx4.reserve());
    assert_pending!(r4.poll());

    // Using one of the reserved slots should allow a new handle to become ready
    permit1.send(1);

    // We also need to receive for the slot to be free
    assert!(!r3.is_woken());
    rx.recv().await.unwrap();
    // Now there's a free slot!
    assert!(r3.is_woken());
    assert!(!r4.is_woken());

    // Dropping a permit should also open up a slot
    drop(permit2);
    assert!(r4.is_woken());

    let mut r1 = task::spawn(tx1.reserve());
    assert_pending!(r1.poll());
}

#[tokio::test]
async fn send_recv_stream_with_buffer() {
    use tokio::stream::StreamExt;

    let (tx, mut rx) = mpsc::channel::<i32>(16);

    tokio::spawn(async move {
        assert_ok!(tx.send(1).await);
        assert_ok!(tx.send(2).await);
    });

    assert_eq!(Some(1), rx.next().await);
    assert_eq!(Some(2), rx.next().await);
    assert_eq!(None, rx.next().await);
}

#[tokio::test]
async fn async_send_recv_with_buffer() {
    let (tx, mut rx) = mpsc::channel(16);

    tokio::spawn(async move {
        assert_ok!(tx.send(1).await);
        assert_ok!(tx.send(2).await);
    });

    assert_eq!(Some(1), rx.recv().await);
    assert_eq!(Some(2), rx.recv().await);
    assert_eq!(None, rx.recv().await);
}

#[tokio::test]
async fn start_send_past_cap() {
    use std::future::Future;

    let mut t1 = task::spawn(());

    let (tx1, mut rx) = mpsc::channel(1);
    let tx2 = tx1.clone();

    assert_ok!(tx1.try_send(()));

    let mut r1 = Box::pin(tx1.reserve());
    t1.enter(|cx, _| assert_pending!(r1.as_mut().poll(cx)));

    {
        let mut r2 = task::spawn(tx2.reserve());
        assert_pending!(r2.poll());

        drop(r1);

        assert!(rx.recv().await.is_some());

        assert!(r2.is_woken());
        assert!(!t1.is_woken());
    }

    drop(tx1);
    drop(tx2);

    assert!(rx.recv().await.is_none());
}

#[test]
#[should_panic]
fn buffer_gteq_one() {
    mpsc::channel::<i32>(0);
}

#[tokio::test]
async fn send_recv_unbounded() {
    let (tx, mut rx) = mpsc::unbounded_channel::<i32>();

    // Using `try_send`
    assert_ok!(tx.send(1));
    assert_ok!(tx.send(2));

    assert_eq!(rx.recv().await, Some(1));
    assert_eq!(rx.recv().await, Some(2));

    drop(tx);

    assert!(rx.recv().await.is_none());
}

#[tokio::test]
async fn async_send_recv_unbounded() {
    let (tx, mut rx) = mpsc::unbounded_channel();

    tokio::spawn(async move {
        assert_ok!(tx.send(1));
        assert_ok!(tx.send(2));
    });

    assert_eq!(Some(1), rx.recv().await);
    assert_eq!(Some(2), rx.recv().await);
    assert_eq!(None, rx.recv().await);
}

#[tokio::test]
async fn send_recv_stream_unbounded() {
    use tokio::stream::StreamExt;

    let (tx, mut rx) = mpsc::unbounded_channel::<i32>();

    tokio::spawn(async move {
        assert_ok!(tx.send(1));
        assert_ok!(tx.send(2));
    });

    assert_eq!(Some(1), rx.next().await);
    assert_eq!(Some(2), rx.next().await);
    assert_eq!(None, rx.next().await);
}

#[tokio::test]
async fn no_t_bounds_buffer() {
    struct NoImpls;

    let (tx, mut rx) = mpsc::channel(100);

    // sender should be Debug even though T isn't Debug
    println!("{:?}", tx);
    // same with Receiver
    println!("{:?}", rx);
    // and sender should be Clone even though T isn't Clone
    assert!(tx.clone().try_send(NoImpls).is_ok());

    assert!(rx.recv().await.is_some());
}

#[tokio::test]
async fn no_t_bounds_unbounded() {
    struct NoImpls;

    let (tx, mut rx) = mpsc::unbounded_channel();

    // sender should be Debug even though T isn't Debug
    println!("{:?}", tx);
    // same with Receiver
    println!("{:?}", rx);
    // and sender should be Clone even though T isn't Clone
    assert!(tx.clone().send(NoImpls).is_ok());

    assert!(rx.recv().await.is_some());
}

#[tokio::test]
async fn send_recv_buffer_limited() {
    let (tx, mut rx) = mpsc::channel::<i32>(1);

    // Reserve capacity
    let p1 = assert_ok!(tx.reserve().await);

    // Send first message
    p1.send(1);

    // Not ready
    let mut p2 = task::spawn(tx.reserve());
    assert_pending!(p2.poll());

    // Take the value
    assert!(rx.recv().await.is_some());

    // Notified
    assert!(p2.is_woken());

    // Trying to send fails
    assert_err!(tx.try_send(1337));

    // Send second
    let permit = assert_ready_ok!(p2.poll());
    permit.send(2);

    assert!(rx.recv().await.is_some());
}

#[tokio::test]
async fn recv_close_gets_none_idle() {
    let (tx, mut rx) = mpsc::channel::<i32>(10);

    rx.close();

    assert!(rx.recv().await.is_none());

    assert_err!(tx.send(1).await);
}

#[tokio::test]
async fn recv_close_gets_none_reserved() {
    let (tx1, mut rx) = mpsc::channel::<i32>(1);
    let tx2 = tx1.clone();

    let permit1 = assert_ok!(tx1.reserve().await);
    let mut permit2 = task::spawn(tx2.reserve());
    assert_pending!(permit2.poll());

    rx.close();

    assert!(permit2.is_woken());
    assert_ready_err!(permit2.poll());

    {
        let mut recv = task::spawn(rx.recv());
        assert_pending!(recv.poll());

        permit1.send(123);
        assert!(recv.is_woken());

        let v = assert_ready!(recv.poll());
        assert_eq!(v, Some(123));
    }

    assert!(rx.recv().await.is_none());
}

#[tokio::test]
async fn tx_close_gets_none() {
    let (_, mut rx) = mpsc::channel::<i32>(10);
    assert!(rx.recv().await.is_none());
}

#[tokio::test]
async fn try_send_fail() {
    let (tx, mut rx) = mpsc::channel(1);

    tx.try_send("hello").unwrap();

    // This should fail
    match assert_err!(tx.try_send("fail")) {
        TrySendError::Full(..) => {}
        _ => panic!(),
    }

    assert_eq!(rx.recv().await, Some("hello"));

    assert_ok!(tx.try_send("goodbye"));
    drop(tx);

    assert_eq!(rx.recv().await, Some("goodbye"));
    assert!(rx.recv().await.is_none());
}

#[tokio::test]
async fn drop_permit_releases_permit() {
    // poll_ready reserves capacity, ensure that the capacity is released if tx
    // is dropped w/o sending a value.
    let (tx1, _rx) = mpsc::channel::<i32>(1);
    let tx2 = tx1.clone();

    let permit = assert_ok!(tx1.reserve().await);

    let mut reserve2 = task::spawn(tx2.reserve());
    assert_pending!(reserve2.poll());

    drop(permit);

    assert!(reserve2.is_woken());
    assert_ready_ok!(reserve2.poll());
}

#[tokio::test]
async fn dropping_rx_closes_channel() {
    let (tx, rx) = mpsc::channel(100);

    let msg = Arc::new(());
    assert_ok!(tx.try_send(msg.clone()));

    drop(rx);
    assert_err!(tx.reserve().await);
    assert_eq!(1, Arc::strong_count(&msg));
}

#[test]
fn dropping_rx_closes_channel_for_try() {
    let (tx, rx) = mpsc::channel(100);

    let msg = Arc::new(());
    tx.try_send(msg.clone()).unwrap();

    drop(rx);

    {
        let err = assert_err!(tx.try_send(msg.clone()));
        match err {
            TrySendError::Closed(..) => {}
            _ => panic!(),
        }
    }

    assert_eq!(1, Arc::strong_count(&msg));
}

#[test]
fn unconsumed_messages_are_dropped() {
    let msg = Arc::new(());

    let (tx, rx) = mpsc::channel(100);

    tx.try_send(msg.clone()).unwrap();

    assert_eq!(2, Arc::strong_count(&msg));

    drop((tx, rx));

    assert_eq!(1, Arc::strong_count(&msg));
}

#[test]
fn try_recv() {
    let (tx, mut rx) = mpsc::channel(1);
    match rx.try_recv() {
        Err(TryRecvError::Empty) => {}
        _ => panic!(),
    }
    tx.try_send(42).unwrap();
    match rx.try_recv() {
        Ok(42) => {}
        _ => panic!(),
    }
    drop(tx);
    match rx.try_recv() {
        Err(TryRecvError::Closed) => {}
        _ => panic!(),
    }
}

#[test]
fn try_recv_unbounded() {
    let (tx, mut rx) = mpsc::unbounded_channel();
    match rx.try_recv() {
        Err(TryRecvError::Empty) => {}
        _ => panic!(),
    }
    tx.send(42).unwrap();
    match rx.try_recv() {
        Ok(42) => {}
        _ => panic!(),
    }
    drop(tx);
    match rx.try_recv() {
        Err(TryRecvError::Closed) => {}
        _ => panic!(),
    }
}

#[test]
fn blocking_recv() {
    let (tx, mut rx) = mpsc::channel::<u8>(1);

    let sync_code = thread::spawn(move || {
        assert_eq!(Some(10), rx.blocking_recv());
    });

    Runtime::new().unwrap().block_on(async move {
        let _ = tx.send(10).await;
    });
    sync_code.join().unwrap()
}

#[tokio::test]
#[should_panic]
async fn blocking_recv_async() {
    let (_tx, mut rx) = mpsc::channel::<()>(1);
    let _ = rx.blocking_recv();
}

#[test]
fn blocking_send() {
    let (tx, mut rx) = mpsc::channel::<u8>(1);

    let sync_code = thread::spawn(move || {
        tx.blocking_send(10).unwrap();
    });

    Runtime::new().unwrap().block_on(async move {
        assert_eq!(Some(10), rx.recv().await);
    });
    sync_code.join().unwrap()
}

#[tokio::test]
#[should_panic]
async fn blocking_send_async() {
    let (tx, _rx) = mpsc::channel::<()>(1);
    let _ = tx.blocking_send(());
}

#[tokio::test]
async fn ready_close_cancel_bounded() {
    let (tx, mut rx) = mpsc::channel::<()>(100);
    let _tx2 = tx.clone();

    let permit = assert_ok!(tx.reserve().await);

    rx.close();

    let mut recv = task::spawn(rx.recv());
    assert_pending!(recv.poll());

    drop(permit);

    assert!(recv.is_woken());
    let val = assert_ready!(recv.poll());
    assert!(val.is_none());
}

#[tokio::test]
async fn permit_available_not_acquired_close() {
    let (tx1, mut rx) = mpsc::channel::<()>(1);
    let tx2 = tx1.clone();

    let permit1 = assert_ok!(tx1.reserve().await);

    let mut permit2 = task::spawn(tx2.reserve());
    assert_pending!(permit2.poll());

    rx.close();

    drop(permit1);
    assert!(permit2.is_woken());

    drop(permit2);
    assert!(rx.recv().await.is_none());
}
<|endoftext|>


<commit_before>extern crate crowbook_localize;
use crowbook_localize::{Localizer, Extractor};

use std::path::Path;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=lang/fr.po");
    let mut extractor = Extractor::new();
    extractor.add_messages_from_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/src")).unwrap();
    extractor.write_pot_file(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/crowbook.pot")).unwrap();

    let mut localizer = Localizer::new(&extractor);
    localizer.add_lang("fr", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/fr.po"))).unwrap();
    let dest_path = Path::new(env!("OUT_DIR")).join("hello.rs");
    localizer.write_macro_file(dest_path.to_str().unwrap()).unwrap();
}
<commit_msg>Fix build.rs<commit_after>extern crate crowbook_localize;
use crowbook_localize::{Localizer, Extractor};

use std::path::Path;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=lang/fr.po");
    let mut extractor = Extractor::new();
    extractor.add_messages_from_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/src")).unwrap();
    extractor.write_pot_file(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/crowbook.pot")).unwrap();

    let mut localizer = Localizer::new(&extractor);
    localizer.add_lang("fr", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/fr.po"))).unwrap();
    let dest_path = Path::new(env!("OUT_DIR")).join("localize_macros.rs");
    localizer.write_macro_file(dest_path.to_str().unwrap()).unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate openssl;

use openssl::asn1;
use openssl::ec;
use openssl::nid::Nid;
use openssl::pkey::PKey;
use openssl::x509;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    println!("cargo:rerun-if-changed=crypto_data/opensk.key");
    println!("cargo:rerun-if-changed=crypto_data/opensk_cert.pem");

    let out_dir = env::var_os("OUT_DIR").unwrap();
    let priv_key_bin_path = Path::new(&out_dir).join("opensk_pkey.bin");
    let cert_bin_path = Path::new(&out_dir).join("opensk_cert.bin");
    let aaguid_bin_path = Path::new(&out_dir).join("opensk_aaguid.bin");

    // Load the OpenSSL PEM ECC key
    let ecc_data = include_bytes!("crypto_data/opensk.key");
    let pkey = ec::EcKey::private_key_from_pem(ecc_data)
        .ok()
        .expect("Failed to load OpenSK private key file");

    // Check key validity
    pkey.check_key().unwrap();
    assert_eq!(pkey.group().curve_name(), Some(Nid::X9_62_PRIME256V1));

    // Private keys generated by OpenSSL have variable size but we only handle
    // constant size. Serialization is done in big endian so if the size is less
    // than 32 bytes, we need to prepend with null bytes.
    // If the size is 33 bytes, this means the serialized BigInt is negative.
    // Any other size is invalid.
    let priv_key_hex = pkey.private_key().to_hex_str().unwrap();
    let priv_key_vec = pkey.private_key().to_vec();
    let key_len = priv_key_vec.len();

    assert!(
        key_len >= 30,
        "Invalid private key (too small): {} ({:#?})",
        priv_key_hex,
        priv_key_vec,
    );
    assert!(
        key_len <= 33,
        "Invalid private key (too big): {} ({:#?})",
        priv_key_hex,
        priv_key_vec,
    );

    // Copy OpenSSL generated key to our vec, starting from the end
    let mut output_vec = [0u8; 32];
    let min_key_len = std::cmp::min(key_len, 32);
    output_vec[32usize.saturating_sub(min_key_len)..]
        .copy_from_slice(&priv_key_vec[key_len.saturating_sub(min_key_len)..]);

    // Create the raw private key out of the OpenSSL data
    let mut priv_key_bin_file = File::create(&priv_key_bin_path).unwrap();
    priv_key_bin_file.write_all(&output_vec).unwrap();

    // Convert the PEM certificate to DER and extract the serial for AAGUID
    let input_pem_cert = include_bytes!("crypto_data/opensk_cert.pem");
    let cert = x509::X509::from_pem(input_pem_cert)
        .ok()
        .expect("Failed to load OpenSK certificate");

    // Do some sanity check on the certificate
    assert!(cert
        .public_key()
        .unwrap()
        .public_eq(&PKey::from_ec_key(pkey).unwrap()));
    let now = asn1::Asn1Time::days_from_now(0).unwrap();
    assert!(cert.not_after() > now);
    assert!(cert.not_before() <= now);

    let mut cert_bin_file = File::create(&cert_bin_path).unwrap();
    cert_bin_file.write_all(&cert.to_der().unwrap()).unwrap();

    let mut aaguid_bin_file = File::create(&aaguid_bin_path).unwrap();
    let mut serial = cert.serial_number().to_bn().unwrap().to_vec();
    serial.resize(16, 0);
    aaguid_bin_file.write_all(&serial).unwrap();
}
<commit_msg>Address comments on pull-request<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate openssl;

use openssl::asn1;
use openssl::ec;
use openssl::nid::Nid;
use openssl::pkey::PKey;
use openssl::x509;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    println!("cargo:rerun-if-changed=crypto_data/opensk.key");
    println!("cargo:rerun-if-changed=crypto_data/opensk_cert.pem");

    let out_dir = env::var_os("OUT_DIR").unwrap();
    let priv_key_bin_path = Path::new(&out_dir).join("opensk_pkey.bin");
    let cert_bin_path = Path::new(&out_dir).join("opensk_cert.bin");
    let aaguid_bin_path = Path::new(&out_dir).join("opensk_aaguid.bin");

    // Load the OpenSSL PEM ECC key
    let ecc_data = include_bytes!("crypto_data/opensk.key");
    let pkey = ec::EcKey::private_key_from_pem(ecc_data)
        .ok()
        .expect("Failed to load OpenSK private key file");

    // Check key validity
    pkey.check_key().unwrap();
    assert_eq!(pkey.group().curve_name(), Some(Nid::X9_62_PRIME256V1));

    // Private keys generated by OpenSSL have variable size but we only handle
    // constant size. Serialization is done in big endian so if the size is less
    // than 32 bytes, we need to prepend with null bytes.
    // If the size is 33 bytes, this means the serialized BigInt is negative.
    // Any other size is invalid.
    let priv_key_hex = pkey.private_key().to_hex_str().unwrap();
    let priv_key_vec = pkey.private_key().to_vec();
    let key_len = priv_key_vec.len();

    assert!(
        key_len <= 33,
        "Invalid private key (too big): {} ({:#?})",
        priv_key_hex,
        priv_key_vec,
    );

    // Copy OpenSSL generated key to our vec, starting from the end
    let mut output_vec = [0u8; 32];
    let min_key_len = std::cmp::min(key_len, 32);
    output_vec[32 - min_key_len..].copy_from_slice(&priv_key_vec[key_len - min_key_len..]);

    // Create the raw private key out of the OpenSSL data
    let mut priv_key_bin_file = File::create(&priv_key_bin_path).unwrap();
    priv_key_bin_file.write_all(&output_vec).unwrap();

    // Convert the PEM certificate to DER and extract the serial for AAGUID
    let input_pem_cert = include_bytes!("crypto_data/opensk_cert.pem");
    let cert = x509::X509::from_pem(input_pem_cert)
        .ok()
        .expect("Failed to load OpenSK certificate");

    // Do some sanity check on the certificate
    assert!(cert
        .public_key()
        .unwrap()
        .public_eq(&PKey::from_ec_key(pkey).unwrap()));
    let now = asn1::Asn1Time::days_from_now(0).unwrap();
    assert!(cert.not_after() > now);
    assert!(cert.not_before() <= now);

    let mut cert_bin_file = File::create(&cert_bin_path).unwrap();
    cert_bin_file.write_all(&cert.to_der().unwrap()).unwrap();

    let mut aaguid_bin_file = File::create(&aaguid_bin_path).unwrap();
    let mut serial = cert.serial_number().to_bn().unwrap().to_vec();
    serial.resize(16, 0);
    aaguid_bin_file.write_all(&serial).unwrap();
}
<|endoftext|>


<commit_before>extern crate pkg_config;

use std::process::Command;
use std::fs;
use std::path::Path;
use std::env;
use std::env::consts;
use std::path::PathBuf;

fn main() {
    let wcd = env::current_dir().unwrap();
    let build = PathBuf::from(&wcd.join("ext/libqmlrswrapper/build"));
    let _ = fs::create_dir_all(&build);

    /*
     * Support Qt installed via the Ports system on BSD-like systems.
     *
     * The native libs are in `/usr/local/lib`, which is not linked against by default.
     * This means that either the user or every package has to add this if they want to link
     * against something that is not part of the core distribution in `/usr/lib`.
     *
     * See https://wiki.freebsd.org/WarnerLosh/UsrLocal for the line of reasoning & how this will
     * change in the future.
     */
    if cfg!(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd",
                target_os = "dragonfly", target_os = "bitrig")) {
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    /*
     * Parameters for supporting QT on OS X
     *
     * Because QT5 conflicts with QT4 the homebrew package manager won't link
     * the QT5 package into the default search paths for libraries, to deal
     * with this we need to give pkg-config and cmake a nudge in the right
     * direction.
     */
    if cfg!(target_os = "macos") {
        // We use the QTDIR or QTDIR64 env variables to find the location of
        // Qt5. If these are not set, we use the default homebrew install
        // location.
        let qtdir_variable = match consts::ARCH {
            "x86_64" => "QTDIR64",
            _ => "QTDIR",
        };
        let mut qt5_lib_path = PathBuf::new();
        qt5_lib_path.push(env::var(qtdir_variable).unwrap_or(String::from("/usr/local/opt/qt5")));
        qt5_lib_path.push(Path::new("lib"));

        if qt5_lib_path.exists() {
            // First nudge cmake in the direction of the .cmake files added by
            // homebrew. This clobbers the existing value if present, it's
            // unlikely to be present though.
            env::set_var("CMAKE_PREFIX_PATH", qt5_lib_path.join("cmake"));

            // Nudge pkg-config in the direction of the brewed QT to ensure the
            // correct compiler flags get found for the project.
            env::set_var("PKG_CONFIG_PATH", qt5_lib_path.join("pkgconfig"));
        } else {
            panic!("QT5 was not found at the expected location ({}) please install it via homebrew, or set the {} env variable.",
                qt5_lib_path.display(), qtdir_variable);
        }
    }

    let mut myargs = vec![];
    if cfg!(windows) {
        let is_msys = env::var("MSYSTEM").is_ok();

        if is_msys {
            myargs.push("-GMSYS Makefiles");
        } else {
            myargs.push("-GVisual Studio 12 2013 Win64");
        }

        myargs.push("..");
    } else {
        myargs.push("..");
    }

    let cmake_output = Command::new("cmake").args(&myargs).current_dir(&build).output().unwrap_or_else(|e| {
        panic!("Failed to run cmake: {}", e);
    });
    let cmake_stderr = String::from_utf8(cmake_output.stderr).unwrap();
    if !cmake_stderr.is_empty() {
        panic!("cmake produced stderr: {}", cmake_stderr);
    }

    Command::new("cmake")
        .args(&vec!["--build","."])
        .current_dir(&build)
        .status().and_then(|x| Ok(x.success()) ).unwrap_or_else(|e| {
            panic!("Failed to run build: {}", e);
        });

    println!("cargo:rustc-link-lib=static=qmlrswrapper");

    if cfg!(windows) {
        println!("cargo:rustc-link-search=native={}\\system32",env::var("WINDIR").unwrap());
        println!("cargo:rustc-link-search=native={}\\Debug",build.display());
        println!("cargo:rustc-link-search=native={}\\lib",env::var("QTDIR").unwrap());

        println!("cargo:rustc-link-lib=dylib=Qt5Core");
        println!("cargo:rustc-link-lib=dylib=Qt5Gui");
        println!("cargo:rustc-link-lib=dylib=Qt5Qml");
        println!("cargo:rustc-link-lib=dylib=Qt5Quick");
    } else {
        println!("cargo:rustc-link-search=native={}{}",build.display(),if cfg!(windows) { "\\Debug" } else { "" });
        println!("cargo:rustc-link-lib=dylib=stdc++");
        pkg_config::find_library("Qt5Core Qt5Gui Qt5Qml Qt5Quick").unwrap();
    }
}
<commit_msg>Check for bad libEGL symlink in build.rs<commit_after>extern crate pkg_config;

use std::process::Command;
use std::fs;
use std::path::Path;
use std::env;
use std::env::consts;
use std::path::PathBuf;

fn main() {
    let wcd = env::current_dir().unwrap();
    let build = PathBuf::from(&wcd.join("ext/libqmlrswrapper/build"));
    let _ = fs::create_dir_all(&build);

    /*
     * Support Qt installed via the Ports system on BSD-like systems.
     *
     * The native libs are in `/usr/local/lib`, which is not linked against by default.
     * This means that either the user or every package has to add this if they want to link
     * against something that is not part of the core distribution in `/usr/lib`.
     *
     * See https://wiki.freebsd.org/WarnerLosh/UsrLocal for the line of reasoning & how this will
     * change in the future.
     */
    if cfg!(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd",
                target_os = "dragonfly", target_os = "bitrig")) {
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    /*
     * Parameters for supporting QT on OS X
     *
     * Because QT5 conflicts with QT4 the homebrew package manager won't link
     * the QT5 package into the default search paths for libraries, to deal
     * with this we need to give pkg-config and cmake a nudge in the right
     * direction.
     */
    if cfg!(target_os = "macos") {
        // We use the QTDIR or QTDIR64 env variables to find the location of
        // Qt5. If these are not set, we use the default homebrew install
        // location.
        let qtdir_variable = match consts::ARCH {
            "x86_64" => "QTDIR64",
            _ => "QTDIR",
        };
        let mut qt5_lib_path = PathBuf::new();
        qt5_lib_path.push(env::var(qtdir_variable).unwrap_or(String::from("/usr/local/opt/qt5")));
        qt5_lib_path.push(Path::new("lib"));

        if qt5_lib_path.exists() {
            // First nudge cmake in the direction of the .cmake files added by
            // homebrew. This clobbers the existing value if present, it's
            // unlikely to be present though.
            env::set_var("CMAKE_PREFIX_PATH", qt5_lib_path.join("cmake"));

            // Nudge pkg-config in the direction of the brewed QT to ensure the
            // correct compiler flags get found for the project.
            env::set_var("PKG_CONFIG_PATH", qt5_lib_path.join("pkgconfig"));
        } else {
            panic!("QT5 was not found at the expected location ({}) please install it via homebrew, or set the {} env variable.",
                qt5_lib_path.display(), qtdir_variable);
        }
    }

    let mut myargs = vec![];
    if cfg!(windows) {
        let is_msys = env::var("MSYSTEM").is_ok();

        if is_msys {
            myargs.push("-GMSYS Makefiles");
        } else {
            myargs.push("-GVisual Studio 12 2013 Win64");
        }

        myargs.push("..");
    } else {
        myargs.push("..");
    }

    let cmake_output = Command::new("cmake").args(&myargs).current_dir(&build).output().unwrap_or_else(|e| {
        panic!("Failed to run cmake: {}", e);
    });

    let cmake_stderr = String::from_utf8(cmake_output.stderr).unwrap();

    if !cmake_stderr.is_empty() {
        // Check for nvidia issue
        check_qt_egl_reference_error(cmake_stderr.clone());
        panic!("cmake produced stderr: {}", cmake_stderr);
    }

    Command::new("cmake")
        .args(&vec!["--build","."])
        .current_dir(&build)
        .status().and_then(|x| Ok(x.success()) ).unwrap_or_else(|e| {
            panic!("Failed to run build: {}", e);
        });

    println!("cargo:rustc-link-lib=static=qmlrswrapper");

    if cfg!(windows) {
        println!("cargo:rustc-link-search=native={}\\system32",env::var("WINDIR").unwrap());
        println!("cargo:rustc-link-search=native={}\\Debug",build.display());
        println!("cargo:rustc-link-search=native={}\\lib",env::var("QTDIR").unwrap());

        println!("cargo:rustc-link-lib=dylib=Qt5Core");
        println!("cargo:rustc-link-lib=dylib=Qt5Gui");
        println!("cargo:rustc-link-lib=dylib=Qt5Qml");
        println!("cargo:rustc-link-lib=dylib=Qt5Quick");
    } else {
        println!("cargo:rustc-link-search=native={}{}",build.display(),if cfg!(windows) { "\\Debug" } else { "" });
        println!("cargo:rustc-link-lib=dylib=stdc++");
        pkg_config::find_library("Qt5Core Qt5Gui Qt5Qml Qt5Quick").unwrap();
    }
}

// This function checks for a special, more confusing, case of cmake failure.
// Nvidia installer creates a faulty set of symbolic links that confuse the Qt
// compilation process, we directly check the error message rather than checking
// the library paths so we can ensure we're tracking the exact issue.
fn check_qt_egl_reference_error(err_str: String) {
    let error_preface = "The imported target \"Qt5::Gui\" references the file";
    // Check if we have both the error preface
    if err_str.contains(error_preface) &&
        // .. and we include libGL in the error message
        (err_str.contains("libEGL.so") || err_str.contains("libGL.so")) {

        println!("It appears cmake has failed to build because of a bad symlink
        to libEGL.so or libGL.so, this error typically occurs because the NVidia
        installer fails to to repair the links to existing libGL bindings --
        remove the bad symbolic link (typically located at /usr/lib64/libGL.so)
        and ensure that you have a symbolic link to an existing copy of both
        libraries .");
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::process::Command;
use std::env;

fn main() {
    let root = env::var("CARGO_MANIFEST_DIR").unwrap();

    Command::new("make").current_dir(format!("{}/htslib", root))
                        .arg("CFLAGS=-g -Wall -O2 -fPIC")
                        .arg("lib-static")
                        .status().ok().expect("Failed to build htslib");

    println!("cargo:rustc-flags=-L {}/htslib -l static=hts -l z", root);
}
<commit_msg>Properly check for build errors when building htslib.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::process::Command;
use std::env;

fn main() {
    let root = env::var("CARGO_MANIFEST_DIR").unwrap();
    if Command::new("make").current_dir(format!("{}/htslib", root))
                           .arg("CFLAGS=-g -Wall -O2 -fPIC")
                           .arg("lib-static")
                           .status().ok().expect("failed to retrieve exit status")
                           .success() != true {
        panic!("failed to build htslib");
    }

    println!("cargo:rustc-flags=-L {}/htslib -l static=hts -l z", root);
}
<|endoftext|>


<commit_before>use crate::data_access::pic_repository::PicRepository;
use crate::discord_client::CommandHandler;

pub struct PicCommand {
    pic_repository: Box<PicRepository + Send>,
}

impl PicCommand {
    pub fn new(pic_repository: Box<PicRepository + Send>) -> PicCommand {
        PicCommand { pic_repository }
    }
}

impl CommandHandler for PicCommand {
    fn process_command(
        &self,
        command: &str,
        _tennant_id: u64,
        send_message_callback: &Fn(&str) -> (),
    ) -> Result<(), Box<std::error::Error>> {
        let parameters = get_search_parameters(command);

        match self.pic_repository.get_random_picture(&parameters) {
            Ok(result) => {
                send_message_callback(&result.uri);
                Ok(())
            }
            Err(error) => {
                send_message_callback("画像を取得ができませんでした");
                Err(error)
            }
        }
    }
}

fn get_search_parameters(command: &str) -> Vec<&str> {
    let mut result: Vec<&str> = Vec::new();

    let paramaters: Vec<&str> = command.split_whitespace().collect();
    for word in paramaters.iter().skip(1) {
        result.push(word);
    }

    result
}

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

    #[test]
    fn test_get_search_parameters() {
        let empty_vec: Vec<&str> = Vec::new();
        assert_eq!(empty_vec, get_search_parameters("pic"));
        assert_eq!(
            vec!["tag1", "tag2", "tag3"],
            get_search_parameters("pic tag1 tag2 tag3")
        );
        assert_eq!(
            vec!["一番", "に", "サン"],
            get_search_parameters("pic 一番 に サン")
        );
    }
}
<commit_msg>Improve japanese text in pic command<commit_after>use crate::data_access::pic_repository::PicRepository;
use crate::discord_client::CommandHandler;

pub struct PicCommand {
    pic_repository: Box<PicRepository + Send>,
}

impl PicCommand {
    pub fn new(pic_repository: Box<PicRepository + Send>) -> PicCommand {
        PicCommand { pic_repository }
    }
}

impl CommandHandler for PicCommand {
    fn process_command(
        &self,
        command: &str,
        _tennant_id: u64,
        send_message_callback: &Fn(&str) -> (),
    ) -> Result<(), Box<std::error::Error>> {
        let parameters = get_search_parameters(command);

        match self.pic_repository.get_random_picture(&parameters) {
            Ok(result) => {
                send_message_callback(&result.uri);
                Ok(())
            }
            Err(error) => {
                send_message_callback("画像を取得できない");
                Err(error)
            }
        }
    }
}

fn get_search_parameters(command: &str) -> Vec<&str> {
    let mut result: Vec<&str> = Vec::new();

    let paramaters: Vec<&str> = command.split_whitespace().collect();
    for word in paramaters.iter().skip(1) {
        result.push(word);
    }

    result
}

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

    #[test]
    fn test_get_search_parameters() {
        let empty_vec: Vec<&str> = Vec::new();
        assert_eq!(empty_vec, get_search_parameters("pic"));
        assert_eq!(
            vec!["tag1", "tag2", "tag3"],
            get_search_parameters("pic tag1 tag2 tag3")
        );
        assert_eq!(
            vec!["一番", "に", "サン"],
            get_search_parameters("pic 一番 に サン")
        );
    }
}
<|endoftext|>


<commit_before>extern crate crypto;

use crypto::md5::Md5;
use crypto::digest::Digest;

fn find_hash(word: &str, mut start: i32) -> (char, char, i32)
{
    let mut hasher = Md5::new();
    loop {
        let num = start.to_string();
        hasher.reset();
        hasher.input_str(word);
        hasher.input_str(&num);

        let hash = hasher.result_str();
        if &hash[0..5] == "00000" {
            return (hash.chars().nth(5).unwrap(), hash.chars().nth(6).unwrap(), start);
        }

        start += 1;
    }
}

fn valid_pos(c: char) -> bool
{
    '0' <= c && c <= '7'
}

fn pos(c: char) -> i32
{
    ((c as u8) - ('0' as u8)) as i32
}

fn main() {
    let input = "cxdnnyjw";

    let mut start = 0;
    let mut password = ['-'; 8];
    let mut used = [false; 8];

    let mut found = 0;
    let mut printed = 0;

    while found < 8 {
        let (c1, c2, num) = find_hash(input, start);
        start = num + 1;

        if valid_pos(c1) {
            let p = pos(c1) as usize;
            if !used[p] {
                found += 1;
                password[p] = c2;
                used[p] = true;
            }
        }

        if printed < 8 {
            print!("{}", c1);
            printed += 1;
        }
    }

    let result: String = password.iter().cloned().collect();
    println!("\n{}", result);
}
<commit_msg>Reimplement day 5 with iterators.<commit_after>extern crate crypto;

use crypto::md5::Md5;
use crypto::digest::Digest;

fn five_zeroes(a: u8, b: u8, c: u8) -> bool
{
    (a | b | (c >> 4)) == 0
}

struct Hasher {
    index: i32,
    base: String,
    hasher: Md5,
}

impl Hasher {
    fn new(start: &str) -> Hasher { Hasher {index: 0, base: String::from(start), hasher: Md5::new() } }
}

impl Iterator for Hasher {
    type Item = String;

    fn next(&mut self) -> Option<String> {
        let mut digest = [0u8; 16];
        loop {
            let num = self.index.to_string();
            self.index += 1;
            self.hasher.reset();

            self.hasher.input_str(&self.base);
            self.hasher.input_str(&num);

            self.hasher.result(&mut digest);

            if five_zeroes(digest[0], digest[1], digest[2]) {
                return Some(self.hasher.result_str());
            }
        }
    }
}

fn valid_pos(c: char) -> bool
{
    '0' <= c && c <= '7'
}

fn pos(c: char) -> i32
{
    ((c as u8) - ('0' as u8)) as i32
}

fn main() {
    let input = "cxdnnyjw";

    let mut password = ['-'; 8];
    let mut used = [false; 8];

    let mut found = 0;
    let mut printed = 0;

    for hash in Hasher::new(input) {
        let c1 = hash.chars().nth(5).unwrap();
        let c2 = hash.chars().nth(6).unwrap();

        if valid_pos(c1) {
            let p = pos(c1) as usize;
            if !used[p] {
                found += 1;
                password[p] = c2;
                used[p] = true;

                if found >= 8 {
                    break;
                }
            }
        }

        if printed < 8 {
            print!("{}", c1);
            printed += 1;
        }
    }

    let result: String = password.iter().cloned().collect();
    println!("\n{}", result);
}
<|endoftext|>


<commit_before>//! Crate to `#include` C++ headers in your Rust code, and generate
//! idiomatic bindings using `cxx`. See [include_cpp] for details.

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{
    fs::File,
    io::Write,
    os::unix::prelude::PermissionsExt,
    path::{Path, PathBuf},
    process::Command,
};

use autocxx_engine::preprocess;
use clap::{crate_authors, crate_version, App, Arg, ArgMatches};
use indoc::indoc;
use itertools::Itertools;
use tempfile::TempDir;

static LONG_HELP: &str = indoc! {"
Command line utility to minimize autocxx bug cases.

This is a wrapper for creduce.

Example command-line:
autocxx-reduce -I my-inc-dir -h my-header -d 'generate!(\"MyClass\")' -k -- --n 64 --remove-pass pass_line_markers
"};

fn main() {
    let matches = App::new("autocxx-reduce")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Reduce a C++ test case")
        .long_about(LONG_HELP)
        .arg(
            Arg::with_name("inc")
                .short("I")
                .long("inc")
                .multiple(true)
                .number_of_values(1)
                .value_name("INCLUDE DIRS")
                .help("include path")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("define")
                .short("D")
                .long("define")
                .multiple(true)
                .number_of_values(1)
                .value_name("DEFINE")
                .help("macro definition")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("header")
                .short("h")
                .long("header")
                .multiple(true)
                .number_of_values(1)
                .required(true)
                .value_name("HEADER")
                .help("header file name")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("directive")
                .short("d")
                .long("directive")
                .multiple(true)
                .number_of_values(1)
                .value_name("DIRECTIVE")
                .help("directives to put within include_cpp!")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("problem")
                .short("p")
                .long("problem")
                .required(true)
                .value_name("PROBLEM")
                .help("problem string we're looking for")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("creduce")
                .long("creduce")
                .required(true)
                .value_name("PATH")
                .help("creduce binary location")
                .default_value("/usr/bin/creduce")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("output")
                .short("o")
                .long("output")
                .value_name("OUTPUT")
                .help("where to write minimized output")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("keep")
                .short("k")
                .long("keep-dir")
                .help("keep the temporary directory for debugging purposes"),
        )
        .arg(Arg::with_name("creduce-args").last(true).multiple(true))
        .get_matches();
    run(matches).unwrap();
}

fn run(matches: ArgMatches) -> Result<(), std::io::Error> {
    let keep_tmp = matches.is_present("keep");
    let tmp_dir = TempDir::new()?;
    let r = do_run(matches, &tmp_dir);
    if keep_tmp {
        println!(
            "Keeping temp dir created at: {}",
            tmp_dir.into_path().to_str().unwrap()
        );
    }
    r
}

fn do_run(matches: ArgMatches, tmp_dir: &TempDir) -> Result<(), std::io::Error> {
    let incs: Vec<_> = matches
        .values_of("inc")
        .unwrap_or_default()
        .map(PathBuf::from)
        .collect();
    let defs: Vec<_> = matches.values_of("define").unwrap_or_default().collect();
    let headers: Vec<_> = matches.values_of("header").unwrap_or_default().collect();
    let listing_path = tmp_dir.path().join("listing.h");
    create_concatenated_header(&headers, &listing_path)?;
    let concat_path = tmp_dir.path().join("concat.h");
    announce_progress(&format!(
        "Preprocessing {:?} to {:?}",
        listing_path, concat_path
    ));
    preprocess(&listing_path, &concat_path, &incs, &defs)?;
    let rs_path = tmp_dir.path().join("input.rs");
    let directives: Vec<_> = std::iter::once("#include \"concat.h\"\n".to_string())
        .chain(
            matches
                .values_of("directive")
                .unwrap_or_default()
                .map(|s| format!("{}\n", s)),
        )
        .collect();
    create_rs_file(&rs_path, &directives)?;
    run_sample_gen_cmd(&rs_path, &tmp_dir.path())?;
    let interestingness_test = tmp_dir.path().join("test.sh");
    create_interestingness_test(
        &interestingness_test,
        matches.value_of("problem").unwrap(),
        &rs_path,
    )?;
    run_interestingness_test(&interestingness_test);
    run_creduce(
        matches.value_of("creduce").unwrap(),
        &interestingness_test,
        &concat_path,
        matches.values_of("creduce-args").unwrap_or_default(),
    );
    let output_path = matches.value_of("output");
    match output_path {
        None => print_minimized_case(&concat_path)?,
        Some(output_path) => {
            std::fs::copy(&concat_path, &PathBuf::from(output_path))?;
        }
    };
    Ok(())
}

fn announce_progress(msg: &str) {
    println!("=== {} ===", msg);
}

fn print_minimized_case(concat_path: &Path) -> Result<(), std::io::Error> {
    announce_progress("Completed. Minimized test case:");
    let contents = std::fs::read_to_string(concat_path)?;
    println!("{}", contents);
    Ok(())
}

/// Arguments we always pass to creduce. This pass always seems to cause a crash
/// as far as I can tell, so always exclude it. It may be environment-dependent,
/// of course, but as I'm the primary user of this tool I am ruthlessly removing it.
const CREDUCE_STANDARD_ARGS: &[&str] = &["--remove-pass", "pass_line_markers"];

fn run_creduce<'a>(
    creduce_cmd: &str,
    interestingness_test: &Path,
    concat_path: &Path,
    creduce_args: impl Iterator<Item = &'a str>,
) {
    announce_progress("creduce");
    Command::new(creduce_cmd)
        .arg(interestingness_test.to_str().unwrap())
        .arg(concat_path.to_str().unwrap())
        .args(CREDUCE_STANDARD_ARGS)
        .args(creduce_args)
        .status()
        .expect("failed to creduce");
}

fn run_sample_gen_cmd(rs_file: &Path, tmp_dir: &Path) -> Result<(), std::io::Error> {
    let (gen_cmd, args) = format_gen_cmd(rs_file, tmp_dir.to_str().unwrap())?;
    let args = args.collect::<Vec<_>>();
    let args_str = args.join(" ");
    announce_progress(&format!(
        "Running sample gen cmd: {} {}",
        gen_cmd.to_str().unwrap(),
        args_str
    ));
    Command::new(gen_cmd).args(args).status()?;
    Ok(())
}

fn format_gen_cmd(
    rs_file: &Path,
    dir: &str,
) -> Result<(PathBuf, impl Iterator<Item = String>), std::io::Error> {
    let me = std::env::current_exe()?;
    let gen = me.parent().unwrap().join("autocxx-gen");
    let args = [
        "-o".to_string(),
        dir.to_string(),
        "-I".to_string(),
        dir.to_string(),
        rs_file.to_str().unwrap().to_string(),
        "--gen-rs-complete".to_string(),
    ]
    .to_vec();
    Ok((gen, args.into_iter()))
}

fn create_interestingness_test(
    test_path: &Path,
    problem: &str,
    rs_file: &Path,
) -> Result<(), std::io::Error> {
    announce_progress("Creating interestingness test");
    // Ensure we refer to the input header by relative path
    // because creduce will invoke us in some other directory with
    // a copy thereof.
    let (gen_cmd, mut args) = format_gen_cmd(rs_file, "$(pwd)")?;
    let args = args.join(" ");
    let content = format!(
        indoc! {"
        #!/bin/sh
        {} {} 2>&1 | grep \"{}\"  >/dev/null 2>&1
    "},
        gen_cmd.to_str().unwrap(),
        args,
        problem
    );
    println!("Interestingness test:\n{}", content);
    {
        let mut file = File::create(test_path)?;
        file.write_all(content.as_bytes())?;
    }

    let mut perms = std::fs::metadata(&test_path)?.permissions();
    perms.set_mode(0o700);
    std::fs::set_permissions(&test_path, perms)?;
    Ok(())
}

fn run_interestingness_test(test_path: &Path) {
    announce_progress("Running interestingness test");
    let status = Command::new(test_path).status().unwrap();
    announce_progress(&format!(
        "Have run interestingness test - result is {:?}",
        status.code()
    ));
}

fn create_rs_file(rs_path: &Path, directives: &[String]) -> Result<(), std::io::Error> {
    announce_progress("Creating Rust input file");
    let mut file = File::create(rs_path)?;
    file.write_all("use autocxx::include_cpp;\ninclude_cpp! (\n".as_bytes())?;
    for directive in directives {
        file.write_all(directive.as_bytes())?;
    }
    file.write_all(");\n".as_bytes())?;
    Ok(())
}

fn create_concatenated_header(headers: &[&str], listing_path: &Path) -> Result<(), std::io::Error> {
    announce_progress("Creating preprocessed header");
    let mut file = File::create(listing_path)?;
    for header in headers {
        file.write_all(format!("#include \"{}\"\n", header).as_bytes())?;
    }
    Ok(())
}
<commit_msg>Allow searching for bad code in reduction.<commit_after>//! Crate to `#include` C++ headers in your Rust code, and generate
//! idiomatic bindings using `cxx`. See [include_cpp] for details.

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{
    fs::File,
    io::Write,
    os::unix::prelude::PermissionsExt,
    path::{Path, PathBuf},
    process::Command,
};

use autocxx_engine::preprocess;
use clap::{crate_authors, crate_version, App, Arg, ArgMatches};
use indoc::indoc;
use itertools::Itertools;
use tempfile::TempDir;

static LONG_HELP: &str = indoc! {"
Command line utility to minimize autocxx bug cases.

This is a wrapper for creduce.

Example command-line:
autocxx-reduce -I my-inc-dir -h my-header -d 'generate!(\"MyClass\")' -k -- --n 64 --remove-pass pass_line_markers
"};

fn main() {
    let matches = App::new("autocxx-reduce")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Reduce a C++ test case")
        .long_about(LONG_HELP)
        .arg(
            Arg::with_name("inc")
                .short("I")
                .long("inc")
                .multiple(true)
                .number_of_values(1)
                .value_name("INCLUDE DIRS")
                .help("include path")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("define")
                .short("D")
                .long("define")
                .multiple(true)
                .number_of_values(1)
                .value_name("DEFINE")
                .help("macro definition")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("header")
                .short("h")
                .long("header")
                .multiple(true)
                .number_of_values(1)
                .required(true)
                .value_name("HEADER")
                .help("header file name")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("directive")
                .short("d")
                .long("directive")
                .multiple(true)
                .number_of_values(1)
                .value_name("DIRECTIVE")
                .help("directives to put within include_cpp!")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("problem")
                .short("p")
                .long("problem")
                .required(true)
                .value_name("PROBLEM")
                .help("problem string we're looking for... may be in logs, or in generated C++, or generated .rs")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("creduce")
                .long("creduce")
                .required(true)
                .value_name("PATH")
                .help("creduce binary location")
                .default_value("/usr/bin/creduce")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("output")
                .short("o")
                .long("output")
                .value_name("OUTPUT")
                .help("where to write minimized output")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("keep")
                .short("k")
                .long("keep-dir")
                .help("keep the temporary directory for debugging purposes"),
        )
        .arg(Arg::with_name("creduce-args").last(true).multiple(true))
        .get_matches();
    run(matches).unwrap();
}

fn run(matches: ArgMatches) -> Result<(), std::io::Error> {
    let keep_tmp = matches.is_present("keep");
    let tmp_dir = TempDir::new()?;
    let r = do_run(matches, &tmp_dir);
    if keep_tmp {
        println!(
            "Keeping temp dir created at: {}",
            tmp_dir.into_path().to_str().unwrap()
        );
    }
    r
}

fn do_run(matches: ArgMatches, tmp_dir: &TempDir) -> Result<(), std::io::Error> {
    let incs: Vec<_> = matches
        .values_of("inc")
        .unwrap_or_default()
        .map(PathBuf::from)
        .collect();
    let defs: Vec<_> = matches.values_of("define").unwrap_or_default().collect();
    let headers: Vec<_> = matches.values_of("header").unwrap_or_default().collect();
    let listing_path = tmp_dir.path().join("listing.h");
    create_concatenated_header(&headers, &listing_path)?;
    let concat_path = tmp_dir.path().join("concat.h");
    announce_progress(&format!(
        "Preprocessing {:?} to {:?}",
        listing_path, concat_path
    ));
    preprocess(&listing_path, &concat_path, &incs, &defs)?;
    let rs_path = tmp_dir.path().join("input.rs");
    let directives: Vec<_> = std::iter::once("#include \"concat.h\"\n".to_string())
        .chain(
            matches
                .values_of("directive")
                .unwrap_or_default()
                .map(|s| format!("{}\n", s)),
        )
        .collect();
    create_rs_file(&rs_path, &directives)?;
    run_sample_gen_cmd(&rs_path, &tmp_dir.path())?;
    let interestingness_test = tmp_dir.path().join("test.sh");
    create_interestingness_test(
        &interestingness_test,
        matches.value_of("problem").unwrap(),
        &rs_path,
    )?;
    run_interestingness_test(&interestingness_test);
    run_creduce(
        matches.value_of("creduce").unwrap(),
        &interestingness_test,
        &concat_path,
        matches.values_of("creduce-args").unwrap_or_default(),
    );
    let output_path = matches.value_of("output");
    match output_path {
        None => print_minimized_case(&concat_path)?,
        Some(output_path) => {
            std::fs::copy(&concat_path, &PathBuf::from(output_path))?;
        }
    };
    Ok(())
}

fn announce_progress(msg: &str) {
    println!("=== {} ===", msg);
}

fn print_minimized_case(concat_path: &Path) -> Result<(), std::io::Error> {
    announce_progress("Completed. Minimized test case:");
    let contents = std::fs::read_to_string(concat_path)?;
    println!("{}", contents);
    Ok(())
}

/// Arguments we always pass to creduce. This pass always seems to cause a crash
/// as far as I can tell, so always exclude it. It may be environment-dependent,
/// of course, but as I'm the primary user of this tool I am ruthlessly removing it.
const CREDUCE_STANDARD_ARGS: &[&str] = &["--remove-pass", "pass_line_markers"];

fn run_creduce<'a>(
    creduce_cmd: &str,
    interestingness_test: &Path,
    concat_path: &Path,
    creduce_args: impl Iterator<Item = &'a str>,
) {
    announce_progress("creduce");
    Command::new(creduce_cmd)
        .arg(interestingness_test.to_str().unwrap())
        .arg(concat_path.to_str().unwrap())
        .args(CREDUCE_STANDARD_ARGS)
        .args(creduce_args)
        .status()
        .expect("failed to creduce");
}

fn run_sample_gen_cmd(rs_file: &Path, tmp_dir: &Path) -> Result<(), std::io::Error> {
    let (gen_cmd, args) = format_gen_cmd(rs_file, tmp_dir.to_str().unwrap())?;
    let args = args.collect::<Vec<_>>();
    let args_str = args.join(" ");
    announce_progress(&format!(
        "Running sample gen cmd: {} {}",
        gen_cmd.to_str().unwrap(),
        args_str
    ));
    Command::new(gen_cmd).args(args).status()?;
    Ok(())
}

fn format_gen_cmd(
    rs_file: &Path,
    dir: &str,
) -> Result<(PathBuf, impl Iterator<Item = String>), std::io::Error> {
    let me = std::env::current_exe()?;
    let gen = me.parent().unwrap().join("autocxx-gen");
    let args = [
        "-o".to_string(),
        dir.to_string(),
        "-I".to_string(),
        dir.to_string(),
        rs_file.to_str().unwrap().to_string(),
        "--gen-rs-complete".to_string(),
        "--gen-cpp".to_string(),
    ]
    .to_vec();
    Ok((gen, args.into_iter()))
}

fn create_interestingness_test(
    test_path: &Path,
    problem: &str,
    rs_file: &Path,
) -> Result<(), std::io::Error> {
    announce_progress("Creating interestingness test");
    // Ensure we refer to the input header by relative path
    // because creduce will invoke us in some other directory with
    // a copy thereof.
    let (gen_cmd, mut args) = format_gen_cmd(rs_file, "$(pwd)")?;
    let args = args.join(" ");
    let content = format!(
        indoc! {"
        #!/bin/sh
        ({} {} 2>&1 && cat gen.complete.rs && cat autocxxgen.h) | grep \"{}\"  >/dev/null 2>&1
    "},
        gen_cmd.to_str().unwrap(),
        args,
        problem
    );
    println!("Interestingness test:\n{}", content);
    {
        let mut file = File::create(test_path)?;
        file.write_all(content.as_bytes())?;
    }

    let mut perms = std::fs::metadata(&test_path)?.permissions();
    perms.set_mode(0o700);
    std::fs::set_permissions(&test_path, perms)?;
    Ok(())
}

fn run_interestingness_test(test_path: &Path) {
    announce_progress("Running interestingness test");
    let status = Command::new(test_path).status().unwrap();
    announce_progress(&format!(
        "Have run interestingness test - result is {:?}",
        status.code()
    ));
}

fn create_rs_file(rs_path: &Path, directives: &[String]) -> Result<(), std::io::Error> {
    announce_progress("Creating Rust input file");
    let mut file = File::create(rs_path)?;
    file.write_all("use autocxx::include_cpp;\ninclude_cpp! (\n".as_bytes())?;
    for directive in directives {
        file.write_all(directive.as_bytes())?;
    }
    file.write_all(");\n".as_bytes())?;
    Ok(())
}

fn create_concatenated_header(headers: &[&str], listing_path: &Path) -> Result<(), std::io::Error> {
    announce_progress("Creating preprocessed header");
    let mut file = File::create(listing_path)?;
    for header in headers {
        file.write_all(format!("#include \"{}\"\n", header).as_bytes())?;
    }
    Ok(())
}
<|endoftext|>