<commit_before>use embedded_hal::spi::{self, ErrorType, SpiBus, SpiBusFlush, SpiBusRead, SpiBusWrite, SpiDevice};
use embedded_hal_nb::spi::FullDuplex;
use std::io;

use super::{Error, Spi};

impl ErrorType for Spi {
    type Error = Error;
}

impl spi::Error for Error {
    fn kind(&self) -> spi::ErrorKind {
        spi::ErrorKind::Other
    }
}

/// `Transfer<u8>` trait implementation for `embedded-hal` v1.0.0-alpha.8.
impl SpiBus<u8> for Spi {
    fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
        Spi::transfer(self, read, write)?;

        Ok(())
    }

    fn transfer_in_place(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> {
        let write_buffer = buffer.to_vec();
        self.transfer(buffer, &write_buffer)
    }
}

/// `Transfer<u8>` trait implementation for `embedded-hal` v0.2.7.
impl embedded_hal_0::blocking::spi::Transfer<u8> for Spi {
    type Error = Error;

    fn transfer<'a>(&mut self, buffer: &'a mut [u8]) -> Result<&'a [u8], Self::Error> {
        let write_buffer = buffer.to_vec();
        SpiBus::transfer(self, buffer, &write_buffer)?;
        Ok(buffer)
    }
}

/// `SpiBusWrite<u8>` trait implementation for `embedded-hal` v1.0.0-alpha.8.
impl SpiBusWrite<u8> for Spi {
    fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
        Spi::write(self, buffer)?;

        Ok(())
    }
}

/// `Write<u8>` trait implementation for `embedded-hal` v0.2.7.
impl embedded_hal_0::blocking::spi::Write<u8> for Spi {
    type Error = Error;

    fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
        SpiBusWrite::write(self, buffer)
    }
}

/// `SpiBusRead<u8>` trait implementation for `embedded-hal` v1.0.0-alpha.8.
impl SpiBusRead<u8> for Spi {
    fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> {
        Spi::read(self, buffer)?;

        Ok(())
    }
}

/// `SpiBusFlush` trait implementation for `embedded-hal` v1.0.0-alpha.8.
impl SpiBusFlush for Spi {
    fn flush(&mut self) -> Result<(), Self::Error> {
        Ok(())
    }
}

/// `FullDuplex<u8>` trait implementation for `embedded-hal` v1.0.0-alpha.8.
impl FullDuplex<u8> for Spi {
    fn read(&mut self) -> nb::Result<u8, Self::Error> {
        if let Some(last_read) = self.last_read.take() {
            Ok(last_read)
        } else {
            Err(nb::Error::WouldBlock)
        }
    }

    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
        let mut read_buffer: [u8; 1] = [0];

        Spi::transfer(self, &mut read_buffer, &[byte])?;
        self.last_read = Some(read_buffer[0]);

        Ok(())
    }
}

/// `FullDuplex<u8>` trait implementation for `embedded-hal` v0.2.7.
impl embedded_hal_0::spi::FullDuplex<u8> for Spi {
    type Error = Error;

    fn read(&mut self) -> nb::Result<u8, Self::Error> {
        FullDuplex::read(self)
    }

    fn send(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
        FullDuplex::write(self, byte)
    }
}

/// Simple implementation of [embedded_hal::spi::blocking::SpiDevice]
///
/// You only need this when using the `embedded_hal` Spi trait interface.
///
/// Slave-select is currently handled at the bus level.
/// This no-op device implementation can be used to satisfy the trait.
// TODO: The underlying crate::spi::Spi shall be split up to support proper slave-select handling here.
pub struct SimpleHalSpiDevice<B> {
    bus: B,
}

impl<B> SimpleHalSpiDevice<B> {
    pub fn new(bus: B) -> SimpleHalSpiDevice<B> {
        SimpleHalSpiDevice { bus }
    }
}

impl<B: ErrorType> SpiDevice for SimpleHalSpiDevice<B> {
    type Bus = B;

    fn transaction<R>(
        &mut self,
        f: impl FnOnce(&mut Self::Bus) -> Result<R, <Self::Bus as ErrorType>::Error>,
    ) -> Result<R, Self::Error> {
        f(&mut self.bus).map_err(|_| {
            Error::Io(io::Error::new(
                io::ErrorKind::Other,
                "SimpleHalSpiDevice transaction error",
            ))
        })
    }
}

impl<B: ErrorType> ErrorType for SimpleHalSpiDevice<B> {
    type Error = Error;
}
<commit_msg>Update documentation<commit_after>use embedded_hal::spi::{self, ErrorType, SpiBus, SpiBusFlush, SpiBusRead, SpiBusWrite, SpiDevice};
use embedded_hal_nb::spi::FullDuplex;
use std::io;

use super::{Error, Spi};

impl ErrorType for Spi {
    type Error = Error;
}

impl spi::Error for Error {
    fn kind(&self) -> spi::ErrorKind {
        spi::ErrorKind::Other
    }
}

/// `Transfer<u8>` trait implementation for `embedded-hal` v1.0.0-alpha.8.
impl SpiBus<u8> for Spi {
    fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
        Spi::transfer(self, read, write)?;

        Ok(())
    }

    fn transfer_in_place(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> {
        let write_buffer = buffer.to_vec();
        self.transfer(buffer, &write_buffer)
    }
}

/// `Transfer<u8>` trait implementation for `embedded-hal` v0.2.7.
impl embedded_hal_0::blocking::spi::Transfer<u8> for Spi {
    type Error = Error;

    fn transfer<'a>(&mut self, buffer: &'a mut [u8]) -> Result<&'a [u8], Self::Error> {
        let write_buffer = buffer.to_vec();
        SpiBus::transfer(self, buffer, &write_buffer)?;
        Ok(buffer)
    }
}

/// `SpiBusWrite<u8>` trait implementation for `embedded-hal` v1.0.0-alpha.8.
impl SpiBusWrite<u8> for Spi {
    fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
        Spi::write(self, buffer)?;

        Ok(())
    }
}

/// `Write<u8>` trait implementation for `embedded-hal` v0.2.7.
impl embedded_hal_0::blocking::spi::Write<u8> for Spi {
    type Error = Error;

    fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
        SpiBusWrite::write(self, buffer)
    }
}

/// `SpiBusRead<u8>` trait implementation for `embedded-hal` v1.0.0-alpha.8.
impl SpiBusRead<u8> for Spi {
    fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> {
        Spi::read(self, buffer)?;

        Ok(())
    }
}

/// `SpiBusFlush` trait implementation for `embedded-hal` v1.0.0-alpha.8.
impl SpiBusFlush for Spi {
    fn flush(&mut self) -> Result<(), Self::Error> {
        Ok(())
    }
}

/// `FullDuplex<u8>` trait implementation for `embedded-hal` v1.0.0-alpha.8.
impl FullDuplex<u8> for Spi {
    fn read(&mut self) -> nb::Result<u8, Self::Error> {
        if let Some(last_read) = self.last_read.take() {
            Ok(last_read)
        } else {
            Err(nb::Error::WouldBlock)
        }
    }

    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
        let mut read_buffer: [u8; 1] = [0];

        Spi::transfer(self, &mut read_buffer, &[byte])?;
        self.last_read = Some(read_buffer[0]);

        Ok(())
    }
}

/// `FullDuplex<u8>` trait implementation for `embedded-hal` v0.2.7.
impl embedded_hal_0::spi::FullDuplex<u8> for Spi {
    type Error = Error;

    fn read(&mut self) -> nb::Result<u8, Self::Error> {
        FullDuplex::read(self)
    }

    fn send(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
        FullDuplex::write(self, byte)
    }
}

/// Simple implementation of [embedded_hal::spi::SpiDevice]
///
/// You only need this when using the `embedded_hal` Spi trait interface.
///
/// Slave-select is currently handled at the bus level.
/// This no-op device implementation can be used to satisfy the trait.
// TODO: The underlying crate::spi::Spi shall be split up to support proper slave-select handling here.
pub struct SimpleHalSpiDevice<B> {
    bus: B,
}

impl<B> SimpleHalSpiDevice<B> {
    pub fn new(bus: B) -> SimpleHalSpiDevice<B> {
        SimpleHalSpiDevice { bus }
    }
}

impl<B: ErrorType> SpiDevice for SimpleHalSpiDevice<B> {
    type Bus = B;

    fn transaction<R>(
        &mut self,
        f: impl FnOnce(&mut Self::Bus) -> Result<R, <Self::Bus as ErrorType>::Error>,
    ) -> Result<R, Self::Error> {
        f(&mut self.bus).map_err(|_| {
            Error::Io(io::Error::new(
                io::ErrorKind::Other,
                "SimpleHalSpiDevice transaction error",
            ))
        })
    }
}

impl<B: ErrorType> ErrorType for SimpleHalSpiDevice<B> {
    type Error = Error;
}
<|endoftext|>


<commit_before>use Module;
use socket::Socket;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Source {
    DISABLED,
    NOW,
    CH1_PE,
    CH1_NE,
    CH2_PE,
    CH2_NE,
    EXT_PE,
    EXT_NE,
    AWG_PE,
    AWG_NE,
}

impl ::std::convert::Into<String> for Source {
    fn into(self) -> String {
        let s = match self {
            Source::DISABLED => "DISABLED",
            Source::NOW => "NOW",
            Source::CH1_PE => "CH1_PE",
            Source::CH1_NE => "CH1_NE",
            Source::CH2_PE => "CH2_PE",
            Source::CH2_NE => "CH2_NE",
            Source::EXT_PE => "EXT_PE",
            Source::EXT_NE => "EXT_NE",
            Source::AWG_PE => "AWG_PE",
            Source::AWG_NE => "AWG_NE",
        };

        String::from(s)
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum State {
    WAIT,
    TD,
}

impl ::std::str::FromStr for State {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "WAIT" => Ok(State::WAIT),
            "TD" => Ok(State::TD),
            state => Err(format!("Unknow state '{}'", state)),
        }
    }
}

#[derive(Clone)]
pub struct Trigger {
    socket: Socket,
}

impl ::Module for Trigger {
    fn new(socket: Socket) -> Self {
        Trigger {
            socket,
        }
    }
}

impl Trigger {
    /**
     * Trigger immediately or set trigger source & edge.
     *
     * https://forum.redpitaya.com/viewtopic.php?f=14&t=1014
     */
    pub fn enable(&self, source: Source) {
        self.socket.send(format!("ACQ:TRIG {}", Into::<String>::into(source)));
    }

    /**
     * Disable triggering.
     */
    pub fn disable(&self) {
        self.enable(Source::DISABLED);
    }

    /**
     *  Get trigger status.
     *
     *  If DISABLED -> TD else WAIT.
     */
    pub fn get_state(&self) -> Result<State, String> {
        self.socket.send("ACQ:TRIG:STAT?")
            .unwrap()
            .parse()
    }

    /**
     * Set trigger delay in samples.
     */
    pub fn set_delay(&self, delay: u16) {
        self.socket.send(format!("ACQ:TRIG:DLY {}", delay));
    }

    /**
     * Get trigger delay in samples.
     */
    pub fn get_delay(&self) -> Result<u16, <u16 as ::std::str::FromStr>::Err> {
        self.socket.send("ACQ:TRIG:DLY?")
            .unwrap()
            .parse()
    }

    /**
     * Set trigger delay in ns.
     */
    pub fn set_delay_in_ns(&self, delay: u8) {
        self.socket.send(format!("ACQ:TRIG:DLY:NS {}", delay));
    }

    /**
     * Get trigger delay in ns.
     */
    pub fn get_delay_in_ns(&self) -> Result<u8, <u8 as ::std::str::FromStr>::Err> {
        self.socket.send("ACQ:TRIG:DLY:NS?")
            .unwrap()
            .replace("ns", "")
            .parse()
    }

    /**
     * Sets the trigger threshold hysteresis value in volts.
     *
     * Value must be outside to enable the trigger again.
     */
    pub fn set_hysteresis(&self, hysteresis: f32) {
        self.socket.send(format!("ACQ:TRIG:HYST {}", hysteresis));
    }

    /**
     * Gets currently set trigger threshold hysteresis value in volts.
     */
    pub fn get_hysteresis(&self) -> Result<f32, <f32 as ::std::str::FromStr>::Err> {
        self.socket.send("ACQ:TRIG:HYST?")
            .unwrap()
            .parse()
    }

    /**
     * Set trigger level in mV.
     */
    pub fn set_level(&self, level: f32) {
        self.socket.send(format!("ACQ:TRIG:LEV {}", level));
    }

    /**
     * Get trigger level in mV.
     */
    pub fn get_level(&self) -> Result<f32, <f32 as ::std::str::FromStr>::Err> {
        self.socket.send("ACQ:TRIG:LEV?")
            .unwrap()
            .replace("mV", "")
            .parse()
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_status() {
        let (rx, rp) = ::test::create_client();

        rp.trigger.enable(::trigger::Source::NOW);
        assert_eq!("ACQ:TRIG NOW\r\n", rx.recv().unwrap());

        #[cfg(feature = "mock")]
        assert_eq!(rp.trigger.get_state(), Ok(::trigger::State::TD));

        #[cfg(not(feature = "mock"))]
        assert!(rp.trigger.get_state().is_ok());

        rp.trigger.disable();
        assert_eq!("ACQ:TRIG DISABLED\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_delay() {
        let (rx, rp) = ::test::create_client();

        rp.trigger.set_delay(2314);
        assert_eq!("ACQ:TRIG:DLY 2314\r\n", rx.recv().unwrap());

        assert_eq!(rp.trigger.get_delay(), Ok(2314));
    }

    #[test]
    fn test_delay_in_ns() {
        let (rx, rp) = ::test::create_client();

        rp.trigger.set_delay_in_ns(128);
        assert_eq!("ACQ:TRIG:DLY:NS 128\r\n", rx.recv().unwrap());

        assert_eq!(rp.trigger.get_delay_in_ns(), Ok(128));
    }

    #[test]
    fn test_hysteresis() {
        let (rx, rp) = ::test::create_client();

        rp.trigger.set_hysteresis(0.75);
        assert_eq!("ACQ:TRIG:HYST 0.75\r\n", rx.recv().unwrap());

        assert_eq!(rp.trigger.get_hysteresis(), Ok(0.75));
    }

    #[test]
    fn test_level() {
        let (rx, rp) = ::test::create_client();

        rp.trigger.set_level(0.4);
        assert_eq!("ACQ:TRIG:LEV 0.4\r\n", rx.recv().unwrap());

        assert_eq!(rp.trigger.get_level(), Ok(0.4));
    }
}
<commit_msg>Fix mocked trigger::test::test_status<commit_after>use Module;
use socket::Socket;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Source {
    DISABLED,
    NOW,
    CH1_PE,
    CH1_NE,
    CH2_PE,
    CH2_NE,
    EXT_PE,
    EXT_NE,
    AWG_PE,
    AWG_NE,
}

impl ::std::convert::Into<String> for Source {
    fn into(self) -> String {
        let s = match self {
            Source::DISABLED => "DISABLED",
            Source::NOW => "NOW",
            Source::CH1_PE => "CH1_PE",
            Source::CH1_NE => "CH1_NE",
            Source::CH2_PE => "CH2_PE",
            Source::CH2_NE => "CH2_NE",
            Source::EXT_PE => "EXT_PE",
            Source::EXT_NE => "EXT_NE",
            Source::AWG_PE => "AWG_PE",
            Source::AWG_NE => "AWG_NE",
        };

        String::from(s)
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum State {
    WAIT,
    TD,
}

impl ::std::str::FromStr for State {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "WAIT" => Ok(State::WAIT),
            "TD" => Ok(State::TD),
            state => Err(format!("Unknow state '{}'", state)),
        }
    }
}

#[derive(Clone)]
pub struct Trigger {
    socket: Socket,
}

impl ::Module for Trigger {
    fn new(socket: Socket) -> Self {
        Trigger {
            socket,
        }
    }
}

impl Trigger {
    /**
     * Trigger immediately or set trigger source & edge.
     *
     * https://forum.redpitaya.com/viewtopic.php?f=14&t=1014
     */
    pub fn enable(&self, source: Source) {
        self.socket.send(format!("ACQ:TRIG {}", Into::<String>::into(source)));
    }

    /**
     * Disable triggering.
     */
    pub fn disable(&self) {
        self.enable(Source::DISABLED);
    }

    /**
     *  Get trigger status.
     *
     *  If DISABLED -> TD else WAIT.
     */
    pub fn get_state(&self) -> Result<State, String> {
        self.socket.send("ACQ:TRIG:STAT?")
            .unwrap()
            .parse()
    }

    /**
     * Set trigger delay in samples.
     */
    pub fn set_delay(&self, delay: u16) {
        self.socket.send(format!("ACQ:TRIG:DLY {}", delay));
    }

    /**
     * Get trigger delay in samples.
     */
    pub fn get_delay(&self) -> Result<u16, <u16 as ::std::str::FromStr>::Err> {
        self.socket.send("ACQ:TRIG:DLY?")
            .unwrap()
            .parse()
    }

    /**
     * Set trigger delay in ns.
     */
    pub fn set_delay_in_ns(&self, delay: u8) {
        self.socket.send(format!("ACQ:TRIG:DLY:NS {}", delay));
    }

    /**
     * Get trigger delay in ns.
     */
    pub fn get_delay_in_ns(&self) -> Result<u8, <u8 as ::std::str::FromStr>::Err> {
        self.socket.send("ACQ:TRIG:DLY:NS?")
            .unwrap()
            .replace("ns", "")
            .parse()
    }

    /**
     * Sets the trigger threshold hysteresis value in volts.
     *
     * Value must be outside to enable the trigger again.
     */
    pub fn set_hysteresis(&self, hysteresis: f32) {
        self.socket.send(format!("ACQ:TRIG:HYST {}", hysteresis));
    }

    /**
     * Gets currently set trigger threshold hysteresis value in volts.
     */
    pub fn get_hysteresis(&self) -> Result<f32, <f32 as ::std::str::FromStr>::Err> {
        self.socket.send("ACQ:TRIG:HYST?")
            .unwrap()
            .parse()
    }

    /**
     * Set trigger level in mV.
     */
    pub fn set_level(&self, level: f32) {
        self.socket.send(format!("ACQ:TRIG:LEV {}", level));
    }

    /**
     * Get trigger level in mV.
     */
    pub fn get_level(&self) -> Result<f32, <f32 as ::std::str::FromStr>::Err> {
        self.socket.send("ACQ:TRIG:LEV?")
            .unwrap()
            .replace("mV", "")
            .parse()
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_status() {
        let (rx, rp) = ::test::create_client();

        rp.trigger.enable(::trigger::Source::NOW);
        assert_eq!("ACQ:TRIG NOW\r\n", rx.recv().unwrap());

        #[cfg(feature = "mock")]
        assert_eq!(rp.trigger.get_state(), Ok(::trigger::State::WAIT));

        #[cfg(not(feature = "mock"))]
        assert!(rp.trigger.get_state().is_ok());

        rp.trigger.disable();
        assert_eq!("ACQ:TRIG DISABLED\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_delay() {
        let (rx, rp) = ::test::create_client();

        rp.trigger.set_delay(2314);
        assert_eq!("ACQ:TRIG:DLY 2314\r\n", rx.recv().unwrap());

        assert_eq!(rp.trigger.get_delay(), Ok(2314));
    }

    #[test]
    fn test_delay_in_ns() {
        let (rx, rp) = ::test::create_client();

        rp.trigger.set_delay_in_ns(128);
        assert_eq!("ACQ:TRIG:DLY:NS 128\r\n", rx.recv().unwrap());

        assert_eq!(rp.trigger.get_delay_in_ns(), Ok(128));
    }

    #[test]
    fn test_hysteresis() {
        let (rx, rp) = ::test::create_client();

        rp.trigger.set_hysteresis(0.75);
        assert_eq!("ACQ:TRIG:HYST 0.75\r\n", rx.recv().unwrap());

        assert_eq!(rp.trigger.get_hysteresis(), Ok(0.75));
    }

    #[test]
    fn test_level() {
        let (rx, rp) = ::test::create_client();

        rp.trigger.set_level(0.4);
        assert_eq!("ACQ:TRIG:LEV 0.4\r\n", rx.recv().unwrap());

        assert_eq!(rp.trigger.get_level(), Ok(0.4));
    }
}
<|endoftext|>


<commit_before>
//! Various methods for computing with vectors.

use {Matrix2d, Ray, Vec2d, Rectangle};

/// Multiplies two matrices.
#[inline(always)]
pub fn multiply(m: &[f64, ..6], b: &[f64, ..6]) -> Matrix2d {
    [m[0]*b[0]+m[1]*b[3]+m[2]*0.0,  m[0]*b[1]+m[1]*b[4]+m[2]*0.0,  m[0]*b[2]+m[1]*b[5]+m[2]*1.0,
     m[3]*b[0]+m[4]*b[3]+m[5]*0.0,  m[3]*b[1]+m[4]*b[4]+m[5]*0.0,  m[3]*b[2]+m[4]*b[5]+m[5]*1.0]
}

/// Creates a translation matrix.
#[inline(always)]
pub fn translate(x: f64, y: f64) -> Matrix2d {
    [1.0, 0.0, x,
     0.0, 1.0, y]
}

/// Creates a rotation matrix.
#[inline(always)]
pub fn rotate_radians(angle: f64) -> Matrix2d {
    let c = angle.cos();
    let s = angle.sin();
    [c, s, 0.0,
    -s, c, 0.0]
}

/// Create a scale matrix.
#[inline(always)]
pub fn scale(sx: f64, sy: f64) -> Matrix2d {
    [sx, 0.0, 0.0,
     0.0, sy, 0.0]
}

/// Create a shear matrix.
#[inline(always)]
pub fn shear(sx: f64, sy: f64) -> Matrix2d {
    [1.0, sx, 0.0,
     sy, 1.0, 0.0]
}

/// Compute the shortest vector from point to ray.
/// A ray stores starting point and directional vector.
#[inline(always)]
pub fn separation(ray: Ray, x: f64, y: f64) -> Vec2d {
    // Get the directional vector.
    let (dir_x, dir_y) = (ray[2], ray[3]);
    // Get displacement vector from point.
    let (dx, dy) = (ray[0] - x, ray[1] - y);
    // Compute the component of position in ray direction.
    let dot = dir_x * x + dir_y * y;
    // The directional vector multiplied with the dot gives us a parallel vector.
    // When we subtract this from the displacement we get a vector normal to the ray.
    // This is the shortest vector from the point to the ray.
    [dx - dot * dir_x, dy - dot * dir_y]
}

/// Returns the least separation out of four.
/// Each seperation can be computed using `separation` function.
/// The separation returned can be used to solve collision of rectangles.
#[inline(always)]
pub fn least_separation_4(sep1: Vec2d, sep2: Vec2d, sep3: Vec2d, sep4: Vec2d) -> Vec2d {
    let dot1 = sep1[0] * sep1[0] + sep1[1] * sep1[1];
    let dot2 = sep2[0] * sep2[0] + sep2[1] * sep2[1];
    let dot3 = sep3[0] * sep3[0] + sep3[1] * sep3[1];
    let dot4 = sep4[0] * sep4[0] + sep4[1] * sep4[1];
    // Search for the smallest dot product.
    if dot1 < dot2 {
        if dot3 < dot4 {
            if dot1 < dot3 { sep1 } else { sep3 }
        } else {
            if dot1 < dot4 { sep1 } else { sep4 }
        }
    } else {
        if dot3 < dot4 {
            if dot2 < dot3 { sep2 } else { sep3 }
        } else {
            if dot2 < dot4 { sep2 } else { sep4 }
        }
    }
}

/// Shrinks a rectangle by a factor on all sides.
#[inline(always)]
pub fn margin(rect: &Rectangle, m: f64) -> Rectangle {
    [rect[0] + m, rect[1] + m, rect[2] - 2.0 * m, rect[3] - 2.0 * m]
}

<commit_msg>Added `relative_rectangle`<commit_after>
//! Various methods for computing with vectors.

use {Matrix2d, Ray, Vec2d, Rectangle};

/// Multiplies two matrices.
#[inline(always)]
pub fn multiply(m: &[f64, ..6], b: &[f64, ..6]) -> Matrix2d {
    [m[0]*b[0]+m[1]*b[3]+m[2]*0.0,  m[0]*b[1]+m[1]*b[4]+m[2]*0.0,  m[0]*b[2]+m[1]*b[5]+m[2]*1.0,
     m[3]*b[0]+m[4]*b[3]+m[5]*0.0,  m[3]*b[1]+m[4]*b[4]+m[5]*0.0,  m[3]*b[2]+m[4]*b[5]+m[5]*1.0]
}

/// Creates a translation matrix.
#[inline(always)]
pub fn translate(x: f64, y: f64) -> Matrix2d {
    [1.0, 0.0, x,
     0.0, 1.0, y]
}

/// Creates a rotation matrix.
#[inline(always)]
pub fn rotate_radians(angle: f64) -> Matrix2d {
    let c = angle.cos();
    let s = angle.sin();
    [c, s, 0.0,
    -s, c, 0.0]
}

/// Create a scale matrix.
#[inline(always)]
pub fn scale(sx: f64, sy: f64) -> Matrix2d {
    [sx, 0.0, 0.0,
     0.0, sy, 0.0]
}

/// Create a shear matrix.
#[inline(always)]
pub fn shear(sx: f64, sy: f64) -> Matrix2d {
    [1.0, sx, 0.0,
     sy, 1.0, 0.0]
}

/// Compute the shortest vector from point to ray.
/// A ray stores starting point and directional vector.
#[inline(always)]
pub fn separation(ray: Ray, x: f64, y: f64) -> Vec2d {
    // Get the directional vector.
    let (dir_x, dir_y) = (ray[2], ray[3]);
    // Get displacement vector from point.
    let (dx, dy) = (ray[0] - x, ray[1] - y);
    // Compute the component of position in ray direction.
    let dot = dir_x * x + dir_y * y;
    // The directional vector multiplied with the dot gives us a parallel vector.
    // When we subtract this from the displacement we get a vector normal to the ray.
    // This is the shortest vector from the point to the ray.
    [dx - dot * dir_x, dy - dot * dir_y]
}

/// Returns the least separation out of four.
/// Each seperation can be computed using `separation` function.
/// The separation returned can be used to solve collision of rectangles.
#[inline(always)]
pub fn least_separation_4(sep1: Vec2d, sep2: Vec2d, sep3: Vec2d, sep4: Vec2d) -> Vec2d {
    let dot1 = sep1[0] * sep1[0] + sep1[1] * sep1[1];
    let dot2 = sep2[0] * sep2[0] + sep2[1] * sep2[1];
    let dot3 = sep3[0] * sep3[0] + sep3[1] * sep3[1];
    let dot4 = sep4[0] * sep4[0] + sep4[1] * sep4[1];
    // Search for the smallest dot product.
    if dot1 < dot2 {
        if dot3 < dot4 {
            if dot1 < dot3 { sep1 } else { sep3 }
        } else {
            if dot1 < dot4 { sep1 } else { sep4 }
        }
    } else {
        if dot3 < dot4 {
            if dot2 < dot3 { sep2 } else { sep3 }
        } else {
            if dot2 < dot4 { sep2 } else { sep4 }
        }
    }
}

/// Shrinks a rectangle by a factor on all sides.
#[inline(always)]
pub fn margin(rect: &Rectangle, m: f64) -> Rectangle {
    [rect[0] + m, rect[1] + m, rect[2] - 2.0 * m, rect[3] - 2.0 * m]
}

/// Computes a relative rectangle using the rectangle as a tile.
#[inline(always)]
pub fn relative_rectangle(rect: &Rectangle, x: f64, y: f64) -> Rectangle {
    [rect[0] + x * rect[2], rect[1] + y * rect[3], rect[2], rect[3]]
}

<|endoftext|>


<commit_before>use EnumMap;
use Internal;

use core::iter::Enumerate;
use core::marker::PhantomData;
use core::slice;

/// Immutable enum map iterator
///
/// This struct is created by `iter` method or `into_iter` on a reference
/// to `EnumMap`.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate enum_map;
/// #[macro_use]
/// extern crate enum_map_derive;
///
/// #[derive(EnumMap)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     assert_eq!(map[Example::A], 3);
///     for (key, &value) in &map {
///         assert_eq!(match key {
///             Example::A => 3,
///             _ => 0,
///         }, value);
///     }
/// }
/// ```
pub struct Iter<'a, K, V: 'a> {
    _phantom: PhantomData<K>,
    iterator: Enumerate<slice::Iter<'a, V>>,
}

impl<'a, K: Internal<V>, V> Iterator for Iter<'a, K, V> {
    type Item = (K, &'a V);
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator.next().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }
}

impl<'a, K: Internal<V>, V> DoubleEndedIterator for Iter<'a, K, V> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator.next_back().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }
}

impl<'a, K: Internal<V>, V> ExactSizeIterator for Iter<'a, K, V> {}

impl<'a, K: Internal<V>, V> IntoIterator for &'a EnumMap<K, V> {
    type Item = (K, &'a V);
    type IntoIter = Iter<'a, K, V>;
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            _phantom: PhantomData,
            iterator: K::slice(&self.array).iter().enumerate(),
        }
    }
}

/// Mutable map iterator
///
/// This struct is created by `iter_mut` method or `into_iter` on a mutable
/// reference to `EnumMap`.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate enum_map;
/// #[macro_use]
/// extern crate enum_map_derive;
///
/// #[derive(Debug, EnumMap)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     for (_, value) in &mut map {
///         *value += 1;
///     }
///     assert_eq!(map, enum_map! { Example::A => 4, _ => 1 });
/// }
/// ```
pub struct IterMut<'a, K, V: 'a> {
    _phantom: PhantomData<K>,
    iterator: Enumerate<slice::IterMut<'a, V>>,
}

impl<'a, K: Internal<V>, V> Iterator for IterMut<'a, K, V> {
    type Item = (K, &'a mut V);
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator.next().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }
}

impl<'a, K: Internal<V>, V> DoubleEndedIterator for IterMut<'a, K, V> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator.next_back().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }
}

impl<'a, K: Internal<V>, V> ExactSizeIterator for IterMut<'a, K, V> {}

impl<'a, K: Internal<V>, V> IntoIterator for &'a mut EnumMap<K, V> {
    type Item = (K, &'a mut V);
    type IntoIter = IterMut<'a, K, V>;
    fn into_iter(self) -> Self::IntoIter {
        IterMut {
            _phantom: PhantomData,
            iterator: K::slice_mut(&mut self.array).iter_mut().enumerate(),
        }
    }
}
<commit_msg>Modify IntoIterator impls to use as_slice<commit_after>use EnumMap;
use Internal;

use core::iter::Enumerate;
use core::marker::PhantomData;
use core::slice;

/// Immutable enum map iterator
///
/// This struct is created by `iter` method or `into_iter` on a reference
/// to `EnumMap`.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate enum_map;
/// #[macro_use]
/// extern crate enum_map_derive;
///
/// #[derive(EnumMap)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     assert_eq!(map[Example::A], 3);
///     for (key, &value) in &map {
///         assert_eq!(match key {
///             Example::A => 3,
///             _ => 0,
///         }, value);
///     }
/// }
/// ```
pub struct Iter<'a, K, V: 'a> {
    _phantom: PhantomData<K>,
    iterator: Enumerate<slice::Iter<'a, V>>,
}

impl<'a, K: Internal<V>, V> Iterator for Iter<'a, K, V> {
    type Item = (K, &'a V);
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator.next().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }
}

impl<'a, K: Internal<V>, V> DoubleEndedIterator for Iter<'a, K, V> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator.next_back().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }
}

impl<'a, K: Internal<V>, V> ExactSizeIterator for Iter<'a, K, V> {}

impl<'a, K: Internal<V>, V> IntoIterator for &'a EnumMap<K, V> {
    type Item = (K, &'a V);
    type IntoIter = Iter<'a, K, V>;
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            _phantom: PhantomData,
            iterator: self.as_slice().iter().enumerate(),
        }
    }
}

/// Mutable map iterator
///
/// This struct is created by `iter_mut` method or `into_iter` on a mutable
/// reference to `EnumMap`.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate enum_map;
/// #[macro_use]
/// extern crate enum_map_derive;
///
/// #[derive(Debug, EnumMap)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     for (_, value) in &mut map {
///         *value += 1;
///     }
///     assert_eq!(map, enum_map! { Example::A => 4, _ => 1 });
/// }
/// ```
pub struct IterMut<'a, K, V: 'a> {
    _phantom: PhantomData<K>,
    iterator: Enumerate<slice::IterMut<'a, V>>,
}

impl<'a, K: Internal<V>, V> Iterator for IterMut<'a, K, V> {
    type Item = (K, &'a mut V);
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator.next().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }
}

impl<'a, K: Internal<V>, V> DoubleEndedIterator for IterMut<'a, K, V> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator.next_back().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }
}

impl<'a, K: Internal<V>, V> ExactSizeIterator for IterMut<'a, K, V> {}

impl<'a, K: Internal<V>, V> IntoIterator for &'a mut EnumMap<K, V> {
    type Item = (K, &'a mut V);
    type IntoIter = IterMut<'a, K, V>;
    fn into_iter(self) -> Self::IntoIter {
        IterMut {
            _phantom: PhantomData,
            iterator: self.as_mut_slice().iter_mut().enumerate(),
        }
    }
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use ra_syntax::ast;

use crate::completion::{
    CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
};

pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
    // complete keyword "crate" in use stmt
    let source_range = ctx.source_range();
    match (ctx.use_item_syntax.as_ref(), ctx.path_prefix.as_ref()) {
        (Some(_), None) => {
            CompletionItem::new(CompletionKind::Keyword, source_range, "crate::")
                .kind(CompletionItemKind::Keyword)
                .insert_text("crate::")
                .add_to(acc);
            CompletionItem::new(CompletionKind::Keyword, source_range, "self")
                .kind(CompletionItemKind::Keyword)
                .add_to(acc);
            CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
                .kind(CompletionItemKind::Keyword)
                .insert_text("super::")
                .add_to(acc);
        }
        (Some(_), Some(_)) => {
            CompletionItem::new(CompletionKind::Keyword, source_range, "self")
                .kind(CompletionItemKind::Keyword)
                .add_to(acc);
            CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
                .kind(CompletionItemKind::Keyword)
                .insert_text("super::")
                .add_to(acc);
        }
        _ => {}
    }
}

pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
    let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
    if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
        add_keyword(ctx, acc, "where", "where ");
        return;
    }
    if ctx.unsafe_is_prev {
        if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
            add_keyword(ctx, acc, "fn", "fn $0() {}")
        }

        if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
            || ctx.block_expr_parent
        {
            add_keyword(ctx, acc, "trait", "trait $0 {}");
            add_keyword(ctx, acc, "impl", "impl $0 {}");
        }

        return;
    }
    if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
        add_keyword(ctx, acc, "fn", "fn $0() {}");
    }
    if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
        || ctx.block_expr_parent
    {
        add_keyword(ctx, acc, "use", "use ");
        add_keyword(ctx, acc, "impl", "impl $0 {}");
        add_keyword(ctx, acc, "trait", "trait $0 {}");
    }

    if ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent {
        add_keyword(ctx, acc, "enum", "enum $0 {}");
        add_keyword(ctx, acc, "struct", "struct $0 {}");
        add_keyword(ctx, acc, "union", "union $0 {}");
    }

    if ctx.block_expr_parent || ctx.is_match_arm {
        add_keyword(ctx, acc, "match", "match $0 {}");
        add_keyword(ctx, acc, "loop", "loop {$0}");
    }
    if ctx.block_expr_parent {
        add_keyword(ctx, acc, "while", "while $0 {}");
    }
    if ctx.if_is_prev || ctx.block_expr_parent {
        add_keyword(ctx, acc, "let", "let ");
    }
    if ctx.if_is_prev || ctx.block_expr_parent || ctx.is_match_arm {
        add_keyword(ctx, acc, "if", "if ");
        add_keyword(ctx, acc, "if let", "if let ");
    }
    if ctx.after_if {
        add_keyword(ctx, acc, "else", "else {$0}");
        add_keyword(ctx, acc, "else if", "else if $0 {}");
    }
    if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
        || ctx.block_expr_parent
    {
        add_keyword(ctx, acc, "mod", "mod $0 {}");
    }
    if ctx.bind_pat_parent || ctx.ref_pat_parent {
        add_keyword(ctx, acc, "mut", "mut ");
    }
    if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
        add_keyword(ctx, acc, "const", "const ");
        add_keyword(ctx, acc, "type", "type ");
    }
    if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
        || ctx.block_expr_parent
    {
        add_keyword(ctx, acc, "static", "static ");
    };
    if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
        || ctx.block_expr_parent
    {
        add_keyword(ctx, acc, "extern", "extern ");
    }
    if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent || ctx.is_match_arm {
        add_keyword(ctx, acc, "unsafe", "unsafe ");
    }
    if ctx.in_loop_body {
        if ctx.can_be_stmt {
            add_keyword(ctx, acc, "continue", "continue;");
            add_keyword(ctx, acc, "break", "break;");
        } else {
            add_keyword(ctx, acc, "continue", "continue");
            add_keyword(ctx, acc, "break", "break");
        }
    }
    if ctx.has_item_list_or_source_file_parent && !ctx.has_trait_parent {
        add_keyword(ctx, acc, "pub", "pub ")
    }

    if !ctx.is_trivial_path {
        return;
    }
    let fn_def = match &ctx.function_syntax {
        Some(it) => it,
        None => return,
    };
    acc.add_all(complete_return(ctx, &fn_def, ctx.can_be_stmt));
}

fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem {
    let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
        .kind(CompletionItemKind::Keyword);

    match ctx.config.snippet_cap {
        Some(cap) => res.insert_snippet(cap, snippet),
        _ => res.insert_text(if snippet.contains('$') { kw } else { snippet }),
    }
    .build()
}

fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
    acc.add(keyword(ctx, kw, snippet));
}

fn complete_return(
    ctx: &CompletionContext,
    fn_def: &ast::FnDef,
    can_be_stmt: bool,
) -> Option<CompletionItem> {
    let snip = match (can_be_stmt, fn_def.ret_type().is_some()) {
        (true, true) => "return $0;",
        (true, false) => "return;",
        (false, true) => "return $0",
        (false, false) => "return",
    };
    Some(keyword(ctx, "return", snip))
}

#[cfg(test)]
mod tests {
    use crate::completion::{test_utils::completion_list, CompletionKind};
    use insta::assert_snapshot;

    fn get_keyword_completions(code: &str) -> String {
        completion_list(code, CompletionKind::Keyword)
    }

    #[test]
    fn test_keywords_in_use_stmt() {
        assert_snapshot!(
            get_keyword_completions(r"use <|>"),
            @r###"
            kw crate::
            kw self
            kw super::
        "###
        );

        assert_snapshot!(
            get_keyword_completions(r"use a::<|>"),
            @r###"
            kw self
            kw super::
        "###
        );

        assert_snapshot!(
            get_keyword_completions(r"use a::{b, <|>}"),
            @r###"
            kw self
            kw super::
        "###
        );
    }

    #[test]
    fn test_keywords_at_source_file_level() {
        assert_snapshot!(
            get_keyword_completions(r"m<|>"),
            @r###"
            kw const
            kw enum
            kw extern
            kw fn
            kw impl
            kw mod
            kw pub
            kw static
            kw struct
            kw trait
            kw type
            kw union
            kw unsafe
            kw use
        "###
        );
    }

    #[test]
    fn test_keywords_in_function() {
        assert_snapshot!(
            get_keyword_completions(r"fn quux() { <|> }"),
            @r###"
            kw const
            kw extern
            kw fn
            kw if
            kw if let
            kw impl
            kw let
            kw loop
            kw match
            kw mod
            kw return
            kw static
            kw trait
            kw type
            kw unsafe
            kw use
            kw while
        "###
        );
    }

    #[test]
    fn test_keywords_inside_block() {
        assert_snapshot!(
            get_keyword_completions(r"fn quux() { if true { <|> } }"),
            @r###"
            kw const
            kw extern
            kw fn
            kw if
            kw if let
            kw impl
            kw let
            kw loop
            kw match
            kw mod
            kw return
            kw static
            kw trait
            kw type
            kw unsafe
            kw use
            kw while
        "###
        );
    }

    #[test]
    fn test_keywords_after_if() {
        assert_snapshot!(
            get_keyword_completions(
                r"
                fn quux() {
                    if true {
                        ()
                    } <|>
                }
                ",
            ),
            @r###"
            kw const
            kw else
            kw else if
            kw extern
            kw fn
            kw if
            kw if let
            kw impl
            kw let
            kw loop
            kw match
            kw mod
            kw return
            kw static
            kw trait
            kw type
            kw unsafe
            kw use
            kw while
        "###
        );
    }

    #[test]
    fn test_keywords_in_match_arm() {
        assert_snapshot!(
            get_keyword_completions(
                r"
                fn quux() -> i32 {
                    match () {
                        () => <|>
                    }
                }
                ",
            ),
            @r###"
            kw if
            kw if let
            kw loop
            kw match
            kw return
            kw unsafe
        "###
        );
    }

    #[test]
    fn test_keywords_in_trait_def() {
        assert_snapshot!(
            get_keyword_completions(r"trait My { <|> }"),
            @r###"
            kw const
            kw fn
            kw type
            kw unsafe
        "###
        );
    }

    #[test]
    fn test_keywords_in_impl_def() {
        assert_snapshot!(
            get_keyword_completions(r"impl My { <|> }"),
            @r###"
            kw const
            kw fn
            kw pub
            kw type
            kw unsafe
        "###
        );
    }

    #[test]
    fn test_keywords_in_loop() {
        assert_snapshot!(
            get_keyword_completions(r"fn my() { loop { <|> } }"),
            @r###"
            kw break
            kw const
            kw continue
            kw extern
            kw fn
            kw if
            kw if let
            kw impl
            kw let
            kw loop
            kw match
            kw mod
            kw return
            kw static
            kw trait
            kw type
            kw unsafe
            kw use
            kw while
        "###
        );
    }

    #[test]
    fn test_keywords_after_unsafe_in_item_list() {
        assert_snapshot!(
            get_keyword_completions(r"unsafe <|>"),
            @r###"
            kw fn
            kw impl
            kw trait
        "###
        );
    }

    #[test]
    fn test_keywords_after_unsafe_in_block_expr() {
        assert_snapshot!(
            get_keyword_completions(r"fn my_fn() { unsafe <|> }"),
            @r###"
            kw fn
            kw impl
            kw trait
        "###
        );
    }

    #[test]
    fn test_mut_in_ref_and_in_fn_parameters_list() {
        assert_snapshot!(
            get_keyword_completions(r"fn my_fn(&<|>) {}"),
            @r###"
            kw mut
        "###
        );
        assert_snapshot!(
            get_keyword_completions(r"fn my_fn(<|>) {}"),
            @r###"
            kw mut
        "###
        );
        assert_snapshot!(
            get_keyword_completions(r"fn my_fn() { let &<|> }"),
            @r###"
            kw mut
        "###
        );
    }

    #[test]
    fn test_where_keyword() {
        assert_snapshot!(
            get_keyword_completions(r"trait A <|>"),
            @r###"
            kw where
        "###
        );
        assert_snapshot!(
            get_keyword_completions(r"impl A <|>"),
            @r###"
            kw where
        "###
        );
    }
}
<commit_msg>Auto-completion no longer occurs on comments<commit_after>//! FIXME: write short doc here

use ra_syntax::{ast, SyntaxKind};

use crate::completion::{
    CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
};

pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
    // complete keyword "crate" in use stmt
    let source_range = ctx.source_range();
    match (ctx.use_item_syntax.as_ref(), ctx.path_prefix.as_ref()) {
        (Some(_), None) => {
            CompletionItem::new(CompletionKind::Keyword, source_range, "crate::")
                .kind(CompletionItemKind::Keyword)
                .insert_text("crate::")
                .add_to(acc);
            CompletionItem::new(CompletionKind::Keyword, source_range, "self")
                .kind(CompletionItemKind::Keyword)
                .add_to(acc);
            CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
                .kind(CompletionItemKind::Keyword)
                .insert_text("super::")
                .add_to(acc);
        }
        (Some(_), Some(_)) => {
            CompletionItem::new(CompletionKind::Keyword, source_range, "self")
                .kind(CompletionItemKind::Keyword)
                .add_to(acc);
            CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
                .kind(CompletionItemKind::Keyword)
                .insert_text("super::")
                .add_to(acc);
        }
        _ => {}
    }
}

pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
    if ctx.token.kind() == SyntaxKind::COMMENT {
        return;
    }

    let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
    if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
        add_keyword(ctx, acc, "where", "where ");
        return;
    }
    if ctx.unsafe_is_prev {
        if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
            add_keyword(ctx, acc, "fn", "fn $0() {}")
        }

        if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
            || ctx.block_expr_parent
        {
            add_keyword(ctx, acc, "trait", "trait $0 {}");
            add_keyword(ctx, acc, "impl", "impl $0 {}");
        }

        return;
    }
    if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
        add_keyword(ctx, acc, "fn", "fn $0() {}");
    }
    if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
        || ctx.block_expr_parent
    {
        add_keyword(ctx, acc, "use", "use ");
        add_keyword(ctx, acc, "impl", "impl $0 {}");
        add_keyword(ctx, acc, "trait", "trait $0 {}");
    }

    if ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent {
        add_keyword(ctx, acc, "enum", "enum $0 {}");
        add_keyword(ctx, acc, "struct", "struct $0 {}");
        add_keyword(ctx, acc, "union", "union $0 {}");
    }

    if ctx.block_expr_parent || ctx.is_match_arm {
        add_keyword(ctx, acc, "match", "match $0 {}");
        add_keyword(ctx, acc, "loop", "loop {$0}");
    }
    if ctx.block_expr_parent {
        add_keyword(ctx, acc, "while", "while $0 {}");
    }
    if ctx.if_is_prev || ctx.block_expr_parent {
        add_keyword(ctx, acc, "let", "let ");
    }
    if ctx.if_is_prev || ctx.block_expr_parent || ctx.is_match_arm {
        add_keyword(ctx, acc, "if", "if ");
        add_keyword(ctx, acc, "if let", "if let ");
    }
    if ctx.after_if {
        add_keyword(ctx, acc, "else", "else {$0}");
        add_keyword(ctx, acc, "else if", "else if $0 {}");
    }
    if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
        || ctx.block_expr_parent
    {
        add_keyword(ctx, acc, "mod", "mod $0 {}");
    }
    if ctx.bind_pat_parent || ctx.ref_pat_parent {
        add_keyword(ctx, acc, "mut", "mut ");
    }
    if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
        add_keyword(ctx, acc, "const", "const ");
        add_keyword(ctx, acc, "type", "type ");
    }
    if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
        || ctx.block_expr_parent
    {
        add_keyword(ctx, acc, "static", "static ");
    };
    if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent)
        || ctx.block_expr_parent
    {
        add_keyword(ctx, acc, "extern", "extern ");
    }
    if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent || ctx.is_match_arm {
        add_keyword(ctx, acc, "unsafe", "unsafe ");
    }
    if ctx.in_loop_body {
        if ctx.can_be_stmt {
            add_keyword(ctx, acc, "continue", "continue;");
            add_keyword(ctx, acc, "break", "break;");
        } else {
            add_keyword(ctx, acc, "continue", "continue");
            add_keyword(ctx, acc, "break", "break");
        }
    }
    if ctx.has_item_list_or_source_file_parent && !ctx.has_trait_parent {
        add_keyword(ctx, acc, "pub", "pub ")
    }

    if !ctx.is_trivial_path {
        return;
    }
    let fn_def = match &ctx.function_syntax {
        Some(it) => it,
        None => return,
    };
    acc.add_all(complete_return(ctx, &fn_def, ctx.can_be_stmt));
}

fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem {
    let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
        .kind(CompletionItemKind::Keyword);

    match ctx.config.snippet_cap {
        Some(cap) => res.insert_snippet(cap, snippet),
        _ => res.insert_text(if snippet.contains('$') { kw } else { snippet }),
    }
    .build()
}

fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
    acc.add(keyword(ctx, kw, snippet));
}

fn complete_return(
    ctx: &CompletionContext,
    fn_def: &ast::FnDef,
    can_be_stmt: bool,
) -> Option<CompletionItem> {
    let snip = match (can_be_stmt, fn_def.ret_type().is_some()) {
        (true, true) => "return $0;",
        (true, false) => "return;",
        (false, true) => "return $0",
        (false, false) => "return",
    };
    Some(keyword(ctx, "return", snip))
}

#[cfg(test)]
mod tests {
    use crate::completion::{test_utils::completion_list, CompletionKind};
    use insta::assert_snapshot;

    fn get_keyword_completions(code: &str) -> String {
        completion_list(code, CompletionKind::Keyword)
    }

    #[test]
    fn test_keywords_in_use_stmt() {
        assert_snapshot!(
            get_keyword_completions(r"use <|>"),
            @r###"
            kw crate::
            kw self
            kw super::
        "###
        );

        assert_snapshot!(
            get_keyword_completions(r"use a::<|>"),
            @r###"
            kw self
            kw super::
        "###
        );

        assert_snapshot!(
            get_keyword_completions(r"use a::{b, <|>}"),
            @r###"
            kw self
            kw super::
        "###
        );
    }

    #[test]
    fn test_keywords_at_source_file_level() {
        assert_snapshot!(
            get_keyword_completions(r"m<|>"),
            @r###"
            kw const
            kw enum
            kw extern
            kw fn
            kw impl
            kw mod
            kw pub
            kw static
            kw struct
            kw trait
            kw type
            kw union
            kw unsafe
            kw use
        "###
        );
    }

    #[test]
    fn test_keywords_in_function() {
        assert_snapshot!(
            get_keyword_completions(r"fn quux() { <|> }"),
            @r###"
            kw const
            kw extern
            kw fn
            kw if
            kw if let
            kw impl
            kw let
            kw loop
            kw match
            kw mod
            kw return
            kw static
            kw trait
            kw type
            kw unsafe
            kw use
            kw while
        "###
        );
    }

    #[test]
    fn test_keywords_inside_block() {
        assert_snapshot!(
            get_keyword_completions(r"fn quux() { if true { <|> } }"),
            @r###"
            kw const
            kw extern
            kw fn
            kw if
            kw if let
            kw impl
            kw let
            kw loop
            kw match
            kw mod
            kw return
            kw static
            kw trait
            kw type
            kw unsafe
            kw use
            kw while
        "###
        );
    }

    #[test]
    fn test_keywords_after_if() {
        assert_snapshot!(
            get_keyword_completions(
                r"
                fn quux() {
                    if true {
                        ()
                    } <|>
                }
                ",
            ),
            @r###"
            kw const
            kw else
            kw else if
            kw extern
            kw fn
            kw if
            kw if let
            kw impl
            kw let
            kw loop
            kw match
            kw mod
            kw return
            kw static
            kw trait
            kw type
            kw unsafe
            kw use
            kw while
        "###
        );
    }

    #[test]
    fn test_keywords_in_match_arm() {
        assert_snapshot!(
            get_keyword_completions(
                r"
                fn quux() -> i32 {
                    match () {
                        () => <|>
                    }
                }
                ",
            ),
            @r###"
            kw if
            kw if let
            kw loop
            kw match
            kw return
            kw unsafe
        "###
        );
    }

    #[test]
    fn test_keywords_in_trait_def() {
        assert_snapshot!(
            get_keyword_completions(r"trait My { <|> }"),
            @r###"
            kw const
            kw fn
            kw type
            kw unsafe
        "###
        );
    }

    #[test]
    fn test_keywords_in_impl_def() {
        assert_snapshot!(
            get_keyword_completions(r"impl My { <|> }"),
            @r###"
            kw const
            kw fn
            kw pub
            kw type
            kw unsafe
        "###
        );
    }

    #[test]
    fn test_keywords_in_loop() {
        assert_snapshot!(
            get_keyword_completions(r"fn my() { loop { <|> } }"),
            @r###"
            kw break
            kw const
            kw continue
            kw extern
            kw fn
            kw if
            kw if let
            kw impl
            kw let
            kw loop
            kw match
            kw mod
            kw return
            kw static
            kw trait
            kw type
            kw unsafe
            kw use
            kw while
        "###
        );
    }

    #[test]
    fn test_keywords_after_unsafe_in_item_list() {
        assert_snapshot!(
            get_keyword_completions(r"unsafe <|>"),
            @r###"
            kw fn
            kw impl
            kw trait
        "###
        );
    }

    #[test]
    fn test_keywords_after_unsafe_in_block_expr() {
        assert_snapshot!(
            get_keyword_completions(r"fn my_fn() { unsafe <|> }"),
            @r###"
            kw fn
            kw impl
            kw trait
        "###
        );
    }

    #[test]
    fn test_mut_in_ref_and_in_fn_parameters_list() {
        assert_snapshot!(
            get_keyword_completions(r"fn my_fn(&<|>) {}"),
            @r###"
            kw mut
        "###
        );
        assert_snapshot!(
            get_keyword_completions(r"fn my_fn(<|>) {}"),
            @r###"
            kw mut
        "###
        );
        assert_snapshot!(
            get_keyword_completions(r"fn my_fn() { let &<|> }"),
            @r###"
            kw mut
        "###
        );
    }

    #[test]
    fn test_where_keyword() {
        assert_snapshot!(
            get_keyword_completions(r"trait A <|>"),
            @r###"
            kw where
        "###
        );
        assert_snapshot!(
            get_keyword_completions(r"impl A <|>"),
            @r###"
            kw where
        "###
        );
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::{
    fun::{FnAnalysis, FnKind, FnPhase, FnPrePhase, MethodKind, TraitMethodKind},
    pod::PodAnalysis,
};
use crate::conversion::api::Api;
use crate::conversion::{
    api::TypeKind,
    error_reporter::{convert_apis, convert_item_apis},
    ConvertError,
};
use std::collections::HashSet;

/// Spot types with pure virtual functions and mark them abstract.
pub(crate) fn mark_types_abstract(mut apis: Vec<Api<FnPrePhase>>) -> Vec<Api<FnPrePhase>> {
    let mut abstract_types: HashSet<_> = apis
        .iter()
        .filter_map(|api| match &api {
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind: FnKind::Method(self_ty_name, MethodKind::PureVirtual(_)),
                        ..
                    },
                ..
            } => Some(self_ty_name.clone()),
            _ => None,
        })
        .collect();

    for mut api in apis.iter_mut() {
        match &mut api {
            Api::Struct { analysis, name, .. } if abstract_types.contains(&name.name) => {
                analysis.kind = TypeKind::Abstract;
            }
            _ => {}
        }
    }

    // Spot any derived classes (recursively). Also, any types which have a base
    // class that's not on the allowlist are presumed to be abstract, because we
    // have no way of knowing (as they're not on the allowlist, there will be
    // no methods associated so we won't be able to spot pure virtual methods).
    let mut iterate = true;
    while iterate {
        iterate = false;
        for mut api in apis.iter_mut() {
            match &mut api {
                Api::Struct {
                    analysis: PodAnalysis { bases, kind, .. },
                    ..
                } if *kind != TypeKind::Abstract && (!abstract_types.is_disjoint(bases)) => {
                    *kind = TypeKind::Abstract;
                    abstract_types.insert(api.name().clone());
                    // Recurse in case there are further dependent types
                    iterate = true;
                }
                _ => {}
            }
        }
    }

    // We also need to remove any constructors belonging to these
    // abstract types.
    apis.retain(|api| {
        !matches!(&api,
        Api::Function {
            analysis:
                FnAnalysis {
                    kind: FnKind::Method(self_ty, MethodKind::MakeUnique | MethodKind::Constructor)
                        | FnKind::TraitMethod{ kind: TraitMethodKind::CopyConstructor | TraitMethodKind::MoveConstructor, impl_for: self_ty, ..},
                    ..
                },
                ..
        } if abstract_types.contains(self_ty))
    });

    // Finally, if there are any types which are nested inside other types,
    // they can't be abstract. This is due to two small limitations in cxx.
    // Imagine we have class Foo { class Bar }
    // 1) using "type Foo = super::bindgen::root::Foo_Bar" results
    //    in the creation of std::unique_ptr code which isn't acceptable
    //    for an abtract class
    // 2) using "type Foo;" isn't possible unless Foo is a top-level item
    //    within its namespace. Any outer names will be interpreted as namespace
    //    names and result in cxx generating "namespace Foo { class Bar }"".
    let mut results = Vec::new();
    convert_item_apis(apis, &mut results, |api| match api {
        Api::Struct {
            analysis:
                PodAnalysis {
                    kind: TypeKind::Abstract,
                    ..
                },
            ..
        } if api
            .cpp_name()
            .as_ref()
            .map(|n| n.contains("::"))
            .unwrap_or_default() =>
        {
            Err(ConvertError::AbstractNestedType)
        }
        _ => Ok(Box::new(std::iter::once(api))),
    });
    results
}

pub(crate) fn discard_ignored_functions(apis: Vec<Api<FnPhase>>) -> Vec<Api<FnPhase>> {
    // Some APIs can't be generated, e.g. because they're protected.
    // Now we've finished analyzing abstract types and constructors, we'll
    // convert them to IgnoredI
    let mut apis_new = Vec::new();
    convert_apis(
        apis,
        &mut apis_new,
        |name, fun, analysis, name_for_gc| {
            analysis.ignore_reason.clone()?;
            Ok(Box::new(std::iter::once(Api::Function {
                name,
                fun,
                analysis,
                name_for_gc,
            })))
        },
        Api::struct_unchanged,
        Api::enum_unchanged,
        Api::typedef_unchanged,
    );
    apis_new
}
<commit_msg>Cease to use iter_mut() on API list.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::{
    fun::{FnAnalysis, FnKind, FnPhase, FnPrePhase, MethodKind, TraitMethodKind},
    pod::PodAnalysis,
};
use crate::conversion::api::Api;
use crate::conversion::{
    api::TypeKind,
    error_reporter::{convert_apis, convert_item_apis},
    ConvertError,
};
use std::collections::HashSet;

/// Spot types with pure virtual functions and mark them abstract.
pub(crate) fn mark_types_abstract(mut apis: Vec<Api<FnPrePhase>>) -> Vec<Api<FnPrePhase>> {
    let mut abstract_types: HashSet<_> = apis
        .iter()
        .filter_map(|api| match &api {
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind: FnKind::Method(self_ty_name, MethodKind::PureVirtual(_)),
                        ..
                    },
                ..
            } => Some(self_ty_name.clone()),
            _ => None,
        })
        .collect();

    // Spot any derived classes (recursively). Also, any types which have a base
    // class that's not on the allowlist are presumed to be abstract, because we
    // have no way of knowing (as they're not on the allowlist, there will be
    // no methods associated so we won't be able to spot pure virtual methods).
    let mut iterate = true;
    while iterate {
        iterate = false;
        apis = apis
            .into_iter()
            .map(|api| {
                match api {
                    Api::Struct {
                        analysis:
                            PodAnalysis {
                                bases,
                                kind: TypeKind::Pod | TypeKind::NonPod,
                                castable_bases,
                                field_types,
                                movable,
                                is_generic,
                            },
                        name,
                        details,
                    } if abstract_types.contains(&name.name)
                        || !abstract_types.is_disjoint(&bases) =>
                    {
                        abstract_types.insert(name.name.clone());
                        // Recurse in case there are further dependent types
                        iterate = true;
                        Api::Struct {
                            analysis: PodAnalysis {
                                bases,
                                kind: TypeKind::Abstract,
                                castable_bases,
                                field_types,
                                movable,
                                is_generic,
                            },
                            name,
                            details,
                        }
                    }
                    _ => api,
                }
            })
            .collect()
    }

    // We also need to remove any constructors belonging to these
    // abstract types.
    apis.retain(|api| {
        !matches!(&api,
        Api::Function {
            analysis:
                FnAnalysis {
                    kind: FnKind::Method(self_ty, MethodKind::MakeUnique | MethodKind::Constructor)
                        | FnKind::TraitMethod{ kind: TraitMethodKind::CopyConstructor | TraitMethodKind::MoveConstructor, impl_for: self_ty, ..},
                    ..
                },
                ..
        } if abstract_types.contains(self_ty))
    });

    // Finally, if there are any types which are nested inside other types,
    // they can't be abstract. This is due to two small limitations in cxx.
    // Imagine we have class Foo { class Bar }
    // 1) using "type Foo = super::bindgen::root::Foo_Bar" results
    //    in the creation of std::unique_ptr code which isn't acceptable
    //    for an abtract class
    // 2) using "type Foo;" isn't possible unless Foo is a top-level item
    //    within its namespace. Any outer names will be interpreted as namespace
    //    names and result in cxx generating "namespace Foo { class Bar }"".
    let mut results = Vec::new();
    convert_item_apis(apis, &mut results, |api| match api {
        Api::Struct {
            analysis:
                PodAnalysis {
                    kind: TypeKind::Abstract,
                    ..
                },
            ..
        } if api
            .cpp_name()
            .as_ref()
            .map(|n| n.contains("::"))
            .unwrap_or_default() =>
        {
            Err(ConvertError::AbstractNestedType)
        }
        _ => Ok(Box::new(std::iter::once(api))),
    });
    results
}

pub(crate) fn discard_ignored_functions(apis: Vec<Api<FnPhase>>) -> Vec<Api<FnPhase>> {
    // Some APIs can't be generated, e.g. because they're protected.
    // Now we've finished analyzing abstract types and constructors, we'll
    // convert them to IgnoredI
    let mut apis_new = Vec::new();
    convert_apis(
        apis,
        &mut apis_new,
        |name, fun, analysis, name_for_gc| {
            analysis.ignore_reason.clone()?;
            Ok(Box::new(std::iter::once(Api::Function {
                name,
                fun,
                analysis,
                name_for_gc,
            })))
        },
        Api::struct_unchanged,
        Api::enum_unchanged,
        Api::typedef_unchanged,
    );
    apis_new
}
<|endoftext|>


<commit_before>#![feature(i128_type, inclusive_range_syntax)]

fn fac_ratio(n: i128, k: i128) -> i128 {
    (k + 1..n + 1).fold(1, |i, a| i * a)
}

fn fac(n: i128) -> i128 {
    fac_ratio(n, 1)
}

fn main() {
    let n = 20;

    println!("{}", fac_ratio(n + n, n) / fac(n));
}
<commit_msg>unused feature<commit_after>#![feature(i128_type)]

fn fac_ratio(n: i128, k: i128) -> i128 {
    (k + 1..n + 1).fold(1, |i, a| i * a)
}

fn fac(n: i128) -> i128 {
    fac_ratio(n, 1)
}

fn main() {
    let n = 20;

    println!("{}", fac_ratio(n + n, n) / fac(n));
}
<|endoftext|>


<commit_before>extern crate lp_modeler;
extern crate quote;
use quote::quote;

use lp_modeler::dsl::*;

#[test]
fn test_quotations() {
  use LpExpression::*;
  let a = LpInteger { name : "a" . to_string ( ) , lower_bound : None , upper_bound : None };
  let quoted_a = quote!(#a);
  let quoted_a_str = "LpInteger { name : \"a\" . to_string ( ) , lower_bound : None , upper_bound : None }";
  assert_eq!(quoted_a.to_string(), quoted_a_str);

  let exp : LpExpression = a.clone().into();
  let quoted_exp = quote!(#exp);
  let quoted_exp_str = "LpExpression :: ConsInt ( ".to_owned() + quoted_a_str + " )";
  assert_eq!(quoted_exp.to_string(), quoted_exp_str);

  let full_exp = LpExpression::MulExpr ( Box::new ( LpExpression::SubExpr ( Box::new ( LpExpression::EmptyExpr ) , Box::new ( LpExpression::LitVal ( 1f32 ) ) ) ) , Box::new ( LpExpression::AddExpr ( Box::new ( LpExpression::ConsCont ( LpContinuous { name : "x".to_string() , lower_bound : None , upper_bound : None } ) ) , Box::new ( LpExpression::ConsInt ( LpInteger { name : "y".to_string() , lower_bound : None , upper_bound : None } ) ) ) ) );

  let full_exp_quoted = quote!(#full_exp);
  let full_exp_str = "LpExpression :: MulExpr ( Box :: new ( LpExpression :: SubExpr ( Box :: new ( LpExpression :: EmptyExpr ) , Box :: new ( LpExpression :: LitVal ( 1f32 ) ) ) ) , Box :: new ( LpExpression :: AddExpr ( Box :: new ( LpExpression :: ConsCont ( LpContinuous { name : \"x\" . to_string ( ) , lower_bound : None , upper_bound : None } ) ) , Box :: new ( LpExpression :: ConsInt ( LpInteger { name : \"y\" . to_string ( ) , lower_bound : None , upper_bound : None } ) ) ) ) )";
  assert_eq!(full_exp_quoted.to_string(), full_exp_str);

  // a.equal(&b);
  let a_eq_b = LpConstraint( SubExpr( Box::new ( ConsInt ( LpInteger { name : "a" . to_string ( ) , lower_bound : None , upper_bound : None } ) ) , Box::new ( ConsInt ( LpInteger { name : "b" . to_string ( ) , lower_bound : None , upper_bound : None } ) ) ) , Constraint::Equal , LitVal(0f32));

  let quoted_a_eq_b = quote!(#a_eq_b);
  let a_eq_b_str = "LpConstraint ( LpExpression :: SubExpr ( Box :: new ( LpExpression :: ConsInt ( LpInteger { name : \"a\" . to_string ( ) , lower_bound : None , upper_bound : None } ) ) , Box :: new ( LpExpression :: ConsInt ( LpInteger { name : \"b\" . to_string ( ) , lower_bound : None , upper_bound : None } ) ) ) , Constraint :: Equal , LpExpression :: LitVal ( 0f32 ) )";
  assert_eq!(quoted_a_eq_b.to_string(), a_eq_b_str)
}
<commit_msg>fix test<commit_after>extern crate lp_modeler;
extern crate quote;
use quote::quote;

use lp_modeler::dsl::*;

#[test]
fn test_quotations() {
  use LpExpression::*;
  let a = LpInteger { name : "a" . to_string () , lower_bound : None , upper_bound : None };
  let quoted_a = quote!(#a);
  let quoted_a_str = "LpInteger { name : \"a\" . to_string () , lower_bound : None , upper_bound : None }";
  assert_eq!(quoted_a.to_string(), quoted_a_str);

  let exp : LpExpression = a.clone().into();
  let quoted_exp = quote!(#exp);
  let quoted_exp_str = "LpExpression :: ConsInt (".to_owned() + quoted_a_str + ")";
  assert_eq!(quoted_exp.to_string(), quoted_exp_str);

  let full_exp = LpExpression::MulExpr ( Box::new ( LpExpression::SubExpr ( Box::new ( LpExpression::EmptyExpr ) , Box::new ( LpExpression::LitVal ( 1f32 ) ) ) ) , Box::new ( LpExpression::AddExpr ( Box::new ( LpExpression::ConsCont ( LpContinuous { name : "x".to_string() , lower_bound : None , upper_bound : None } ) ) , Box::new ( LpExpression::ConsInt ( LpInteger { name : "y".to_string() , lower_bound : None , upper_bound : None } ) ) ) ) );

  let full_exp_quoted = quote!(#full_exp);
  let full_exp_str = "LpExpression :: MulExpr (Box :: new (LpExpression :: SubExpr (Box :: new (LpExpression :: EmptyExpr) , Box :: new (LpExpression :: LitVal (1f32)))) , Box :: new (LpExpression :: AddExpr (Box :: new (LpExpression :: ConsCont (LpContinuous { name : \"x\" . to_string () , lower_bound : None , upper_bound : None })) , Box :: new (LpExpression :: ConsInt (LpInteger { name : \"y\" . to_string () , lower_bound : None , upper_bound : None })))))";
  assert_eq!(full_exp_quoted.to_string(), full_exp_str);

  // a.equal(&b);
  let a_eq_b = LpConstraint( SubExpr( Box::new ( ConsInt ( LpInteger { name : "a" . to_string ( ) , lower_bound : None , upper_bound : None } ) ) , Box::new ( ConsInt ( LpInteger { name : "b" . to_string ( ) , lower_bound : None , upper_bound : None } ) ) ) , Constraint::Equal , LitVal(0f32));

  let quoted_a_eq_b = quote!(#a_eq_b);
  let a_eq_b_str = "LpConstraint (LpExpression :: SubExpr (Box :: new (LpExpression :: ConsInt (LpInteger { name : \"a\" . to_string () , lower_bound : None , upper_bound : None })) , Box :: new (LpExpression :: ConsInt (LpInteger { name : \"b\" . to_string () , lower_bound : None , upper_bound : None }))) , Constraint :: Equal , LpExpression :: LitVal (0f32))";
  assert_eq!(quoted_a_eq_b.to_string(), a_eq_b_str)
}
<|endoftext|>


<commit_before>use std::env;
use std::process::{Command, Stdio};
use std::path::{Path, PathBuf};
use std::io::{Read, Write};
use std::fs::{File, copy};

extern crate nom_bibtex;
use nom_bibtex::Bibtex;

extern crate tempdir;
use tempdir::TempDir;

mod text;

fn read_file(filename: &str) -> Vec<u8> {
    let mut file = File::open(filename).unwrap();
    let mut content = Vec::new();
    file.read_to_end(&mut content).unwrap();

    content
}

fn get_bin_dir() -> PathBuf {
    env::current_exe()
        .expect("test bin's directory")
        .parent()
        .expect("test bin's parent directory")
        .parent()
        .expect("executable's directory")
        .to_path_buf()
}

fn cmd_aux2bib() -> Command {
    let path = if cfg!(not(windows)) {
        get_bin_dir().join("aux2bib")
    } else {
        get_bin_dir().join("aux2bib.exe")
    };
    if !path.is_file() {
        panic!("aux2bib binary {:?} was not found", path);
    }
    let mut cmd = Command::new(path);
    cmd.env_clear()
        .stderr(Stdio::piped())
        .stdout(Stdio::piped());

    cmd
}

fn cmd_blg2bib() -> Command {
    let path = if cfg!(not(windows)) {
        get_bin_dir().join("blg2bib")
    } else {
        get_bin_dir().join("blg2bib.exe")
    };
    if !path.is_file() {
        panic!("blg2bib binary {:?} was not found", path);
    }
    let mut cmd = Command::new(path);
    cmd.env_clear()
        .stderr(Stdio::piped())
        .stdout(Stdio::piped());

    cmd
}

fn check_output_aux_bibtex(bibtex: &Bibtex) {
    let bib = bibtex.bibliographies();
    assert_eq!(2, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Higgs:2014aqa");
    assert_eq!(
        bib[0].tags()[0],
        ("author".into(), "Higgs, Peter W.".into())
    );
    assert_eq!(
        bib[0].tags()[1],
        (
            "title".into(),
            "{Nobel Lecture: Evading the Goldstone theorem}".into(),
        )
    );
    assert_eq!(bib[0].tags()[4], ("year".into(), "2014".into()));

    assert_eq!(bib[1].entry_type(), "article");
    assert_eq!(bib[1].citation_key(), "Higgs:2015mei");
    assert_eq!(bib[1].tags()[0], ("author".into(), "Higgs, P. W.".into()));
    assert_eq!(
        bib[1].tags()[1],
        ("title".into(), "{Evading the Goldstone theorem}".into(),)
    );
    assert_eq!(bib[1].tags()[4], ("year".into(), "2015".into()));
}

fn check_output_aux_biblatex(bibtex: &Bibtex) {
    let bib = bibtex.bibliographies();
    assert_eq!(4, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Guth:1980zm");
    assert_eq!(bib[0].tags()[0], ("author".into(), "Guth, Alan H.".into()));
    assert_eq!(bib[0].tags()[1], (
        "title".into(),
        "{The Inflationary Universe: A Possible Solution to the\n                        Horizon and Flatness Problems}"
            .into(),
    ));
    assert_eq!(bib[0].tags()[4], ("year".into(), "1981".into()));

    assert_eq!(bib[3].entry_type(), "ARTICLE");
    assert_eq!(bib[3].citation_key(), "1982PhRvL..48.1220A");
    assert_eq!(
        bib[3].tags()[1],
        (
            "title".into(),
            "{Cosmology for grand unified theories with radiatively induced symmetry breaking}"
                .into(),
        )
    );
    assert_eq!(bib[3].tags()[4], ("year".into(), "1982".into()));
}

fn check_output_blg_bibtex(bibtex: &Bibtex) {
    let bib = bibtex.bibliographies();
    assert_eq!(2, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Higgs:2014aqa");
    assert_eq!(
        bib[0].tags()[0],
        ("author".into(), "Higgs, Peter W.".into())
    );
    assert_eq!(
        bib[0].tags()[1],
        (
            "title".into(),
            "{Nobel Lecture: Evading the Goldstone theorem}".into(),
        )
    );
    assert_eq!(bib[0].tags()[4], ("year".into(), "2014".into()));

    assert_eq!(bib[1].entry_type(), "article");
    assert_eq!(bib[1].citation_key(), "Higgs:2015mei");
    assert_eq!(bib[1].tags()[0], ("author".into(), "Higgs, P. W.".into()));
    assert_eq!(
        bib[1].tags()[1],
        ("title".into(), "{Evading the Goldstone theorem}".into(),)
    );
    assert_eq!(bib[1].tags()[4], ("year".into(), "2015".into()));
}

fn check_output_blg_biblatex(bibtex: &Bibtex) {
    let bib = bibtex.bibliographies();
    assert_eq!(4, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Guth:1980zm");
    assert_eq!(bib[0].tags()[0], ("author".into(), "Guth, Alan H.".into()));
    assert_eq!(bib[0].tags()[1], (
        "title".into(),
        "{The Inflationary Universe: A Possible Solution to the\n                        Horizon and Flatness Problems}"
            .into(),
    ));
    assert_eq!(bib[0].tags()[4], ("year".into(), "1981".into()));

    assert_eq!(bib[3].entry_type(), "ARTICLE");
    assert_eq!(bib[3].citation_key(), "1982PhRvL..48.1220A");
    assert_eq!(
        bib[3].tags()[1],
        (
            "title".into(),
            "{Cosmology for grand unified theories with radiatively induced symmetry breaking}"
                .into(),
        )
    );
    assert_eq!(bib[3].tags()[4], ("year".into(), "1982".into()));
}

#[cfg(not(windows))]
#[test]
fn aux2bib_runs() {
    let mut cmd = cmd_aux2bib()
        .arg("--help")
        .spawn()
        .expect("Failed to execute aux2bib");

    let error_code = cmd.wait().expect("Failed to wait on aux2bib");

    assert!(error_code.success());
}

#[cfg(not(windows))]
#[test]
fn blg2bib_runs() {
    let mut cmd = cmd_blg2bib()
        .arg("--help")
        .spawn()
        .expect("Failed to execute blg2bib");

    let error_code = cmd.wait().expect("Failed to wait on blg2bib");

    assert!(error_code.success());
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_stdout_empty() {
    let mut child = cmd_aux2bib()
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    {
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(b"").expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());
    assert_eq!(output.stdout, []);
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_stdout_empty() {
    let mut child = cmd_blg2bib()
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute blg2bib");

    {
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(b"").expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());
    assert_eq!(output.stdout, []);
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_stdout_bibtex() {
    let mut child = cmd_aux2bib()
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    {
        let input = read_file("example_files/test_bibtex.aux");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());

    let bibtex = Bibtex::parse(std::str::from_utf8(&output.stdout).unwrap())
        .expect("Valid bibtex file content");

    check_output_aux_bibtex(&bibtex);
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_stdout_biblatex() {
    let mut child = cmd_aux2bib()
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    {
        let input = read_file("example_files/test_biber.aux");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());

    let bibtex_raw = &[
        text::MONTH_STRINGS,
        std::str::from_utf8(&output.stdout).unwrap(),
    ].join("\n");
    let bibtex = Bibtex::parse(bibtex_raw).expect("Valid bibtex file content");

    check_output_aux_biblatex(&bibtex);
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_stdout_bibtex() {
    let mut child = cmd_blg2bib()
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    {
        let input = read_file("example_files/test_bibtex.blg");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());

    let bibtex = Bibtex::parse(std::str::from_utf8(&output.stdout).unwrap())
        .expect("Valid bibtex file content");

    check_output_blg_bibtex(&bibtex);
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_stdout_biblatex() {
    let mut child = cmd_blg2bib()
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute blg2bib");

    {
        let input = read_file("example_files/test_biber.blg");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());

    let bibtex_raw = &[
        text::MONTH_STRINGS,
        std::str::from_utf8(&output.stdout).unwrap(),
    ].join("\n");
    let bibtex = Bibtex::parse(bibtex_raw).expect("Valid bibtex file content");

    check_output_blg_biblatex(&bibtex);
}

#[cfg(not(windows))]
#[test]
fn aux2bib_file_stdout_bibtex() {
    let filename_in = "test_bibtex.aux";

    let tmp_dir = TempDir::new("inspirer_test").expect("Failed to create tmp_dir");
    copy(
        Path::new("example_files").join(filename_in),
        tmp_dir.path().join(filename_in),
    ).expect("Failed to copy test input");

    let child = cmd_aux2bib()
        .current_dir(tmp_dir.path())
        .arg(filename_in)
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());

    let bibtex = Bibtex::parse(std::str::from_utf8(&output.stdout).unwrap())
        .expect("Valid bibtex file content");

    check_output_aux_bibtex(&bibtex);
}

#[cfg(not(windows))]
#[test]
// Test for panic when the input file does not exist
fn aux2bib_file_stdout_bibtex_input_no_exist() {
    let filename_in = "test_bibtex.aux";

    let tmp_dir = TempDir::new("inspirer_test").expect("Failed to create tmp_dir");

    let child = cmd_aux2bib()
        .current_dir(tmp_dir.path())
        .arg(filename_in)
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert_eq!(output.status.code().expect("Process exited"), 1);
    // Check that there is nothing written to stdout
    assert_eq!(output.stdout, []);
}

#[cfg(not(windows))]
#[test]
fn aux2bib_file_file_bibtex() {
    let filename_in = "test_bibtex.aux";
    let filename_out = "autobib.bib";

    let tmp_dir = TempDir::new("inspirer_test").expect("Failed to create tmp_dir");
    copy(
        Path::new("example_files").join(filename_in),
        tmp_dir.path().join(filename_in),
    ).expect("Failed to copy test input");

    let child = cmd_aux2bib()
        .current_dir(tmp_dir.path())
        .arg(filename_in)
        .arg(filename_out)
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");
    assert!(output.status.success());
    // Check that there is nothing written to stdout
    assert_eq!(output.stdout, []);

    let mut output = Vec::new();
    let mut output_file = File::open(tmp_dir.path().join(filename_out))
        .expect("Output file not written");
    output_file
        .read_to_end(&mut output)
        .expect("Failed to read output file");

    let bibtex = Bibtex::parse(std::str::from_utf8(&output).unwrap())
        .expect("Valid bibtex file content");

    check_output_aux_bibtex(&bibtex);
}
<commit_msg>tests: Print more output from integration tests<commit_after>use std::env;
use std::process::{Command, Stdio};
use std::path::{Path, PathBuf};
use std::io::{Read, Write};
use std::fs::{copy, File};

extern crate nom_bibtex;
use nom_bibtex::Bibtex;

extern crate tempdir;
use tempdir::TempDir;

mod text;

fn read_file(filename: &str) -> Vec<u8> {
    let mut file = File::open(filename).unwrap();
    let mut content = Vec::new();
    file.read_to_end(&mut content).unwrap();

    content
}

fn get_bin_dir() -> PathBuf {
    env::current_exe()
        .expect("test bin's directory")
        .parent()
        .expect("test bin's parent directory")
        .parent()
        .expect("executable's directory")
        .to_path_buf()
}

fn cmd_aux2bib() -> Command {
    let path = if cfg!(not(windows)) {
        get_bin_dir().join("aux2bib")
    } else {
        get_bin_dir().join("aux2bib.exe")
    };
    if !path.is_file() {
        panic!("aux2bib binary {:?} was not found", path);
    }
    let mut cmd = Command::new(path);
    cmd.env_clear()
        .stderr(Stdio::piped())
        .stdout(Stdio::piped());

    cmd
}

fn cmd_blg2bib() -> Command {
    let path = if cfg!(not(windows)) {
        get_bin_dir().join("blg2bib")
    } else {
        get_bin_dir().join("blg2bib.exe")
    };
    if !path.is_file() {
        panic!("blg2bib binary {:?} was not found", path);
    }
    let mut cmd = Command::new(path);
    cmd.env_clear()
        .stderr(Stdio::piped())
        .stdout(Stdio::piped());

    cmd
}

fn check_output_aux_bibtex(bibtex: &Bibtex) {
    let bib = bibtex.bibliographies();
    assert_eq!(2, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Higgs:2014aqa");
    assert_eq!(
        bib[0].tags()[0],
        ("author".into(), "Higgs, Peter W.".into())
    );
    assert_eq!(
        bib[0].tags()[1],
        (
            "title".into(),
            "{Nobel Lecture: Evading the Goldstone theorem}".into(),
        )
    );
    assert_eq!(bib[0].tags()[4], ("year".into(), "2014".into()));

    assert_eq!(bib[1].entry_type(), "article");
    assert_eq!(bib[1].citation_key(), "Higgs:2015mei");
    assert_eq!(bib[1].tags()[0], ("author".into(), "Higgs, P. W.".into()));
    assert_eq!(
        bib[1].tags()[1],
        ("title".into(), "{Evading the Goldstone theorem}".into(),)
    );
    assert_eq!(bib[1].tags()[4], ("year".into(), "2015".into()));
}

fn check_output_aux_biblatex(bibtex: &Bibtex) {
    let bib = bibtex.bibliographies();
    assert_eq!(4, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Guth:1980zm");
    assert_eq!(bib[0].tags()[0], ("author".into(), "Guth, Alan H.".into()));
    assert_eq!(bib[0].tags()[1], (
        "title".into(),
        "{The Inflationary Universe: A Possible Solution to the\n                        Horizon and Flatness Problems}"
            .into(),
    ));
    assert_eq!(bib[0].tags()[4], ("year".into(), "1981".into()));

    assert_eq!(bib[3].entry_type(), "ARTICLE");
    assert_eq!(bib[3].citation_key(), "1982PhRvL..48.1220A");
    assert_eq!(
        bib[3].tags()[1],
        (
            "title".into(),
            "{Cosmology for grand unified theories with radiatively induced symmetry breaking}"
                .into(),
        )
    );
    assert_eq!(bib[3].tags()[4], ("year".into(), "1982".into()));
}

fn check_output_blg_bibtex(bibtex: &Bibtex) {
    let bib = bibtex.bibliographies();
    assert_eq!(2, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Higgs:2014aqa");
    assert_eq!(
        bib[0].tags()[0],
        ("author".into(), "Higgs, Peter W.".into())
    );
    assert_eq!(
        bib[0].tags()[1],
        (
            "title".into(),
            "{Nobel Lecture: Evading the Goldstone theorem}".into(),
        )
    );
    assert_eq!(bib[0].tags()[4], ("year".into(), "2014".into()));

    assert_eq!(bib[1].entry_type(), "article");
    assert_eq!(bib[1].citation_key(), "Higgs:2015mei");
    assert_eq!(bib[1].tags()[0], ("author".into(), "Higgs, P. W.".into()));
    assert_eq!(
        bib[1].tags()[1],
        ("title".into(), "{Evading the Goldstone theorem}".into(),)
    );
    assert_eq!(bib[1].tags()[4], ("year".into(), "2015".into()));
}

fn check_output_blg_biblatex(bibtex: &Bibtex) {
    let bib = bibtex.bibliographies();
    assert_eq!(4, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Guth:1980zm");
    assert_eq!(bib[0].tags()[0], ("author".into(), "Guth, Alan H.".into()));
    assert_eq!(bib[0].tags()[1], (
        "title".into(),
        "{The Inflationary Universe: A Possible Solution to the\n                        Horizon and Flatness Problems}"
            .into(),
    ));
    assert_eq!(bib[0].tags()[4], ("year".into(), "1981".into()));

    assert_eq!(bib[3].entry_type(), "ARTICLE");
    assert_eq!(bib[3].citation_key(), "1982PhRvL..48.1220A");
    assert_eq!(
        bib[3].tags()[1],
        (
            "title".into(),
            "{Cosmology for grand unified theories with radiatively induced symmetry breaking}"
                .into(),
        )
    );
    assert_eq!(bib[3].tags()[4], ("year".into(), "1982".into()));
}

#[cfg(not(windows))]
#[test]
fn aux2bib_runs() {
    let mut child = cmd_aux2bib()
        .arg("--help")
        .spawn()
        .expect("Failed to execute aux2bib");

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    println!("{:?}", output);
    assert!(output.status.success());
}

#[cfg(not(windows))]
#[test]
fn blg2bib_runs() {
    let mut child = cmd_blg2bib()
        .arg("--help")
        .spawn()
        .expect("Failed to execute blg2bib");

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    println!("{:?}", output);
    assert!(output.status.success());
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_stdout_empty() {
    let mut child = cmd_aux2bib()
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    {
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(b"").expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    println!("{:?}", output);
    assert!(output.status.success());
    assert_eq!(output.stdout, []);
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_stdout_empty() {
    let mut child = cmd_blg2bib()
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute blg2bib");

    {
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(b"").expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    println!("{:?}", output);
    assert!(output.status.success());
    assert_eq!(output.stdout, []);
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_stdout_bibtex() {
    let mut child = cmd_aux2bib()
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    {
        let input = read_file("example_files/test_bibtex.aux");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    println!("{:?}", output);
    assert!(output.status.success());

    let bibtex = Bibtex::parse(std::str::from_utf8(&output.stdout).unwrap())
        .expect("Valid bibtex file content");

    check_output_aux_bibtex(&bibtex);
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_stdout_biblatex() {
    let mut child = cmd_aux2bib()
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    {
        let input = read_file("example_files/test_biber.aux");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    println!("{:?}", output);
    assert!(output.status.success());

    let bibtex_raw = &[
        text::MONTH_STRINGS,
        std::str::from_utf8(&output.stdout).unwrap(),
    ].join("\n");
    let bibtex = Bibtex::parse(bibtex_raw).expect("Valid bibtex file content");

    check_output_aux_biblatex(&bibtex);
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_stdout_bibtex() {
    let mut child = cmd_blg2bib()
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    {
        let input = read_file("example_files/test_bibtex.blg");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    println!("{:?}", output);
    assert!(output.status.success());

    let bibtex = Bibtex::parse(std::str::from_utf8(&output.stdout).unwrap())
        .expect("Valid bibtex file content");

    check_output_blg_bibtex(&bibtex);
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_stdout_biblatex() {
    let mut child = cmd_blg2bib()
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute blg2bib");

    {
        let input = read_file("example_files/test_biber.blg");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    println!("{:?}", output);
    assert!(output.status.success());

    let bibtex_raw = &[
        text::MONTH_STRINGS,
        std::str::from_utf8(&output.stdout).unwrap(),
    ].join("\n");
    let bibtex = Bibtex::parse(bibtex_raw).expect("Valid bibtex file content");

    check_output_blg_biblatex(&bibtex);
}

#[cfg(not(windows))]
#[test]
fn aux2bib_file_stdout_bibtex() {
    let filename_in = "test_bibtex.aux";

    let tmp_dir = TempDir::new("inspirer_test").expect("Failed to create tmp_dir");
    copy(
        Path::new("example_files").join(filename_in),
        tmp_dir.path().join(filename_in),
    ).expect("Failed to copy test input");

    let child = cmd_aux2bib()
        .current_dir(tmp_dir.path())
        .arg(filename_in)
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    println!("{:?}", output);
    assert!(output.status.success());

    let bibtex = Bibtex::parse(std::str::from_utf8(&output.stdout).unwrap())
        .expect("Valid bibtex file content");

    check_output_aux_bibtex(&bibtex);
}

#[cfg(not(windows))]
#[test]
// Test for panic when the input file does not exist
fn aux2bib_file_stdout_bibtex_input_no_exist() {
    let filename_in = "test_bibtex.aux";

    let tmp_dir = TempDir::new("inspirer_test").expect("Failed to create tmp_dir");

    let child = cmd_aux2bib()
        .current_dir(tmp_dir.path())
        .arg(filename_in)
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    println!("{:?}", output);
    assert_eq!(output.status.code().expect("Process exited"), 1);
    // Check that there is nothing written to stdout
    assert_eq!(output.stdout, []);
}

#[cfg(not(windows))]
#[test]
fn aux2bib_file_file_bibtex() {
    let filename_in = "test_bibtex.aux";
    let filename_out = "autobib.bib";

    let tmp_dir = TempDir::new("inspirer_test").expect("Failed to create tmp_dir");
    copy(
        Path::new("example_files").join(filename_in),
        tmp_dir.path().join(filename_in),
    ).expect("Failed to copy test input");

    let child = cmd_aux2bib()
        .current_dir(tmp_dir.path())
        .arg(filename_in)
        .arg(filename_out)
        .stdin(Stdio::piped())
        .spawn()
        .expect("Failed to execute aux2bib");

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");
    println!("{:?}", output);
    assert!(output.status.success());
    // Check that there is nothing written to stdout
    assert_eq!(output.stdout, []);

    let mut output = Vec::new();
    let mut output_file =
        File::open(tmp_dir.path().join(filename_out)).expect("Output file not written");
    output_file
        .read_to_end(&mut output)
        .expect("Failed to read output file");

    let bibtex =
        Bibtex::parse(std::str::from_utf8(&output).unwrap()).expect("Valid bibtex file content");

    check_output_aux_bibtex(&bibtex);
}
<|endoftext|>